r292: *** empty log message ***
[ctsim.git] / libctgraphics / sgp.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:       sgp.cpp             Simple Graphics Package
5 **      Programmer: Kevin Rosenberg
6 **
7 **  This is part of the CTSim program
8 **  Copyright (C) 1983-2000 Kevin Rosenberg
9 **
10 **  $Id: sgp.cpp,v 1.19 2000/12/18 02:23:43 kevin Exp $
11 **
12 **  This program is free software; you can redistribute it and/or modify
13 **  it under the terms of the GNU General Public License (version 2) as
14 **  published by the Free Software Foundation.
15 **
16 **  This program is distributed in the hope that it will be useful,
17 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 **  GNU General Public License for more details.
20 **
21 **  You should have received a copy of the GNU General Public License
22 **  along with this program; if not, write to the Free Software
23 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 ******************************************************************************/
25
26 #include <stdio.h>
27 #include <math.h>
28 #include "ctsupport.h"
29 #include "sgp.h"
30
31
32 RGBColor SGP::s_aRGBColor[] =
33 {
34   RGBColor (0, 0, 0),
35   RGBColor (0, 0, 128),
36   RGBColor (0, 128, 0),
37   RGBColor (0, 128, 128),
38   RGBColor (128, 0, 0),
39   RGBColor (128, 0, 128),
40   RGBColor (128, 128, 0),
41   RGBColor (80, 80, 80),
42   RGBColor (160, 160, 160),
43   RGBColor (0, 0, 255),
44   RGBColor (0, 255, 0),
45   RGBColor (0, 255, 255),
46   RGBColor (255, 0, 0),
47   RGBColor (255, 0, 255),
48   RGBColor (255, 255, 0),
49   RGBColor (255, 255, 255),
50 };
51
52 int SGP::s_iRGBColorCount = sizeof(s_aRGBColor) / sizeof(class RGBColor);
53
54 #ifdef HAVE_WXWINDOWS
55 SGPDriver::SGPDriver (wxDC* pDC, int xsize, int ysize)
56   : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_idDriver(0), m_pDC(pDC)
57 {
58   m_idDriver |= SGPDRIVER_WXWINDOWS;
59 }
60 #endif
61
62 SGPDriver::SGPDriver (const char* szWinTitle, int xsize, int ysize)
63   : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
64 {
65 #ifdef HAVE_G2_H
66   m_idG2 = g2_open_X11X (m_iPhysicalXSize, m_iPhysicalYSize, 10, 10, const_cast<char*>(szWinTitle), const_cast<char*>(szWinTitle), NULL, -1, -1);
67   m_idDriver |= SGPDRIVER_G2;
68 #endif
69 }
70
71 SGPDriver::~SGPDriver ()
72 {
73 #if HAVE_G2_H
74   if (isG2()) 
75     g2_close (m_idG2);
76 #endif
77 }
78
79
80 // NAME
81 //   SGP::SGP        Constructor for Simple Graphics Package
82
83 SGP::SGP (const SGPDriver& driver)
84   : m_driver (driver)
85 {
86   m_iPhysicalXSize = m_driver.getPhysicalXSize();
87   m_iPhysicalYSize = m_driver.getPhysicalYSize();
88
89   wc_to_ndc.setIdentity ();
90   mc_to_ndc.setIdentity();
91   ndc_to_mc.setIdentity();
92   m_ctm.setIdentity();
93
94 #if HAVE_WXWINDOWS
95   m_pen.SetWidth(1);
96   m_pen.SetStyle(wxSOLID);
97
98   if (m_driver.isWX()) {
99     static const double dScreenDPI = 82;
100     static const double dPointsPerInch = 72.;
101     m_dPointsPerPixel = dPointsPerInch / dScreenDPI;
102     const int iTestPointSize = 72;
103     m_font.SetPointSize (iTestPointSize);
104     m_driver.idWX()->SetFont(m_font);
105     double dTestCharHeight = m_driver.idWX()->GetCharHeight();
106     m_dPointsPerPixel = iTestPointSize / dTestCharHeight;\r
107         m_driver.idWX()->SetBrush (*wxWHITE_BRUSH);
108   }
109 #endif
110
111   setWindow (0., 0., 1., 1.);
112   setViewport (0., 0., 1., 1.);
113   moveAbs (0., 0.);
114   stylusNDC (0., 0., false);
115   
116   setTextAngle (0.);
117   setTextPointSize (12);
118   setColor (C_BLACK);
119 }
120
121
122 void
123 SGP::stylusNDC (double x, double y, bool beam)
124 {
125   int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
126   int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
127   if (m_driver.isWX())
128     yp = m_iPhysicalYSize - yp;
129
130   if (beam) {
131 #if HAVE_WXWINDOWS
132     if (m_driver.isWX())
133       m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
134 #endif
135 #if HAVE_G2_H
136     if (m_driver.isG2())
137       g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
138 #endif
139   }
140   m_iCurrentPhysicalX = xp;
141   m_iCurrentPhysicalY = yp;
142 }
143
144 void
145 SGP::markerNDC (double x, double y)
146 {
147 }
148
149 void
150 SGP::pointNDC (double x, double y)
151 {
152 }
153
154
155 // NAME
156 //    clear     Clear Window
157
158 void 
159 SGP::eraseWindow ()
160 {
161 #if HAVE_G2_H
162   if (m_driver.isG2())
163     g2_clear (m_driver.idG2());
164 #endif
165 #if HAVE_WXWINDOWS
166   if (m_driver.isWX())
167     m_driver.idWX()->Clear();
168 #endif
169 }
170
171 // NAME
172 //      sgp2_window             Set window in world coordinates
173  
174
175 void
176 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
177 {
178   if (xmin >= xmax || ymin >= ymax) {
179     sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
180     return;
181   }
182   
183   xw_min = xmin;
184   yw_min = ymin;
185   xw_max = xmax;
186   yw_max = ymax;
187   m_bRecalcTransform = true;
188 }
189
190
191 // NAME
192 //      sgp2_viewport                   Set viewport in NDC
193
194 void
195 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
196 {
197   if (xmin >= xmax || ymin >= ymax) {
198     sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
199     return;
200   }
201     
202   xv_min = xmin;
203   yv_min = ymin;
204   xv_max = xmax;
205   yv_max = ymax;
206   m_bRecalcTransform = true;
207   
208   viewNDC[0] = xmin;                    // Array for clip_rect() 
209   viewNDC[1] = ymin;
210   viewNDC[2] = xmax;
211   viewNDC[3] = ymax;
212 }
213
214 void
215 SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax)
216 {
217     xmin = xv_min;
218     ymin = yv_min;
219     xmax = xv_max;
220     ymax = yv_max;
221 }
222
223 void
224 SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax)
225 {
226     xmin = xw_min;
227     ymin = yw_min;
228     xmax = xw_max;
229     ymax = yw_max;
230 }
231
232
233 // NAME
234 //      frameViewport           draw box around viewport
235
236 void
237 SGP::frameViewport (void)
238 {
239   stylusNDC (xv_min, yv_min, false);
240   stylusNDC (xv_max, yv_min, true);
241   stylusNDC (xv_max, yv_max, true);
242   stylusNDC (xv_min, yv_max, true);
243   stylusNDC (xv_min, yv_min, true);
244 }
245
246 void
247 SGP::setTextColor (int iFGcolor, int iBGcolor)
248 {
249 #if HAVE_WXWINDOWS
250   if (m_driver.isWX()) {
251     if (iFGcolor >= 0) {
252       wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
253       m_driver.idWX()->SetTextForeground (colour);
254     }
255     if (iBGcolor >= 0) {
256       wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
257       m_driver.idWX()->SetTextBackground (colour);
258     }
259   }
260 #endif
261 }
262
263 void 
264 SGP::setColor (int icol)
265 {
266   if (icol >= 0 && icol < s_iRGBColorCount) {
267 #if HAVE_G2_H
268     if (m_driver.isG2()) {
269       int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
270       g2_pen (m_driver.idG2(), iInk);
271     }
272 #endif
273 #if HAVE_WXWINDOWS
274     if (m_driver.isWX()) {
275       wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
276       m_pen.SetColour (colour);
277       m_driver.idWX()->SetPen (m_pen);
278     }
279 #endif
280   }
281 }
282
283 void 
284 SGP::setPenWidth (int iWidth)
285 {
286   if (iWidth >= 0) {
287 #if HAVE_WXWINDOWS
288     if (m_driver.isWX()) {
289       m_pen.SetWidth (iWidth);
290       m_driver.idWX()->SetPen (m_pen);
291     }
292 #endif
293   }
294 }
295
296 void
297 SGP::setRasterOp (int ro)
298 {
299 #if HAVE_WXWINDOWS
300   if (m_driver.isWX()) {
301     int wxFxn = -1;
302     switch (ro) {
303     case RO_AND:
304       wxFxn = wxAND;
305       break;
306     case RO_AND_INVERT:
307       wxFxn = wxAND_INVERT;
308       break;
309     case RO_AND_REVERSE:
310       wxFxn = wxAND_REVERSE;
311       break;
312     case RO_CLEAR:
313       wxFxn = wxCLEAR;
314       break;
315     case RO_COPY:
316       wxFxn = wxCOPY;
317       break;
318     case RO_EQUIV:
319       wxFxn = wxEQUIV;
320       break;
321     case RO_INVERT:
322       wxFxn = wxINVERT;
323       break;
324     case RO_NAND:
325       wxFxn = wxNAND;
326       break;
327     case RO_NOR:
328       wxFxn = wxNOR;
329       break;
330     case RO_NO_OP:
331       wxFxn = wxNO_OP;
332       break;
333     case RO_OR:
334       wxFxn = wxOR;
335       break;
336     case RO_OR_INVERT:
337       wxFxn = wxOR_INVERT;
338       break;
339     case RO_OR_REVERSE:
340       wxFxn = wxOR_REVERSE;
341       break;
342     case RO_SET:
343       wxFxn = wxSET;
344       break;
345     case RO_SRC_INVERT:
346       wxFxn = wxSRC_INVERT;
347       break;
348     case RO_XOR:
349       wxFxn = wxXOR;
350       break;
351     }
352     if (wxFxn >= 0)
353       m_driver.idWX()->SetLogicalFunction (wxFxn);
354   }
355 #endif
356 }
357
358
359 void
360 SGP::setMarker (int idMarke, int iColor)
361 {
362 }
363
364 //==============================================================
365 // set line style.  Pass 16 bit repeating pattern               
366 //==============================================================
367 void 
368 SGP::setLineStyle (int style)
369 {
370 }
371
372 //==============================================================
373 // absolute draw to                                             
374 //*==============================================================
375
376 void 
377 SGP::lineAbs (double x, double y)
378 {
379   if (m_bRecalcTransform)
380     calc_transform();
381
382   double x1 = m_dCurrentWorldX;
383   double y1 = m_dCurrentWorldY;
384   mc_to_ndc.transformPoint (&x1, &y1);
385
386   double x2 = x;
387   double y2 = y;
388   mc_to_ndc.transformPoint (&x2, &y2);
389   
390   if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport 
391     stylusNDC (x1, y1, false);  // move to first point
392     stylusNDC (x2, y2, true);  // draw to second point 
393   }
394
395   m_dCurrentWorldX = x;
396   m_dCurrentWorldY = y;
397 }
398
399 void 
400 SGP::moveAbs (double x, double y)
401 {
402     m_dCurrentWorldX = x;
403     m_dCurrentWorldY = y;                       /* moves are not clipped */
404 }
405
406 void 
407 SGP::lineRel (double x, double y)
408 {
409   lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
410 }
411
412 void 
413 SGP::moveRel (double x, double y)
414 {
415   moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
416 }
417
418
419 // Height is in master coordinates
420 void
421 SGP::setTextSize (double height)
422 {
423     height /= (xw_max - xw_min);
424 #if HAVE_G2_H
425   if (m_driver.isG2())
426     g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
427 #endif
428 #if HAVE_WXWINDOWS
429   if (m_driver.isWX()) {
430       double dHeightPixels = height * m_iPhysicalYSize;
431       double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
432       m_font.SetPointSize (nearest<int>(dHeightPoints));
433       m_driver.idWX()->SetFont (m_font);
434   }
435 #endif
436 }
437
438 void
439 SGP::setTextNDCSize (double height)
440 {
441     double dHeightPixels = height * m_iPhysicalYSize;
442 #if HAVE_G2_H
443   if (m_driver.isG2())
444     g2_set_font_size(m_driver.idG2(), nearest<int>(dHeightPixels));
445 #endif
446 #if HAVE_WXWINDOWS
447   if (m_driver.isWX()) {
448       double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
449       m_font.SetPointSize (nearest<int>(dHeightPoints));
450       m_driver.idWX()->SetFont (m_font);
451   }
452 #endif
453 }
454
455 void
456 SGP::setTextPointSize (double height)
457 {
458 #if HAVE_G2_H
459     //  if (m_driver.isG2())
460     //    g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
461 #endif
462 #if HAVE_WXWINDOWS
463   if (m_driver.isWX()) {
464       m_font.SetPointSize (static_cast<int>(height+0.5));
465       m_driver.idWX()->SetFont (m_font);
466   }
467 #endif
468 }
469
470 void
471 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
472 {
473 #if HAVE_WXWINDOWS
474   if (m_driver.isWX()) {
475     wxString sText (szText);
476     wxCoord deviceW, deviceH;
477     m_driver.idWX()->GetTextExtent (sText, &deviceW, &deviceH);
478     *worldW = static_cast<double>(deviceW) / static_cast<double>(m_iPhysicalXSize);;
479     *worldH = static_cast<double>(deviceH) / static_cast<double>(m_iPhysicalYSize);
480     *worldW *= (xw_max - xw_min);
481     *worldH *= (yw_max - yw_min);
482   }
483 #endif
484 }
485
486 double
487 SGP::getCharHeight ()
488 {
489   double dHeight = (1. / 25.);
490
491 #if HAVE_WXWINDOWS
492   if (m_driver.isWX()) {
493     dHeight = m_driver.idWX()->GetCharHeight();
494     dHeight /= static_cast<double>(m_iPhysicalYSize);
495   }
496 #endif
497   dHeight *= (yw_max - yw_min);
498   return dHeight;
499 }
500
501 double
502 SGP::getCharWidth ()
503 {
504   double dWidth = (1. / 80.);
505
506 #if HAVE_WXWINDOWS
507   if (m_driver.isWX()) {
508     dWidth = m_driver.idWX()->GetCharWidth();
509     dWidth /= static_cast<double>(m_iPhysicalXSize);
510   }
511 #endif
512   dWidth *= (xw_max - xw_min);
513   return dWidth;
514 }
515
516 void
517 SGP::setTextAngle (double angle)
518 {
519   m_dTextAngle = convertRadiansToDegrees(angle);
520 }
521
522 void 
523 SGP::polylineAbs (double x[], double y[], int n)
524 {
525   if (m_bRecalcTransform)
526     calc_transform();
527
528   double x1 = x[0], y1 = y[0];
529   mc_to_ndc.transformPoint (&x1, &y1);
530   double x2 = x[1], y2 = y[1];
531   mc_to_ndc.transformPoint (&x2, &y2);
532
533   double xt = x2;       // don't pass (x2,y2) to clip, we need them 
534   double yt = y2;       // as the beginning point of the next line 
535
536   if (clip_rect (x1, y1, xt, yt, viewNDC)) {
537     stylusNDC (x1, y1, false);
538     stylusNDC (xt, yt, true);
539   }
540   
541   for (int i = 2; i < n; i++) {
542     x1 = x2; y1 = y2;                   // NDC endpoint of last line 
543     x2 = x[i];  y2 = y[i];
544     mc_to_ndc.transformPoint (&x2, &y2);
545     xt = x2;
546     yt = y2;
547     if (clip_rect (x1, y1, xt, yt, viewNDC)) {
548       stylusNDC (x1, y1, false);
549       stylusNDC (xt, yt, true);
550     }
551   }
552 }
553
554
555 void 
556 SGP::markerAbs (double x, double y)
557 {
558   if (m_bRecalcTransform)
559     calc_transform();
560
561   double xndc = x;
562   double yndc = y;
563   mc_to_ndc.transformPoint (&xndc, &yndc);
564   markerNDC (xndc, yndc); 
565   stylusNDC (xndc, yndc, false);            // move to location 
566   m_dCurrentWorldX = x;
567   m_dCurrentWorldY = y;
568 }
569
570
571 void 
572 SGP::markerRel (double x, double y)
573 {
574   markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
575 }
576
577
578 void 
579 SGP::pointAbs (double x, double y)
580 {
581   if (m_bRecalcTransform)
582     calc_transform();
583   double xndc = x, yndc = y;
584   mc_to_ndc.transformPoint (&xndc, &yndc);
585   pointNDC (xndc, yndc);
586   stylusNDC (xndc, yndc, false);            // move to location 
587   m_dCurrentWorldX = x;
588   m_dCurrentWorldY = y;
589 }
590
591
592 void 
593 SGP::pointRel (double x, double y)
594 {
595   pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
596 }
597
598
599 void
600 SGP::drawText (const std::string& rsMessage)
601 {
602   drawText (rsMessage.c_str());
603 }
604
605 void 
606 SGP::drawText (const char *pszMessage)
607 {
608   if (m_bRecalcTransform)
609     calc_transform();
610
611   double xndc = m_dCurrentWorldX;
612   double yndc = m_dCurrentWorldY;
613   mc_to_ndc.transformPoint (&xndc, &yndc);
614
615   stylusNDC (xndc, yndc, false);            // move to location 
616
617 #if HAVE_G2_H
618   if (m_driver.isG2()) {
619     g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
620   }
621 #endif
622 #if HAVE_WXWINDOWS
623   if (m_driver.isWX()) {
624     wxString str (pszMessage);
625     m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
626   }
627 #endif
628 }
629
630
631 // NAME
632 //   drawRect                           Draw box in graphics mode
633 //
634 // SYNOPSIS
635 //   drawbox (xmin, ymin, xmax, ymax)
636 //   double xmin, ymin                  Lower left corner of box
637 //   double xmax, ymax                  Upper left corner of box
638 //
639 // NOTES
640 //   This routine leaves the current position of graphic cursor at lower
641 //   left corner of box.
642
643 void
644 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
645 {
646         moveAbs (xmin, ymin);
647         lineAbs (xmax, ymin);
648         lineAbs (xmax, ymax);
649         lineAbs (xmin, ymax);
650         lineAbs (xmin, ymin);
651 }
652
653 // FUNCTION
654 // sgp2_circle - draw circle of radius r at current center              
655  
656 void 
657 SGP::drawCircle (const double r)
658 {
659         drawArc (r, 0.0, TWOPI);
660 }
661
662 //==============================================================
663 // draw arc around current center.  angles in radius    
664 //==============================================================
665
666 void 
667 SGP::drawArc (const double r, double start, double stop)
668 {
669   if (start > stop) {
670     double temp = start;
671     start = stop;
672     stop = temp;
673   }
674
675   double x = r * cos ((double) start);
676   double y = r * sin ((double) start);
677   moveRel (x, y);          // move from center to start of arc 
678
679   const double thetaIncrement = (5 * (TWOPI / 360)); 
680   double cosTheta = cos(thetaIncrement);
681   double sinTheta = sin(thetaIncrement);
682
683   double angle, xp, yp;
684   for (angle = start; angle < stop - thetaIncrement; angle += thetaIncrement) {
685     xp = cosTheta * x - sinTheta * y; // translate point by thetaIncrement
686     yp = sinTheta * x + cosTheta * y;
687     lineAbs (xp, yp);
688     x = xp; y = yp;
689   }
690
691   double c = cos (stop - angle);
692   double s = sin (stop - angle);
693   xp = c * x - s * y;
694   yp = s * x + c * y;
695   lineAbs (xp, yp);
696
697   x = r * cos (stop);
698   y = r * sin (stop);
699   moveRel (-x, -y);             // move back to center of circle 
700 }
701
702
703
704 ///////////////////////////////////////////////////////////////////////
705 // Coordinate Transformations
706 ///////////////////////////////////////////////////////////////////////
707
708
709 void
710 SGP::transformNDCtoMC (double* x, double* y)
711 {
712   if (m_bRecalcTransform)
713     calc_transform();
714   ndc_to_mc.transformPoint (x, y);
715 }
716
717
718 void
719 SGP::transformMCtoNDC (double* x, double* y)
720 {
721   if (m_bRecalcTransform)
722     calc_transform();
723   mc_to_ndc.transformPoint (x, y);
724 }
725
726
727 void
728 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
729 {
730   if (m_bRecalcTransform)
731     calc_transform();
732   *x = xIn;
733   *y = yIn;
734   mc_to_ndc.transformPoint (x, y);
735 }
736
737
738 // NAME
739 //      calc_transform                  Calculate transform matrices
740
741 void
742 SGP::calc_transform ()
743 {
744   double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
745   double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
746     
747   wc_to_ndc.setIdentity();
748   wc_to_ndc.mtx[0][0] = scaleX;
749   wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
750   wc_to_ndc.mtx[1][1] = scaleY;
751   wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
752
753   mc_to_ndc = m_ctm * wc_to_ndc;
754   ndc_to_mc = mc_to_ndc.invert();
755
756   m_bRecalcTransform = false;
757 }
758
759 void
760 SGP::ctmClear ()
761 {
762   m_ctm.setIdentity();
763   calc_transform();
764 }
765
766 void 
767 SGP::ctmSet (const TransformationMatrix2D& m)
768 {
769   m_ctm = m;
770   calc_transform();
771 }
772
773
774 void
775 SGP::preTranslate  (double x, double y)
776 {
777     TransformationMatrix2D m;
778
779     m.setTranslate (x, y);
780     ctmSet (m * m_ctm);
781 }
782
783
784 void 
785 SGP::postTranslate (double x, double y)
786 {
787     TransformationMatrix2D m;
788
789     m.setTranslate (x, y);
790     ctmSet (m_ctm * m);
791 }
792
793
794 void 
795 SGP::preScale (double sx, double sy)
796 {
797     TransformationMatrix2D m;
798
799     m.setScale (sx, sy);
800     ctmSet (m * m_ctm);
801 }
802
803
804 void 
805 SGP::postScale (double sx, double sy)
806 {
807     TransformationMatrix2D m;
808
809     m.setScale (sx, sy);
810     m_ctm = m_ctm * m;
811     ctmSet (m_ctm * m);
812 }
813
814
815 void 
816 SGP::preRotate (double theta)
817 {
818     TransformationMatrix2D m;
819
820     m.setRotate (theta);
821     m_ctm = m * m_ctm;
822     ctmSet (m * m_ctm);
823 }
824
825
826 void 
827 SGP::postRotate (double theta)
828 {
829     TransformationMatrix2D m;
830
831     m.setRotate (theta);
832     ctmSet (m_ctm * m);
833 }
834
835
836 void 
837 SGP::preShear (double shrx, double shry)
838 {
839     TransformationMatrix2D m;
840
841     m.setShear (shrx, shry);
842     ctmSet (m * m_ctm);
843 }
844
845
846 void 
847 SGP::postShear (double shrx, double shry)
848 {
849     TransformationMatrix2D m;
850
851     m.setShear (shrx, shry);
852     ctmSet (m_ctm * m);
853 }
854
855
856 ////////////////////////////////////////////////////////////////////////
857 //  Bitmap Markers
858 ////////////////////////////////////////////////////////////////////////
859
860 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
861 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] = 
862 {
863     {'\000', '\000', '\010', '\000', '\000'},    // small dot 
864     {'\000', '\034', '\024', '\034', '\000'},    // empty square 
865     {'\000', '\034', '\034', '\034', '\000'},    // filled square 
866     {'\000', '\010', '\024', '\010', '\000'},    // empty diamond 
867     {'\000', '\010', '\034', '\010', '\000'},    // filled diamond 
868     {'\010', '\010', '\076', '\010', '\010'},    // cross 
869     {'\000', '\024', '\010', '\024', '\000'},    // X 
870     {'\034', '\042', '\042', '\042', '\034'},    // open circle 
871     {'\034', '\076', '\076', '\076', '\034'},    // filled circle 
872     {'\076', '\042', '\042', '\042', '\076'},    // big open square 
873     {'\010', '\024', '\042', '\024', '\010'},    // big open diamond 
874 };
875
876
877 #if HAVE_WXWINDOWS
878 void
879 SGP::setDC (wxDC* pDC)
880 {
881   if (m_driver.isWX())
882     m_driver.setDC(pDC);
883 }
884 #endif