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