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.12 2000/08/31 08:38:58 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), m_pDC(pDC)
58 m_idDriver |= SGPDRIVER_WXWINDOWS;
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)
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;
71 SGPDriver::~SGPDriver ()
79 // SGP::SGP Constructor for Simple Graphics Package
81 SGP::SGP (const SGPDriver& driver)
84 m_iPhysicalXSize = m_driver.getPhysicalXSize();
85 m_iPhysicalYSize = m_driver.getPhysicalYSize();
87 wc_to_ndc.setIdentity ();
88 mc_to_ndc.setIdentity();
89 ndc_to_mc.setIdentity();
94 m_pen.SetStyle(wxSOLID);
97 setWindow (0., 0., 1., 1.);
98 setViewport (0., 0., 1., 1.);
100 stylusNDC (0., 0., false);
103 setTextSize (1. / 25.);
109 SGP::stylusNDC (double x, double y, bool beam)
111 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
112 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
114 yp = m_iPhysicalYSize - yp;
119 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
123 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
126 m_iCurrentPhysicalX = xp;
127 m_iCurrentPhysicalY = yp;
131 SGP::markerNDC (double x, double y)
136 SGP::pointNDC (double x, double y)
142 // clear Clear Window
149 g2_clear (m_driver.idG2());
153 m_driver.idWX()->Clear();
158 // sgp2_window Set window in world coordinates
162 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
164 if (xmin >= xmax || ymin >= ymax) {
165 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
173 m_bRecalcTransform = true;
178 // sgp2_viewport Set viewport in NDC
181 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
183 if (xmin >= xmax || ymin >= ymax) {
184 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
192 m_bRecalcTransform = true;
194 viewNDC[0] = xmin; // Array for clip_rect()
201 SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax)
211 // frameViewport draw box around viewport
214 SGP::frameViewport (void)
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);
224 SGP::setTextColor (int iFGcolor, int iBGcolor)
227 if (m_driver.isWX()) {
229 wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
230 m_driver.idWX()->SetTextForeground (colour);
233 wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
234 m_driver.idWX()->SetTextBackground (colour);
241 SGP::setColor (int icol)
243 if (icol >= 0 && icol < s_iRGBColorCount) {
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);
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);
261 SGP::setPenWidth (int iWidth)
265 if (m_driver.isWX()) {
266 m_pen.SetWidth (iWidth);
267 m_driver.idWX()->SetPen (m_pen);
274 SGP::setRasterOp (int ro)
277 if (m_driver.isWX()) {
284 wxFxn = wxAND_INVERT;
287 wxFxn = wxAND_REVERSE;
317 wxFxn = wxOR_REVERSE;
323 wxFxn = wxSRC_INVERT;
330 m_driver.idWX()->SetLogicalFunction (wxFxn);
337 SGP::setMarker (int idMarke, int iColor)
341 //==============================================================
342 // set line style. Pass 16 bit repeating pattern
343 //==============================================================
345 SGP::setLineStyle (int style)
349 //==============================================================
351 //*==============================================================
354 SGP::lineAbs (double x, double y)
356 if (m_bRecalcTransform)
359 double x1 = m_dCurrentWorldX;
360 double y1 = m_dCurrentWorldY;
361 mc_to_ndc.transformPoint (&x1, &y1);
365 mc_to_ndc.transformPoint (&x2, &y2);
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
372 m_dCurrentWorldX = x;
373 m_dCurrentWorldY = y;
377 SGP::moveAbs (double x, double y)
379 m_dCurrentWorldX = x;
380 m_dCurrentWorldY = y; /* moves are not clipped */
384 SGP::lineRel (double x, double y)
386 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
390 SGP::moveRel (double x, double y)
392 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
396 SGP::setTextSize (double height)
399 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
403 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
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);
420 SGP::getCharHeight ()
422 double dHeight = (1. / 25.);
425 if (m_driver.isWX()) {
426 dHeight = m_driver.idWX()->GetCharHeight();
427 dHeight /= static_cast<double>(m_iPhysicalYSize);;
430 return (dHeight * (xw_max - xw_min));
434 SGP::setTextAngle (double angle)
436 m_dTextAngle = angle;
440 SGP::polylineAbs (double x[], double y[], int n)
442 if (m_bRecalcTransform)
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);
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
453 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
454 stylusNDC (x1, y1, false);
455 stylusNDC (xt, yt, true);
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);
464 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
465 stylusNDC (x1, y1, false);
466 stylusNDC (xt, yt, true);
473 SGP::markerAbs (double x, double y)
475 if (m_bRecalcTransform)
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;
489 SGP::markerRel (double x, double y)
491 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
496 SGP::pointAbs (double x, double y)
498 if (m_bRecalcTransform)
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;
510 SGP::pointRel (double x, double y)
512 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
517 SGP::drawText (const string& rsMessage)
519 drawText (rsMessage.c_str());
523 SGP::drawText (const char *pszMessage)
525 if (m_bRecalcTransform)
528 double xndc = m_dCurrentWorldX;
529 double yndc = m_dCurrentWorldY;
530 mc_to_ndc.transformPoint (&xndc, &yndc);
532 stylusNDC (xndc, yndc, false); // move to location
535 if (m_driver.isG2()) {
536 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
540 if (m_driver.isWX()) {
541 wxString str (pszMessage);
542 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
549 // drawRect Draw box in graphics mode
552 // drawbox (xmin, ymin, xmax, ymax)
553 // double xmin, ymin Lower left corner of box
554 // double xmax, ymax Upper left corner of box
557 // This routine leaves the current position of graphic cursor at lower
558 // left corner of box.
561 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
563 moveAbs (xmin, ymin);
564 lineAbs (xmax, ymin);
565 lineAbs (xmax, ymax);
566 lineAbs (xmin, ymax);
567 lineAbs (xmin, ymin);
571 // sgp2_circle - draw circle of radius r at current center
574 SGP::drawCircle (const double r)
576 drawArc (r, 0.0, TWOPI);
579 //==============================================================
580 // draw arc around current center. angles in radius
581 //==============================================================
584 SGP::drawArc (const double r, double start, double stop)
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
596 const double thetaIncrement = (5 * (TWOPI / 360));
597 double cosTheta = cos(thetaIncrement);
598 double sinTheta = sin(thetaIncrement);
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;
608 double c = cos (stop - angle);
609 double s = sin (stop - angle);
616 moveRel (-x, -y); // move back to center of circle
621 ///////////////////////////////////////////////////////////////////////
622 // Coordinate Transformations
623 ///////////////////////////////////////////////////////////////////////
627 SGP::transformNDCtoMC (double* x, double* y)
629 if (m_bRecalcTransform)
631 ndc_to_mc.transformPoint (x, y);
636 SGP::transformMCtoNDC (double* x, double* y)
638 if (m_bRecalcTransform)
640 mc_to_ndc.transformPoint (x, y);
645 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
647 if (m_bRecalcTransform)
651 mc_to_ndc.transformPoint (x, y);
656 // calc_transform Calculate transform matrices
659 SGP::calc_transform ()
661 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
662 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
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;
670 mc_to_ndc = m_ctm * wc_to_ndc;
671 ndc_to_mc = mc_to_ndc.invert();
673 m_bRecalcTransform = false;
684 SGP::ctmSet (const TransformationMatrix2D& m)
692 SGP::preTranslate (double x, double y)
694 TransformationMatrix2D m;
696 m.setTranslate (x, y);
702 SGP::postTranslate (double x, double y)
704 TransformationMatrix2D m;
706 m.setTranslate (x, y);
712 SGP::preScale (double sx, double sy)
714 TransformationMatrix2D m;
722 SGP::postScale (double sx, double sy)
724 TransformationMatrix2D m;
733 SGP::preRotate (double theta)
735 TransformationMatrix2D m;
744 SGP::postRotate (double theta)
746 TransformationMatrix2D m;
754 SGP::preShear (double shrx, double shry)
756 TransformationMatrix2D m;
758 m.setShear (shrx, shry);
764 SGP::postShear (double shrx, double shry)
766 TransformationMatrix2D m;
768 m.setShear (shrx, shry);
773 ////////////////////////////////////////////////////////////////////////
775 ////////////////////////////////////////////////////////////////////////
777 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
778 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
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
796 SGP::setDC (wxDC* pDC)