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.27 2001/01/12 21:53:27 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();
95 initFromDC (driver.idWX());
98 setWindow (0., 0., 1., 1.);
99 setViewport (0., 0., 1., 1.);
101 stylusNDC (0., 0., false);
104 setTextPointSize (12);
106 setLineStyle (LS_SOLID);
110 #ifdef HAVE_WXWINDOWS
112 SGP::initFromDC (wxDC* pDC)
116 if (m_driver.isWX()) {
117 static const double dScreenDPI = 82;
118 static const double dPointsPerInch = 72.;
119 m_dPointsPerPixel = dPointsPerInch / dScreenDPI;
120 const int iTestPointSize = 12;
121 m_pFont = new wxFont (wxROMAN, wxNORMAL, wxNORMAL, wxNORMAL);
122 m_pFont->SetPointSize (iTestPointSize);
123 m_pFont->SetWeight (wxNORMAL);
124 m_pFont->SetStyle (wxNORMAL);
125 m_pFont->SetFamily (wxROMAN);
127 m_pFont->SetFaceName(wxString("times new roman"));
129 m_driver.idWX()->SetFont (*m_pFont);
130 double dTestCharHeight = m_driver.idWX()->GetCharHeight();
131 m_dPointsPerPixel = iTestPointSize / dTestCharHeight;
132 m_driver.idWX()->SetBackground (*wxWHITE_BRUSH);
141 if (m_driver.isWX()) {
142 // m_driver.idWX()->SetFont (wxNullFont);
149 SGP::stylusNDC (double x, double y, bool beam)
151 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
152 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
154 yp = m_iPhysicalYSize - yp;
159 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
163 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
166 m_iCurrentPhysicalX = xp;
167 m_iCurrentPhysicalY = yp;
171 SGP::markerNDC (double x, double y)
176 SGP::pointNDC (double x, double y)
182 // clear Clear Window
189 g2_clear (m_driver.idG2());
192 if (m_driver.isWX()) {
194 brushWhite.SetColour(255,255,255);
195 m_driver.idWX()->SetBackground(brushWhite);
196 m_driver.idWX()->Clear();
197 m_driver.idWX()->SetBackground(wxNullBrush);
200 pen.SetColour(255,255,255);
201 m_driver.idWX()->SetBrush (brushWhite);
202 m_driver.idWX()->DrawRectangle (0, 0, m_iPhysicalXSize, m_iPhysicalYSize);
203 m_driver.idWX()->SetBrush (wxNullBrush);
210 // sgp2_window Set window in world coordinates
214 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
216 if (xmin >= xmax || ymin >= ymax) {
217 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
225 m_bRecalcTransform = true;
230 // sgp2_viewport Set viewport in NDC
233 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
235 if (xmin >= xmax || ymin >= ymax) {
236 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
244 m_bRecalcTransform = true;
246 viewNDC[0] = xmin; // Array for clip_rect()
253 SGP::getViewport (double& xmin, double& ymin, double& xmax, double& ymax)
262 SGP::getWindow (double& xmin, double& ymin, double& xmax, double& ymax)
272 // frameViewport draw box around viewport
275 SGP::frameViewport (void)
277 stylusNDC (xv_min, yv_min, false);
278 stylusNDC (xv_max, yv_min, true);
279 stylusNDC (xv_max, yv_max, true);
280 stylusNDC (xv_min, yv_max, true);
281 stylusNDC (xv_min, yv_min, true);
285 SGP::setTextColor (int iFGcolor, int iBGcolor)
288 if (m_driver.isWX()) {
290 wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
291 m_driver.idWX()->SetTextForeground (colour);
294 wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
295 m_driver.idWX()->SetTextBackground (colour);
302 SGP::setColor (int icol)
304 if (icol >= 0 && icol < s_iRGBColorCount) {
306 if (m_driver.isG2()) {
307 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
308 g2_pen (m_driver.idG2(), iInk);
312 if (m_driver.isWX()) {
313 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
314 m_pen.SetColour (colour);
315 m_driver.idWX()->SetPen (m_pen);
322 SGP::setPenWidth (int iWidth)
326 if (m_driver.isWX()) {
327 m_pen.SetWidth (iWidth);
328 m_driver.idWX()->SetPen (m_pen);
335 SGP::setRasterOp (int ro)
338 if (m_driver.isWX()) {
345 wxFxn = wxAND_INVERT;
348 wxFxn = wxAND_REVERSE;
378 wxFxn = wxOR_REVERSE;
384 wxFxn = wxSRC_INVERT;
391 m_driver.idWX()->SetLogicalFunction (wxFxn);
398 SGP::setMarker (int idMarke, int iColor)
402 //==============================================================
403 // set line style. Pass 16 bit repeating pattern
404 //==============================================================
406 SGP::setLineStyle (int style)
408 m_iLinestyle = style;
411 if (m_driver.isWX()) {
412 switch (m_iLinestyle) {
414 m_pen.SetStyle (wxSOLID);
417 m_pen.SetStyle (wxLONG_DASH);
420 m_pen.SetStyle (wxSHORT_DASH);
423 m_pen.SetStyle (wxDOT_DASH);
426 m_pen.SetStyle (wxCROSS_HATCH);
429 m_pen.SetStyle (wxDOT);
432 m_pen.SetStyle (wxSOLID);
435 m_driver.idWX()->SetPen (m_pen);
440 //==============================================================
442 //*==============================================================
445 SGP::lineAbs (double x, double y)
447 if (m_bRecalcTransform)
450 double x1 = m_dCurrentWorldX;
451 double y1 = m_dCurrentWorldY;
452 mc_to_ndc.transformPoint (&x1, &y1);
456 mc_to_ndc.transformPoint (&x2, &y2);
458 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
459 stylusNDC (x1, y1, false); // move to first point
460 stylusNDC (x2, y2, true); // draw to second point
463 m_dCurrentWorldX = x;
464 m_dCurrentWorldY = y;
468 SGP::moveAbs (double x, double y)
470 m_dCurrentWorldX = x;
471 m_dCurrentWorldY = y; /* moves are not clipped */
475 SGP::lineRel (double x, double y)
477 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
481 SGP::moveRel (double x, double y)
483 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
487 // Height is in master coordinates
489 SGP::setTextSize (double height)
491 height /= (yw_max - yw_min); // convert to NDC
494 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
497 if (m_driver.isWX()) {
498 double dHeightPixels = height * m_iPhysicalYSize;
499 double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
500 m_pFont->SetPointSize (nearest<int>(dHeightPoints));
501 m_driver.idWX()->SetFont (*m_pFont);
507 SGP::setTextNDCSize (double height)
509 double dHeightPixels = height * m_iPhysicalYSize;
512 g2_set_font_size(m_driver.idG2(), nearest<int>(dHeightPixels));
515 if (m_driver.isWX()) {
516 double dHeightPoints = dHeightPixels * m_dPointsPerPixel;
517 m_pFont->SetPointSize (nearest<int>(dHeightPoints));
518 m_driver.idWX()->SetFont (*m_pFont);
524 SGP::setTextPointSize (double height)
527 // if (m_driver.isG2())
528 // g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
531 if (m_driver.isWX()) {
532 m_iTextPointSize = static_cast<int>(height+0.5);
533 m_pFont->SetPointSize (m_iTextPointSize);
534 m_driver.idWX()->SetFont (*m_pFont);
540 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
543 if (m_driver.isWX()) {
544 wxString sText (szText);
545 wxCoord deviceW, deviceH;
546 m_driver.idWX()->GetTextExtent (sText, &deviceW, &deviceH);
547 if (m_dTextAngle == 90 || m_dTextAngle == -90) {
548 wxCoord temp = deviceW;
552 *worldW = (xw_max - xw_min) * deviceW / static_cast<double>(m_iPhysicalXSize);;
553 *worldH = (yw_max - yw_min) * deviceH / static_cast<double>(m_iPhysicalYSize);
559 SGP::getCharHeight ()
561 double dHeight = (1. / 25.);
564 if (m_driver.isWX()) {
565 dHeight = m_driver.idWX()->GetCharHeight();
566 dHeight /= static_cast<double>(m_iPhysicalYSize);
567 dHeight /= (yv_max - yv_min); // scale to viewport;
570 dHeight *= (yw_max - yw_min); // scale to world coordinates
577 double dWidth = (1. / 80.);
580 if (m_driver.isWX()) {
581 dWidth = m_driver.idWX()->GetCharWidth();
582 dWidth /= static_cast<double>(m_iPhysicalXSize);
583 dWidth /= (xv_max - xv_min); // scale to viewport
586 dWidth *= (xw_max - xw_min); //scale to world coordinates
591 SGP::setTextAngle (double angle)
593 m_dTextAngle = convertRadiansToDegrees(angle);
597 SGP::polylineAbs (double x[], double y[], int n)
599 if (m_bRecalcTransform)
602 double x1 = x[0], y1 = y[0];
603 mc_to_ndc.transformPoint (&x1, &y1);
604 double x2 = x[1], y2 = y[1];
605 mc_to_ndc.transformPoint (&x2, &y2);
607 double xt = x2; // don't pass (x2,y2) to clip, we need them
608 double yt = y2; // as the beginning point of the next line
610 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
611 stylusNDC (x1, y1, false);
612 stylusNDC (xt, yt, true);
615 for (int i = 2; i < n; i++) {
616 x1 = x2; y1 = y2; // NDC endpoint of last line
617 x2 = x[i]; y2 = y[i];
618 mc_to_ndc.transformPoint (&x2, &y2);
621 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
622 stylusNDC (x1, y1, false);
623 stylusNDC (xt, yt, true);
630 SGP::markerAbs (double x, double y)
632 if (m_bRecalcTransform)
637 mc_to_ndc.transformPoint (&xndc, &yndc);
638 markerNDC (xndc, yndc);
639 stylusNDC (xndc, yndc, false); // move to location
640 m_dCurrentWorldX = x;
641 m_dCurrentWorldY = y;
646 SGP::markerRel (double x, double y)
648 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
653 SGP::pointAbs (double x, double y)
655 if (m_bRecalcTransform)
657 double xndc = x, yndc = y;
658 mc_to_ndc.transformPoint (&xndc, &yndc);
659 pointNDC (xndc, yndc);
660 stylusNDC (xndc, yndc, false); // move to location
661 m_dCurrentWorldX = x;
662 m_dCurrentWorldY = y;
667 SGP::pointRel (double x, double y)
669 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
674 SGP::drawText (const std::string& rsMessage)
676 drawText (rsMessage.c_str());
680 SGP::drawText (const char *pszMessage)
682 if (m_bRecalcTransform)
685 double xndc = m_dCurrentWorldX;
686 double yndc = m_dCurrentWorldY;
687 mc_to_ndc.transformPoint (&xndc, &yndc);
689 stylusNDC (xndc, yndc, false); // move to location
692 if (m_driver.isG2()) {
693 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
697 if (m_driver.isWX()) {
698 wxString str (pszMessage);
699 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
706 // drawRect Draw box in graphics mode
709 // drawbox (xmin, ymin, xmax, ymax)
710 // double xmin, ymin Lower left corner of box
711 // double xmax, ymax Upper left corner of box
714 // This routine leaves the current position of graphic cursor at lower
715 // left corner of box.
718 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
720 moveAbs (xmin, ymin);
721 lineAbs (xmax, ymin);
722 lineAbs (xmax, ymax);
723 lineAbs (xmin, ymax);
724 lineAbs (xmin, ymin);
728 // sgp2_circle - draw circle of radius r at current center
731 SGP::drawCircle (const double r)
733 drawArc (r, 0.0, TWOPI);
736 //==============================================================
737 // draw arc around current center. angles in radius
738 //==============================================================
741 SGP::drawArc (const double r, double start, double stop)
749 double x = r * cos ((double) start);
750 double y = r * sin ((double) start);
751 moveRel (x, y); // move from center to start of arc
753 const double thetaIncrement = (5 * (TWOPI / 360));
754 double cosTheta = cos(thetaIncrement);
755 double sinTheta = sin(thetaIncrement);
757 double angle, xp, yp;
758 for (angle = start; angle < stop - thetaIncrement; angle += thetaIncrement) {
759 xp = cosTheta * x - sinTheta * y; // translate point by thetaIncrement
760 yp = sinTheta * x + cosTheta * y;
765 double c = cos (stop - angle);
766 double s = sin (stop - angle);
773 moveRel (-x, -y); // move back to center of circle
778 ///////////////////////////////////////////////////////////////////////
779 // Coordinate Transformations
780 ///////////////////////////////////////////////////////////////////////
784 SGP::transformNDCtoMC (double* x, double* y)
786 if (m_bRecalcTransform)
788 ndc_to_mc.transformPoint (x, y);
793 SGP::transformMCtoNDC (double* x, double* y)
795 if (m_bRecalcTransform)
797 mc_to_ndc.transformPoint (x, y);
802 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
804 if (m_bRecalcTransform)
808 mc_to_ndc.transformPoint (x, y);
813 // calc_transform Calculate transform matrices
816 SGP::calc_transform ()
818 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
819 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
821 wc_to_ndc.setIdentity();
822 wc_to_ndc.mtx[0][0] = scaleX;
823 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
824 wc_to_ndc.mtx[1][1] = scaleY;
825 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
827 mc_to_ndc = m_ctm * wc_to_ndc;
828 ndc_to_mc = mc_to_ndc.invert();
830 m_bRecalcTransform = false;
841 SGP::ctmSet (const TransformationMatrix2D& m)
849 SGP::preTranslate (double x, double y)
851 TransformationMatrix2D m;
853 m.setTranslate (x, y);
859 SGP::postTranslate (double x, double y)
861 TransformationMatrix2D m;
863 m.setTranslate (x, y);
869 SGP::preScale (double sx, double sy)
871 TransformationMatrix2D m;
879 SGP::postScale (double sx, double sy)
881 TransformationMatrix2D m;
890 SGP::preRotate (double theta)
892 TransformationMatrix2D m;
901 SGP::postRotate (double theta)
903 TransformationMatrix2D m;
911 SGP::preShear (double shrx, double shry)
913 TransformationMatrix2D m;
915 m.setShear (shrx, shry);
921 SGP::postShear (double shrx, double shry)
923 TransformationMatrix2D m;
925 m.setShear (shrx, shry);
930 ////////////////////////////////////////////////////////////////////////
932 ////////////////////////////////////////////////////////////////////////
934 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
935 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
937 {'\000', '\000', '\010', '\000', '\000'}, // small dot
938 {'\000', '\034', '\024', '\034', '\000'}, // empty square
939 {'\000', '\034', '\034', '\034', '\000'}, // filled square
940 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
941 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
942 {'\010', '\010', '\076', '\010', '\010'}, // cross
943 {'\000', '\024', '\010', '\024', '\000'}, // X
944 {'\034', '\042', '\042', '\042', '\034'}, // open circle
945 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
946 {'\076', '\042', '\042', '\042', '\076'}, // big open square
947 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond
953 SGP::setDC (wxDC* pDC)
955 if (m_driver.isWX()) {
958 setTextPointSize (m_iTextPointSize);