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.11 2000/08/27 20:32:55 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)
59 m_idDriver |= SGPDRIVER_WXWINDOWS;
63 SGPDriver::SGPDriver (const char* szWinTitle = "", int xsize = 640, int ysize = 480)
64 : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
67 m_idG2 = g2_open_X11X (m_iPhysicalXSize, m_iPhysicalYSize, 10, 10, const_cast<char*>(szWinTitle), const_cast<char*>(szWinTitle), NULL, -1, -1);
68 m_idDriver |= SGPDRIVER_G2;
72 SGPDriver::~SGPDriver ()
80 // SGP::SGP Constructor for Simple Graphics Package
82 SGP::SGP (const SGPDriver& driver)
85 m_iPhysicalXSize = m_driver.getPhysicalXSize();
86 m_iPhysicalYSize = m_driver.getPhysicalYSize();
88 wc_to_ndc.setIdentity ();
89 mc_to_ndc.setIdentity();
90 ndc_to_mc.setIdentity();
95 m_pen.SetStyle(wxSOLID);
98 setWindow (0., 0., 1., 1.);
99 setViewport (0., 0., 1., 1.);
101 stylusNDC (0., 0., false);
104 setTextSize (1. / 25.);
111 SGP::stylusNDC (double x, double y, bool beam)
113 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
114 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
116 yp = m_iPhysicalYSize - yp;
121 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
125 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
128 m_iCurrentPhysicalX = xp;
129 m_iCurrentPhysicalY = yp;
133 SGP::markerNDC (double x, double y)
138 SGP::pointNDC (double x, double y)
144 // clear Clear Window
151 g2_clear (m_driver.idG2());
155 m_driver.idWX()->Clear();
160 // sgp2_window Set window in world coordinates
164 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
166 if (xmin >= xmax || ymin >= ymax) {
167 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
175 m_bRecalcTransform = true;
180 // sgp2_viewport Set viewport in NDC
183 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
185 if (xmin >= xmax || ymin >= ymax) {
186 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
194 m_bRecalcTransform = true;
196 viewNDC[0] = xmin; // Array for clip_rect()
204 // frameViewport draw box around viewport
207 SGP::frameViewport (void)
209 stylusNDC (xv_min, yv_min, false);
210 stylusNDC (xv_max, yv_min, true);
211 stylusNDC (xv_max, yv_max, true);
212 stylusNDC (xv_min, yv_max, true);
213 stylusNDC (xv_min, yv_min, true);
217 SGP::setTextColor (int iFGcolor, int iBGcolor)
220 if (m_driver.isWX()) {
222 wxColor colour (s_aRGBColor[iFGcolor].getRed(), s_aRGBColor[iFGcolor].getGreen(), s_aRGBColor[iFGcolor].getBlue());
223 m_driver.idWX()->SetTextForeground (colour);
226 wxColor colour (s_aRGBColor[iBGcolor].getRed(), s_aRGBColor[iBGcolor].getGreen(), s_aRGBColor[iBGcolor].getBlue());
227 m_driver.idWX()->SetTextBackground (colour);
234 SGP::setColor (int icol)
236 if (icol >= 0 && icol < s_iRGBColorCount) {
238 if (m_driver.isG2()) {
239 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
240 g2_pen (m_driver.idG2(), iInk);
244 if (m_driver.isWX()) {
245 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
246 m_pen.SetColour (colour);
247 m_driver.idWX()->SetPen (m_pen);
254 SGP::setPenWidth (int iWidth)
258 if (m_driver.isWX()) {
259 m_pen.SetWidth (iWidth);
260 m_driver.idWX()->SetPen (m_pen);
267 SGP::setRasterOp (int ro)
270 if (m_driver.isWX()) {
277 wxFxn = wxAND_INVERT;
280 wxFxn = wxAND_REVERSE;
310 wxFxn = wxOR_REVERSE;
316 wxFxn = wxSRC_INVERT;
323 m_driver.idWX()->SetLogicalFunction (wxFxn);
330 SGP::setMarker (int idMarke, int iColor)
334 //==============================================================
335 // set line style. Pass 16 bit repeating pattern
336 //==============================================================
338 SGP::setLineStyle (int style)
342 //==============================================================
344 //*==============================================================
347 SGP::lineAbs (double x, double y)
349 if (m_bRecalcTransform)
352 double x1 = m_dCurrentWorldX;
353 double y1 = m_dCurrentWorldY;
354 mc_to_ndc.transformPoint (&x1, &y1);
358 mc_to_ndc.transformPoint (&x2, &y2);
360 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
361 stylusNDC (x1, y1, false); // move to first point
362 stylusNDC (x2, y2, true); // draw to second point
365 m_dCurrentWorldX = x;
366 m_dCurrentWorldY = y;
370 SGP::moveAbs (double x, double y)
372 m_dCurrentWorldX = x;
373 m_dCurrentWorldY = y; /* moves are not clipped */
377 SGP::lineRel (double x, double y)
379 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
383 SGP::moveRel (double x, double y)
385 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
389 SGP::setTextSize (double height)
392 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
396 SGP::getTextExtent (const char* szText, double* worldW, double* worldH)
399 if (m_driver.isWX()) {
400 wxString sText (szText);
401 wxCoord deviceW, deviceH;
402 m_driver.idWX()->GetTextExtent (sText, &deviceW, &deviceH);
403 *worldW = static_cast<double>(deviceW) / static_cast<double>(m_iPhysicalXSize);;
404 *worldH = static_cast<double>(deviceH) / static_cast<double>(m_iPhysicalYSize);
405 // cout << deviceW << ", " << deviceH << ", " << *worldW << ", " << *worldH << endl;
406 *worldW *= (xw_max - xw_min);
407 *worldH *= (yw_max - yw_min);
413 SGP::getCharHeight ()
415 double dHeight = (1. / 25.);
418 if (m_driver.isWX()) {
419 dHeight = m_driver.idWX()->GetCharHeight();
420 dHeight /= static_cast<double>(m_iPhysicalYSize);;
423 return (dHeight * (xw_max - xw_min));
427 SGP::setTextAngle (double angle)
429 m_dTextAngle = angle;
433 SGP::polylineAbs (double x[], double y[], int n)
435 if (m_bRecalcTransform)
438 double x1 = x[0], y1 = y[0];
439 mc_to_ndc.transformPoint (&x1, &y1);
440 double x2 = x[1], y2 = y[1];
441 mc_to_ndc.transformPoint (&x2, &y2);
443 double xt = x2; // don't pass (x2,y2) to clip, we need them
444 double yt = y2; // as the beginning point of the next line
446 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
447 stylusNDC (x1, y1, false);
448 stylusNDC (xt, yt, true);
451 for (int i = 2; i < n; i++) {
452 x1 = x2; y1 = y2; // NDC endpoint of last line
453 x2 = x[i]; y2 = y[i];
454 mc_to_ndc.transformPoint (&x2, &y2);
457 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
458 stylusNDC (x1, y1, false);
459 stylusNDC (xt, yt, true);
466 SGP::markerAbs (double x, double y)
468 if (m_bRecalcTransform)
473 mc_to_ndc.transformPoint (&xndc, &yndc);
474 markerNDC (xndc, yndc);
475 stylusNDC (xndc, yndc, false); // move to location
476 m_dCurrentWorldX = x;
477 m_dCurrentWorldY = y;
482 SGP::markerRel (double x, double y)
484 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
489 SGP::pointAbs (double x, double y)
491 if (m_bRecalcTransform)
493 double xndc = x, yndc = y;
494 mc_to_ndc.transformPoint (&xndc, &yndc);
495 pointNDC (xndc, yndc);
496 stylusNDC (xndc, yndc, false); // move to location
497 m_dCurrentWorldX = x;
498 m_dCurrentWorldY = y;
503 SGP::pointRel (double x, double y)
505 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
510 SGP::drawText (const string& rsMessage)
512 drawText (rsMessage.c_str());
516 SGP::drawText (const char *pszMessage)
518 if (m_bRecalcTransform)
521 double xndc = m_dCurrentWorldX;
522 double yndc = m_dCurrentWorldY;
523 mc_to_ndc.transformPoint (&xndc, &yndc);
525 stylusNDC (xndc, yndc, false); // move to location
528 if (m_driver.isG2()) {
529 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
533 if (m_driver.isWX()) {
534 wxString str (pszMessage);
535 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
542 // drawRect Draw box in graphics mode
545 // drawbox (xmin, ymin, xmax, ymax)
546 // double xmin, ymin Lower left corner of box
547 // double xmax, ymax Upper left corner of box
550 // This routine leaves the current position of graphic cursor at lower
551 // left corner of box.
554 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
556 moveAbs (xmin, ymin);
557 lineAbs (xmax, ymin);
558 lineAbs (xmax, ymax);
559 lineAbs (xmin, ymax);
560 lineAbs (xmin, ymin);
564 // sgp2_circle - draw circle of radius r at current center
567 SGP::drawCircle (const double r)
569 drawArc (r, 0.0, 7.0);
572 // =============================================================
573 // draw arc around current center. pass angles and radius
574 //==============================================================
577 SGP::drawArc (const double r, double start, double stop)
579 if ((stop-start) > 2 * PI)
580 stop = start + 2 * PI;
581 if ((start-stop) > 2 * PI)
582 stop = start + 2 * PI;
583 while (start >= stop)
586 double x = r * cos ((double) start);
587 double y = r * sin ((double) start);
588 moveRel (x, y); // move from center to start of arc
590 double theta = 5 * PI / 180;
591 double c = cos(theta);
592 double s = sin(theta);
594 double angle, xp, yp;
595 for (angle = start; angle < stop - theta; angle += theta) {
598 lineRel (xp - x, yp - y);
602 c = cos (stop - angle);
603 s = sin (stop - angle);
606 lineRel (xp - x, yp - y);
608 x = r * cos ((double) stop);
609 y = r * sin ((double) stop);
610 moveRel (-x, -y); // move back to center of circle
615 ///////////////////////////////////////////////////////////////////////
616 // Coordinate Transformations
617 ///////////////////////////////////////////////////////////////////////
621 SGP::transformNDCtoMC (double* x, double* y)
623 if (m_bRecalcTransform)
625 ndc_to_mc.transformPoint (x, y);
630 SGP::transformMCtoNDC (double* x, double* y)
632 if (m_bRecalcTransform)
634 mc_to_ndc.transformPoint (x, y);
639 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
641 if (m_bRecalcTransform)
645 mc_to_ndc.transformPoint (x, y);
650 // calc_transform Calculate transform matrices
653 SGP::calc_transform ()
655 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
656 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
658 wc_to_ndc.setIdentity();
659 wc_to_ndc.mtx[0][0] = scaleX;
660 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
661 wc_to_ndc.mtx[1][1] = scaleY;
662 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
664 mc_to_ndc = m_ctm * wc_to_ndc;
665 ndc_to_mc = mc_to_ndc.invert();
667 m_bRecalcTransform = false;
678 SGP::ctmSet (const TransformationMatrix2D& m)
686 SGP::preTranslate (double x, double y)
688 TransformationMatrix2D m;
690 m.setTranslate (x, y);
696 SGP::postTranslate (double x, double y)
698 TransformationMatrix2D m;
700 m.setTranslate (x, y);
706 SGP::preScale (double sx, double sy)
708 TransformationMatrix2D m;
716 SGP::postScale (double sx, double sy)
718 TransformationMatrix2D m;
727 SGP::preRotate (double theta)
729 TransformationMatrix2D m;
738 SGP::postRotate (double theta)
740 TransformationMatrix2D m;
748 SGP::preShear (double shrx, double shry)
750 TransformationMatrix2D m;
752 m.setShear (shrx, shry);
758 SGP::postShear (double shrx, double shry)
760 TransformationMatrix2D m;
762 m.setShear (shrx, shry);
767 ////////////////////////////////////////////////////////////////////////
769 ////////////////////////////////////////////////////////////////////////
771 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
772 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
774 {'\000', '\000', '\010', '\000', '\000'}, // small dot
775 {'\000', '\034', '\024', '\034', '\000'}, // empty square
776 {'\000', '\034', '\034', '\034', '\000'}, // filled square
777 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
778 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
779 {'\010', '\010', '\076', '\010', '\010'}, // cross
780 {'\000', '\024', '\010', '\024', '\000'}, // X
781 {'\034', '\042', '\042', '\042', '\034'}, // open circle
782 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
783 {'\076', '\042', '\042', '\042', '\076'}, // big open square
784 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond