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