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.13 2000/09/02 05:10:39 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)
210 SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax)
220 // frameViewport draw box around viewport
223 SGP::frameViewport (void)
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);
233 SGP::setTextColor (int iFGcolor, int iBGcolor)
236 if (m_driver.isWX()) {
238 wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
239 m_driver.idWX()->SetTextForeground (colour);
242 wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
243 m_driver.idWX()->SetTextBackground (colour);
250 SGP::setColor (int icol)
252 if (icol >= 0 && icol < s_iRGBColorCount) {
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);
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);
270 SGP::setPenWidth (int iWidth)
274 if (m_driver.isWX()) {
275 m_pen.SetWidth (iWidth);
276 m_driver.idWX()->SetPen (m_pen);
283 SGP::setRasterOp (int ro)
286 if (m_driver.isWX()) {
293 wxFxn = wxAND_INVERT;
296 wxFxn = wxAND_REVERSE;
326 wxFxn = wxOR_REVERSE;
332 wxFxn = wxSRC_INVERT;
339 m_driver.idWX()->SetLogicalFunction (wxFxn);
346 SGP::setMarker (int idMarke, int iColor)
350 //==============================================================
351 // set line style. Pass 16 bit repeating pattern
352 //==============================================================
354 SGP::setLineStyle (int style)
358 //==============================================================
360 //*==============================================================
363 SGP::lineAbs (double x, double y)
365 if (m_bRecalcTransform)
368 double x1 = m_dCurrentWorldX;
369 double y1 = m_dCurrentWorldY;
370 mc_to_ndc.transformPoint (&x1, &y1);
374 mc_to_ndc.transformPoint (&x2, &y2);
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
381 m_dCurrentWorldX = x;
382 m_dCurrentWorldY = y;
386 SGP::moveAbs (double x, double y)
388 m_dCurrentWorldX = x;
389 m_dCurrentWorldY = y; /* moves are not clipped */
393 SGP::lineRel (double x, double y)
395 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
399 SGP::moveRel (double x, double y)
401 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
405 SGP::setTextSize (double height)
408 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
412 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
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);
429 SGP::getCharHeight ()
431 double dHeight = (1. / 25.);
434 if (m_driver.isWX()) {
435 dHeight = m_driver.idWX()->GetCharHeight();
436 dHeight /= static_cast<double>(m_iPhysicalYSize);;
439 return (dHeight * (xw_max - xw_min));
443 SGP::setTextAngle (double angle)
445 m_dTextAngle = angle;
449 SGP::polylineAbs (double x[], double y[], int n)
451 if (m_bRecalcTransform)
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);
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
462 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
463 stylusNDC (x1, y1, false);
464 stylusNDC (xt, yt, true);
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);
473 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
474 stylusNDC (x1, y1, false);
475 stylusNDC (xt, yt, true);
482 SGP::markerAbs (double x, double y)
484 if (m_bRecalcTransform)
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;
498 SGP::markerRel (double x, double y)
500 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
505 SGP::pointAbs (double x, double y)
507 if (m_bRecalcTransform)
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;
519 SGP::pointRel (double x, double y)
521 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
526 SGP::drawText (const string& rsMessage)
528 drawText (rsMessage.c_str());
532 SGP::drawText (const char *pszMessage)
534 if (m_bRecalcTransform)
537 double xndc = m_dCurrentWorldX;
538 double yndc = m_dCurrentWorldY;
539 mc_to_ndc.transformPoint (&xndc, &yndc);
541 stylusNDC (xndc, yndc, false); // move to location
544 if (m_driver.isG2()) {
545 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
549 if (m_driver.isWX()) {
550 wxString str (pszMessage);
551 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
558 // drawRect Draw box in graphics mode
561 // drawbox (xmin, ymin, xmax, ymax)
562 // double xmin, ymin Lower left corner of box
563 // double xmax, ymax Upper left corner of box
566 // This routine leaves the current position of graphic cursor at lower
567 // left corner of box.
570 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
572 moveAbs (xmin, ymin);
573 lineAbs (xmax, ymin);
574 lineAbs (xmax, ymax);
575 lineAbs (xmin, ymax);
576 lineAbs (xmin, ymin);
580 // sgp2_circle - draw circle of radius r at current center
583 SGP::drawCircle (const double r)
585 drawArc (r, 0.0, TWOPI);
588 //==============================================================
589 // draw arc around current center. angles in radius
590 //==============================================================
593 SGP::drawArc (const double r, double start, double stop)
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
605 const double thetaIncrement = (5 * (TWOPI / 360));
606 double cosTheta = cos(thetaIncrement);
607 double sinTheta = sin(thetaIncrement);
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;
617 double c = cos (stop - angle);
618 double s = sin (stop - angle);
625 moveRel (-x, -y); // move back to center of circle
630 ///////////////////////////////////////////////////////////////////////
631 // Coordinate Transformations
632 ///////////////////////////////////////////////////////////////////////
636 SGP::transformNDCtoMC (double* x, double* y)
638 if (m_bRecalcTransform)
640 ndc_to_mc.transformPoint (x, y);
645 SGP::transformMCtoNDC (double* x, double* y)
647 if (m_bRecalcTransform)
649 mc_to_ndc.transformPoint (x, y);
654 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
656 if (m_bRecalcTransform)
660 mc_to_ndc.transformPoint (x, y);
665 // calc_transform Calculate transform matrices
668 SGP::calc_transform ()
670 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
671 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
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;
679 mc_to_ndc = m_ctm * wc_to_ndc;
680 ndc_to_mc = mc_to_ndc.invert();
682 m_bRecalcTransform = false;
693 SGP::ctmSet (const TransformationMatrix2D& m)
701 SGP::preTranslate (double x, double y)
703 TransformationMatrix2D m;
705 m.setTranslate (x, y);
711 SGP::postTranslate (double x, double y)
713 TransformationMatrix2D m;
715 m.setTranslate (x, y);
721 SGP::preScale (double sx, double sy)
723 TransformationMatrix2D m;
731 SGP::postScale (double sx, double sy)
733 TransformationMatrix2D m;
742 SGP::preRotate (double theta)
744 TransformationMatrix2D m;
753 SGP::postRotate (double theta)
755 TransformationMatrix2D m;
763 SGP::preShear (double shrx, double shry)
765 TransformationMatrix2D m;
767 m.setShear (shrx, shry);
773 SGP::postShear (double shrx, double shry)
775 TransformationMatrix2D m;
777 m.setShear (shrx, shry);
782 ////////////////////////////////////////////////////////////////////////
784 ////////////////////////////////////////////////////////////////////////
786 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
787 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
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
805 SGP::setDC (wxDC* pDC)