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.10 2000/08/25 15:59: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 = 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)
88 m_iPhysicalXSize = m_driver.getPhysicalXSize();
89 m_iPhysicalYSize = m_driver.getPhysicalYSize();
91 wc_to_ndc.setIdentity ();
92 mc_to_ndc.setIdentity();
93 ndc_to_mc.setIdentity();
96 setWindow (0., 0., 1., 1.);
97 setViewport (0., 0., 1., 1.);
99 stylusNDC (0., 0., false);
102 setTextSize (1. / 25.);
108 SGP::stylusNDC (double x, double y, bool beam)
110 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
111 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
113 yp = m_iPhysicalYSize - yp;
118 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
122 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
125 m_iCurrentPhysicalX = xp;
126 m_iCurrentPhysicalY = yp;
130 SGP::markerNDC (double x, double y)
135 SGP::pointNDC (double x, double y)
141 // clear Clear Window
148 g2_clear (m_driver.idG2());
152 m_driver.idWX()->Clear();
157 // sgp2_window Set window in world coordinates
161 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
163 if (xmin >= xmax || ymin >= ymax) {
164 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
172 m_bRecalcTransform = true;
177 // sgp2_viewport Set viewport in NDC
180 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
182 if (xmin >= xmax || ymin >= ymax) {
183 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
191 m_bRecalcTransform = true;
193 viewNDC[0] = xmin; // Array for clip_rect()
201 // frameViewport draw box around viewport
204 SGP::frameViewport (void)
206 stylusNDC (xv_min, yv_min, 0);
207 stylusNDC (xv_max, yv_min, 1);
208 stylusNDC (xv_max, yv_max, 1);
209 stylusNDC (xv_min, yv_max, 1);
210 stylusNDC (xv_min, yv_min, 1);
214 SGP::setTextColor (int iFGcolor, int iBGcolor)
219 SGP::setColor (int icol)
221 if (icol >= 0 && icol < s_iRGBColorCount) {
223 if (m_driver.isG2()) {
224 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
225 g2_pen (m_driver.idG2(), iInk);
229 if (m_driver.isWX()) {
230 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
232 m_pPen = new wxPen (colour, 1, wxSOLID);
233 m_driver.idWX()->SetPen (*m_pPen);
240 SGP::setRasterOp (int ro)
243 if (m_driver.isWX()) {
250 wxFxn = wxAND_INVERT;
253 wxFxn = wxAND_REVERSE;
283 wxFxn = wxOR_REVERSE;
289 wxFxn = wxSRC_INVERT;
296 m_driver.idWX()->SetLogicalFunction (wxFxn);
303 SGP::setMarker (int idMarke, int iColor)
307 //==============================================================
308 // set line style. Pass 16 bit repeating pattern
309 //==============================================================
311 SGP::setLineStyle (int style)
315 //==============================================================
317 //*==============================================================
320 SGP::lineAbs (double x, double y)
322 if (m_bRecalcTransform)
325 double x1 = m_dCurrentWorldX;
326 double y1 = m_dCurrentWorldY;
327 mc_to_ndc.transformPoint (&x1, &y1);
331 mc_to_ndc.transformPoint (&x2, &y2);
333 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
334 stylusNDC (x1, y1, 0); // move to first point
335 stylusNDC (x2, y2, 1); // draw to second point
338 m_dCurrentWorldX = x;
339 m_dCurrentWorldY = y;
343 SGP::moveAbs (double x, double y)
345 m_dCurrentWorldX = x;
346 m_dCurrentWorldY = y; /* moves are not clipped */
350 SGP::lineRel (double x, double y)
352 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
356 SGP::moveRel (double x, double y)
358 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
362 SGP::setTextSize (double height)
365 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
369 SGP::setTextAngle (double angle)
371 m_dTextAngle = angle;
375 SGP::polylineAbs (double x[], double y[], int n)
377 if (m_bRecalcTransform)
380 double x1 = x[0], y1 = y[0];
381 mc_to_ndc.transformPoint (&x1, &y1);
382 double x2 = x[1], y2 = y[1];
383 mc_to_ndc.transformPoint (&x2, &y2);
385 double xt = x2; // don't pass (x2,y2) to clip, we need them
386 double yt = y2; // as the beginning point of the next line
388 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
389 stylusNDC (x1, y1, 0);
390 stylusNDC (xt, yt, 1);
393 for (int i = 2; i < n; i++) {
394 x1 = x2; y1 = y2; // NDC endpoint of last line
395 x2 = x[i]; y2 = y[i];
396 mc_to_ndc.transformPoint (&x2, &y2);
399 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
400 stylusNDC (x1, y1, 0);
401 stylusNDC (xt, yt, 1);
408 SGP::markerAbs (double x, double y)
410 if (m_bRecalcTransform)
415 mc_to_ndc.transformPoint (&xndc, &yndc);
416 markerNDC (xndc, yndc);
417 stylusNDC (xndc, yndc, false); // move to location
418 m_dCurrentWorldX = x;
419 m_dCurrentWorldY = y;
424 SGP::markerRel (double x, double y)
426 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
431 SGP::pointAbs (double x, double y)
433 if (m_bRecalcTransform)
435 double xndc = x, yndc = y;
436 mc_to_ndc.transformPoint (&xndc, &yndc);
437 pointNDC (xndc, yndc);
438 stylusNDC (xndc, yndc, false); // move to location
439 m_dCurrentWorldX = x;
440 m_dCurrentWorldY = y;
445 SGP::pointRel (double x, double y)
447 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
452 SGP::drawText (const string& rsMessage)
454 drawText (rsMessage.c_str());
458 SGP::drawText (const char *pszMessage)
460 if (m_bRecalcTransform)
463 double xndc = m_dCurrentWorldX;
464 double yndc = m_dCurrentWorldY;
465 mc_to_ndc.transformPoint (&xndc, &yndc);
467 stylusNDC (xndc, yndc, false); // move to location
470 if (m_driver.isG2()) {
471 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
475 if (m_driver.isWX()) {
476 wxString str (pszMessage);
477 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
484 // drawRect Draw box in graphics mode
487 // drawbox (xmin, ymin, xmax, ymax)
488 // double xmin, ymin Lower left corner of box
489 // double xmax, ymax Upper left corner of box
492 // This routine leaves the current position of graphic cursor at lower
493 // left corner of box.
496 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
498 moveAbs (xmin, ymin);
499 lineAbs (xmax, ymin);
500 lineAbs (xmax, ymax);
501 lineAbs (xmin, ymax);
502 lineAbs (xmin, ymin);
506 // sgp2_circle - draw circle of radius r at current center
509 SGP::drawCircle (const double r)
511 drawArc (0.0, 7.0, r);
514 // =============================================================
515 // draw arc around current center. pass angles and radius
516 //==============================================================
519 SGP::drawArc (double start, double stop, const double r)
521 if ((stop-start) > 2 * PI)
522 stop = start + 2 * PI;
523 if ((start-stop) > 2 * PI)
524 stop = start + 2 * PI;
525 while (start >= stop)
528 double x = r * cos ((double) start);
529 double y = r * sin ((double) start);
530 moveRel (x, y); // move from center to start of arc
532 double theta = 5 * PI / 180;
533 double c = cos(theta);
534 double s = sin(theta);
536 double angle, xp, yp;
537 for (angle = start; angle < stop - theta; angle += theta) {
540 lineRel (xp - x, yp - y);
544 c = cos (stop - angle);
545 s = sin (stop - angle);
548 lineRel (xp - x, yp - y);
550 x = r * cos ((double) stop);
551 y = r * sin ((double) stop);
552 moveRel (-x, -y); // move back to center of circle
557 ///////////////////////////////////////////////////////////////////////
558 // Coordinate Transformations
559 ///////////////////////////////////////////////////////////////////////
563 SGP::transformNDCtoMC (double* x, double* y)
565 if (m_bRecalcTransform)
567 ndc_to_mc.transformPoint (x, y);
572 SGP::transformMCtoNDC (double* x, double* y)
574 if (m_bRecalcTransform)
576 mc_to_ndc.transformPoint (x, y);
581 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
583 if (m_bRecalcTransform)
587 mc_to_ndc.transformPoint (x, y);
592 // calc_transform Calculate transform matrices
595 SGP::calc_transform ()
597 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
598 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
600 wc_to_ndc.setIdentity();
601 wc_to_ndc.mtx[0][0] = scaleX;
602 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
603 wc_to_ndc.mtx[1][1] = scaleY;
604 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
606 mc_to_ndc = m_ctm * wc_to_ndc;
607 ndc_to_mc = mc_to_ndc.invert();
609 m_bRecalcTransform = false;
620 SGP::ctmSet (const TransformationMatrix2D& m)
628 SGP::preTranslate (double x, double y)
630 TransformationMatrix2D m;
632 m.setTranslate (x, y);
638 SGP::postTranslate (double x, double y)
640 TransformationMatrix2D m;
642 m.setTranslate (x, y);
648 SGP::preScale (double sx, double sy)
650 TransformationMatrix2D m;
658 SGP::postScale (double sx, double sy)
660 TransformationMatrix2D m;
669 SGP::preRotate (double theta)
671 TransformationMatrix2D m;
680 SGP::postRotate (double theta)
682 TransformationMatrix2D m;
690 SGP::preShear (double shrx, double shry)
692 TransformationMatrix2D m;
694 m.setShear (shrx, shry);
700 SGP::postShear (double shrx, double shry)
702 TransformationMatrix2D m;
704 m.setShear (shrx, shry);
709 ////////////////////////////////////////////////////////////////////////
711 ////////////////////////////////////////////////////////////////////////
713 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
714 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
716 {'\000', '\000', '\010', '\000', '\000'}, // small dot
717 {'\000', '\034', '\024', '\034', '\000'}, // empty square
718 {'\000', '\034', '\034', '\034', '\000'}, // filled square
719 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
720 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
721 {'\010', '\010', '\076', '\010', '\010'}, // cross
722 {'\000', '\024', '\010', '\024', '\000'}, // X
723 {'\034', '\042', '\042', '\042', '\034'}, // open circle
724 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
725 {'\076', '\042', '\042', '\042', '\076'}, // big open square
726 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond