r142: *** empty log message ***
[ctsim.git] / libctgraphics / sgp.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:       sgp.c               Simple Graphics Package
5 **      Programmer: Kevin Rosenberg
6 **
7 **  This is part of the CTSim program
8 **  Copyright (C) 1983-2000 Kevin Rosenberg
9 **
10 **  $Id: sgp.cpp,v 1.4 2000/07/11 10:32:44 kevin Exp $
11 **
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.
15 **
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.
20 **
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 ******************************************************************************/
25
26 #include <stdio.h>
27 #include <math.h>
28 #include "ctsupport.h"
29 #include "sgp.h"
30
31
32 static SGP_ID _sgp2_cwin = NULL;
33
34 extern CHARSPEC cspec;
35
36
37 /* NAME
38  *   sgp2_init                          Initialize 2 graphics system
39  *
40  * SYNOPSIS
41  *   sgp2_init()
42  */
43
44 SGP_ID
45 sgp2_init (int xsize, int ysize, const char *win_title )
46 {
47     SGP_ID gid;
48
49     gid = new SGP_WINDOW;
50     _sgp2_cwin = gid;
51  
52     if (xsize <= 0)
53         xsize = 640;
54     if (ysize <= 0)
55         ysize = 480;
56
57     gid->pw_xsize = xsize;
58     gid->pw_ysize = ysize;
59     strncpy(gid->title, win_title, sizeof(gid->title));
60
61     gid->recalc_mc_to_ndc = TRUE;
62     gid->recalc_ndc_to_mc = TRUE;
63     ident_gmtx_2 (gid->wc_to_ndc_x);
64     ident_gmtx_2 (gid->mc_to_ndc_x);
65     ident_gmtx_2 (gid->ndc_to_mc_x);
66     ident_gmtx_2 (gid->ctm_2_x);
67
68     sgp2_window (0., 0., 1., 1.);
69     sgp2_viewport (0., 0., 1., 1.);
70     ctm_clr_2 ();
71     sgp2_move_abs (0., 0.);
72
73 #if HAVE_G2_H
74     gid->g2_id = g2_open_X11X (gid->pw_xsize, gid->pw_ysize, 10, 10, gid->title, gid->title, NULL, -1, -1);
75 #endif
76
77     _sgp2_init_dev (_sgp2_cwin);
78     
79     return (gid);
80 }
81
82
83 void
84 sgp2_close (SGP_ID gid)
85 {
86 #if HAVE_G2_H    
87   if (gid)
88     g2_close (gid->g2_id);
89 #endif
90   if (gid == _sgp2_cwin)
91     _sgp2_cwin = NULL;
92
93   delete gid;
94 }
95
96 void
97 sgp2_set_active_win (SGP_ID gid)
98 {
99     _sgp2_cwin = gid;
100 }
101
102 SGP_ID
103 sgp2_get_active_win (void)
104 {
105     return (_sgp2_cwin);
106 }
107
108
109 /* NAME
110  *      sgp2_clear          Clear window
111  */
112
113 void 
114 sgp2_clear ()
115 {
116 #if HAVE_G2
117     if (_sgp_cwin != NULL)
118         g2_clear (gid->g2_id);
119 #endif
120 }
121
122 /* NAME
123  *      sgp2_window             Set window in world coordinates
124  */
125
126 void
127 sgp2_window (double xmin, double ymin, double xmax, double ymax)
128 {
129     if (_sgp2_cwin == NULL)
130        return;
131
132     if (xmin >= xmax || ymin >= ymax) {
133         sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_window]");
134         return;
135     }
136
137     _sgp2_cwin->xw_min = xmin;
138     _sgp2_cwin->yw_min = ymin;
139     _sgp2_cwin->xw_max = xmax;
140     _sgp2_cwin->yw_max = ymax;
141     calc_wc_to_ndc();
142 }
143
144
145 /* NAME
146  *      sgp2_viewport                   Set viewport in NDC
147  */
148
149 void
150 sgp2_viewport (double xmin, double ymin, double xmax, double ymax)
151 {
152     if (_sgp2_cwin == NULL)
153        return;
154
155     if (xmin >= xmax || ymin >= ymax) {
156         sys_error (ERR_WARNING, "Minimum > Maximum [sgp2_viewport]");
157         return;
158     }
159     
160     _sgp2_cwin->xv_min = xmin;
161     _sgp2_cwin->yv_min = ymin;
162     _sgp2_cwin->xv_max = xmax;
163     _sgp2_cwin->yv_max = ymax;
164     calc_wc_to_ndc();
165     
166     _sgp2_cwin->view[0] = xmin;                 /* Array for clip_rect() */
167     _sgp2_cwin->view[1] = ymin;
168     _sgp2_cwin->view[2] = xmax;
169     _sgp2_cwin->view[3] = ymax;
170 }
171
172
173 /* NAME
174  *      sgp2_frame_vpt          draw box around viewport
175  */
176
177 void
178 sgp2_frame_vpt (void)
179 {
180     if (_sgp2_cwin == NULL)
181         return;
182
183     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_min, 0);
184     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_max, _sgp2_cwin->yv_min, 1);
185     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_max, _sgp2_cwin->yv_max, 1);
186     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_max, 1);
187     _sgp2_stylus (_sgp2_cwin, _sgp2_cwin->xv_min, _sgp2_cwin->yv_min, 1);
188 }
189
190
191 /* NAME
192  *      calc_wc_to_ndc                  Calculate transform matrix
193  */
194
195 void
196 calc_wc_to_ndc (void)
197 {
198     double sx, sy;
199     
200     if (_sgp2_cwin == NULL)
201         return;
202
203     sx = (_sgp2_cwin->xv_max - _sgp2_cwin->xv_min) / (_sgp2_cwin->xw_max - _sgp2_cwin->xw_min);
204     sy = (_sgp2_cwin->yv_max - _sgp2_cwin->yv_min) / (_sgp2_cwin->yw_max - _sgp2_cwin->yw_min);
205     
206     ident_gmtx_2 (_sgp2_cwin->wc_to_ndc_x);
207     _sgp2_cwin->wc_to_ndc_x[0][0] = sx;
208     _sgp2_cwin->wc_to_ndc_x[2][0] = _sgp2_cwin->xv_min - sx * _sgp2_cwin->xw_min;
209     _sgp2_cwin->wc_to_ndc_x[1][1] = sy;
210     _sgp2_cwin->wc_to_ndc_x[2][1] = _sgp2_cwin->yv_min - sy * _sgp2_cwin->yw_min;
211     
212     _sgp2_cwin->recalc_mc_to_ndc = TRUE;
213     _sgp2_cwin->recalc_ndc_to_mc = TRUE;
214 }
215
216
217 void 
218 calc_ndc_to_mc (void)
219 {
220     if (_sgp2_cwin == NULL)
221         return;
222
223     if (_sgp2_cwin->recalc_mc_to_ndc) {
224         mult_gmtx_2 (_sgp2_cwin->ctm_2_x, _sgp2_cwin->wc_to_ndc_x, _sgp2_cwin->mc_to_ndc_x);
225         _sgp2_cwin->recalc_mc_to_ndc = FALSE;
226     }
227     
228     invert_gmtx_2 (_sgp2_cwin->mc_to_ndc_x, _sgp2_cwin->ndc_to_mc_x);
229     _sgp2_cwin->recalc_ndc_to_mc = FALSE;
230 }
231
232
233 /* NAME
234  *      wc_to_ndc                       Map from world coordinates to NDC
235  */
236
237 void 
238 wc_to_ndc (double xw, double yw, double *xn, double *yn)
239 {
240     if (_sgp2_cwin == NULL)
241         return;
242
243     if (_sgp2_cwin->recalc_mc_to_ndc) {
244         mult_gmtx_2 (_sgp2_cwin->ctm_2_x, _sgp2_cwin->wc_to_ndc_x, _sgp2_cwin->mc_to_ndc_x);
245         _sgp2_cwin->recalc_mc_to_ndc = FALSE;
246     }
247
248     *xn = xw * _sgp2_cwin->mc_to_ndc_x[0][0] + yw * _sgp2_cwin->mc_to_ndc_x[1][0] + _sgp2_cwin->mc_to_ndc_x[2][0];
249     *yn = xw * _sgp2_cwin->mc_to_ndc_x[0][1] + yw * _sgp2_cwin->mc_to_ndc_x[1][1] + _sgp2_cwin->mc_to_ndc_x[2][1];
250 }
251
252
253 /*==============================================================*/
254 /* map from normalized device coords. to world coordinates      */
255 /*==============================================================*/
256 void
257 ndc_to_wc (double xn, double yn, double *xw, double *yw)
258 {
259     if (_sgp2_cwin == NULL)
260         return;
261
262     if (_sgp2_cwin->recalc_ndc_to_mc) {
263         calc_ndc_to_mc();
264         _sgp2_cwin->recalc_ndc_to_mc = FALSE;
265     }
266
267     *xw = xn * _sgp2_cwin->ndc_to_mc_x[0][0] + yn * _sgp2_cwin->ndc_to_mc_x[1][0] + _sgp2_cwin->ndc_to_mc_x[2][0];
268     *yw = xn * _sgp2_cwin->ndc_to_mc_x[0][1] + yn * _sgp2_cwin->ndc_to_mc_x[1][1] + _sgp2_cwin->ndc_to_mc_x[2][1];
269 }
270
271
272 /*==============================================================*/
273 /* set the color                                                */
274 /*==============================================================*/
275 void 
276 sgp2_color (int icol)
277 {
278     setcolor(icol);
279 }
280
281 /*==============================================================*/
282 /* set line style.  Pass 16 bit repeating pattern               */
283 /*==============================================================*/
284 void 
285 sgp2_line_style (int style)
286 {
287     setlinestyle(style);
288 }
289
290 /*==============================================================*/
291 /* absolute draw to                                             */
292 /*==============================================================*/
293 void 
294 sgp2_line_abs (double x, double y)
295 {
296     double x1, y1, x2, y2;
297
298     if (_sgp2_cwin == NULL)
299         return;
300
301     wc_to_ndc (_sgp2_cwin->curx, _sgp2_cwin->cury, &x1, &y1);
302     wc_to_ndc (x, y, &x2, &y2);
303
304     if (clip_rect (x1, y1, x2, y2, _sgp2_cwin->view) == TRUE) { /* clip to viewport */
305         _sgp2_stylus (_sgp2_cwin, x1, y1, 0);           /* move to first point */
306         _sgp2_stylus (_sgp2_cwin, x2, y2, 1);           /* draw to second point */
307     }
308
309     _sgp2_cwin->curx = x;
310     _sgp2_cwin->cury = y;
311 }
312
313 /*==============================================================*/
314 /* absolute move to                                             */
315 /*==============================================================*/
316 void 
317 sgp2_move_abs (double x, double y)
318 {
319     if (_sgp2_cwin == NULL)
320         return;
321
322     _sgp2_cwin->curx = x;
323     _sgp2_cwin->cury = y;                       /* moves are not clipped */
324 }
325
326 /*==============================================================*/
327 /* vector draw                                                  */
328 /*==============================================================*/
329 void 
330 sgp2_line_rel (double x, double y)
331 {
332     if (_sgp2_cwin != NULL)
333         sgp2_line_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
334 }
335
336 /*==============================================================*/
337 /* vector move                                                  */
338 /*==============================================================*/
339 void 
340 sgp2_move_rel (double x, double y)
341 {
342     if (_sgp2_cwin != NULL)
343         sgp2_move_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
344 }
345
346 /*==============================================================*/
347 /* draw text                                                    */
348 /*==============================================================*/
349 void 
350 sgp2_draw_text (char *message)
351 {
352     double sx,sy;
353     if (_sgp2_cwin == NULL)
354         return;
355
356     wc_to_ndc (_sgp2_cwin->curx, _sgp2_cwin->cury, &sx, &sy);
357     _sgp2_stylus (_sgp2_cwin, sx, sy, 0);       /* move to location */
358     _sgp2_dev_text (_sgp2_cwin, message);
359 }
360
361 void
362 charsize (double wid, double height)
363 {
364     _sgp2_set_text (_sgp2_cwin, wid, height, cspec.textangle, cspec.font);
365 }
366
367 void
368 textangle (double angle)
369 {
370     _sgp2_set_text (_sgp2_cwin, cspec.width, cspec.height, angle, cspec.font);
371 }
372
373 void 
374 sgp2_polyline_abs (double x[], double y[], int n)
375 {
376     double x1, y1, x2, y2;
377     int i;
378     double xt, yt;
379
380     if (_sgp2_cwin == NULL || n < 2)
381         return;
382
383     wc_to_ndc (x[0], y[0], &x1, &y1);
384     wc_to_ndc (x[1], y[1], &x2, &y2);
385
386     xt = x2;            /* don't pass (x2,y2) to clip, we need them */
387     yt = y2;            /* as the beginning point of the next line */
388
389     if (clip_rect (x1, y1, xt, yt, _sgp2_cwin->view) == TRUE) {
390         _sgp2_stylus (_sgp2_cwin, x1, y1, 0);
391         _sgp2_stylus (_sgp2_cwin, xt, yt, 1);
392     }
393
394     for (i = 2; i < n; i++) {
395         x1 = x2;                        /* NDC endpoint of last line */
396         y1 = y2;
397         wc_to_ndc (x[i], y[i], &x2, &y2);
398         xt = x2;
399         yt = y2;
400         if (clip_rect (x1, y1, xt, yt, _sgp2_cwin->view) == TRUE) {
401             _sgp2_stylus (_sgp2_cwin, x1, y1, 0);
402             _sgp2_stylus (_sgp2_cwin, xt, yt, 1);
403         }
404     }
405 }
406
407
408 void 
409 sgp2_mark_abs (double x, double y)
410 {
411     double xndc, yndc;
412
413     if (_sgp2_cwin == NULL)
414         return;
415
416     wc_to_ndc (x, y, &xndc, &yndc);
417     markndc (_sgp2_cwin, xndc, yndc);
418     _sgp2_cwin->curx = x;
419     _sgp2_cwin->cury = y;
420 }
421
422
423 void 
424 sgp2_mark_rel (double x, double y)
425 {
426     sgp2_mark_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
427 }
428
429
430 void 
431 sgp2_point_abs (double x, double y)
432 {
433     double xndc, yndc;
434
435     if (_sgp2_cwin == NULL)
436         return;;
437
438     wc_to_ndc (x, y, &xndc, &yndc);
439     pntndc (_sgp2_cwin, xndc, yndc);
440     _sgp2_cwin->curx = x;
441     _sgp2_cwin->cury = y;
442 }
443
444
445 void 
446 sgp2_point_rel (double x, double y)
447 {
448     sgp2_point_abs (x + _sgp2_cwin->curx, y + _sgp2_cwin->cury);
449 }
450
451
452 /* NAME
453  *   sgp2_draw_rect                             Draw box in graphics mode
454  *
455  * SYNOPSIS
456  *   drawbox (xmin, ymin, xmax, ymax)
457  *   double xmin, ymin                  Lower left corner of box
458  *   double xmax, ymax                  Upper left corner of box
459  *
460  * NOTES
461  *   This routine leaves the current position of graphic cursor at lower
462  *   left corner of box.
463  */
464
465 void
466 sgp2_draw_rect(double xmin, double ymin, double xmax, double ymax)
467 {
468         sgp2_move_abs (xmin, ymin);
469         sgp2_line_abs (xmax, ymin);
470         sgp2_line_abs (xmax, ymax);
471         sgp2_line_abs (xmin, ymax);
472         sgp2_line_abs (xmin, ymin);
473 }
474
475 /* FUNCTION
476  * sgp2_circle - draw circle of radius r at current center              
477  */
478
479 void 
480 sgp2_draw_circle (const double r)
481 {
482         sgp2_draw_arc (0.0, 7.0, r);
483 }
484
485 /*==============================================================*/
486 /* draw arc around current center.  pass angles and radius      */
487 /*==============================================================*/
488
489 void 
490 sgp2_draw_arc (double start, double stop, const double r)
491 {
492         double c, s, theta, angle;
493         float x, y, xp, yp;
494
495         if ((stop-start) > 2 * PI)
496             stop = start + 2 * PI;
497         if ((start-stop) > 2 * PI)
498             stop = start + 2 * PI;
499         while (start >= stop)
500             stop += 2*PI;
501
502         x = r * cos ((double) start);
503         y = r * sin ((double) start);
504         sgp2_move_rel (x, y);          /* move from center to start of arc */
505
506         theta = 5 * PI / 180;
507         c = cos(theta);
508         s = sin(theta);
509
510         for (angle = start; angle < stop - theta; angle += theta) {
511             xp = c * x - s * y;
512             yp = s * x + c * y;
513             sgp2_line_rel (xp - x, yp - y);
514             x = xp; y = yp;
515         }
516
517         c = cos (stop - angle);
518         s = sin (stop - angle);
519         xp = c * x - s * y;
520         yp = s * x + c * y;
521         sgp2_line_rel (xp - x, yp - y);
522
523         x = r * cos ((double) stop);
524         y = r * sin ((double) stop);
525         sgp2_move_rel (-x, -y);         /* move back to center of circle */
526 }
527
528
529 /*----------------------------------------------------------------------*/
530 /*                   Current Transformation Matrix Routine              */
531 /*----------------------------------------------------------------------*/
532
533
534 /* NAME
535  *      ctm_clr_2                       Clear current transformation matrix
536  *
537  * SYNOPSIS
538  *      ctm_clr_2()
539  */
540
541 void 
542 ctm_clr_2 (void)
543 {
544     GRFMTX_2D m;
545
546     ident_gmtx_2 (m);
547     ctm_set_2 (m);
548 }
549
550
551 /* NAME
552  *      ctm_get_2                       Get ctm
553  *
554  * SYNOPSIS
555  *      ctm_get_2 (m)
556  * OUT  GRFMTX_2D m                     Copy of ctm
557  */
558
559 void 
560 ctm_get_2 (GRFMTX_2D m)
561 {
562     int x, y;
563
564     if (_sgp2_cwin == NULL)
565         return;
566
567     for (x = 0; x < 3; x++)
568         for (y = 0; y < 3; y++)
569             m[x][y] = _sgp2_cwin->ctm_2_x[x][y];
570 }
571
572
573 /* NAME
574  *      ctm_set_2                       Set ctm to a matrix
575  *
576  * SYNOPSIS
577  *      ctm_get_ctm_2 (m)
578  * IN   GRFMTX m                        New ctm
579  */
580
581 void 
582 ctm_set_2 (GRFMTX_2D m)
583 {
584     int x, y;
585     if (_sgp2_cwin == NULL)
586         return;
587
588     for (x = 0; x < 3; x++)
589         for (y = 0; y < 3; y++)
590             _sgp2_cwin->ctm_2_x[x][y] = m[x][y];
591
592     _sgp2_cwin->recalc_ndc_to_mc = TRUE;
593     _sgp2_cwin->recalc_mc_to_ndc = TRUE;
594 }
595
596
597 void 
598 ctm_pre_mult_2 (GRFMTX_2D m)
599 {
600     GRFMTX_2D new_ctm;
601
602     mult_gmtx_2 (m, _sgp2_cwin->ctm_2_x, new_ctm);
603     ctm_set_2 (new_ctm);
604 }
605
606
607 void 
608 ctm_post_mult_2 (GRFMTX_2D m)
609 {
610     GRFMTX_2D new_ctm;
611
612     mult_gmtx_2 (_sgp2_cwin->ctm_2_x, m, new_ctm);
613     ctm_set_2 (new_ctm);
614 }