666f7593d0e9562aa0eb527483c13b0f05fafacd
[ctsim.git] / libctgraphics / ezplot.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **    EZPLOT                                    
5 **
6 **  This is part of the CTSim program
7 **  Copyright (C) 1983-2000 Kevin Rosenberg
8 **
9 **  $Id: ezplot.cpp,v 1.4 2000/07/04 18:33:35 kevin Exp $
10 **
11 **  This program is free software; you can redistribute it and/or modify
12 **  it under the terms of the GNU General Public License (version 2) as
13 **  published by the Free Software Foundation.
14 **
15 **  This program is distributed in the hope that it will be useful,
16 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 **  GNU General Public License for more details.
19 **
20 **  You should have received a copy of the GNU General Public License
21 **  along with this program; if not, write to the Free Software
22 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 ******************************************************************************/
24
25 #include "ezplot.h"
26 #include "algo.h"
27
28
29 static int plot (SGP_ID *gid);
30 static void drawaxis(void);
31 static void symbol (int sym, double symwidth, double symheight);
32
33 /*-------------------------------------*/
34 /* GLOBAL variables for EZPLOT & EZSET */
35 /*-------------------------------------*/
36
37 bool ezplot_firstcall = TRUE;   /* set to false on first call to EZSET or EZPLOT */
38 struct ezplot_var ez;           /* ezplot variables */
39
40 /*----------------*/
41 /* DEFAULT values */
42 /*----------------*/
43
44 #define TICKRATIO 0.4           /* ratio of minor to major tick lengths */
45 #define MAXNUMFMT 15            /* maximum length of a numeric format */
46
47 #define DEF_CRTMODE    0  /*GM_HIGHRES*/        /* default crt mode */
48 #define DEF_CHARHEIGHT (1./43.) /* default size of characters in NDC */
49 #define DEF_CHARWIDTH  (1./80.)
50
51 #define DEF_CURVE_CLR   C_YELLOW
52
53
54 /*----------------------------------------------------------------------*/
55 /*                              GLOBAL VARIABLES                        */
56 /*----------------------------------------------------------------------*/
57
58 static
59 double charwidth, charheight;   /* Size of characters in NDC */
60
61 static
62 double  xp_min, xp_max,
63     yp_min, yp_max;             /* boundry of plot frame in NDC */
64 static
65 double  xa_min, xa_max,
66     ya_min, ya_max;             /* extent of axes in NDC */
67 static
68 double  xgw_min, xgw_max,
69     ygw_min, ygw_max;   /* boundary of graph in input coords */
70 static
71 double  xgn_min, xgn_max,
72     ygn_min, ygn_max;   /* boundy of graph in NDC */
73 static
74 double xt_min, xt_max,
75     yt_min, yt_max;             /* boundary of axis ticks */
76
77 static
78 double  xl_min, xl_max,
79     yl_min, yl_max;             /* boundary of legend box */
80
81 static  double title_row;       /* y-coord of title row */
82
83 static  double xtl_ofs;         /* Offset y-coord of x tick labels from axis */
84 static  double ytl_ofs;         /* Offset x-coord of y tick labels from axis */
85
86 static  double xlbl_row;        /* row of x label in world coord */
87 static  double ylbl_col;        /* column of y label in world coord */
88
89 static
90 double xw_tickinc, yw_tickinc;  /* increment between major ticks in WC */
91
92 static
93 double xn_tickinc, yn_tickinc;  /* increment between major ticks in NDC */
94
95 static int x_nint, y_nint;      /* number of intervals along x & y axes */
96 static int x_fldwid, x_frac;    /* numeric field sizes & number of digits   */
97 static int y_fldwid, y_frac;    /* in fraction of number, used for printf() */
98
99 static double xtl_wid, ytl_wid; /* length of ticks labels in NDC */
100 static double tl_height;        /* height of tick labels in NDC */
101
102 static char x_numfmt[20];       /* format to print x tick labels */
103 static char y_numfmt[20];       /* format to print y tick labels */
104
105
106 /*----------------------------------------------------------------------
107  * FUNCTION IDENTICIFATION
108  *
109  *      Name:           EZPLOT
110  *      Programmer:     Kevin Rosenberg
111  *      Date:            5-83 Version 1
112  *                      11-84 Version 2
113  *
114  * SYNOPSIS
115  *      ezplot (x, y, n)
116  *      double x[]      x-coordinates of point  makeing up a curve 
117  *      double y[]      y-coordinates of points makeing up a curve
118  *      int    n        Number of points in curve
119  *
120  * DESCRIPTION
121  *          This is a sophisticated plotting program.
122  *
123  *----------------------------------------------------------------------*/
124
125
126 SGP_ID 
127 ezplot (float x[], double y[], int num)
128 {
129   double dx [num];
130
131   for (int i = 0; i < num; i++)
132     dx[i] = x[i];
133
134   ezplot (dx, y, num);
135 }
136
137
138 SGP_ID
139 ezplot (double x[], double y[], int num)
140 {
141     unsigned int size, i;
142     SGP_ID gid = NULL;
143
144     if (ez.i_plotimmediate == TRUE) {
145         plot (&gid);
146         return (gid);
147     }
148
149     if (num < 1)
150         return (NULL);
151
152     if (ezplot_firstcall == TRUE)
153         ezinit();
154
155     if (ez.o_unknowncurves == FALSE && ez.i_numcurves >= ez.o_reqcurves)
156         ezclear ();
157
158     if (ez.i_numcurves < MAXCURVES &&
159         (ez.o_unknowncurves == TRUE || ez.i_numcurves < ez.o_reqcurves)) {
160         size = num * sizeof(double);
161         ez.curve[ez.i_numcurves].x = new double [size];
162         ez.curve[ez.i_numcurves].y = new double [size];
163         for (i = 0; i < num; i++) {
164             ez.curve[ez.i_numcurves].x[i] = x[i];
165             ez.curve[ez.i_numcurves].y[i] = y[i];
166         }
167         ez.curve[ez.i_numcurves].numpts = num;
168         ez.curve[ez.i_numcurves].color = ez.o_color;
169         ez.curve[ez.i_numcurves].linestyle = ez.o_linestyle;
170         ez.curve[ez.i_numcurves].symbol = ez.o_symbol;
171         ez.curve[ez.i_numcurves].symfreq = ez.o_symfreq;
172         strncpy (ez.curve[ez.i_numcurves].legend, ez.c_legend, MAXLEGEND);
173         ++ez.i_numcurves;
174     }
175     
176     if (ez.o_unknowncurves == FALSE && ez.i_numcurves >= ez.o_reqcurves) {
177         plot (&gid);
178         ezclear ();
179     }
180
181     return (gid);
182 }
183
184
185 /* NAME
186  *   plot               INTERNAL: Plots all curves collected by ezplot()
187  *
188  * SYNOPSIS
189  *   plot()
190  *
191  * DESCRIPTION
192  *   This routine plots the curves that have stored by ezplot().
193  *
194  * CALLED BY
195  *   EZPLOT() only
196  *
197  * CALLS
198  *   drawaxis() & make_numfmt()
199  */
200
201 static int plot (SGP_ID *gid)
202 {
203     double xmin, xmax;          /* extend of curves in world coord  */
204     double ymin, ymax;
205     double x_added_ticks;               /* number of tick spaces added to axis */
206     double y_added_ticks;
207     double symwidth, symheight; /* size of symbol in NDC */
208     double leg_width, leg_height;       /* size of legend box */
209     int num_leg;                        /* number of legend titles */
210     int max_leg;                        /* longest legend in characters */
211     int i, j, ip, ic, n;
212
213     if (ez.i_numcurves <= 0)
214         return (FALSE);
215
216     if (ez.o_ustart == FALSE && *gid == NULL) {
217         *gid = sgp2_init (0, 0, "Ezplot");
218     }
219     
220     if (ez.s_textsize == TRUE)
221         charheight = ez.v_textsize;
222     else
223         charheight = DEF_CHARHEIGHT;
224     
225     gp_set_aspect (CRTDEV, 1.0);
226     
227     xmin = xmax = ez.curve[0].x[0];
228     ymin = ymax = ez.curve[0].y[0];
229     
230     for (ic = 0; ic < ez.i_numcurves; ic++) {
231         for (ip = 0; ip < ez.curve[ic].numpts; ip++) {
232             if (ez.curve[ic].x[ip] > xmax)
233                 xmax = ez.curve[ic].x[ip];
234             else if (ez.curve[ic].x[ip] < xmin)
235                 xmin = ez.curve[ic].x[ip];
236             if (ez.curve[ic].y[ip] > ymax)
237                 ymax = ez.curve[ic].y[ip];
238             else if (ez.curve[ic].y[ip] < ymin)
239                 ymin = ez.curve[ic].y[ip];
240         }
241     }
242     
243     /* extend graph limits for user defined axis cross positions */
244     
245     if (ez.s_xcross == TRUE)
246         {
247             if (ez.v_xcross < xmin)
248                 xmin = ez.v_xcross;
249             else if (ez.v_xcross > xmax)
250                 xmax = ez.v_xcross;
251         }
252     
253     if (ez.s_ycross == TRUE)
254         {
255             if (ez.v_ycross < ymin)
256                 ymin = ez.v_ycross;
257             else if (ez.v_ycross > ymax)
258                 ymax = ez.v_ycross;
259         }
260     
261     /* find nice endpoints for axes */
262
263     axis_scale (xmin, xmax, ez.o_xmajortick - 1, &xgw_min, &xgw_max, &x_nint);
264     axis_scale (ymin, ymax, ez.o_ymajortick - 1, &ygw_min, &ygw_max, &y_nint);
265     
266     /* check if user set x-axis extents */
267     
268     if (ez.s_xmin == TRUE) {
269         xgw_min = ez.v_xmin;
270         x_nint = ez.o_xmajortick - 1;
271     }
272     if (ez.s_xmax == TRUE) {
273         xgw_max = ez.v_xmax;
274         x_nint = ez.o_xmajortick - 1;
275     }
276     
277     /* check if user set y-axis extents */
278     
279     if (ez.s_ymin == TRUE) {
280         ygw_min = ez.v_ymin;
281         y_nint = ez.o_ymajortick - 1;
282     }
283     if (ez.s_ymax == TRUE) {
284         ygw_max = ez.v_ymax;
285         y_nint = ez.o_ymajortick - 1;
286     }
287     
288     /* calculate increment between major axis in world coordinates */
289     
290     xw_tickinc = (xgw_max - xgw_min) / x_nint;
291     yw_tickinc = (ygw_max - ygw_min) / y_nint;
292     
293     /* we have now calcuated xgw_min, xyw_max, ygw_min, & ygw_max */
294     
295     /* set the number of decimal point to users' setting or default */
296     /* Two formats for numbers
297        Fixed:    -nnn.f
298        Exponent: -n.fffE+eee
299     */
300     
301     if (ez.s_lxfrac == TRUE)
302         x_frac = ez.v_lxfrac;
303     else
304         x_frac = -1;
305     
306     if (ez.s_lyfrac == TRUE)
307         y_frac = ez.v_lyfrac;
308     else
309         y_frac = -1;
310     
311     make_numfmt (x_numfmt, &x_fldwid, &x_frac, xgw_min, xgw_max, x_nint);
312     make_numfmt (y_numfmt, &y_fldwid, &y_frac, ygw_min, ygw_max, y_nint);
313     
314     xtl_wid = x_fldwid * charwidth;             /* calc size of tick labels */
315     ytl_wid = y_fldwid * charwidth;
316     tl_height = charheight;
317     
318     /* calculate the extent of the plot frame */
319     
320     xp_min = ez.o_xporigin;
321     yp_min = ez.o_yporigin;
322     xp_max = xp_min + ez.o_xlength;
323     yp_max = yp_min + ez.o_ylength;
324
325     xp_min = clamp (xp_min, 0., 1.);
326     xp_max = clamp (xp_max, 0., 1.);
327     yp_min = clamp (yp_min, 0., 1.);
328     yp_max = clamp (yp_max, 0., 1.);
329     
330     xa_min = xp_min;            /* extent of axes */
331     xa_max = xp_max;
332     ya_min = yp_min;
333     ya_max = yp_max;
334     
335     /* adjust frame for title */
336     
337     if (strlen(ez.c_title) != 0)
338         ya_max -= 2.5 * charheight;
339     title_row = ya_max + 0.5 * charheight;
340     
341     /* calculate legend box boundaries */
342     
343     max_leg = 0;                        /* longest legend in characters */
344     num_leg = 0;                        /* number of legend titles */
345     for (i = 0; i < ez.i_numcurves; i++)
346         if ((n = strlen(ez.curve[i].legend)) > 0) {
347             ++num_leg;
348             max_leg = max(max_leg, n);
349         }
350     
351     if (num_leg > 0 && ez.o_legendbox != NOLEGEND) {
352         leg_width  = (max_leg + 2) * charwidth;
353         leg_height = num_leg * 3 * charheight;
354         
355         if (ez.s_xlegend == TRUE)
356             xl_max = ez.v_xlegend;
357         else {
358             xl_max = xa_max;
359             if (ez.o_legendbox == OUTSIDE)
360                 xa_max -= (leg_width + 0.5 * charwidth);
361         }
362         xl_min = xl_max - leg_width;
363
364         if (ez.s_ylegend == TRUE)
365             yl_max = ez.v_ylegend;
366         else
367             yl_max = ya_max;
368
369         yl_min = yl_max - leg_height;
370
371         sgp2_window  (xl_min, yl_min, xl_max, yl_max);
372         sgp2_viewport (xl_min, yl_min, xl_max, yl_max);
373
374         sgp2_color (ez.clr_legend);
375         sgp2_draw_rect (xl_min, yl_min, xl_max, yl_max);
376
377         n = 0;                  /* current legend position */
378         for (i = 0; i < ez.i_numcurves; i++) {
379             double xmin, xmax, xinc, y;
380
381             if (strlen(ez.curve[i].legend) == 0)
382                 continue;
383
384             xmin = xl_min + 1.0 * charwidth;
385             xmax = xl_max - 1.0 * charwidth;
386             y = yl_max - (2.0 + n * 3) * charheight;
387
388             sgp2_move_abs (xmin, y + 0.5 * charheight);
389             sgp2_draw_text (ez.curve[i].legend);
390             sgp2_color (ez.curve[i].color);
391             if (ez.curve[i].linestyle != LS_NOLINE) {
392                 sgp2_line_style (ez.curve[i].linestyle);
393                 sgp2_move_abs (xmin, y);
394                 sgp2_line_abs (xmax, y);
395             }
396             if (ez.curve[i].symbol > 0) {
397                 xinc = (xmax - xmin) / (5 - 1);
398                 sgp2_line_style (LS_SOLID);
399                 for (j = 0; j < 5; j++) {
400                     sgp2_move_abs (xmin + j * xinc, y);
401                     symbol(ez.curve[i].symbol,
402                            0.5 * charwidth, 0.5 * charheight);
403                 }
404             }
405             ++n;                /* move to next legend position */
406         }
407     }   /* end legend printing */
408
409     /* calculate the extent of the axes */
410
411     /*-------------------------*/
412     /* adjust frame for labels */
413     /*-------------------------*/
414
415     /* x-label */
416
417     if (strlen(ez.c_xlabel) > 0)
418         ya_min += 3.0 * charheight;
419     xlbl_row = xp_min;          /* put x-label on bottom of plot frame */
420
421     /* y-label */
422
423     if (strlen(ez.c_ylabel) > 0)
424         xa_min += 3.0 * charwidth;      /* reverse charsize because writing */
425     /* text sideways */
426     ylbl_col = xp_min + 2 * charwidth;
427
428     /*------------------------------*/
429     /* adjust frame for tick labels */
430     /*------------------------------*/
431
432     /* calc offset of tick labels from axes */
433
434     if (ez.o_xaxis == NOAXIS || ez.o_xtlabel == FALSE)
435         xtl_ofs = 0.0;
436     else if (ez.o_xticks == BELOW)
437         xtl_ofs = -2.5 * charheight;
438     else if (ez.o_xticks == ABOVE)
439         xtl_ofs = 1.5 * charheight;
440
441     if (ez.o_yaxis == NOAXIS || ez.o_ytlabel == FALSE)
442         ytl_ofs = 0.0;
443     else if (ez.o_yticks == LEFT)
444         ytl_ofs = -(1 + y_fldwid) * charwidth;
445     else if (ez.o_yticks == RIGHT)
446         ytl_ofs = 1.5 * charwidth;
447
448     /* see if need to shrink axis extents and/or tick extents */
449
450     if (xtl_ofs != 0.0 && ez.s_ycross == FALSE) {
451         if (ez.o_xticks == BELOW) {
452             ya_min += 2.5 * charheight;
453             yt_min = ya_min;
454         } else if (ez.o_xticks == ABOVE) {
455             ya_min += 0.0;
456             yt_min = ya_min + 2.5 * charheight;
457         }
458     } else                      /* noaxis, no t-labels, or user set cross */
459         yt_min = ya_min;
460
461     if (ytl_ofs != 0.0 && ez.s_xcross == FALSE) {
462         if (ez.o_yticks == LEFT) {
463             xa_min += (1 + y_fldwid) * charwidth;
464             xt_min = xa_min;
465         } else if (ez.o_yticks == RIGHT) {
466             xa_min += 0.0;
467             xt_min = xa_min + ytl_ofs + y_fldwid * charwidth;
468         }
469     } else
470         xt_min = xa_min;
471
472     xt_max = xa_max;
473     yt_max = ya_max;
474
475     /* decrease size of graph, if necessary, to accommadate space */
476     /* between axis boundary and boundary of ticks */
477
478     x_added_ticks = -1;
479     y_added_ticks = -1;
480
481     if (ez.o_xaxis == NOAXIS || ez.o_xtlabel == FALSE)
482         x_added_ticks = 0;
483     if (ez.o_yaxis == NOAXIS || ez.o_ytlabel == FALSE)
484         y_added_ticks = 0;
485
486     if (ez.o_grid == TRUE) {
487         if (x_added_ticks < 0)
488             x_added_ticks = 2;
489         if (y_added_ticks < 0)
490             y_added_ticks = 2;
491     }
492
493     if (x_added_ticks < 0)
494         {
495             if (ez.o_yticks == LEFT || ez.s_ycross)
496                 x_added_ticks = 1;
497             else
498                 x_added_ticks = 2;
499         }
500
501     if (y_added_ticks < 0)
502         {
503             if (ez.o_xticks == BELOW || ez.s_xcross)
504                 y_added_ticks = 1;
505             else
506                 y_added_ticks = 2;
507         }
508
509     xn_tickinc = (xt_max - xt_min) / (x_nint + x_added_ticks);
510     yn_tickinc = (yt_max - yt_min) / (y_nint + y_added_ticks);
511
512     xt_min += 0.5 * x_added_ticks * xn_tickinc;
513     xt_max -= 0.5 * x_added_ticks * xn_tickinc;
514     yt_min += 0.5 * y_added_ticks * yn_tickinc;
515     yt_max -= 0.5 * y_added_ticks * yn_tickinc;
516
517     xgn_min = xt_min;
518     xgn_max = xt_max;
519     ygn_min = yt_min;
520     ygn_max = yt_max;
521
522     /*---------------------------------------------------------------------------*/
523
524     /* PLOT CURVES */
525
526     sgp2_line_style (LS_SOLID);
527     drawaxis();
528
529     /* Convert WC in graph boundary to axis boundary */
530     {
531         double xmin, xmax, ymin, ymax;
532
533         sgp2_window  (xgw_min, ygw_min, xgw_max, ygw_max);      /* Graph boundary */
534         sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max);
535
536         ndc_to_wc (xa_min, ya_min, &xmin, &ymin);       /* calc WC of axis */
537         ndc_to_wc (xa_max, ya_max, &xmax, &ymax);       /* boundaries */
538
539         sgp2_window  (xmin, ymin, xmax, ymax);          /* Set window to axis */
540         sgp2_viewport (xa_min, ya_min, xa_max, ya_max); /* boundaries */
541     }
542  
543     symwidth = charwidth * (xgw_max - xgw_min);
544     symheight = charheight * (ygw_max - ygw_min);
545
546     for (ic = 0; ic < ez.i_numcurves; ic++) {
547         sgp2_color (ez.curve[ic].color);
548         if (ez.curve[ic].linestyle != LS_NOLINE) {
549             sgp2_line_style (ez.curve[ic].linestyle);
550             sgp2_polyline_abs (ez.curve[ic].x, ez.curve[ic].y, ez.curve[ic].numpts);
551         }
552         if (ez.curve[ic].symbol > 0) {
553             sgp2_line_style(LS_SOLID);
554             sgp2_move_abs (ez.curve[ic].x[0], ez.curve[ic].y[0]);
555             symbol (ez.curve[ic].symbol, symwidth, symheight);
556             for (i = 1; i < ez.curve[ic].numpts; i++)
557                 if (i % ez.curve[ic].symfreq == 0 || i == ez.curve[ic].numpts - 1) {
558                     sgp2_move_abs (ez.curve[ic].x[i], ez.curve[ic].y[i]);
559                     symbol (ez.curve[ic].symbol, symwidth, symheight);
560                 }
561         }
562     }
563  
564     if (ez.o_ufinish == FALSE)
565         termgrf2 ();
566  
567     return (TRUE);
568 }
569
570
571 /* NAME
572  *   drawaxis                   INTERNAL routine to draw axis & label them
573  *
574  * SYNOPSIS
575  *   drawaxis()
576  */
577
578 static void drawaxis(void)
579 {
580     double xticklen = 0, yticklen = 0; /* length of ticks in NDC */
581     double minorinc;            /* increment between minor axes */
582     double xaxispos, yaxispos;  /* crossing of axes */
583     double x, y, x2, y2;
584     bool axis_near;                     /* TRUE if axis too close to print t-label */
585     int i, j;
586     char str[100];
587     char *numstr;
588
589     charsize (charwidth, charheight);
590     settextclr (1, -1);
591
592     if (ez.o_xticks == ABOVE)
593         xticklen = charheight;
594     else if (ez.o_xticks == BELOW)
595         xticklen = -charheight;
596
597     if (ez.o_yticks == RIGHT)
598         yticklen = charwidth;
599     else if (ez.o_yticks == LEFT)
600         yticklen = -charwidth;
601
602     sgp2_window  (xp_min, yp_min, xp_max, yp_max);
603     sgp2_viewport (xp_min, yp_min, xp_max, yp_max);
604
605     if (strlen (ez.c_title) != 0) {
606         sgp2_move_abs (xa_min + (xa_max-xa_min)/2 - strlen(ez.c_title)*charwidth, title_row);
607         charsize (charwidth * 2.0, charheight * 2.0);
608         settextclr (ez.clr_title, -1);
609         sgp2_draw_text (ez.c_title);
610         charsize (charwidth, charheight);
611     }
612
613     if (ez.o_grid == TRUE || ez.o_box == TRUE) {
614         sgp2_color (ez.clr_axis);
615         sgp2_move_abs (xa_min, ya_min);
616         sgp2_line_abs (xa_max, ya_min);
617         sgp2_line_abs (xa_max, ya_max);
618         sgp2_line_abs (xa_min, ya_max);
619         sgp2_line_abs (xa_min, ya_min);
620     }
621
622     /* calculate position of axes */
623
624     /* x-axis */
625     if (ez.s_ycross == TRUE) {  /* convert users' world-coord */
626         xaxispos = ez.v_ycross; /* axis to its position in NDC */
627         sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max);
628         sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max);
629         x = xgw_min;
630         wc_to_ndc (x, xaxispos, &x, &xaxispos);
631     } else
632         xaxispos = ya_min;
633
634     /* y-axis */
635     if (ez.s_xcross == TRUE) {  /* convert users' world-coord */
636         yaxispos = ez.v_xcross; /* axis to its NDC position */
637         sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max);
638         sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max);
639         y = ygw_min;
640         wc_to_ndc (yaxispos, y, &yaxispos, &y);
641     } else
642         yaxispos = xa_min;
643
644     /*-------------*/
645     /* draw x-axis */
646     /*-------------*/
647
648     if (ez.o_xaxis == LINEAR) {
649         sgp2_window (xp_min, yp_min, xp_max, yp_max);
650         sgp2_viewport (xp_min, yp_min, xp_max, yp_max);
651
652         /* draw axis line */
653
654         sgp2_color (ez.clr_axis);
655         if (ez.o_tag && !ez.o_grid && !ez.o_box && ez.s_xcross) {
656             sgp2_move_abs (xa_min, xaxispos - charheight);
657             sgp2_line_abs (xa_min, xaxispos + charheight);
658         }
659         sgp2_move_abs (xa_min, xaxispos);
660         sgp2_line_abs (xa_max, xaxispos);
661         if (ez.o_tag && !ez.o_grid && !ez.o_box) {
662             sgp2_move_abs (xa_max, xaxispos - charheight);
663             sgp2_line_abs (xa_max, xaxispos + charheight);
664         }
665
666         if (ez.o_grid == TRUE) {
667             sgp2_color (ez.clr_grid);
668             for (i = 0; i <= x_nint; i++) {
669                 sgp2_move_abs (xt_min + xn_tickinc * i, ya_max);
670                 sgp2_line_abs (xt_min + xn_tickinc * i, ya_min);
671             }
672         }
673         sgp2_move_abs (xa_min + (xa_max-xa_min)/2 - strlen(ez.c_xlabel)*charwidth, xlbl_row);
674         charsize (charwidth * 2.0, charheight * 2.0);
675         settextclr (ez.clr_label, -1);
676         sgp2_draw_text (ez.c_xlabel);
677         charsize (charwidth, charheight);
678         minorinc = xn_tickinc / (ez.o_xminortick + 1);
679
680         for (i = 0; i <= x_nint; i++) {
681             x = xt_min + xn_tickinc * i;
682             sgp2_color (ez.clr_axis);
683             sgp2_move_abs (x, xaxispos);
684             sgp2_line_abs (x, xaxispos + xticklen);
685             if (i != x_nint)
686                 for (j = 1; j <= ez.o_xminortick; j++) {
687                     x2 = x + minorinc * j;
688                     sgp2_move_abs (x2, xaxispos);
689                     sgp2_line_abs (x2, xaxispos + TICKRATIO * xticklen);
690                 }
691             axis_near = FALSE;
692             if (xaxispos + xtl_ofs > ya_min && ez.o_yaxis != NOAXIS) {
693                 double xw, x, y, d;
694
695                 xw = xgw_min + i * xw_tickinc;
696                 sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max);
697                 sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max);
698                 wc_to_ndc (xw, y, &x, &y);
699                 sgp2_window (xp_min, yp_min, xp_max, yp_max);
700                 sgp2_viewport (xp_min, yp_min, xp_max, yp_max);
701                 d = x - yaxispos;
702                 if (ez.o_yticks == RIGHT && d >= 0  && d < 0.9 * xn_tickinc)
703                     axis_near = TRUE;
704                 if (ez.o_yticks == LEFT && d <= 0 && d > -0.9 * xn_tickinc)
705                     axis_near = TRUE;
706             }
707
708             if (ez.o_xtlabel == TRUE && axis_near == FALSE) {
709                 snprintf (str, sizeof(str), x_numfmt, xgw_min + xw_tickinc * i);
710                 numstr = str_skip_head (str, " ");
711                 sgp2_move_abs (x-strlen(numstr)*charwidth/2,xaxispos + xtl_ofs);
712                 settextclr (ez.clr_number, -1);
713                 sgp2_draw_text (numstr);
714             }
715         }
716     }           /* x - axis */
717
718
719     /*--------*/
720     /* y-axis */
721     /*--------*/
722
723     if (ez.o_yaxis == LINEAR) {
724         sgp2_window  (xp_min, yp_min, xp_max, yp_max);
725         sgp2_viewport (xp_min, yp_min, xp_max, yp_max);
726
727         sgp2_color (ez.clr_axis);
728         if (ez.o_tag && !ez.o_grid && !ez.o_box && ez.s_ycross) {
729             sgp2_move_abs (yaxispos - charwidth, ya_min);
730             sgp2_line_abs (yaxispos + charwidth, ya_min);
731         }
732         sgp2_move_abs (yaxispos, ya_min);
733         sgp2_line_abs (yaxispos, ya_max);
734         if (ez.o_tag && !ez.o_grid && !ez.o_box) {
735             sgp2_move_abs (yaxispos - charwidth, ya_max);
736             sgp2_line_abs (yaxispos + charwidth, ya_max);
737         }
738
739         if (ez.o_grid == TRUE) {
740             sgp2_color (ez.clr_grid);
741             for (i = 0; i <= y_nint; i++) {
742                 y = yt_min + yn_tickinc * i;
743                 sgp2_move_abs (xa_max, y);
744                 sgp2_line_abs (xa_min, y);
745             }
746         }
747         sgp2_move_abs (ylbl_col,ya_min + (ya_max-ya_min)/2 - strlen(ez.c_ylabel)*charheight);
748         textangle (HALFPI);
749         charsize (2 * charheight, 2 * charwidth);       /* axis reversed */
750         settextclr (ez.clr_label, -1);
751         sgp2_draw_text (ez.c_ylabel);
752         textangle (0.0);
753         charsize (charwidth, charheight);
754         minorinc = yn_tickinc / (ez.o_yminortick + 1);
755
756         for (i = 0; i <= y_nint; i++) {
757             y = yt_min + yn_tickinc * i;
758             sgp2_color (ez.clr_axis);
759             sgp2_move_abs (yaxispos, y);
760             sgp2_line_abs (yaxispos + yticklen, y);
761             if (i != y_nint)
762                 for (j = 1; j <= ez.o_yminortick; j++) {
763                     y2 = y + minorinc * j;
764                     sgp2_move_abs (yaxispos, y2);
765                     sgp2_line_abs (yaxispos + TICKRATIO * yticklen, y2);
766                 }
767             axis_near = FALSE;
768             if (yaxispos + ytl_ofs > xa_min && ez.o_xaxis != NOAXIS) {
769                 double yw, x, y, d;
770
771                 yw = ygw_min + i * yw_tickinc;
772                 sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max);
773                 sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max);
774                 wc_to_ndc (x, yw, &x, &y);
775                 sgp2_window (xp_min, yp_min, xp_max, yp_max);
776                 sgp2_viewport (xp_min, yp_min, xp_max, yp_max);
777                 d = y - xaxispos;
778                 if (ez.o_xticks == ABOVE && d >= 0 && d < 0.9 * yn_tickinc)
779                     axis_near = TRUE;
780                 if (ez.o_xticks == BELOW && d <= 0 && d > -0.9 * yn_tickinc)
781                     axis_near = TRUE;
782             }
783             if (ez.o_ytlabel == TRUE && axis_near == FALSE) {
784                 snprintf (str, sizeof(str), y_numfmt, ygw_min + yw_tickinc * i);
785                 sgp2_move_abs (yaxispos + ytl_ofs, y - 0.5 * charheight);
786                 settextclr (ez.clr_number, -1);
787                 sgp2_draw_text (str);
788             }
789         }
790     }           /* y - axis */
791 }
792
793
794 static void 
795 symbol (int sym, double symwidth, double symheight)
796 {
797     if (sym <= 0)
798         return;
799
800     if (sym == SB_CROSS) {
801         sgp2_move_rel (-0.5 * symwidth, -0.5 * symheight);
802         sgp2_line_rel (symwidth, symheight);
803         sgp2_move_rel (-symwidth, 0.0);
804         sgp2_line_rel (symwidth, -symheight);
805         sgp2_move_rel (-0.5 * symwidth, 0.5 * symheight);
806     } else if (sym == SB_PLUS) {
807         sgp2_move_rel (-0.5 * symwidth, 0.0);
808         sgp2_line_rel (symwidth, 0.0);
809         sgp2_move_rel (-0.5 * symwidth, -0.5 * symheight);
810         sgp2_line_rel (0.0, symheight);
811         sgp2_move_rel (0.0, -0.5 * symheight);
812     } else if (sym == SB_BOX) {
813         sgp2_move_rel (-0.5 * symwidth, -0.5 * symheight);
814         sgp2_line_rel (symwidth, 0.0);
815         sgp2_line_rel (0.0, symheight);
816         sgp2_line_rel (-symwidth, 0.0);
817         sgp2_line_rel (0.0, -symheight);
818         sgp2_move_rel (0.5 * symwidth, 0.5 * symheight);
819     } else if (sym == SB_CIRCLE) {
820         sgp2_draw_circle (symwidth);
821     } else if (sym == SB_ERRORBAR) {
822         sgp2_move_rel (-0.5 * symwidth, 0.5 * symheight);
823         sgp2_line_rel (symwidth, 0.0);
824         sgp2_move_rel (-0.5 * symwidth, 0.0);
825         sgp2_line_rel (0.0, -symheight);
826         sgp2_move_rel (-0.5 * symwidth, 0.0);
827         sgp2_line_rel (symwidth, 0.0);
828         sgp2_move_rel (-0.5 * symwidth, 0.5 * symheight);
829     }
830 }
831
832
833 void ezinit(void)
834 {
835     /* EZPLOT Variables */
836
837     charwidth = DEF_CHARWIDTH;  /* KR_FIX: Make these ez.o_ variables */
838     charheight = DEF_CHARHEIGHT;
839
840     /* EZPLOT & EZSET Variables */
841
842     strcpy (ez.c_xlabel, "X axis");
843     strcpy (ez.c_ylabel, "Y axis");
844     strcpy (ez.c_title, "");
845     strcpy (ez.c_legend, "");
846
847     ezplot_firstcall = FALSE;
848
849     ez.i_numcurves = 0;
850     ez.i_plotimmediate = FALSE;
851
852     ez.o_reqcurves = 1;
853     ez.o_unknowncurves = FALSE;
854
855     ez.o_ustart = FALSE;
856     ez.o_ufinish = FALSE;
857
858     ez.o_xporigin = 0.0;
859     ez.o_yporigin = 0.0;
860     ez.o_xlength  = 1.0;
861     ez.o_ylength  = 1.0;
862
863     ez.o_xaxis = LINEAR;
864     ez.o_yaxis = LINEAR;
865
866     ez.o_grid = FALSE;
867     ez.o_box = FALSE;
868
869     ez.o_xmajortick = 10;
870     ez.o_ymajortick =  8;
871     ez.o_xminortick =  4;
872     ez.o_yminortick =  4;
873
874     ez.o_color = DEF_CURVE_CLR;
875     ez.o_symfreq = 1;
876     ez.o_symbol = -1;
877     ez.o_linestyle = LS_SOLID;
878
879     ez.o_xtlabel = TRUE;
880     ez.o_ytlabel = TRUE;
881     ez.o_xticks = BELOW;
882     ez.o_yticks = LEFT;
883
884     ez.o_legendbox = INSIDE;
885     ez.o_tag = FALSE;
886
887     ez.s_xtitle   = FALSE;
888     ez.s_ytitle   = FALSE;
889     ez.s_xcross   = FALSE;
890     ez.s_ycross   = FALSE;
891     ez.s_lxfrac   = FALSE;
892     ez.s_lyfrac   = FALSE;
893     ez.s_xlegend  = FALSE;
894     ez.s_ylegend  = FALSE;
895     ez.s_textsize = FALSE;
896
897     ez.d_usecrt = TRUE;
898     ez.d_useprt = FALSE;
899     ez.d_crtmode = DEF_CRTMODE;
900     ez.d_prtmode = PRTMODE_DEF;
901     ez.d_xprtbuf = XBUF_DEF;
902     ez.d_yprtbuf = YBUF_DEF;
903
904     ez.clr_axis   = C_WHITE;            /* set fixed colors */
905     ez.clr_title  = (C_CYAN+8);
906     ez.clr_label  = (C_CYAN+8);
907     ez.clr_legend = (C_RED+8);
908     ez.clr_number = (C_GREEN+8);
909     ez.clr_grid   = (C_BLACK+8);
910 }
911
912 void ezfree(void)
913 {
914     static char errmsg[] = "EZFREE in EZPLOT";
915     int i;
916     
917     for (i = 0; i < ez.i_numcurves; i++) {
918         delete ez.curve[i].x;
919         delete ez.curve[i].y;
920     }
921     ez.i_numcurves = 0;
922 }
923
924 void ezclear(void)
925 {
926     ezfree();
927     ezinit();
928 }