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.5 2000/07/28 08:28: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"
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 + 0.5);
87 int yp = static_cast<int>(y * m_iPhysicalYSize + 0.5);
90 m_driver.idWX()->DrawLine (m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
92 g2_line (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, xp, yp);
94 m_iCurrentPhysicalX = xp;
95 m_iCurrentPhysicalY = yp;
99 SGP::markerNDC (double x, double y)
104 SGP::pointNDC (double x, double y)
110 // clear Clear Window
116 g2_clear (m_driver.idG2());
118 m_driver.idWX()->Clear();
122 // sgp2_window Set window in world coordinates
126 SGP::setWindow (double xmin, double ymin, double xmax, double ymax)
128 if (xmin >= xmax || ymin >= ymax) {
129 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
137 m_bRecalcTransform = true;
142 // sgp2_viewport Set viewport in NDC
145 SGP::setViewport (double xmin, double ymin, double xmax, double ymax)
147 if (xmin >= xmax || ymin >= ymax) {
148 sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
156 m_bRecalcTransform = true;
158 viewNDC[0] = xmin; // Array for clip_rect()
166 // frameViewport draw box around viewport
169 SGP::frameViewport (void)
171 stylusNDC (xv_min, yv_min, 0);
172 stylusNDC (xv_max, yv_min, 1);
173 stylusNDC (xv_max, yv_max, 1);
174 stylusNDC (xv_min, yv_max, 1);
175 stylusNDC (xv_min, yv_min, 1);
179 SGP::setTextColor (int iFGcolor, int iBGcolor)
184 SGP::setColor (int icol)
189 SGP::setMarker (int idMarke, int iColor)
193 //==============================================================
194 // set line style. Pass 16 bit repeating pattern
195 //==============================================================
197 SGP::setLineStyle (int style)
201 //==============================================================
203 //*==============================================================
206 SGP::lineAbs (double x, double y)
208 if (m_bRecalcTransform)
211 double x1 = m_dCurrentWorldX;
212 double y1 = m_dCurrentWorldY;
213 mc_to_ndc.transformPoint (&x1, &y1);
217 mc_to_ndc.transformPoint (&x1, &y2);
219 if (clip_rect (x1, y1, x2, y2, viewNDC) == true) { // clip to viewport
220 stylusNDC (x1, y1, 0); // move to first point
221 stylusNDC (x2, y2, 1); // draw to second point
224 m_dCurrentWorldX = x;
225 m_dCurrentWorldY = y;
229 SGP::moveAbs (double x, double y)
231 m_dCurrentWorldX = x;
232 m_dCurrentWorldY = y; /* moves are not clipped */
236 SGP::lineRel (double x, double y)
238 lineAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
242 SGP::moveRel (double x, double y)
244 moveAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
248 SGP::setTextSize (double height)
251 g2_set_font_size(m_driver.idG2(), (height * m_iPhysicalYSize));
255 SGP::setTextAngle (double angle)
257 m_dTextAngle = angle;
261 SGP::polylineAbs (double x[], double y[], int n)
263 if (m_bRecalcTransform)
266 double x1 = x[0], y1 = y[0];
267 mc_to_ndc.transformPoint (&x1, &y1);
268 double x2 = x[1], y2 = y[1];
269 mc_to_ndc.transformPoint (&x2, &y2);
271 double xt = x2; // don't pass (x2,y2) to clip, we need them
272 double yt = y2; // as the beginning point of the next line
274 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
275 stylusNDC (x1, y1, 0);
276 stylusNDC (xt, yt, 1);
279 for (int i = 2; i < n; i++) {
280 x1 = x2; y1 = y2; // NDC endpoint of last line
281 x2 = x[i]; y2 = y[i];
282 mc_to_ndc.transformPoint (&x2, &y2);
285 if (clip_rect (x1, y1, xt, yt, viewNDC)) {
286 stylusNDC (x1, y1, 0);
287 stylusNDC (xt, yt, 1);
294 SGP::markerAbs (double x, double y)
296 if (m_bRecalcTransform)
301 mc_to_ndc.transformPoint (&xndc, &yndc);
302 markerNDC (xndc, yndc);
303 stylusNDC (xndc, yndc, false); // move to location
304 m_dCurrentWorldX = x;
305 m_dCurrentWorldY = y;
310 SGP::markerRel (double x, double y)
312 markerAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
317 SGP::pointAbs (double x, double y)
319 if (m_bRecalcTransform)
321 double xndc = x, yndc = y;
322 mc_to_ndc.transformPoint (&xndc, &yndc);
323 pointNDC (xndc, yndc);
324 stylusNDC (xndc, yndc, false); // move to location
325 m_dCurrentWorldX = x;
326 m_dCurrentWorldY = y;
331 SGP::pointRel (double x, double y)
333 pointAbs (x + m_dCurrentWorldX, y + m_dCurrentWorldY);
338 SGP::drawText (const string& rsMessage)
340 drawText (rsMessage.c_str());
344 SGP::drawText (const char *pszMessage)
346 if (m_bRecalcTransform)
349 double xndc = m_dCurrentWorldX;
350 double yndc = m_dCurrentWorldY;
351 mc_to_ndc.transformPoint (&xndc, &yndc);
353 stylusNDC (xndc, yndc, false); // move to location
355 if (m_driver.isG2()) {
356 if (m_dTextAngle == 0.)
357 g2_string (m_driver.idG2(), m_iCurrentPhysicalX, m_iCurrentPhysicalY, const_cast<char*>(pszMessage));
359 if (m_driver.isWX()) {
365 // drawRect Draw box in graphics mode
368 // drawbox (xmin, ymin, xmax, ymax)
369 // double xmin, ymin Lower left corner of box
370 // double xmax, ymax Upper left corner of box
373 // This routine leaves the current position of graphic cursor at lower
374 // left corner of box.
377 SGP::drawRect (double xmin, double ymin, double xmax, double ymax)
379 moveAbs (xmin, ymin);
380 lineAbs (xmax, ymin);
381 lineAbs (xmax, ymax);
382 lineAbs (xmin, ymax);
383 lineAbs (xmin, ymin);
387 // sgp2_circle - draw circle of radius r at current center
390 SGP::drawCircle (const double r)
392 drawArc (0.0, 7.0, r);
395 // =============================================================
396 // draw arc around current center. pass angles and radius
397 //==============================================================
400 SGP::drawArc (double start, double stop, const double r)
402 if ((stop-start) > 2 * PI)
403 stop = start + 2 * PI;
404 if ((start-stop) > 2 * PI)
405 stop = start + 2 * PI;
406 while (start >= stop)
409 double x = r * cos ((double) start);
410 double y = r * sin ((double) start);
411 moveRel (x, y); // move from center to start of arc
413 double theta = 5 * PI / 180;
414 double c = cos(theta);
415 double s = sin(theta);
417 double angle, xp, yp;
418 for (angle = start; angle < stop - theta; angle += theta) {
421 lineRel (xp - x, yp - y);
425 c = cos (stop - angle);
426 s = sin (stop - angle);
429 lineRel (xp - x, yp - y);
431 x = r * cos ((double) stop);
432 y = r * sin ((double) stop);
433 moveRel (-x, -y); // move back to center of circle
438 ///////////////////////////////////////////////////////////////////////
439 // Coordinate Transformations
440 ///////////////////////////////////////////////////////////////////////
444 SGP::transformNDCtoMC (double* x, double* y)
446 if (m_bRecalcTransform)
448 ndc_to_mc.transformPoint (x, y);
453 SGP::transformMCtoNDC (double* x, double* y)
455 if (m_bRecalcTransform)
457 mc_to_ndc.transformPoint (x, y);
462 SGP::transformMCtoNDC (double xIn, double yIn, double* x, double* y)
464 if (m_bRecalcTransform)
468 mc_to_ndc.transformPoint (x, y);
473 // calc_transform Calculate transform matrices
476 SGP::calc_transform ()
478 double scaleX = (xv_max - xv_min) / (xw_max - xw_min);
479 double scaleY = (yv_max - yv_min) / (yw_max - yw_min);
481 wc_to_ndc.setIdentity();
482 wc_to_ndc.mtx[0][0] = scaleX;
483 wc_to_ndc.mtx[2][0] = xv_min - scaleX * xw_min;
484 wc_to_ndc.mtx[1][1] = scaleY;
485 wc_to_ndc.mtx[2][1] = yv_min - scaleY * yw_min;
487 mc_to_ndc = m_ctm * wc_to_ndc;
488 ndc_to_mc = mc_to_ndc.invert();
490 m_bRecalcTransform = false;
501 SGP::ctmSet (const TransformationMatrix2D& m)
509 SGP::preTranslate (double x, double y)
511 TransformationMatrix2D m;
513 m.setTranslate (x, y);
519 SGP::postTranslate (double x, double y)
521 TransformationMatrix2D m;
523 m.setTranslate (x, y);
529 SGP::preScale (double sx, double sy)
531 TransformationMatrix2D m;
539 SGP::postScale (double sx, double sy)
541 TransformationMatrix2D m;
550 SGP::preRotate (double theta)
552 TransformationMatrix2D m;
561 SGP::postRotate (double theta)
563 TransformationMatrix2D m;
571 SGP::preShear (double shrx, double shry)
573 TransformationMatrix2D m;
575 m.setShear (shrx, shry);
581 SGP::postShear (double shrx, double shry)
583 TransformationMatrix2D m;
585 m.setShear (shrx, shry);
590 ////////////////////////////////////////////////////////////////////////
592 ////////////////////////////////////////////////////////////////////////
594 // Pixel patterns of marker symbols (1x1 to 5x5 matrix)
595 const unsigned char SGP::MARKER_BITMAP[MARK_COUNT][5] =
597 {'\000', '\000', '\010', '\000', '\000'}, // small dot
598 {'\000', '\034', '\024', '\034', '\000'}, // empty square
599 {'\000', '\034', '\034', '\034', '\000'}, // filled square
600 {'\000', '\010', '\024', '\010', '\000'}, // empty diamond
601 {'\000', '\010', '\034', '\010', '\000'}, // filled diamond
602 {'\010', '\010', '\076', '\010', '\010'}, // cross
603 {'\000', '\024', '\010', '\024', '\000'}, // X
604 {'\034', '\042', '\042', '\042', '\034'}, // open circle
605 {'\034', '\076', '\076', '\076', '\034'}, // filled circle
606 {'\076', '\042', '\042', '\042', '\076'}, // big open square
607 {'\010', '\024', '\042', '\024', '\010'}, // big open diamond