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