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