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.21 2000/12/18 06:32:13 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, int ysize)
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, int ysize)
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 ()
81 // SGP::SGP Constructor for Simple Graphics Package
83 SGP::SGP (const SGPDriver& driver)
86 m_iPhysicalXSize = m_driver.getPhysicalXSize();
87 m_iPhysicalYSize = m_driver.getPhysicalYSize();
89 wc_to_ndc.setIdentity ();
90 mc_to_ndc.setIdentity();
91 ndc_to_mc.setIdentity();
96 m_pen.SetStyle(wxSOLID);
98 if (m_driver.isWX()) {
99 static const double dScreenDPI = 82;
100 static const double dPointsPerInch = 72.;
101 m_dPointsPerPixel = dPointsPerInch / dScreenDPI;
102 const int iTestPointSize = 12;
103 m_font.SetPointSize (iTestPointSize);
104 m_driver.idWX()->SetFont(m_font);
105 double dTestCharHeight = m_driver.idWX()->GetCharHeight();
106 m_dPointsPerPixel = iTestPointSize / dTestCharHeight;
\r
107 // wxWHITE_BRUSH->SetColour (255, 255, 255);
\r
108 // wxWHITE_BRUSH->SetStyle (wxSOLID);
\r
109 m_driver.idWX()->SetBackground (*wxWHITE_BRUSH);
113 setWindow (0., 0., 1., 1.);
114 setViewport (0., 0., 1., 1.);
116 stylusNDC (0., 0., false);
119 setTextPointSize (12);
125 SGP::stylusNDC (double x, double y, bool beam)
127 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
128 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
130 yp = m_iPhysicalYSize - yp;
135 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
139 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
142 m_iCurrentPhysicalX = xp;
143 m_iCurrentPhysicalY = yp;
147 SGP::markerNDC (double x, double y)
152 SGP::pointNDC (double x, double y)
158 // clear Clear Window
165 g2_clear (m_driver.idG2());
168 if (m_driver.isWX()) {
\r
169 wxBrush brushWhite;
\r
170 brushWhite.SetColour(255,255,255);
\r
171 m_driver.idWX()->SetBackground(brushWhite);
\r
172 m_driver.idWX()->Clear();
\r
173 m_driver.idWX()->SetBackground(wxNullBrush);
\r
176 pen.SetColour(255,255,255);
\r
177 m_driver.idWX()->SetBrush (brushWhite);
\r
178 m_driver.idWX()->DrawRectangle (0, 0, m_iPhysicalXSize, m_iPhysicalYSize);
\r
179 m_driver.idWX()->SetBrush (wxNullBrush);
\r
186 // sgp2_window Set window in world coordinates
190 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
192 if (xmin >= xmax || ymin >= ymax) {
193 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
201 m_bRecalcTransform = true;
206 // sgp2_viewport Set viewport in NDC
209 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
211 if (xmin >= xmax || ymin >= ymax) {
212 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
220 m_bRecalcTransform = true;
222 viewNDC[0] = xmin; // Array for clip_rect()
229 SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax)
238 SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax)
248 // frameViewport draw box around viewport
251 SGP::frameViewport (void)
253 stylusNDC (xv_min, yv_min, false);
254 stylusNDC (xv_max, yv_min, true);
255 stylusNDC (xv_max, yv_max, true);
256 stylusNDC (xv_min, yv_max, true);
257 stylusNDC (xv_min, yv_min, true);
261 SGP::setTextColor (int iFGcolor, int iBGcolor)
264 if (m_driver.isWX()) {
266 wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
267 m_driver.idWX()->SetTextForeground (colour);
270 wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
271 m_driver.idWX()->SetTextBackground (colour);
278 SGP::setColor (int icol)
280 if (icol >= 0 && icol < s_iRGBColorCount) {
282 if (m_driver.isG2()) {
283 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
284 g2_pen (m_driver.idG2(), iInk);
288 if (m_driver.isWX()) {
289 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
290 m_pen.SetColour (colour);
291 m_driver.idWX()->SetPen (m_pen);
298 SGP::setPenWidth (int iWidth)
302 if (m_driver.isWX()) {
303 m_pen.SetWidth (iWidth);
304 m_driver.idWX()->SetPen (m_pen);
311 SGP::setRasterOp (int ro)
314 if (m_driver.isWX()) {
321 wxFxn = wxAND_INVERT;
324 wxFxn = wxAND_REVERSE;
354 wxFxn = wxOR_REVERSE;
360 wxFxn = wxSRC_INVERT;
367 m_driver.idWX()->SetLogicalFunction (wxFxn);
374 SGP::setMarker (int idMarke, int iColor)
378 //==============================================================
379 // set line style. Pass 16 bit repeating pattern
380 //==============================================================
382 SGP::setLineStyle (int style)
386 //==============================================================
388 //*==============================================================
391 SGP::lineAbs (double x, double y)
393 if (m_bRecalcTransform)
396 double x1 = m_dCurrentWorldX;
397 double y1 = m_dCurrentWorldY;
398 mc_to_ndc.transformPoint (&x1, &y1);
402 mc_to_ndc.transformPoint (&x2, &y2);
404 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
405 stylusNDC (x1, y1, false); // move to first point
406 stylusNDC (x2, y2, true); // draw to second point
409 m_dCurrentWorldX = x;
410 m_dCurrentWorldY = y;
414 SGP::moveAbs (double x, double y)
416 m_dCurrentWorldX = x;
417 m_dCurrentWorldY = y; /* moves are not clipped */
421 SGP::lineRel (double x, double y)
423 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
427 SGP::moveRel (double x, double y)
429 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
433 // Height is in master coordinates
435 SGP::setTextSize (double height)
437 height /= (yw_max - yw_min); // convert to NDC
440 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
443 if (m_driver.isWX()) {
444 double dHeightPixels = height * m_iPhysicalYSize;
445 double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
446 m_font.SetPointSize (nearest<int>(dHeightPoints));
447 m_driver.idWX()->SetFont (m_font);
453 SGP::setTextNDCSize (double height)
455 double dHeightPixels = height * m_iPhysicalYSize;
458 g2_set_font_size(m_driver.idG2(), nearest<int>(dHeightPixels));
461 if (m_driver.isWX()) {
462 double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
463 m_font.SetPointSize (nearest<int>(dHeightPoints));
464 m_driver.idWX()->SetFont (m_font);
470 SGP::setTextPointSize (double height)
473 // if (m_driver.isG2())
474 // g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
477 if (m_driver.isWX()) {
478 m_font.SetPointSize (static_cast<int>(height+0.5));
479 m_driver.idWX()->SetFont (m_font);
485 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
488 if (m_driver.isWX()) {
489 wxString sText (szText);
490 wxCoord deviceW, deviceH;
491 m_driver.idWX()->GetTextExtent (sText, &deviceW, &deviceH);
492 *worldW = static_cast<double>(deviceW) / static_cast<double>(m_iPhysicalXSize);;
493 *worldH = static_cast<double>(deviceH) / static_cast<double>(m_iPhysicalYSize);
494 *worldW *= (xw_max - xw_min);
495 *worldH *= (yw_max - yw_min);
501 SGP::getCharHeight ()
503 double dHeight = (1. / 25.);
506 if (m_driver.isWX()) {
507 dHeight = m_driver.idWX()->GetCharHeight();
508 dHeight /= static_cast<double>(m_iPhysicalYSize);
511 dHeight *= (yw_max - yw_min);
518 double dWidth = (1. / 80.);
521 if (m_driver.isWX()) {
522 dWidth = m_driver.idWX()->GetCharWidth();
523 dWidth /= static_cast<double>(m_iPhysicalXSize);
526 dWidth *= (xw_max - xw_min);
531 SGP::setTextAngle (double angle)
533 m_dTextAngle = convertRadiansToDegrees(angle);
537 SGP::polylineAbs (double x[], double y[], int n)
539 if (m_bRecalcTransform)
542 double x1 = x[0], y1 = y[0];
543 mc_to_ndc.transformPoint (&x1, &y1);
544 double x2 = x[1], y2 = y[1];
545 mc_to_ndc.transformPoint (&x2, &y2);
547 double xt = x2; // don't pass (x2,y2) to clip, we need them
548 double yt = y2; // as the beginning point of the next line
550 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
551 stylusNDC (x1, y1, false);
552 stylusNDC (xt, yt, true);
555 for (int i = 2; i < n; i++) {
556 x1 = x2; y1 = y2; // NDC endpoint of last line
557 x2 = x[i]; y2 = y[i];
558 mc_to_ndc.transformPoint (&x2, &y2);
561 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
562 stylusNDC (x1, y1, false);
563 stylusNDC (xt, yt, true);
570 SGP::markerAbs (double x, double y)
572 if (m_bRecalcTransform)
577 mc_to_ndc.transformPoint (&xndc, &yndc);
578 markerNDC (xndc, yndc);
579 stylusNDC (xndc, yndc, false); // move to location
580 m_dCurrentWorldX = x;
581 m_dCurrentWorldY = y;
586 SGP::markerRel (double x, double y)
588 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
593 SGP::pointAbs (double x, double y)
595 if (m_bRecalcTransform)
597 double xndc = x, yndc = y;
598 mc_to_ndc.transformPoint (&xndc, &yndc);
599 pointNDC (xndc, yndc);
600 stylusNDC (xndc, yndc, false); // move to location
601 m_dCurrentWorldX = x;
602 m_dCurrentWorldY = y;
607 SGP::pointRel (double x, double y)
609 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
614 SGP::drawText (const std::string& rsMessage)
616 drawText (rsMessage.c_str());
620 SGP::drawText (const char *pszMessage)
622 if (m_bRecalcTransform)
625 double xndc = m_dCurrentWorldX;
626 double yndc = m_dCurrentWorldY;
627 mc_to_ndc.transformPoint (&xndc, &yndc);
629 stylusNDC (xndc, yndc, false); // move to location
632 if (m_driver.isG2()) {
633 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
637 if (m_driver.isWX()) {
638 wxString str (pszMessage);
639 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
646 // drawRect Draw box in graphics mode
649 // drawbox (xmin, ymin, xmax, ymax)
650 // double xmin, ymin Lower left corner of box
651 // double xmax, ymax Upper left corner of box
654 // This routine leaves the current position of graphic cursor at lower
655 // left corner of box.
658 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
660 moveAbs (xmin, ymin);
661 lineAbs (xmax, ymin);
662 lineAbs (xmax, ymax);
663 lineAbs (xmin, ymax);
664 lineAbs (xmin, ymin);
668 // sgp2_circle - draw circle of radius r at current center
671 SGP::drawCircle (const double r)
673 drawArc (r, 0.0, TWOPI);
676 //==============================================================
677 // draw arc around current center. angles in radius
678 //==============================================================
681 SGP::drawArc (const double r, double start, double stop)
689 double x = r * cos ((double) start);
690 double y = r * sin ((double) start);
691 moveRel (x, y); // move from center to start of arc
693 const double thetaIncrement = (5 * (TWOPI / 360));
694 double cosTheta = cos(thetaIncrement);
695 double sinTheta = sin(thetaIncrement);
697 double angle, xp, yp;
698 for (angle = start; angle < stop - thetaIncrement; angle += thetaIncrement) {
699 xp = cosTheta * x - sinTheta * y; // translate point by thetaIncrement
700 yp = sinTheta * x + cosTheta * y;
705 double c = cos (stop - angle);
706 double s = sin (stop - angle);
713 moveRel (-x, -y); // move back to center of circle
718 ///////////////////////////////////////////////////////////////////////
719 // Coordinate Transformations
720 ///////////////////////////////////////////////////////////////////////
724 SGP::transformNDCtoMC (double* x, double* y)
726 if (m_bRecalcTransform)
728 ndc_to_mc.transformPoint (x, y);
733 SGP::transformMCtoNDC (double* x, double* y)
735 if (m_bRecalcTransform)
737 mc_to_ndc.transformPoint (x, y);
742 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
744 if (m_bRecalcTransform)
748 mc_to_ndc.transformPoint (x, y);
753 // calc_transform Calculate transform matrices
756 SGP::calc_transform ()
758 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
759 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
761 wc_to_ndc.setIdentity();
762 wc_to_ndc.mtx[0][0] = scaleX;
763 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
764 wc_to_ndc.mtx[1][1] = scaleY;
765 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
767 mc_to_ndc = m_ctm * wc_to_ndc;
768 ndc_to_mc = mc_to_ndc.invert();
770 m_bRecalcTransform = false;
781 SGP::ctmSet (const TransformationMatrix2D& m)
789 SGP::preTranslate (double x, double y)
791 TransformationMatrix2D m;
793 m.setTranslate (x, y);
799 SGP::postTranslate (double x, double y)
801 TransformationMatrix2D m;
803 m.setTranslate (x, y);
809 SGP::preScale (double sx, double sy)
811 TransformationMatrix2D m;
819 SGP::postScale (double sx, double sy)
821 TransformationMatrix2D m;
830 SGP::preRotate (double theta)
832 TransformationMatrix2D m;
841 SGP::postRotate (double theta)
843 TransformationMatrix2D m;
851 SGP::preShear (double shrx, double shry)
853 TransformationMatrix2D m;
855 m.setShear (shrx, shry);
861 SGP::postShear (double shrx, double shry)
863 TransformationMatrix2D m;
865 m.setShear (shrx, shry);
870 ////////////////////////////////////////////////////////////////////////
872 ////////////////////////////////////////////////////////////////////////
874 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
875 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
877 {'\000', '\000', '\010', '\000', '\000'}, // small dot
878 {'\000', '\034', '\024', '\034', '\000'}, // empty square
879 {'\000', '\034', '\034', '\034', '\000'}, // filled square
880 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
881 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
882 {'\010', '\010', '\076', '\010', '\010'}, // cross
883 {'\000', '\024', '\010', '\024', '\000'}, // X
884 {'\034', '\042', '\042', '\042', '\034'}, // open circle
885 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
886 {'\076', '\042', '\042', '\042', '\076'}, // big open square
887 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond
893 SGP::setDC (wxDC* pDC)