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.7 2000/07/29 19:50:08 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, const char* szWinTitle = "", int xsize = 640, int ysize = 480)
56 : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), 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();
93 setWindow (0., 0., 1., 1.);
94 setViewport (0., 0., 1., 1.);
96 stylusNDC (0., 0., false);
99 setTextSize (1. / 25.);
105 SGP::stylusNDC (double x, double y, bool beam)
107 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
108 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
110 yp = m_iPhysicalYSize - yp;
115 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
119 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
122 m_iCurrentPhysicalX = xp;
123 m_iCurrentPhysicalY = yp;
127 SGP::markerNDC (double x, double y)
132 SGP::pointNDC (double x, double y)
138 // clear Clear Window
145 g2_clear (m_driver.idG2());
149 m_driver.idWX()->Clear();
154 // sgp2_window Set window in world coordinates
158 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
160 if (xmin >= xmax || ymin >= ymax) {
161 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
169 m_bRecalcTransform = true;
174 // sgp2_viewport Set viewport in NDC
177 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
179 if (xmin >= xmax || ymin >= ymax) {
180 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
188 m_bRecalcTransform = true;
190 viewNDC[0] = xmin; // Array for clip_rect()
198 // frameViewport draw box around viewport
201 SGP::frameViewport (void)
203 stylusNDC (xv_min, yv_min, 0);
204 stylusNDC (xv_max, yv_min, 1);
205 stylusNDC (xv_max, yv_max, 1);
206 stylusNDC (xv_min, yv_max, 1);
207 stylusNDC (xv_min, yv_min, 1);
211 SGP::setTextColor (int iFGcolor, int iBGcolor)
216 SGP::setColor (int icol)
218 if (icol >= 0 && icol < s_iRGBColorCount) {
220 if (m_driver.isG2()) {
221 int iInk = g2_ink (m_driver.idG2(), s_aRGBColor[icol].getRed() / 255., s_aRGBColor[icol].getGreen() / 255., s_aRGBColor[icol].getBlue() / 255.);
222 g2_pen (m_driver.idG2(), iInk);
226 if (m_driver.isWX()) {
227 wxColor colour (s_aRGBColor[icol].getRed(), s_aRGBColor[icol].getGreen(), s_aRGBColor[icol].getBlue());
228 wxPen pen (colour, 1, wxSOLID);
229 m_driver.idWX()->SetPen (pen);
236 SGP::setMarker (int idMarke, int iColor)
240 //==============================================================
241 // set line style. Pass 16 bit repeating pattern
242 //==============================================================
244 SGP::setLineStyle (int style)
248 //==============================================================
250 //*==============================================================
253 SGP::lineAbs (double x, double y)
255 if (m_bRecalcTransform)
258 double x1 = m_dCurrentWorldX;
259 double y1 = m_dCurrentWorldY;
260 mc_to_ndc.transformPoint (&x1, &y1);
264 mc_to_ndc.transformPoint (&x1, &y2);
266 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
267 stylusNDC (x1, y1, 0); // move to first point
268 stylusNDC (x2, y2, 1); // draw to second point
271 m_dCurrentWorldX = x;
272 m_dCurrentWorldY = y;
276 SGP::moveAbs (double x, double y)
278 m_dCurrentWorldX = x;
279 m_dCurrentWorldY = y; /* moves are not clipped */
283 SGP::lineRel (double x, double y)
285 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
289 SGP::moveRel (double x, double y)
291 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
295 SGP::setTextSize (double height)
298 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
302 SGP::setTextAngle (double angle)
304 m_dTextAngle = angle;
308 SGP::polylineAbs (double x[], double y[], int n)
310 if (m_bRecalcTransform)
313 double x1 = x[0], y1 = y[0];
314 mc_to_ndc.transformPoint (&x1, &y1);
315 double x2 = x[1], y2 = y[1];
316 mc_to_ndc.transformPoint (&x2, &y2);
318 double xt = x2; // don't pass (x2,y2) to clip, we need them
319 double yt = y2; // as the beginning point of the next line
321 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
322 stylusNDC (x1, y1, 0);
323 stylusNDC (xt, yt, 1);
326 for (int i = 2; i < n; i++) {
327 x1 = x2; y1 = y2; // NDC endpoint of last line
328 x2 = x[i]; y2 = y[i];
329 mc_to_ndc.transformPoint (&x2, &y2);
332 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
333 stylusNDC (x1, y1, 0);
334 stylusNDC (xt, yt, 1);
341 SGP::markerAbs (double x, double y)
343 if (m_bRecalcTransform)
348 mc_to_ndc.transformPoint (&xndc, &yndc);
349 markerNDC (xndc, yndc);
350 stylusNDC (xndc, yndc, false); // move to location
351 m_dCurrentWorldX = x;
352 m_dCurrentWorldY = y;
357 SGP::markerRel (double x, double y)
359 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
364 SGP::pointAbs (double x, double y)
366 if (m_bRecalcTransform)
368 double xndc = x, yndc = y;
369 mc_to_ndc.transformPoint (&xndc, &yndc);
370 pointNDC (xndc, yndc);
371 stylusNDC (xndc, yndc, false); // move to location
372 m_dCurrentWorldX = x;
373 m_dCurrentWorldY = y;
378 SGP::pointRel (double x, double y)
380 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
385 SGP::drawText (const string& rsMessage)
387 drawText (rsMessage.c_str());
391 SGP::drawText (const char *pszMessage)
393 if (m_bRecalcTransform)
396 double xndc = m_dCurrentWorldX;
397 double yndc = m_dCurrentWorldY;
398 mc_to_ndc.transformPoint (&xndc, &yndc);
400 stylusNDC (xndc, yndc, false); // move to location
403 if (m_driver.isG2()) {
404 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
408 if (m_driver.isWX()) {
409 wxString str (pszMessage);
410 m_driver.idWX()->DrawRotatedText (str, m_iCurrentPhysicalX, m_iCurrentPhysicalY, m_dTextAngle);
417 // drawRect Draw box in graphics mode
420 // drawbox (xmin, ymin, xmax, ymax)
421 // double xmin, ymin Lower left corner of box
422 // double xmax, ymax Upper left corner of box
425 // This routine leaves the current position of graphic cursor at lower
426 // left corner of box.
429 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
431 moveAbs (xmin, ymin);
432 lineAbs (xmax, ymin);
433 lineAbs (xmax, ymax);
434 lineAbs (xmin, ymax);
435 lineAbs (xmin, ymin);
439 // sgp2_circle - draw circle of radius r at current center
442 SGP::drawCircle (const double r)
444 drawArc (0.0, 7.0, r);
447 // =============================================================
448 // draw arc around current center. pass angles and radius
449 //==============================================================
452 SGP::drawArc (double start, double stop, const double r)
454 if ((stop-start) > 2 * PI)
455 stop = start + 2 * PI;
456 if ((start-stop) > 2 * PI)
457 stop = start + 2 * PI;
458 while (start >= stop)
461 double x = r * cos ((double) start);
462 double y = r * sin ((double) start);
463 moveRel (x, y); // move from center to start of arc
465 double theta = 5 * PI / 180;
466 double c = cos(theta);
467 double s = sin(theta);
469 double angle, xp, yp;
470 for (angle = start; angle < stop - theta; angle += theta) {
473 lineRel (xp - x, yp - y);
477 c = cos (stop - angle);
478 s = sin (stop - angle);
481 lineRel (xp - x, yp - y);
483 x = r * cos ((double) stop);
484 y = r * sin ((double) stop);
485 moveRel (-x, -y); // move back to center of circle
490 ///////////////////////////////////////////////////////////////////////
491 // Coordinate Transformations
492 ///////////////////////////////////////////////////////////////////////
496 SGP::transformNDCtoMC (double* x, double* y)
498 if (m_bRecalcTransform)
500 ndc_to_mc.transformPoint (x, y);
505 SGP::transformMCtoNDC (double* x, double* y)
507 if (m_bRecalcTransform)
509 mc_to_ndc.transformPoint (x, y);
514 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
516 if (m_bRecalcTransform)
520 mc_to_ndc.transformPoint (x, y);
525 // calc_transform Calculate transform matrices
528 SGP::calc_transform ()
530 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
531 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
533 wc_to_ndc.setIdentity();
534 wc_to_ndc.mtx[0][0] = scaleX;
535 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
536 wc_to_ndc.mtx[1][1] = scaleY;
537 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
539 mc_to_ndc = m_ctm * wc_to_ndc;
540 ndc_to_mc = mc_to_ndc.invert();
542 m_bRecalcTransform = false;
553 SGP::ctmSet (const TransformationMatrix2D& m)
561 SGP::preTranslate (double x, double y)
563 TransformationMatrix2D m;
565 m.setTranslate (x, y);
571 SGP::postTranslate (double x, double y)
573 TransformationMatrix2D m;
575 m.setTranslate (x, y);
581 SGP::preScale (double sx, double sy)
583 TransformationMatrix2D m;
591 SGP::postScale (double sx, double sy)
593 TransformationMatrix2D m;
602 SGP::preRotate (double theta)
604 TransformationMatrix2D m;
613 SGP::postRotate (double theta)
615 TransformationMatrix2D m;
623 SGP::preShear (double shrx, double shry)
625 TransformationMatrix2D m;
627 m.setShear (shrx, shry);
633 SGP::postShear (double shrx, double shry)
635 TransformationMatrix2D m;
637 m.setShear (shrx, shry);
642 ////////////////////////////////////////////////////////////////////////
644 ////////////////////////////////////////////////////////////////////////
646 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
647 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
649 {'\000', '\000', '\010', '\000', '\000'}, // small dot
650 {'\000', '\034', '\024', '\034', '\000'}, // empty square
651 {'\000', '\034', '\034', '\034', '\000'}, // filled square
652 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
653 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
654 {'\010', '\010', '\076', '\010', '\010'}, // cross
655 {'\000', '\024', '\010', '\024', '\000'}, // X
656 {'\034', '\042', '\042', '\042', '\034'}, // open circle
657 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
658 {'\076', '\042', '\042', '\042', '\076'}, // big open square
659 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond