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.6 2000/07/28 10:51:31 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"
34 SGPDriver::SGPDriver (wxDC* pDC, const char* szWinTitle = "", int xsize = 640, int ysize = 480)
35 : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
38 m_idDriver |= SGPDRIVER_WXWINDOWS;
42 SGPDriver::SGPDriver (const char* szWinTitle = "", int xsize = 640, int ysize = 480)
43 : m_iPhysicalXSize(xsize), m_iPhysicalYSize(ysize), m_sWindowTitle(szWinTitle), m_idDriver(0)
46 m_idG2 = g2_open_X11X (m_iPhysicalXSize, m_iPhysicalYSize, 10, 10, const_cast<char*>(szWinTitle), const_cast<char*>(szWinTitle), NULL, -1, -1);
47 m_idDriver |= SGPDRIVER_G2;
51 SGPDriver::~SGPDriver ()
59 // SGP::SGP Constructor for Simple Graphics Package
61 SGP::SGP (const SGPDriver& driver)
64 m_iPhysicalXSize = m_driver.getPhysicalXSize();
65 m_iPhysicalYSize = m_driver.getPhysicalYSize();
67 wc_to_ndc.setIdentity ();
68 mc_to_ndc.setIdentity();
69 ndc_to_mc.setIdentity();
72 setWindow (0., 0., 1., 1.);
73 setViewport (0., 0., 1., 1.);
75 m_iCurrentPhysicalX = 0;
76 m_iCurrentPhysicalY = 0;
79 setTextSize (1. / 25.);
84 SGP::stylusNDC (double x, double y, bool beam)
86 int xp = static_cast<int>(x * (m_iPhysicalXSize - 1) + 0.5);
87 int yp = static_cast<int>(y * (m_iPhysicalYSize - 1) + 0.5);
89 yp = m_iPhysicalYSize - yp;
93 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
95 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
97 m_iCurrentPhysicalX = xp;
98 m_iCurrentPhysicalY = yp;
102 SGP::markerNDC (double x, double y)
107 SGP::pointNDC (double x, double y)
113 // clear Clear Window
119 g2_clear (m_driver.idG2());
121 m_driver.idWX()->Clear();
125 // sgp2_window Set window in world coordinates
129 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
131 if (xmin >= xmax || ymin >= ymax) {
132 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
140 m_bRecalcTransform = true;
145 // sgp2_viewport Set viewport in NDC
148 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
150 if (xmin >= xmax || ymin >= ymax) {
151 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
159 m_bRecalcTransform = true;
161 viewNDC[0] = xmin; // Array for clip_rect()
169 // frameViewport draw box around viewport
172 SGP::frameViewport (void)
174 stylusNDC (xv_min, yv_min, 0);
175 stylusNDC (xv_max, yv_min, 1);
176 stylusNDC (xv_max, yv_max, 1);
177 stylusNDC (xv_min, yv_max, 1);
178 stylusNDC (xv_min, yv_min, 1);
182 SGP::setTextColor (int iFGcolor, int iBGcolor)
187 SGP::setColor (int icol)
192 SGP::setMarker (int idMarke, int iColor)
196 //==============================================================
197 // set line style. Pass 16 bit repeating pattern
198 //==============================================================
200 SGP::setLineStyle (int style)
204 //==============================================================
206 //*==============================================================
209 SGP::lineAbs (double x, double y)
211 if (m_bRecalcTransform)
214 double x1 = m_dCurrentWorldX;
215 double y1 = m_dCurrentWorldY;
216 mc_to_ndc.transformPoint (&x1, &y1);
220 mc_to_ndc.transformPoint (&x1, &y2);
222 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
223 stylusNDC (x1, y1, 0); // move to first point
224 stylusNDC (x2, y2, 1); // draw to second point
227 m_dCurrentWorldX = x;
228 m_dCurrentWorldY = y;
232 SGP::moveAbs (double x, double y)
234 m_dCurrentWorldX = x;
235 m_dCurrentWorldY = y; /* moves are not clipped */
239 SGP::lineRel (double x, double y)
241 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
245 SGP::moveRel (double x, double y)
247 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
251 SGP::setTextSize (double height)
254 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
258 SGP::setTextAngle (double angle)
260 m_dTextAngle = angle;
264 SGP::polylineAbs (double x[], double y[], int n)
266 if (m_bRecalcTransform)
269 double x1 = x[0], y1 = y[0];
270 mc_to_ndc.transformPoint (&x1, &y1);
271 double x2 = x[1], y2 = y[1];
272 mc_to_ndc.transformPoint (&x2, &y2);
274 double xt = x2; // don't pass (x2,y2) to clip, we need them
275 double yt = y2; // as the beginning point of the next line
277 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
278 stylusNDC (x1, y1, 0);
279 stylusNDC (xt, yt, 1);
282 for (int i = 2; i < n; i++) {
283 x1 = x2; y1 = y2; // NDC endpoint of last line
284 x2 = x[i]; y2 = y[i];
285 mc_to_ndc.transformPoint (&x2, &y2);
288 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
289 stylusNDC (x1, y1, 0);
290 stylusNDC (xt, yt, 1);
297 SGP::markerAbs (double x, double y)
299 if (m_bRecalcTransform)
304 mc_to_ndc.transformPoint (&xndc, &yndc);
305 markerNDC (xndc, yndc);
306 stylusNDC (xndc, yndc, false); // move to location
307 m_dCurrentWorldX = x;
308 m_dCurrentWorldY = y;
313 SGP::markerRel (double x, double y)
315 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
320 SGP::pointAbs (double x, double y)
322 if (m_bRecalcTransform)
324 double xndc = x, yndc = y;
325 mc_to_ndc.transformPoint (&xndc, &yndc);
326 pointNDC (xndc, yndc);
327 stylusNDC (xndc, yndc, false); // move to location
328 m_dCurrentWorldX = x;
329 m_dCurrentWorldY = y;
334 SGP::pointRel (double x, double y)
336 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
341 SGP::drawText (const string& rsMessage)
343 drawText (rsMessage.c_str());
347 SGP::drawText (const char *pszMessage)
349 if (m_bRecalcTransform)
352 double xndc = m_dCurrentWorldX;
353 double yndc = m_dCurrentWorldY;
354 mc_to_ndc.transformPoint (&xndc, &yndc);
356 stylusNDC (xndc, yndc, false); // move to location
358 if (m_driver.isG2()) {
359 if (m_dTextAngle == 0.)
360 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
362 if (m_driver.isWX()) {
368 // drawRect Draw box in graphics mode
371 // drawbox (xmin, ymin, xmax, ymax)
372 // double xmin, ymin Lower left corner of box
373 // double xmax, ymax Upper left corner of box
376 // This routine leaves the current position of graphic cursor at lower
377 // left corner of box.
380 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
382 moveAbs (xmin, ymin);
383 lineAbs (xmax, ymin);
384 lineAbs (xmax, ymax);
385 lineAbs (xmin, ymax);
386 lineAbs (xmin, ymin);
390 // sgp2_circle - draw circle of radius r at current center
393 SGP::drawCircle (const double r)
395 drawArc (0.0, 7.0, r);
398 // =============================================================
399 // draw arc around current center. pass angles and radius
400 //==============================================================
403 SGP::drawArc (double start, double stop, const double r)
405 if ((stop-start) > 2 * PI)
406 stop = start + 2 * PI;
407 if ((start-stop) > 2 * PI)
408 stop = start + 2 * PI;
409 while (start >= stop)
412 double x = r * cos ((double) start);
413 double y = r * sin ((double) start);
414 moveRel (x, y); // move from center to start of arc
416 double theta = 5 * PI / 180;
417 double c = cos(theta);
418 double s = sin(theta);
420 double angle, xp, yp;
421 for (angle = start; angle < stop - theta; angle += theta) {
424 lineRel (xp - x, yp - y);
428 c = cos (stop - angle);
429 s = sin (stop - angle);
432 lineRel (xp - x, yp - y);
434 x = r * cos ((double) stop);
435 y = r * sin ((double) stop);
436 moveRel (-x, -y); // move back to center of circle
441 ///////////////////////////////////////////////////////////////////////
442 // Coordinate Transformations
443 ///////////////////////////////////////////////////////////////////////
447 SGP::transformNDCtoMC (double* x, double* y)
449 if (m_bRecalcTransform)
451 ndc_to_mc.transformPoint (x, y);
456 SGP::transformMCtoNDC (double* x, double* y)
458 if (m_bRecalcTransform)
460 mc_to_ndc.transformPoint (x, y);
465 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
467 if (m_bRecalcTransform)
471 mc_to_ndc.transformPoint (x, y);
476 // calc_transform Calculate transform matrices
479 SGP::calc_transform ()
481 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
482 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
484 wc_to_ndc.setIdentity();
485 wc_to_ndc.mtx[0][0] = scaleX;
486 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
487 wc_to_ndc.mtx[1][1] = scaleY;
488 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
490 mc_to_ndc = m_ctm * wc_to_ndc;
491 ndc_to_mc = mc_to_ndc.invert();
493 m_bRecalcTransform = false;
504 SGP::ctmSet (const TransformationMatrix2D& m)
512 SGP::preTranslate (double x, double y)
514 TransformationMatrix2D m;
516 m.setTranslate (x, y);
522 SGP::postTranslate (double x, double y)
524 TransformationMatrix2D m;
526 m.setTranslate (x, y);
532 SGP::preScale (double sx, double sy)
534 TransformationMatrix2D m;
542 SGP::postScale (double sx, double sy)
544 TransformationMatrix2D m;
553 SGP::preRotate (double theta)
555 TransformationMatrix2D m;
564 SGP::postRotate (double theta)
566 TransformationMatrix2D m;
574 SGP::preShear (double shrx, double shry)
576 TransformationMatrix2D m;
578 m.setShear (shrx, shry);
584 SGP::postShear (double shrx, double shry)
586 TransformationMatrix2D m;
588 m.setShear (shrx, shry);
593 ////////////////////////////////////////////////////////////////////////
595 ////////////////////////////////////////////////////////////////////////
597 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
598 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
600 {'\000', '\000', '\010', '\000', '\000'}, // small dot
601 {'\000', '\034', '\024', '\034', '\000'}, // empty square
602 {'\000', '\034', '\034', '\034', '\000'}, // filled square
603 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
604 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
605 {'\010', '\010', '\076', '\010', '\010'}, // cross
606 {'\000', '\024', '\010', '\024', '\000'}, // X
607 {'\034', '\042', '\042', '\042', '\034'}, // open circle
608 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
609 {'\076', '\042', '\042', '\042', '\076'}, // big open square
610 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond