1 /*****************************************************************************
4 ** Name: sgp.cpp Simple Graphics Package
5 ** Programmer: Kevin Rosenberg
7 ** This is part of the CTSim program
8 ** Copyright (C) 1983-2000 Kevin Rosenberg
10 ** $Id: sgp.cpp,v 1.9 2000/08/02 18:06:00 kevin Exp $
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.
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.
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 ******************************************************************************/
28 #include "ctsupport.h"
32 RGBColor SGP::s_aRGBColor[] =
37 RGBColor (0, 128, 128),
39 RGBColor (128, 0, 128),
40 RGBColor (128, 128, 0),
41 RGBColor (80, 80, 80),
42 RGBColor (160, 160, 160),
45 RGBColor (0, 255, 255),
47 RGBColor (255, 0, 255),
48 RGBColor (255, 255, 0),
49 RGBColor (255, 255, 255),
52 int SGP::s_iRGBColorCount = sizeof(s_aRGBColor) / sizeof(class RGBColor);
55 SGPDriver::SGPDriver (wxDC* pDC, int xsize = 640, int ysize = 480)
56 : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_idDriver(0)
59 m_idDriver |= SGPDRIVER_WXWINDOWS;
63 SGPDriver::SGPDriver (const char* szWinTitle = "", int xsize = 640, int ysize = 480)
64 : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
67 m_idG2 = g2_open_X11X (m_iPhysicalXSize, m_iPhysicalYSize, 10, 10, const_cast<char*>(szWinTitle), const_cast<char*>(szWinTitle), NULL, -1, -1);
68 m_idDriver |= SGPDRIVER_G2;
72 SGPDriver::~SGPDriver ()
80 // SGP::SGP Constructor for Simple Graphics Package
82 SGP::SGP (const SGPDriver& driver)
85 m_iPhysicalXSize = m_driver.getPhysicalXSize();
86 m_iPhysicalYSize = m_driver.getPhysicalYSize();
88 wc_to_ndc.setIdentity ();
89 mc_to_ndc.setIdentity();
90 ndc_to_mc.setIdentity();
93 setWindow (0., 0., 1., 1.);
94 setViewport (0., 0., 1., 1.);
96 stylusNDC (0., 0., false);
99 setTextSize (1. / 25.);
105 SGP::stylusNDC (double x, double y, bool beam)
107 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
108 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
110 yp = m_iPhysicalYSize - yp;
115 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
119 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
122 m_iCurrentPhysicalX = xp;
123 m_iCurrentPhysicalY = yp;
127 SGP::markerNDC (double x, double y)
132 SGP::pointNDC (double x, double y)
138 // clear Clear Window
145 g2_clear (m_driver.idG2());
149 m_driver.idWX()->Clear();
154 // sgp2_window Set window in world coordinates
158 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
160 if (xmin >= xmax || ymin >= ymax) {
161 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
169 m_bRecalcTransform = true;
174 // sgp2_viewport Set viewport in NDC
177 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
179 if (xmin >= xmax || ymin >= ymax) {
180 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
188 m_bRecalcTransform = true;
190 viewNDC[0] = xmin; // Array for clip_rect()
198 // frameViewport draw box around viewport
201 SGP::frameViewport (void)
203 stylusNDC (xv_min, yv_min, 0);
204 stylusNDC (xv_max, yv_min, 1);
205 stylusNDC (xv_max, yv_max, 1);
206 stylusNDC (xv_min, yv_max, 1);
207 stylusNDC (xv_min, yv_min, 1);
211 SGP::setTextColor (int iFGcolor, int iBGcolor)
216 SGP::setColor (int icol)
218 if (icol >= 0 && icol < s_iRGBColorCount) {
220 if (m_driver.isG2()) {
221 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
222 g2_pen (m_driver.idG2(), iInk);
226 if (m_driver.isWX()) {
227 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
228 wxPen pen (colour, 1, wxSOLID);
229 m_driver.idWX()->SetPen (pen);
236 SGP::setRasterOp (int ro)
239 if (m_driver.isWX()) {
246 wxFxn = wxAND_INVERT;
249 wxFxn = wxAND_REVERSE;
279 wxFxn = wxOR_REVERSE;
285 wxFxn = wxSRC_INVERT;
292 m_driver.idWX()->SetLogicalFunction (wxFxn);
299 SGP::setMarker (int idMarke, int iColor)
303 //==============================================================
304 // set line style. Pass 16 bit repeating pattern
305 //==============================================================
307 SGP::setLineStyle (int style)
311 //==============================================================
313 //*==============================================================
316 SGP::lineAbs (double x, double y)
318 if (m_bRecalcTransform)
321 double x1 = m_dCurrentWorldX;
322 double y1 = m_dCurrentWorldY;
323 mc_to_ndc.transformPoint (&x1, &y1);
327 mc_to_ndc.transformPoint (&x2, &y2);
329 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
330 stylusNDC (x1, y1, 0); // move to first point
331 stylusNDC (x2, y2, 1); // draw to second point
334 m_dCurrentWorldX = x;
335 m_dCurrentWorldY = y;
339 SGP::moveAbs (double x, double y)
341 m_dCurrentWorldX = x;
342 m_dCurrentWorldY = y; /* moves are not clipped */
346 SGP::lineRel (double x, double y)
348 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
352 SGP::moveRel (double x, double y)
354 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
358 SGP::setTextSize (double height)
361 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
365 SGP::setTextAngle (double angle)
367 m_dTextAngle = angle;
371 SGP::polylineAbs (double x[], double y[], int n)
373 if (m_bRecalcTransform)
376 double x1 = x[0], y1 = y[0];
377 mc_to_ndc.transformPoint (&x1, &y1);
378 double x2 = x[1], y2 = y[1];
379 mc_to_ndc.transformPoint (&x2, &y2);
381 double xt = x2; // don't pass (x2,y2) to clip, we need them
382 double yt = y2; // as the beginning point of the next line
384 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
385 stylusNDC (x1, y1, 0);
386 stylusNDC (xt, yt, 1);
389 for (int i = 2; i < n; i++) {
390 x1 = x2; y1 = y2; // NDC endpoint of last line
391 x2 = x[i]; y2 = y[i];
392 mc_to_ndc.transformPoint (&x2, &y2);
395 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
396 stylusNDC (x1, y1, 0);
397 stylusNDC (xt, yt, 1);
404 SGP::markerAbs (double x, double y)
406 if (m_bRecalcTransform)
411 mc_to_ndc.transformPoint (&xndc, &yndc);
412 markerNDC (xndc, yndc);
413 stylusNDC (xndc, yndc, false); // move to location
414 m_dCurrentWorldX = x;
415 m_dCurrentWorldY = y;
420 SGP::markerRel (double x, double y)
422 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
427 SGP::pointAbs (double x, double y)
429 if (m_bRecalcTransform)
431 double xndc = x, yndc = y;
432 mc_to_ndc.transformPoint (&xndc, &yndc);
433 pointNDC (xndc, yndc);
434 stylusNDC (xndc, yndc, false); // move to location
435 m_dCurrentWorldX = x;
436 m_dCurrentWorldY = y;
441 SGP::pointRel (double x, double y)
443 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
448 SGP::drawText (const string& rsMessage)
450 drawText (rsMessage.c_str());
454 SGP::drawText (const char *pszMessage)
456 if (m_bRecalcTransform)
459 double xndc = m_dCurrentWorldX;
460 double yndc = m_dCurrentWorldY;
461 mc_to_ndc.transformPoint (&xndc, &yndc);
463 stylusNDC (xndc, yndc, false); // move to location
466 if (m_driver.isG2()) {
467 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
471 if (m_driver.isWX()) {
472 wxString str (pszMessage);
473 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
480 // drawRect Draw box in graphics mode
483 // drawbox (xmin, ymin, xmax, ymax)
484 // double xmin, ymin Lower left corner of box
485 // double xmax, ymax Upper left corner of box
488 // This routine leaves the current position of graphic cursor at lower
489 // left corner of box.
492 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
494 moveAbs (xmin, ymin);
495 lineAbs (xmax, ymin);
496 lineAbs (xmax, ymax);
497 lineAbs (xmin, ymax);
498 lineAbs (xmin, ymin);
502 // sgp2_circle - draw circle of radius r at current center
505 SGP::drawCircle (const double r)
507 drawArc (0.0, 7.0, r);
510 // =============================================================
511 // draw arc around current center. pass angles and radius
512 //==============================================================
515 SGP::drawArc (double start, double stop, const double r)
517 if ((stop-start) > 2 * PI)
518 stop = start + 2 * PI;
519 if ((start-stop) > 2 * PI)
520 stop = start + 2 * PI;
521 while (start >= stop)
524 double x = r * cos ((double) start);
525 double y = r * sin ((double) start);
526 moveRel (x, y); // move from center to start of arc
528 double theta = 5 * PI / 180;
529 double c = cos(theta);
530 double s = sin(theta);
532 double angle, xp, yp;
533 for (angle = start; angle < stop - theta; angle += theta) {
536 lineRel (xp - x, yp - y);
540 c = cos (stop - angle);
541 s = sin (stop - angle);
544 lineRel (xp - x, yp - y);
546 x = r * cos ((double) stop);
547 y = r * sin ((double) stop);
548 moveRel (-x, -y); // move back to center of circle
553 ///////////////////////////////////////////////////////////////////////
554 // Coordinate Transformations
555 ///////////////////////////////////////////////////////////////////////
559 SGP::transformNDCtoMC (double* x, double* y)
561 if (m_bRecalcTransform)
563 ndc_to_mc.transformPoint (x, y);
568 SGP::transformMCtoNDC (double* x, double* y)
570 if (m_bRecalcTransform)
572 mc_to_ndc.transformPoint (x, y);
577 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
579 if (m_bRecalcTransform)
583 mc_to_ndc.transformPoint (x, y);
588 // calc_transform Calculate transform matrices
591 SGP::calc_transform ()
593 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
594 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
596 wc_to_ndc.setIdentity();
597 wc_to_ndc.mtx[0][0] = scaleX;
598 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
599 wc_to_ndc.mtx[1][1] = scaleY;
600 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
602 mc_to_ndc = m_ctm * wc_to_ndc;
603 ndc_to_mc = mc_to_ndc.invert();
605 m_bRecalcTransform = false;
616 SGP::ctmSet (const TransformationMatrix2D& m)
624 SGP::preTranslate (double x, double y)
626 TransformationMatrix2D m;
628 m.setTranslate (x, y);
634 SGP::postTranslate (double x, double y)
636 TransformationMatrix2D m;
638 m.setTranslate (x, y);
644 SGP::preScale (double sx, double sy)
646 TransformationMatrix2D m;
654 SGP::postScale (double sx, double sy)
656 TransformationMatrix2D m;
665 SGP::preRotate (double theta)
667 TransformationMatrix2D m;
676 SGP::postRotate (double theta)
678 TransformationMatrix2D m;
686 SGP::preShear (double shrx, double shry)
688 TransformationMatrix2D m;
690 m.setShear (shrx, shry);
696 SGP::postShear (double shrx, double shry)
698 TransformationMatrix2D m;
700 m.setShear (shrx, shry);
705 ////////////////////////////////////////////////////////////////////////
707 ////////////////////////////////////////////////////////////////////////
709 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
710 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
712 {'\000', '\000', '\010', '\000', '\000'}, // small dot
713 {'\000', '\034', '\024', '\034', '\000'}, // empty square
714 {'\000', '\034', '\034', '\034', '\000'}, // filled square
715 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
716 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
717 {'\010', '\010', '\076', '\010', '\010'}, // cross
718 {'\000', '\024', '\010', '\024', '\000'}, // X
719 {'\034', '\042', '\042', '\042', '\034'}, // open circle
720 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
721 {'\076', '\042', '\042', '\042', '\076'}, // big open square
722 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond