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