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.19 2000/12/18 02:23:43 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 = 72;
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 m_driver.idWX()->SetBrush (*wxWHITE_BRUSH);
111 setWindow (0., 0., 1., 1.);
112 setViewport (0., 0., 1., 1.);
114 stylusNDC (0., 0., false);
117 setTextPointSize (12);
123 SGP::stylusNDC (double x, double y, bool beam)
125 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
126 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
128 yp = m_iPhysicalYSize - yp;
133 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
137 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
140 m_iCurrentPhysicalX = xp;
141 m_iCurrentPhysicalY = yp;
145 SGP::markerNDC (double x, double y)
150 SGP::pointNDC (double x, double y)
156 // clear Clear Window
163 g2_clear (m_driver.idG2());
167 m_driver.idWX()->Clear();
172 // sgp2_window Set window in world coordinates
176 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
178 if (xmin >= xmax || ymin >= ymax) {
179 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
187 m_bRecalcTransform = true;
192 // sgp2_viewport Set viewport in NDC
195 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
197 if (xmin >= xmax || ymin >= ymax) {
198 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
206 m_bRecalcTransform = true;
208 viewNDC[0] = xmin; // Array for clip_rect()
215 SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax)
224 SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax)
234 // frameViewport draw box around viewport
237 SGP::frameViewport (void)
239 stylusNDC (xv_min, yv_min, false);
240 stylusNDC (xv_max, yv_min, true);
241 stylusNDC (xv_max, yv_max, true);
242 stylusNDC (xv_min, yv_max, true);
243 stylusNDC (xv_min, yv_min, true);
247 SGP::setTextColor (int iFGcolor, int iBGcolor)
250 if (m_driver.isWX()) {
252 wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
253 m_driver.idWX()->SetTextForeground (colour);
256 wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
257 m_driver.idWX()->SetTextBackground (colour);
264 SGP::setColor (int icol)
266 if (icol >= 0 && icol < s_iRGBColorCount) {
268 if (m_driver.isG2()) {
269 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
270 g2_pen (m_driver.idG2(), iInk);
274 if (m_driver.isWX()) {
275 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
276 m_pen.SetColour (colour);
277 m_driver.idWX()->SetPen (m_pen);
284 SGP::setPenWidth (int iWidth)
288 if (m_driver.isWX()) {
289 m_pen.SetWidth (iWidth);
290 m_driver.idWX()->SetPen (m_pen);
297 SGP::setRasterOp (int ro)
300 if (m_driver.isWX()) {
307 wxFxn = wxAND_INVERT;
310 wxFxn = wxAND_REVERSE;
340 wxFxn = wxOR_REVERSE;
346 wxFxn = wxSRC_INVERT;
353 m_driver.idWX()->SetLogicalFunction (wxFxn);
360 SGP::setMarker (int idMarke, int iColor)
364 //==============================================================
365 // set line style. Pass 16 bit repeating pattern
366 //==============================================================
368 SGP::setLineStyle (int style)
372 //==============================================================
374 //*==============================================================
377 SGP::lineAbs (double x, double y)
379 if (m_bRecalcTransform)
382 double x1 = m_dCurrentWorldX;
383 double y1 = m_dCurrentWorldY;
384 mc_to_ndc.transformPoint (&x1, &y1);
388 mc_to_ndc.transformPoint (&x2, &y2);
390 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
391 stylusNDC (x1, y1, false); // move to first point
392 stylusNDC (x2, y2, true); // draw to second point
395 m_dCurrentWorldX = x;
396 m_dCurrentWorldY = y;
400 SGP::moveAbs (double x, double y)
402 m_dCurrentWorldX = x;
403 m_dCurrentWorldY = y; /* moves are not clipped */
407 SGP::lineRel (double x, double y)
409 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
413 SGP::moveRel (double x, double y)
415 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
419 // Height is in master coordinates
421 SGP::setTextSize (double height)
423 height /= (xw_max - xw_min);
426 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
429 if (m_driver.isWX()) {
430 double dHeightPixels = height * m_iPhysicalYSize;
431 double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
432 m_font.SetPointSize (nearest<int>(dHeightPoints));
433 m_driver.idWX()->SetFont (m_font);
439 SGP::setTextNDCSize (double height)
441 double dHeightPixels = height * m_iPhysicalYSize;
444 g2_set_font_size(m_driver.idG2(), nearest<int>(dHeightPixels));
447 if (m_driver.isWX()) {
448 double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
449 m_font.SetPointSize (nearest<int>(dHeightPoints));
450 m_driver.idWX()->SetFont (m_font);
456 SGP::setTextPointSize (double height)
459 // if (m_driver.isG2())
460 // g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
463 if (m_driver.isWX()) {
464 m_font.SetPointSize (static_cast<int>(height+0.5));
465 m_driver.idWX()->SetFont (m_font);
471 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
474 if (m_driver.isWX()) {
475 wxString sText (szText);
476 wxCoord deviceW, deviceH;
477 m_driver.idWX()->GetTextExtent (sText, &deviceW, &deviceH);
478 *worldW = static_cast<double>(deviceW) / static_cast<double>(m_iPhysicalXSize);;
479 *worldH = static_cast<double>(deviceH) / static_cast<double>(m_iPhysicalYSize);
480 *worldW *= (xw_max - xw_min);
481 *worldH *= (yw_max - yw_min);
487 SGP::getCharHeight ()
489 double dHeight = (1. / 25.);
492 if (m_driver.isWX()) {
493 dHeight = m_driver.idWX()->GetCharHeight();
494 dHeight /= static_cast<double>(m_iPhysicalYSize);
497 dHeight *= (yw_max - yw_min);
504 double dWidth = (1. / 80.);
507 if (m_driver.isWX()) {
508 dWidth = m_driver.idWX()->GetCharWidth();
509 dWidth /= static_cast<double>(m_iPhysicalXSize);
512 dWidth *= (xw_max - xw_min);
517 SGP::setTextAngle (double angle)
519 m_dTextAngle = convertRadiansToDegrees(angle);
523 SGP::polylineAbs (double x[], double y[], int n)
525 if (m_bRecalcTransform)
528 double x1 = x[0], y1 = y[0];
529 mc_to_ndc.transformPoint (&x1, &y1);
530 double x2 = x[1], y2 = y[1];
531 mc_to_ndc.transformPoint (&x2, &y2);
533 double xt = x2; // don't pass (x2,y2) to clip, we need them
534 double yt = y2; // as the beginning point of the next line
536 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
537 stylusNDC (x1, y1, false);
538 stylusNDC (xt, yt, true);
541 for (int i = 2; i < n; i++) {
542 x1 = x2; y1 = y2; // NDC endpoint of last line
543 x2 = x[i]; y2 = y[i];
544 mc_to_ndc.transformPoint (&x2, &y2);
547 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
548 stylusNDC (x1, y1, false);
549 stylusNDC (xt, yt, true);
556 SGP::markerAbs (double x, double y)
558 if (m_bRecalcTransform)
563 mc_to_ndc.transformPoint (&xndc, &yndc);
564 markerNDC (xndc, yndc);
565 stylusNDC (xndc, yndc, false); // move to location
566 m_dCurrentWorldX = x;
567 m_dCurrentWorldY = y;
572 SGP::markerRel (double x, double y)
574 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
579 SGP::pointAbs (double x, double y)
581 if (m_bRecalcTransform)
583 double xndc = x, yndc = y;
584 mc_to_ndc.transformPoint (&xndc, &yndc);
585 pointNDC (xndc, yndc);
586 stylusNDC (xndc, yndc, false); // move to location
587 m_dCurrentWorldX = x;
588 m_dCurrentWorldY = y;
593 SGP::pointRel (double x, double y)
595 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
600 SGP::drawText (const std::string& rsMessage)
602 drawText (rsMessage.c_str());
606 SGP::drawText (const char *pszMessage)
608 if (m_bRecalcTransform)
611 double xndc = m_dCurrentWorldX;
612 double yndc = m_dCurrentWorldY;
613 mc_to_ndc.transformPoint (&xndc, &yndc);
615 stylusNDC (xndc, yndc, false); // move to location
618 if (m_driver.isG2()) {
619 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
623 if (m_driver.isWX()) {
624 wxString str (pszMessage);
625 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
632 // drawRect Draw box in graphics mode
635 // drawbox (xmin, ymin, xmax, ymax)
636 // double xmin, ymin Lower left corner of box
637 // double xmax, ymax Upper left corner of box
640 // This routine leaves the current position of graphic cursor at lower
641 // left corner of box.
644 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
646 moveAbs (xmin, ymin);
647 lineAbs (xmax, ymin);
648 lineAbs (xmax, ymax);
649 lineAbs (xmin, ymax);
650 lineAbs (xmin, ymin);
654 // sgp2_circle - draw circle of radius r at current center
657 SGP::drawCircle (const double r)
659 drawArc (r, 0.0, TWOPI);
662 //==============================================================
663 // draw arc around current center. angles in radius
664 //==============================================================
667 SGP::drawArc (const double r, double start, double stop)
675 double x = r * cos ((double) start);
676 double y = r * sin ((double) start);
677 moveRel (x, y); // move from center to start of arc
679 const double thetaIncrement = (5 * (TWOPI / 360));
680 double cosTheta = cos(thetaIncrement);
681 double sinTheta = sin(thetaIncrement);
683 double angle, xp, yp;
684 for (angle = start; angle < stop - thetaIncrement; angle += thetaIncrement) {
685 xp = cosTheta * x - sinTheta * y; // translate point by thetaIncrement
686 yp = sinTheta * x + cosTheta * y;
691 double c = cos (stop - angle);
692 double s = sin (stop - angle);
699 moveRel (-x, -y); // move back to center of circle
704 ///////////////////////////////////////////////////////////////////////
705 // Coordinate Transformations
706 ///////////////////////////////////////////////////////////////////////
710 SGP::transformNDCtoMC (double* x, double* y)
712 if (m_bRecalcTransform)
714 ndc_to_mc.transformPoint (x, y);
719 SGP::transformMCtoNDC (double* x, double* y)
721 if (m_bRecalcTransform)
723 mc_to_ndc.transformPoint (x, y);
728 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
730 if (m_bRecalcTransform)
734 mc_to_ndc.transformPoint (x, y);
739 // calc_transform Calculate transform matrices
742 SGP::calc_transform ()
744 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
745 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
747 wc_to_ndc.setIdentity();
748 wc_to_ndc.mtx[0][0] = scaleX;
749 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
750 wc_to_ndc.mtx[1][1] = scaleY;
751 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
753 mc_to_ndc = m_ctm * wc_to_ndc;
754 ndc_to_mc = mc_to_ndc.invert();
756 m_bRecalcTransform = false;
767 SGP::ctmSet (const TransformationMatrix2D& m)
775 SGP::preTranslate (double x, double y)
777 TransformationMatrix2D m;
779 m.setTranslate (x, y);
785 SGP::postTranslate (double x, double y)
787 TransformationMatrix2D m;
789 m.setTranslate (x, y);
795 SGP::preScale (double sx, double sy)
797 TransformationMatrix2D m;
805 SGP::postScale (double sx, double sy)
807 TransformationMatrix2D m;
816 SGP::preRotate (double theta)
818 TransformationMatrix2D m;
827 SGP::postRotate (double theta)
829 TransformationMatrix2D m;
837 SGP::preShear (double shrx, double shry)
839 TransformationMatrix2D m;
841 m.setShear (shrx, shry);
847 SGP::postShear (double shrx, double shry)
849 TransformationMatrix2D m;
851 m.setShear (shrx, shry);
856 ////////////////////////////////////////////////////////////////////////
858 ////////////////////////////////////////////////////////////////////////
860 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
861 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
863 {'\000', '\000', '\010', '\000', '\000'}, // small dot
864 {'\000', '\034', '\024', '\034', '\000'}, // empty square
865 {'\000', '\034', '\034', '\034', '\000'}, // filled square
866 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
867 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
868 {'\010', '\010', '\076', '\010', '\010'}, // cross
869 {'\000', '\024', '\010', '\024', '\000'}, // X
870 {'\034', '\042', '\042', '\042', '\034'}, // open circle
871 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
872 {'\076', '\042', '\042', '\042', '\076'}, // big open square
873 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond
879 SGP::setDC (wxDC* pDC)