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