1 /*----------------------------------------------------------------------------
2  * SciPlot	A generalized plotting widget
3  *
4  * Copyright (c) 1996 Robert W. McMullen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  *
21  * Author: Rob McMullen <rwmcm@mail.ae.utexas.edu>
22  *         http://www.ae.utexas.edu/~rwmcm
23  */
24 
25 #include <X11/IntrinsicP.h>
26 #include <X11/StringDefs.h>
27 
28 #include <stdio.h>
29 
30 #include "SciPlotP.h"
31 
32 #define offset(field) XtOffsetOf(SciPlotRec, plot.field)
33 static XtResource resources[] =
34 {
35   {XtNchartType, XtCMargin, XtRInt, sizeof(int),
36     offset(ChartType), XtRImmediate, (XtPointer) XtCARTESIAN},
37   {XtNdegrees, XtCBoolean, XtRBoolean, sizeof(Boolean),
38     offset(Degrees), XtRImmediate, (XtPointer) True},
39   {XtNdrawMajor, XtCBoolean, XtRBoolean, sizeof(Boolean),
40     offset(DrawMajor), XtRImmediate, (XtPointer) True},
41   {XtNdrawMajorTics, XtCBoolean, XtRBoolean, sizeof(Boolean),
42     offset(DrawMajorTics), XtRImmediate, (XtPointer) True},
43   {XtNdrawMinor, XtCBoolean, XtRBoolean, sizeof(Boolean),
44     offset(DrawMinor), XtRImmediate, (XtPointer) True},
45   {XtNdrawMinorTics, XtCBoolean, XtRBoolean, sizeof(Boolean),
46     offset(DrawMinorTics), XtRImmediate, (XtPointer) True},
47   {XtNmonochrome, XtCBoolean, XtRBoolean, sizeof(Boolean),
48     offset(Monochrome), XtRImmediate, (XtPointer) False},
49   {XtNshowLegend, XtCBoolean, XtRBoolean, sizeof(Boolean),
50     offset(ShowLegend), XtRImmediate, (XtPointer) True},
51   {XtNshowTitle, XtCBoolean, XtRBoolean, sizeof(Boolean),
52     offset(ShowTitle), XtRImmediate, (XtPointer) True},
53   {XtNshowXLabel, XtCBoolean, XtRBoolean, sizeof(Boolean),
54     offset(ShowXLabel), XtRImmediate, (XtPointer) True},
55   {XtNshowYLabel, XtCBoolean, XtRBoolean, sizeof(Boolean),
56     offset(ShowYLabel), XtRImmediate, (XtPointer) True},
57   {XtNxLabel, XtCString, XtRString, sizeof(String),
58     offset(TransientXLabel), XtRString, "X Axis"},
59   {XtNyLabel, XtCString, XtRString, sizeof(String),
60     offset(TransientYLabel), XtRString, "Y Axis"},
61   {XtNplotTitle, XtCString, XtRString, sizeof(String),
62     offset(TransientPlotTitle), XtRString, "Plot"},
63   {XtNmargin, XtCMargin, XtRInt, sizeof(int),
64     offset(Margin), XtRImmediate, (XtPointer) 5},
65   {XtNtitleMargin, XtCMargin, XtRInt, sizeof(int),
66     offset(TitleMargin), XtRImmediate, (XtPointer) 16},
67   {XtNlegendLineSize, XtCMargin, XtRInt, sizeof(int),
68     offset(LegendLineSize), XtRImmediate, (XtPointer) 16},
69   {XtNdefaultMarkerSize, XtCMargin, XtRInt, sizeof(int),
70     offset(DefaultMarkerSize), XtRImmediate, (XtPointer) 3},
71   {XtNlegendMargin, XtCMargin, XtRInt, sizeof(int),
72     offset(LegendMargin), XtRImmediate, (XtPointer) 3},
73   {XtNlegendThroughPlot, XtCBoolean, XtRBoolean, sizeof(Boolean),
74     offset(LegendThroughPlot), XtRImmediate, (XtPointer) False},
75   {XtNtitleFont, XtCMargin, XtRInt, sizeof(int),
76     offset(TitleFont), XtRImmediate, (XtPointer) (XtFONT_HELVETICA | 24)},
77   {XtNlabelFont, XtCMargin, XtRInt, sizeof(int),
78     offset(LabelFont), XtRImmediate, (XtPointer) (XtFONT_TIMES | 18)},
79   {XtNaxisFont, XtCMargin, XtRInt, sizeof(int),
80     offset(AxisFont), XtRImmediate, (XtPointer) (XtFONT_TIMES | 10)},
81   {XtNxAutoScale, XtCBoolean, XtRBoolean, sizeof(Boolean),
82     offset(XAutoScale), XtRImmediate, (XtPointer) True},
83   {XtNyAutoScale, XtCBoolean, XtRBoolean, sizeof(Boolean),
84     offset(YAutoScale), XtRImmediate, (XtPointer) True},
85   {XtNxAxisNumbers, XtCBoolean, XtRBoolean, sizeof(Boolean),
86     offset(XAxisNumbers), XtRImmediate, (XtPointer) True},
87   {XtNyAxisNumbers, XtCBoolean, XtRBoolean, sizeof(Boolean),
88     offset(YAxisNumbers), XtRImmediate, (XtPointer) True},
89   {XtNxLog, XtCBoolean, XtRBoolean, sizeof(Boolean),
90     offset(XLog), XtRImmediate, (XtPointer) False},
91   {XtNyLog, XtCBoolean, XtRBoolean, sizeof(Boolean),
92     offset(YLog), XtRImmediate, (XtPointer) False},
93   {XtNxOrigin, XtCBoolean, XtRBoolean, sizeof(Boolean),
94     offset(XOrigin), XtRImmediate, (XtPointer) False},
95   {XtNyOrigin, XtCBoolean, XtRBoolean, sizeof(Boolean),
96     offset(YOrigin), XtRImmediate, (XtPointer) False},
97   {XtNyNumbersHorizontal, XtCBoolean, XtRBoolean, sizeof(Boolean),
98     offset(YNumHorz), XtRImmediate, (XtPointer) True},
99 };
100 
101 static SciPlotFontDesc font_desc_table[] =
102 {
103   {XtFONT_TIMES, "Times", "times", False, True},
104   {XtFONT_COURIER, "Courier", "courier", True, False},
105   {XtFONT_HELVETICA, "Helvetica", "helvetica", True, False},
106   {XtFONT_LUCIDA, "Lucida", "lucidabright", False, False},
107   {XtFONT_LUCIDASANS, "LucidaSans", "lucida", False, False},
108   {XtFONT_NCSCHOOLBOOK, "NewCenturySchlbk",
109     "new century schoolbook", False, True},
110   {-1, NULL, NULL, False, False},
111 };
112 
113 /*
114  * Private function declarations
115  */
116 
117 static void Redisplay();
118 static void Resize();
119 static Boolean SetValues();
120 static void GetValuesHook();
121 static void Initialize();
122 static void Realize();
123 static void Destroy();
124 
125 static void ComputeAll();
126 static void ComputeAllDimensions();
127 static void DrawAll();
128 static void ItemDrawAll();
129 static void ItemDraw();
130 static void EraseAll();
131 static void FontInit();
132 static int ColorStore();
133 static int FontStore();
134 static int FontnumReplace();
135 
136 
137 
138 SciPlotClassRec sciplotClassRec =
139 {
140   {
141     /* core_class fields        */
142 #ifdef MOTIF
143     /* superclass               */ (WidgetClass) & xmPrimitiveClassRec,
144 #else
145     /* superclass               */ (WidgetClass) & widgetClassRec,
146 #endif
147     /* class_name               */ "SciPlot",
148     /* widget_size              */ sizeof(SciPlotRec),
149     /* class_initialize         */ NULL,
150     /* class_part_initialize    */ NULL,
151     /* class_inited             */ False,
152     /* initialize               */ Initialize,
153     /* initialize_hook          */ NULL,
154     /* realize                  */ Realize,
155     /* actions                  */ NULL,
156     /* num_actions              */ 0,
157     /* resources                */ resources,
158     /* num_resources            */ XtNumber(resources),
159     /* xrm_class                */ NULLQUARK,
160     /* compress_motion          */ True,
161     /* compress_exposure        */ XtExposeCompressMultiple,
162     /* compress_enterleave      */ True,
163     /* visible_interest         */ True,
164     /* destroy                  */ Destroy,
165     /* resize                   */ Resize,
166     /* expose                   */ Redisplay,
167     /* set_values               */ SetValues,
168     /* set_values_hook          */ NULL,
169     /* set_values_almost        */ XtInheritSetValuesAlmost,
170     /* get_values_hook          */ GetValuesHook,
171     /* accept_focus             */ NULL,
172     /* version                  */ XtVersion,
173     /* callback_private         */ NULL,
174     /* tm_table                 */ NULL,
175     /* query_geometry           */ NULL,
176     /* display_accelerator      */ XtInheritDisplayAccelerator,
177     /* extension                */ NULL
178   },
179 #ifdef MOTIF
180   {
181     /* primitive_class fields   */
182     /* border_highlight         */ (XtWidgetProc) _XtInherit,
183     /* border_unhighligh        */ (XtWidgetProc) _XtInherit,
184     /* translations             */ XtInheritTranslations,
185     /* arm_and_activate         */ (XtWidgetProc) _XtInherit,
186     /* syn_resources            */ NULL,
187     /* num_syn_resources        */ 0,
188     /* extension                */ NULL
189   },
190 #endif
191   {
192     /* plot_class fields        */
193     /* dummy                    */ 0
194     /* (some stupid compilers barf on empty structures) */
195   }
196 };
197 
198 WidgetClass sciplotWidgetClass = (WidgetClass) & sciplotClassRec;
199 
200 
201 static void
Initialize(Widget treq,Widget tnew,ArgList args,Cardinal * num)202 Initialize(Widget treq, Widget tnew, ArgList args, Cardinal *num)
203 {
204   SciPlotWidget new;
205 
206   new = (SciPlotWidget) tnew;
207 
208   new->plot.plotlist = NULL;
209   new->plot.alloc_plotlist = 0;
210   new->plot.num_plotlist = 0;
211 
212   new->plot.alloc_drawlist = NUMPLOTITEMALLOC;
213   new->plot.drawlist = (SciPlotItem *) XtCalloc(new->plot.alloc_drawlist,
214     sizeof(SciPlotItem));
215   new->plot.num_drawlist = 0;
216 
217   new->plot.cmap = DefaultColormap(XtDisplay(new),
218     DefaultScreen(XtDisplay(new)));
219 
220   new->plot.xlabel = (char *) XtMalloc(strlen(new->plot.TransientXLabel) + 1);
221   strcpy(new->plot.xlabel, new->plot.TransientXLabel);
222   new->plot.ylabel = (char *) XtMalloc(strlen(new->plot.TransientYLabel) + 1);
223   strcpy(new->plot.ylabel, new->plot.TransientYLabel);
224   new->plot.plotTitle = (char *) XtMalloc(strlen(new->plot.TransientPlotTitle) + 1);
225   strcpy(new->plot.plotTitle, new->plot.TransientPlotTitle);
226   new->plot.TransientXLabel=NULL;
227   new->plot.TransientYLabel=NULL;
228   new->plot.TransientPlotTitle=NULL;
229 
230   new->plot.colors = NULL;
231   new->plot.num_colors = 0;
232   new->plot.fonts = NULL;
233   new->plot.num_fonts = 0;
234 
235   new->plot.update = FALSE;
236   new->plot.UserMin.x = new->plot.UserMin.y = 0.0;
237   new->plot.UserMax.x = new->plot.UserMax.y = 10.0;
238 
239   new->plot.titleFont = FontStore(new, new->plot.TitleFont);
240   new->plot.labelFont = FontStore(new, new->plot.LabelFont);
241   new->plot.axisFont = FontStore(new, new->plot.AxisFont);
242 }
243 
244 static void
GCInitialize(SciPlotWidget new)245 GCInitialize(SciPlotWidget new)
246 {
247   XGCValues values;
248   XtGCMask mask;
249   long colorsave;
250 
251   values.line_style = LineSolid;
252   values.line_width = 0;
253   values.fill_style = FillSolid;
254   values.background = WhitePixelOfScreen(XtScreen(new));
255   values.background = new->core.background_pixel;
256   new->plot.BackgroundColor = ColorStore(new, values.background);
257 #ifdef MOTIF
258   new->core.background_pixel = values.background;
259 #endif
260   values.foreground = colorsave = BlackPixelOfScreen(XtScreen(new));
261   new->plot.ForegroundColor = ColorStore(new, values.foreground);
262 
263   mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground;
264   new->plot.defaultGC = XCreateGC(XtDisplay(new),XtWindow(new), mask, &values);
265 
266   values.foreground = colorsave;
267   values.line_style = LineOnOffDash;
268   new->plot.dashGC = XCreateGC(XtDisplay(new),XtWindow(new), mask, &values);
269 }
270 
271 static void
Realize(Widget aw,XtValueMask * value_mask,XSetWindowAttributes * attributes)272 Realize(Widget aw, XtValueMask * value_mask, XSetWindowAttributes * attributes)
273 {
274   SciPlotWidget w = (SciPlotWidget) aw;
275 
276 #define	superclass	(&widgetClassRec)
277   (*superclass->core_class.realize) (aw, value_mask, attributes);
278 #undef	superclass
279 
280   GCInitialize(w);
281 }
282 
283 static void
Destroy(SciPlotWidget w)284 Destroy(SciPlotWidget w)
285 {
286   int i;
287   SciPlotFont *pf;
288   SciPlotList *p;
289 
290   XFreeGC(XtDisplay(w), w->plot.defaultGC);
291   XFreeGC(XtDisplay(w), w->plot.dashGC);
292   XtFree((char *) w->plot.xlabel);
293   XtFree((char *) w->plot.ylabel);
294   XtFree((char *) w->plot.plotTitle);
295 
296   for (i = 0; i < w->plot.num_fonts; i++) {
297     pf = &w->plot.fonts[i];
298     XFreeFont(XtDisplay((Widget) w), pf->font);
299   }
300   XtFree((char *) w->plot.fonts);
301 
302   XtFree((char *) w->plot.colors);
303 
304   for (i = 0; i < w->plot.alloc_plotlist; i++) {
305     p = w->plot.plotlist + i;
306     if (p->allocated > 0)
307       XtFree((char *) p->data);
308     if (p->legend)
309       XtFree(p->legend);
310   }
311   if (w->plot.alloc_plotlist > 0)
312     XtFree((char *) w->plot.plotlist);
313 
314   EraseAll(w);
315   XtFree((char *) w->plot.drawlist);
316 }
317 
318 static Boolean
SetValues(SciPlotWidget current,SciPlotWidget request,SciPlotWidget new,ArgList args,Cardinal nargs)319 SetValues(SciPlotWidget current, SciPlotWidget request, SciPlotWidget new,
320   ArgList args, Cardinal nargs)
321 {
322   Boolean redisplay = FALSE;
323 
324   if (current->plot.XLog != new->plot.XLog)
325     redisplay = TRUE;
326   else if (current->plot.YLog != new->plot.YLog)
327     redisplay = TRUE;
328   else if (current->plot.XOrigin != new->plot.XOrigin)
329     redisplay = TRUE;
330   else if (current->plot.YOrigin != new->plot.YOrigin)
331     redisplay = TRUE;
332   else if (current->plot.XAxisNumbers != new->plot.XAxisNumbers)
333     redisplay = TRUE;
334   else if (current->plot.YAxisNumbers != new->plot.YAxisNumbers)
335     redisplay = TRUE;
336   else if (current->plot.DrawMajor != new->plot.DrawMajor)
337     redisplay = TRUE;
338   else if (current->plot.DrawMajorTics != new->plot.DrawMajorTics)
339     redisplay = TRUE;
340   else if (current->plot.DrawMinor != new->plot.DrawMinor)
341     redisplay = TRUE;
342   else if (current->plot.DrawMinorTics != new->plot.DrawMinorTics)
343     redisplay = TRUE;
344   else if (current->plot.ChartType != new->plot.ChartType)
345     redisplay = TRUE;
346   else if (current->plot.Degrees != new->plot.Degrees)
347     redisplay = TRUE;
348   else if (current->plot.ShowLegend != new->plot.ShowLegend)
349     redisplay = TRUE;
350   else if (current->plot.ShowTitle != new->plot.ShowTitle)
351     redisplay = TRUE;
352   else if (current->plot.ShowXLabel != new->plot.ShowXLabel)
353     redisplay = TRUE;
354   else if (current->plot.ShowYLabel != new->plot.ShowYLabel)
355     redisplay = TRUE;
356   else if (current->plot.ShowTitle != new->plot.ShowTitle)
357     redisplay = TRUE;
358   else if (current->plot.Monochrome != new->plot.Monochrome)
359     redisplay = TRUE;
360 
361   if (new->plot.TransientXLabel) {
362     if (current->plot.TransientXLabel != new->plot.TransientXLabel ||
363         strcmp(new->plot.TransientXLabel,current->plot.xlabel)!=0) {
364       redisplay = TRUE;
365       XtFree(current->plot.xlabel);
366       new->plot.xlabel = (char *) XtMalloc(strlen(new->plot.TransientXLabel) + 1);
367       strcpy(new->plot.xlabel, new->plot.TransientXLabel);
368       new->plot.TransientXLabel=NULL;
369     }
370   }
371   if (new->plot.TransientYLabel) {
372     if (current->plot.TransientYLabel != new->plot.TransientYLabel ||
373         strcmp(new->plot.TransientYLabel,current->plot.ylabel)!=0) {
374       redisplay = TRUE;
375       XtFree(current->plot.ylabel);
376       new->plot.ylabel = (char *) XtMalloc(strlen(new->plot.TransientYLabel) + 1);
377       strcpy(new->plot.ylabel, new->plot.TransientYLabel);
378       new->plot.TransientYLabel=NULL;
379     }
380   }
381   if (new->plot.TransientPlotTitle) {
382     if (current->plot.TransientPlotTitle != new->plot.TransientPlotTitle ||
383         strcmp(new->plot.TransientPlotTitle,current->plot.plotTitle)!=0) {
384       redisplay = TRUE;
385       XtFree(current->plot.plotTitle);
386       new->plot.plotTitle = (char *) XtMalloc(strlen(new->plot.TransientPlotTitle) + 1);
387       strcpy(new->plot.plotTitle, new->plot.TransientPlotTitle);
388       new->plot.TransientPlotTitle=NULL;
389     }
390   }
391 
392   if (current->plot.AxisFont != new->plot.AxisFont) {
393     redisplay = TRUE;
394     FontnumReplace(new, new->plot.axisFont, new->plot.AxisFont);
395   }
396   if (current->plot.TitleFont != new->plot.TitleFont) {
397     redisplay = TRUE;
398     FontnumReplace(new, new->plot.titleFont, new->plot.TitleFont);
399   }
400   if (current->plot.LabelFont != new->plot.LabelFont) {
401     redisplay = TRUE;
402     FontnumReplace(new, new->plot.labelFont, new->plot.LabelFont);
403   }
404 
405   new->plot.update = redisplay;
406 
407   return redisplay;
408 }
409 
410 static void
GetValuesHook(SciPlotWidget w,ArgList args,Cardinal * num_args)411 GetValuesHook(SciPlotWidget w, ArgList args, Cardinal *num_args)
412 {
413   int i;
414   char **loc;
415 
416   for (i=0; i<*num_args; i++) {
417     loc=(char **)args[i].value;
418     if (strcmp(args[i].name,XtNplotTitle)==0)
419       *loc=w->plot.plotTitle;
420     else if (strcmp(args[i].name,XtNxLabel)==0)
421       *loc=w->plot.xlabel;
422     else if (strcmp(args[i].name,XtNyLabel)==0)
423       *loc=w->plot.ylabel;
424 
425   }
426 }
427 
428 
429 static void
Redisplay(SciPlotWidget w)430 Redisplay(SciPlotWidget w)
431 {
432   if (!XtIsRealized((Widget)w))
433     return;
434 
435   if (w->plot.update) {
436     Resize(w);
437     w->plot.update = FALSE;
438   }
439   else {
440     ItemDrawAll(w);
441   }
442 }
443 
444 static void
Resize(SciPlotWidget w)445 Resize(SciPlotWidget w)
446 {
447   if (!XtIsRealized((Widget)w))
448     return;
449 
450   EraseAll(w);
451   ComputeAll(w);
452   DrawAll(w);
453 }
454 
455 
456 /*
457  * Private SciPlot utility functions
458  */
459 
460 
461 static int
ColorStore(SciPlotWidget w,Pixel color)462 ColorStore (SciPlotWidget w, Pixel color)
463 {
464   w->plot.num_colors++;
465   w->plot.colors = (Pixel *) XtRealloc((char *) w->plot.colors,
466     sizeof(Pixel) * w->plot.num_colors);
467   w->plot.colors[w->plot.num_colors - 1] = color;
468   return w->plot.num_colors - 1;
469 }
470 
471 static void
FontnumStore(SciPlotWidget w,int fontnum,int flag)472 FontnumStore (SciPlotWidget w, int fontnum, int flag)
473 {
474   SciPlotFont *pf;
475   int fontflag, sizeflag, attrflag;
476 
477   pf = &w->plot.fonts[fontnum];
478 
479   fontflag = flag & XtFONT_NAME_MASK;
480   sizeflag = flag & XtFONT_SIZE_MASK;
481   attrflag = flag & XtFONT_ATTRIBUTE_MASK;
482 
483   switch (fontflag) {
484   case XtFONT_TIMES:
485   case XtFONT_COURIER:
486   case XtFONT_HELVETICA:
487   case XtFONT_LUCIDA:
488   case XtFONT_LUCIDASANS:
489   case XtFONT_NCSCHOOLBOOK:
490     break;
491   default:
492     fontflag = XtFONT_NAME_DEFAULT;
493     break;
494   }
495 
496   if (sizeflag < 1)
497     sizeflag = XtFONT_SIZE_DEFAULT;
498 
499   switch (attrflag) {
500   case XtFONT_BOLD:
501   case XtFONT_ITALIC:
502   case XtFONT_BOLD_ITALIC:
503     break;
504   default:
505     attrflag = XtFONT_ATTRIBUTE_DEFAULT;
506     break;
507   }
508   pf->id = flag;
509   FontInit(w, pf);
510 }
511 
512 static int
FontnumReplace(SciPlotWidget w,int fontnum,int flag)513 FontnumReplace (SciPlotWidget w, int fontnum, int flag)
514 {
515   SciPlotFont *pf;
516 
517   pf = &w->plot.fonts[fontnum];
518   XFreeFont(XtDisplay(w), pf->font);
519 
520   FontnumStore(w, fontnum, flag);
521 
522   return fontnum;
523 }
524 
525 static int
FontStore(SciPlotWidget w,int flag)526 FontStore (SciPlotWidget w, int flag)
527 {
528   int fontnum;
529 
530   w->plot.num_fonts++;
531   w->plot.fonts = (SciPlotFont *) XtRealloc((char *) w->plot.fonts,
532     sizeof(SciPlotFont) * w->plot.num_fonts);
533   fontnum = w->plot.num_fonts - 1;
534 
535   FontnumStore(w, fontnum, flag);
536 
537   return fontnum;
538 }
539 
540 static SciPlotFontDesc *
FontDescLookup(int flag)541 FontDescLookup (int flag)
542 {
543   SciPlotFontDesc *pfd;
544 
545   pfd = font_desc_table;
546   while (pfd->flag >= 0) {
547 #ifdef DEBUG_SCIPLOT
548     printf("checking if %d == %d (font %s)\n",
549       flag & XtFONT_NAME_MASK, pfd->flag, pfd->PostScript);
550 #endif
551     if ((flag & XtFONT_NAME_MASK) == pfd->flag)
552       return pfd;
553     pfd++;
554   }
555   return NULL;
556 }
557 
558 
559 static void
FontnumPostScriptString(SciPlotWidget w,int fontnum,char * str)560 FontnumPostScriptString (SciPlotWidget w, int fontnum, char *str)
561 {
562   char temp[128];
563   int flag, bold, italic;
564   SciPlotFontDesc *pfd;
565 
566   flag = w->plot.fonts[fontnum].id;
567   pfd = FontDescLookup(flag);
568   if (pfd) {
569     strcpy(temp, pfd->PostScript);
570     bold = False;
571     italic = False;
572     if (flag & XtFONT_BOLD) {
573       bold = True;
574       strcat(temp, "-Bold");
575     }
576     if (flag & XtFONT_ITALIC) {
577       italic = True;
578       if (!bold)
579 	strcat(temp, "-");
580       if (pfd->PSUsesOblique)
581 	strcat(temp, "Oblique");
582       else
583 	strcat(temp, "Italic");
584     }
585     if (!bold && !italic && pfd->PSUsesRoman) {
586       strcat(temp, "-Roman");
587     }
588 
589     sprintf(str, "/%s findfont %d scalefont",
590       temp,
591       (flag & XtFONT_SIZE_MASK));
592   }
593   else
594     sprintf(str, "/Courier findfond 10 scalefont");
595 }
596 
597 static void
FontX11String(int flag,char * str)598 FontX11String (int flag, char *str)
599 {
600   SciPlotFontDesc *pfd;
601 
602   pfd = FontDescLookup(flag);
603   if (pfd) {
604     sprintf(str, "-*-%s-%s-%s-*-*-%d-*-*-*-*-*-*-*",
605       pfd->X11,
606       (flag & XtFONT_BOLD ? "bold" : "medium"),
607       (flag & XtFONT_ITALIC ? (pfd->PSUsesOblique ? "o" : "i") : "r"),
608       (flag & XtFONT_SIZE_MASK));
609   }
610   else
611     sprintf(str, "fixed");
612 #ifdef DEBUG_SCIPLOT
613   printf("font string=%s\n", str);
614 #endif
615 }
616 
617 static void
FontInit(SciPlotWidget w,SciPlotFont * pf)618 FontInit (SciPlotWidget w, SciPlotFont *pf)
619 {
620   char str[256], **list;
621   int num;
622 
623   FontX11String(pf->id, str);
624   list = XListFonts(XtDisplay(w), str, 100, &num);
625 #ifdef DEBUG_SCIPLOT
626   if (1) {
627     int i;
628 
629     i = 0;
630     while (i < num) {
631       printf("Found font: %s\n", list[i]);
632       i++;
633     }
634   }
635 #endif
636   if (num <= 0) {
637     pf->id &= ~XtFONT_ATTRIBUTE_MASK;
638     pf->id |= XtFONT_ATTRIBUTE_DEFAULT;
639     FontX11String(pf->id, str);
640     list = XListFonts(XtDisplay(w), str, 100, &num);
641 #ifdef DEBUG_SCIPLOT
642     if (1) {
643       int i;
644 
645       i = 0;
646       while (i < num) {
647 	printf("Attr reset: found: %s\n", list[i]);
648 	i++;
649       }
650     }
651 #endif
652   }
653   if (num <= 0) {
654     pf->id &= ~XtFONT_NAME_MASK;
655     pf->id |= XtFONT_NAME_DEFAULT;
656     FontX11String(pf->id, str);
657     list = XListFonts(XtDisplay(w), str, 100, &num);
658 #ifdef DEBUG_SCIPLOT
659     if (1) {
660       int i;
661 
662       i = 0;
663       while (i < num) {
664 	printf("Name reset: found: %s\n", list[i]);
665 	i++;
666       }
667     }
668 #endif
669   }
670   if (num <= 0) {
671     pf->id &= ~XtFONT_SIZE_MASK;
672     pf->id |= XtFONT_SIZE_DEFAULT;
673     FontX11String(pf->id, str);
674     list = XListFonts(XtDisplay(w), str, 100, &num);
675 #ifdef DEBUG_SCIPLOT
676     if (1) {
677       int i;
678 
679       i = 0;
680       while (i < num) {
681 	printf("Size reset: found: %s\n", list[i]);
682 	i++;
683       }
684     }
685 #endif
686   }
687   if (num <= 0)
688     strcpy(str, "fixed");
689   else
690     XFreeFontNames(list);
691   pf->font = XLoadQueryFont(XtDisplay(w), str);
692 }
693 
694 static XFontStruct *
FontFromFontnum(SciPlotWidget w,int fontnum)695 FontFromFontnum (SciPlotWidget w, int fontnum)
696 {
697   XFontStruct *f;
698 
699   if (fontnum >= w->plot.num_fonts)
700     fontnum = 0;
701   f = w->plot.fonts[fontnum].font;
702   return f;
703 }
704 
705 static real
FontHeight(XFontStruct * f)706 FontHeight(XFontStruct *f)
707 {
708   return (real) (f->max_bounds.ascent + f->max_bounds.descent);
709 }
710 
711 static real
FontnumHeight(SciPlotWidget w,int fontnum)712 FontnumHeight(SciPlotWidget w, int fontnum)
713 {
714   XFontStruct *f;
715 
716   f = FontFromFontnum(w, fontnum);
717   return FontHeight(f);
718 }
719 
720 static real
FontDescent(XFontStruct * f)721 FontDescent(XFontStruct *f)
722 {
723   return (real) (f->max_bounds.descent);
724 }
725 
726 static real
FontnumDescent(SciPlotWidget w,int fontnum)727 FontnumDescent(SciPlotWidget w, int fontnum)
728 {
729   XFontStruct *f;
730 
731   f = FontFromFontnum(w, fontnum);
732   return FontDescent(f);
733 }
734 
735 static real
FontAscent(XFontStruct * f)736 FontAscent(XFontStruct *f)
737 {
738   return (real) (f->max_bounds.ascent);
739 }
740 
741 static real
FontnumAscent(SciPlotWidget w,int fontnum)742 FontnumAscent(SciPlotWidget w, int fontnum)
743 {
744   XFontStruct *f;
745 
746   f = FontFromFontnum(w, fontnum);
747   return FontAscent(f);
748 }
749 
750 static real
FontTextWidth(XFontStruct * f,char * c)751 FontTextWidth(XFontStruct *f, char *c)
752 {
753   return (real) XTextWidth(f, c, strlen(c));
754 }
755 
756 static real
FontnumTextWidth(SciPlotWidget w,int fontnum,char * c)757 FontnumTextWidth(SciPlotWidget w, int fontnum, char *c)
758 {
759   XFontStruct *f;
760 
761   f = FontFromFontnum(w, fontnum);
762   return FontTextWidth(f, c);
763 }
764 
765 
766 /*
767  * Private List functions
768  */
769 
770 static int
_ListNew(SciPlotWidget w)771 _ListNew (SciPlotWidget w)
772 {
773   int index;
774   SciPlotList *p;
775   Boolean found;
776 
777 /* First check to see if there is any free space in the index */
778   found = FALSE;
779   for (index = 0; index < w->plot.num_plotlist; index++) {
780     p = w->plot.plotlist + index;
781     if (!p->used) {
782       found = TRUE;
783       break;
784     }
785   }
786 
787 /* If no space is found, increase the size of the index */
788   if (!found) {
789     w->plot.num_plotlist++;
790     if (w->plot.alloc_plotlist == 0) {
791       w->plot.alloc_plotlist = NUMPLOTLINEALLOC;
792       w->plot.plotlist = (SciPlotList *) XtCalloc(w->plot.alloc_plotlist, sizeof(SciPlotList));
793       if (!w->plot.plotlist) {
794 	printf("Can't calloc memory for SciPlotList\n");
795 	exit(1);
796       }
797       w->plot.alloc_plotlist = NUMPLOTLINEALLOC;
798     }
799     else if (w->plot.num_plotlist > w->plot.alloc_plotlist) {
800       w->plot.alloc_plotlist += NUMPLOTLINEALLOC;
801       w->plot.plotlist = (SciPlotList *) XtRealloc((char *) w->plot.plotlist,
802 	w->plot.alloc_plotlist * sizeof(SciPlotList));
803       if (!w->plot.plotlist) {
804 	printf("Can't realloc memory for SciPlotList\n");
805 	exit(1);
806       }
807     }
808     index = w->plot.num_plotlist - 1;
809     p = w->plot.plotlist + index;
810   }
811 
812   p->LineStyle = p->LineColor = p->PointStyle = p->PointColor = 0;
813   p->number = p->allocated = 0;
814   p->data = NULL;
815   p->legend = NULL;
816   p->draw = p->used = TRUE;
817   p->markersize = (real) w->plot.DefaultMarkerSize;
818   return index;
819 }
820 
821 static void
_ListDelete(SciPlotList * p)822 _ListDelete (SciPlotList *p)
823 {
824   p->draw = p->used = FALSE;
825   p->number = p->allocated = 0;
826   if (p->data)
827     XtFree((char *) p->data);
828   p->data = NULL;
829   if (p->legend)
830     XtFree((char *) p->legend);
831   p->legend = NULL;
832 }
833 
834 static SciPlotList *
_ListFind(SciPlotWidget w,int id)835 _ListFind (SciPlotWidget w, int id)
836 {
837   SciPlotList *p;
838 
839   if ((id >= 0) && (id < w->plot.num_plotlist)) {
840     p = w->plot.plotlist + id;
841     if (p->used)
842       return p;
843   }
844   return NULL;
845 }
846 
847 static void
_ListSetStyle(SciPlotList * p,int pcolor,int pstyle,int lcolor,int lstyle)848 _ListSetStyle (SciPlotList *p, int pcolor, int pstyle, int lcolor, int lstyle)
849 {
850 /* Note!  Do checks in here later on... */
851 
852   if (lstyle >= 0)
853     p->LineStyle = lstyle;
854   if (lcolor >= 0)
855     p->LineColor = lcolor;
856   if (pstyle >= 0)
857     p->PointStyle = pstyle;
858   if (pcolor >= 0)
859     p->PointColor = pcolor;
860 }
861 
862 static void
_ListSetLegend(SciPlotList * p,char * legend)863 _ListSetLegend (SciPlotList *p, char *legend)
864 {
865 /* Note!  Do checks in here later on... */
866 
867   p->legend = (char *) XtMalloc(strlen(legend) + 1);
868   strcpy(p->legend, legend);
869 }
870 
871 static void
_ListAllocData(SciPlotList * p,int num)872 _ListAllocData (SciPlotList *p, int num)
873 {
874   if (p->data) {
875     XtFree((char *) p->data);
876     p->allocated = 0;
877   }
878   p->allocated = num + NUMPLOTDATAEXTRA;
879   p->data = (realpair *) XtCalloc(p->allocated, sizeof(realpair));
880   if (!p->data) {
881     p->number = p->allocated = 0;
882   }
883 }
884 
885 static void
_ListReallocData(SciPlotList * p,int more)886 _ListReallocData (SciPlotList *p, int more)
887 {
888   if (!p->data) {
889     _ListAllocData(p, more);
890   }
891   else if (p->number + more > p->allocated) {
892     p->allocated += more + NUMPLOTDATAEXTRA;
893     p->data = (realpair *) XtRealloc((char *) p->data, p->allocated * sizeof(realpair));
894     if (!p->data) {
895       p->number = p->allocated = 0;
896     }
897   }
898 
899 }
900 
901 static void
_ListAddReal(SciPlotList * p,int num,real * xlist,real * ylist)902 _ListAddReal (SciPlotList *p, int num, real *xlist, real *ylist)
903 {
904   int i;
905 
906   _ListReallocData(p, num);
907   if (p->data) {
908     for (i = 0; i < num; i++) {
909       p->data[i + p->number].x = xlist[i];
910       p->data[i + p->number].y = ylist[i];
911     }
912     p->number += num;
913   }
914 }
915 
916 static void
_ListAddFloat(SciPlotList * p,int num,float * xlist,float * ylist)917 _ListAddFloat (SciPlotList *p, int num, float *xlist, float *ylist)
918 {
919   int i;
920 
921   _ListReallocData(p, num);
922   if (p->data) {
923     for (i = 0; i < num; i++) {
924       p->data[i + p->number].x = xlist[i];
925       p->data[i + p->number].y = ylist[i];
926     }
927     p->number += num;
928   }
929 }
930 
931 static void
_ListAddDouble(SciPlotList * p,int num,double * xlist,double * ylist)932 _ListAddDouble (SciPlotList *p, int num, double *xlist, double *ylist)
933 {
934   int i;
935 
936   _ListReallocData(p, num);
937   if (p->data) {
938     for (i = 0; i < num; i++) {
939       p->data[i + p->number].x = xlist[i];
940       p->data[i + p->number].y = ylist[i];
941     }
942     p->number += num;
943   }
944 }
945 
946 static void
_ListSetReal(SciPlotList * p,int num,real * xlist,real * ylist)947 _ListSetReal(SciPlotList *p, int num, real *xlist, real *ylist)
948 {
949   if ((!p->data) || (p->allocated < num))
950     _ListAllocData(p, num);
951   p->number = 0;
952   _ListAddReal(p, num, xlist, ylist);
953 }
954 
955 static void
_ListSetFloat(SciPlotList * p,int num,float * xlist,float * ylist)956 _ListSetFloat (SciPlotList *p, int num, float *xlist, float *ylist)
957 {
958   if ((!p->data) || (p->allocated < num))
959     _ListAllocData(p, num);
960   p->number = 0;
961   _ListAddFloat(p, num, xlist, ylist);
962 }
963 
964 static void
_ListSetDouble(SciPlotList * p,int num,double * xlist,double * ylist)965 _ListSetDouble (SciPlotList *p, int num, double *xlist, double *ylist)
966 {
967   if ((!p->data) || (p->allocated < num))
968     _ListAllocData(p, num);
969   p->number = 0;
970   _ListAddDouble(p, num, xlist, ylist);
971 }
972 
973 
974 /*
975  * Private SciPlot functions
976  */
977 
978 
979 /*
980  * The following vertical text drawing routine uses the "Fill Stippled" idea
981  * found in xvertext-5.0, by Alan Richardson (mppa3@syma.sussex.ac.uk).
982  *
983  * The following code is my interpretation of his idea, including some
984  * hacked together excerpts from his source.  The credit for the clever bits
985  * belongs to him.
986  *
987  * To be complete, portions of the subroutine XDrawVString are
988  * Copyright (c) 1993 Alan Richardson (mppa3@syma.sussex.ac.uk)
989  */
990 static void
XDrawVString(Display * display,Window win,GC gc,int x,int y,char * str,int len,XFontStruct * f)991 XDrawVString (Display *display, Window win, GC gc, int x, int y, char *str, int len, XFontStruct *f)
992 {
993   XImage *before, *after;
994   char *dest, *source;
995   int xloop, yloop, xdest, ydest;
996   Pixmap pix, rotpix;
997   int width, height;
998   GC drawGC;
999 
1000   width = (int) FontTextWidth(f, str);
1001   height = (int) FontHeight(f);
1002 
1003   pix = XCreatePixmap(display, win, width, height, 1);
1004   rotpix = XCreatePixmap(display, win, height, width, 1);
1005 
1006   drawGC = XCreateGC(display, pix, 0L, NULL);
1007   XSetBackground(display, drawGC, 0);
1008   XSetFont(display, drawGC, f->fid);
1009   XSetForeground(display, drawGC, 0);
1010   XFillRectangle(display, pix, drawGC, 0, 0, width, height);
1011   XFillRectangle(display, rotpix, drawGC, 0, 0, height, width);
1012   XSetForeground(display, drawGC, 1);
1013 
1014   XDrawImageString(display, pix, drawGC, 0, (int) FontAscent(f),
1015     str, strlen(str));
1016 
1017   source = (char *) XtCalloc((((width + 7) / 8) * height), 1);
1018   before = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)),
1019     1, XYPixmap, 0, source, width, height, 8, 0);
1020   before->byte_order = before->bitmap_bit_order = MSBFirst;
1021   XGetSubImage(display, pix, 0, 0, width, height, 1L, XYPixmap, before, 0, 0);
1022   source = (char *) XtCalloc((((height + 7) / 8) * width), 1);
1023   after = XCreateImage(display, DefaultVisual(display, DefaultScreen(display)),
1024     1, XYPixmap, 0, source, height, width, 8, 0);
1025   after->byte_order = after->bitmap_bit_order = MSBFirst;
1026 
1027   for (yloop = 0; yloop < height; yloop++) {
1028     for (xloop = 0; xloop < width; xloop++) {
1029       source = before->data + (xloop / 8) +
1030 	(yloop * before->bytes_per_line);
1031       if (*source & (128 >> (xloop % 8))) {
1032 	dest = after->data + (yloop / 8) +
1033 	  ((width - 1 - xloop) * after->bytes_per_line);
1034 	*dest |= (128 >> (yloop % 8));
1035       }
1036     }
1037   }
1038 
1039 #ifdef DEBUG_SCIPLOT_VTEXT
1040   if (1) {
1041     char sourcebit;
1042 
1043     for (yloop = 0; yloop < before->height; yloop++) {
1044       for (xloop = 0; xloop < before->width; xloop++) {
1045 	source = before->data + (xloop / 8) +
1046 	  (yloop * before->bytes_per_line);
1047 	sourcebit = *source & (128 >> (xloop % 8));
1048 	if (sourcebit)
1049 	  putchar('X');
1050 	else
1051 	  putchar('.');
1052       }
1053       putchar('\n');
1054     }
1055 
1056     for (yloop = 0; yloop < after->height; yloop++) {
1057       for (xloop = 0; xloop < after->width; xloop++) {
1058 	source = after->data + (xloop / 8) +
1059 	  (yloop * after->bytes_per_line);
1060 	sourcebit = *source & (128 >> (xloop % 8));
1061 	if (sourcebit)
1062 	  putchar('X');
1063 	else
1064 	  putchar('.');
1065       }
1066       putchar('\n');
1067     }
1068   }
1069 #endif
1070 
1071   xdest = x - (int) FontAscent(f);
1072   if (xdest < 0)
1073     xdest = 0;
1074   ydest = y - width;
1075 
1076   XPutImage(display, rotpix, drawGC, after, 0, 0, 0, 0,
1077     after->width, after->height);
1078 
1079   XSetFillStyle(display, gc, FillStippled);
1080   XSetStipple(display, gc, rotpix);
1081   XSetTSOrigin(display, gc, xdest, ydest);
1082   XFillRectangle(display, win, gc, xdest, ydest, after->width, after->height);
1083   XSetFillStyle(display, gc, FillSolid);
1084 
1085   XFreeGC(display, drawGC);
1086   XDestroyImage(before);
1087   XDestroyImage(after);
1088   XFreePixmap(display, pix);
1089   XFreePixmap(display, rotpix);
1090 
1091 /* Note that it appears that there is a memory leak here, but XDestroyImage
1092  * frees the image data that is XtCalloc'ed
1093  */
1094 
1095 }
1096 
1097 static char dots[] =
1098 {2, 1, 1};
1099 static char widedots[] =
1100 {2, 1, 4};
1101 
1102 static GC
ItemGetGC(SciPlotWidget w,SciPlotItem * item)1103 ItemGetGC (SciPlotWidget w, SciPlotItem *item)
1104 {
1105   GC gc;
1106   short color;
1107 
1108   switch (item->kind.any.style) {
1109   case XtLINE_SOLID:
1110     gc = w->plot.defaultGC;
1111     break;
1112   case XtLINE_DOTTED:
1113     XSetDashes(XtDisplay(w), w->plot.dashGC, 0, &dots[1],
1114       (int) dots[0]);
1115     gc = w->plot.dashGC;
1116     break;
1117   case XtLINE_WIDEDOT:
1118     XSetDashes(XtDisplay(w), w->plot.dashGC, 0, &widedots[1],
1119       (int) widedots[0]);
1120     gc = w->plot.dashGC;
1121     break;
1122   default:
1123     return NULL;
1124     break;
1125   }
1126   if (w->plot.Monochrome)
1127     if (item->kind.any.color > 0)
1128       color = w->plot.ForegroundColor;
1129     else
1130       color = w->plot.BackgroundColor;
1131   else if (item->kind.any.color >= w->plot.num_colors)
1132     color = w->plot.ForegroundColor;
1133   else if (item->kind.any.color <= 0)
1134     color = w->plot.BackgroundColor;
1135   else
1136     color = item->kind.any.color;
1137   XSetForeground(XtDisplay(w), gc, w->plot.colors[color]);
1138   return gc;
1139 }
1140 
1141 static GC
ItemGetFontGC(SciPlotWidget w,SciPlotItem * item)1142 ItemGetFontGC (SciPlotWidget w, SciPlotItem *item)
1143 {
1144   GC gc;
1145   short color, fontnum;
1146 
1147   gc = w->plot.dashGC;
1148   if (w->plot.Monochrome)
1149     if (item->kind.any.color > 0)
1150       color = w->plot.ForegroundColor;
1151     else
1152       color = w->plot.BackgroundColor;
1153   else if (item->kind.any.color >= w->plot.num_colors)
1154     color = w->plot.ForegroundColor;
1155   else if (item->kind.any.color <= 0)
1156     color = w->plot.BackgroundColor;
1157   else
1158     color = item->kind.any.color;
1159   XSetForeground(XtDisplay(w), gc, w->plot.colors[color]);
1160   if (item->kind.text.font >= w->plot.num_fonts)
1161     fontnum = 0;
1162   else
1163     fontnum = item->kind.text.font;
1164 
1165 /*
1166  * fontnum==0 hack:  0 is supposed to be the default font, but the program
1167  * can't seem to get the default font ID from the GC for some reason.  So,
1168  * use a different GC where the default font still exists.
1169  */
1170   XSetFont(XtDisplay(w), gc, w->plot.fonts[fontnum].font->fid);
1171   return gc;
1172 }
1173 
1174 static void
ItemDraw(SciPlotWidget w,SciPlotItem * item)1175 ItemDraw (SciPlotWidget w, SciPlotItem *item)
1176 {
1177   XPoint point[8];
1178   XSegment seg;
1179   XRectangle rect;
1180   int i;
1181   GC gc;
1182 
1183   if (!XtIsRealized((Widget) w))
1184     return;
1185   if ((item->type > SciPlotStartTextTypes) && (item->type < SciPlotEndTextTypes))
1186     gc = ItemGetFontGC(w, item);
1187   else
1188     gc = ItemGetGC(w, item);
1189   if (!gc)
1190     return;
1191   switch (item->type) {
1192   case SciPlotLine:
1193     seg.x1 = (short) item->kind.line.x1;
1194     seg.y1 = (short) item->kind.line.y1;
1195     seg.x2 = (short) item->kind.line.x2;
1196     seg.y2 = (short) item->kind.line.y2;
1197     XDrawSegments(XtDisplay(w), XtWindow(w), gc,
1198       &seg, 1);
1199     break;
1200   case SciPlotRect:
1201     XDrawRectangle(XtDisplay(w), XtWindow(w), gc,
1202       (int) (item->kind.rect.x),
1203       (int) (item->kind.rect.y),
1204       (unsigned int) (item->kind.rect.w),
1205       (unsigned int) (item->kind.rect.h));
1206     break;
1207   case SciPlotFRect:
1208     XFillRectangle(XtDisplay(w), XtWindow(w), gc,
1209       (int) (item->kind.rect.x),
1210       (int) (item->kind.rect.y),
1211       (unsigned int) (item->kind.rect.w),
1212       (unsigned int) (item->kind.rect.h));
1213     XDrawRectangle(XtDisplay(w), XtWindow(w), gc,
1214       (int) (item->kind.rect.x),
1215       (int) (item->kind.rect.y),
1216       (unsigned int) (item->kind.rect.w),
1217       (unsigned int) (item->kind.rect.h));
1218     break;
1219   case SciPlotPoly:
1220     i = 0;
1221     while (i < item->kind.poly.count) {
1222       point[i].x = (int) item->kind.poly.x[i];
1223       point[i].y = (int) item->kind.poly.y[i];
1224       i++;
1225     }
1226     point[i].x = (int) item->kind.poly.x[0];
1227     point[i].y = (int) item->kind.poly.y[0];
1228     XDrawLines(XtDisplay(w), XtWindow(w), gc,
1229       point, i + 1, CoordModeOrigin);
1230     break;
1231   case SciPlotFPoly:
1232     i = 0;
1233     while (i < item->kind.poly.count) {
1234       point[i].x = (int) item->kind.poly.x[i];
1235       point[i].y = (int) item->kind.poly.y[i];
1236       i++;
1237     }
1238     point[i].x = (int) item->kind.poly.x[0];
1239     point[i].y = (int) item->kind.poly.y[0];
1240     XFillPolygon(XtDisplay(w), XtWindow(w), gc,
1241       point, i + 1, Complex, CoordModeOrigin);
1242     XDrawLines(XtDisplay(w), XtWindow(w), gc,
1243       point, i + 1, CoordModeOrigin);
1244     break;
1245   case SciPlotCircle:
1246     XDrawArc(XtDisplay(w), XtWindow(w), gc,
1247       (int) (item->kind.circ.x - item->kind.circ.r),
1248       (int) (item->kind.circ.y - item->kind.circ.r),
1249       (unsigned int) (item->kind.circ.r * 2),
1250       (unsigned int) (item->kind.circ.r * 2),
1251       0 * 64, 360 * 64);
1252     break;
1253   case SciPlotFCircle:
1254     XFillArc(XtDisplay(w), XtWindow(w), gc,
1255       (int) (item->kind.circ.x - item->kind.circ.r),
1256       (int) (item->kind.circ.y - item->kind.circ.r),
1257       (unsigned int) (item->kind.circ.r * 2),
1258       (unsigned int) (item->kind.circ.r * 2),
1259       0 * 64, 360 * 64);
1260     break;
1261   case SciPlotText:
1262     XDrawString(XtDisplay(w), XtWindow(w), gc,
1263       (int) (item->kind.text.x), (int) (item->kind.text.y),
1264       item->kind.text.text,
1265       (int) item->kind.text.length);
1266     break;
1267   case SciPlotVText:
1268     XDrawVString(XtDisplay(w), XtWindow(w), gc,
1269       (int) (item->kind.text.x), (int) (item->kind.text.y),
1270       item->kind.text.text,
1271       (int) item->kind.text.length,
1272       FontFromFontnum(w, item->kind.text.font));
1273     break;
1274   case SciPlotClipRegion:
1275     rect.x = (short) item->kind.line.x1;
1276     rect.y = (short) item->kind.line.y1;
1277     rect.width = (short) item->kind.line.x2;
1278     rect.height = (short) item->kind.line.y2;
1279     XSetClipRectangles(XtDisplay(w), w->plot.dashGC, 0, 0, &rect, 1, Unsorted);
1280     XSetClipRectangles(XtDisplay(w), w->plot.defaultGC, 0, 0, &rect, 1, Unsorted);
1281     break;
1282   case SciPlotClipClear:
1283     XSetClipMask(XtDisplay(w), w->plot.dashGC, None);
1284     XSetClipMask(XtDisplay(w), w->plot.defaultGC, None);
1285     break;
1286   default:
1287     break;
1288   }
1289 }
1290 
1291 static void
ItemDrawAll(SciPlotWidget w)1292 ItemDrawAll (SciPlotWidget w)
1293 {
1294   SciPlotItem *item;
1295   int i;
1296 
1297   if (!XtIsRealized((Widget) w))
1298     return;
1299   item = w->plot.drawlist;
1300   i = 0;
1301   while (i < w->plot.num_drawlist) {
1302     ItemDraw(w, item);
1303     i++;
1304     item++;
1305   }
1306 }
1307 
1308 
1309 
1310 /*
1311  * PostScript (r) functions ------------------------------------------------
1312  *
1313  */
1314 typedef struct {
1315   char *command;
1316   char *prolog;
1317 } PScommands;
1318 
1319 static PScommands psc[] =
1320 {
1321   {"ma", "moveto"},
1322   {"da", "lineto stroke newpath"},
1323   {"la", "lineto"},
1324   {"poly", "closepath stroke newpath"},
1325   {"fpoly", "closepath fill newpath"},
1326   {"box", "1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath stroke newpath"},
1327   {"fbox", "1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath fill newpath"},
1328   {"clipbox", "gsave 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath clip newpath"},
1329   {"unclip", "grestore newpath"},
1330   {"cr", "0 360 arc stroke newpath"},
1331   {"fcr", "0 360 arc fill newpath"},
1332   {"vma", "gsave moveto 90 rotate"},
1333   {"norm", "grestore"},
1334   {"solid", "[] 0 setdash"},
1335   {"dot", "[.25 2] 0 setdash"},
1336   {"widedot", "[.25 8] 0 setdash"},
1337   {"rgb", "setrgbcolor"},
1338   {NULL, NULL}
1339 };
1340 
1341 enum PSenums {
1342   PSmoveto, PSlineto,
1343   PSpolyline, PSendpoly, PSendfill,
1344   PSbox, PSfbox,
1345   PSclipbox, PSunclip,
1346   PScircle, PSfcircle,
1347   PSvmoveto, PSnormal,
1348   PSsolid, PSdot, PSwidedot,
1349   PSrgb
1350 };
1351 
1352 static void
ItemPSDrawAll(SciPlotWidget w,FILE * fd,double yflip,Boolean usecolor)1353 ItemPSDrawAll (SciPlotWidget w, FILE *fd, double yflip, Boolean usecolor)
1354 {
1355   int i, loopcount;
1356   SciPlotItem *item;
1357   XcmsColor currentcolor;
1358   int previousfont, previousline, currentfont, currentline, previouscolor;
1359 
1360   item = w->plot.drawlist;
1361   loopcount = 0;
1362   previousfont = 0;
1363   previouscolor = -1;
1364   previousline = XtLINE_SOLID;
1365   while (loopcount < w->plot.num_drawlist) {
1366 
1367 /* 2 switch blocks:  1st sets up defaults, 2nd actually draws things. */
1368     currentline = previousline;
1369     currentfont = previousfont;
1370     switch (item->type) {
1371     case SciPlotLine:
1372     case SciPlotCircle:
1373       currentline = item->kind.any.style;
1374       break;
1375     default:
1376       break;
1377     }
1378     if (currentline != XtLINE_NONE) {
1379       if (currentline != previousline) {
1380 	switch (item->kind.any.style) {
1381 	case XtLINE_SOLID:
1382 	  fprintf(fd, "%s ", psc[PSsolid].command);
1383 	  break;
1384 	case XtLINE_DOTTED:
1385 	  fprintf(fd, "%s ", psc[PSdot].command);
1386 	  break;
1387 	case XtLINE_WIDEDOT:
1388 	  fprintf(fd, "%s ", psc[PSwidedot].command);
1389 	  break;
1390 	}
1391 	previousline = currentline;
1392       }
1393 
1394       if (usecolor && item->kind.any.color != previouscolor) {
1395 
1396           /* Get Pixel index */
1397         currentcolor.pixel = w->plot.colors[item->kind.any.color];
1398           /* Get RGBi components [0.0,1.0] */
1399         XcmsQueryColor( XtDisplay(w), w->plot.cmap, &currentcolor,
1400           XcmsRGBiFormat );
1401           /* output PostScript command */
1402         fprintf(fd, "%f %f %f %s ", currentcolor.spec.RGBi.red,
1403           currentcolor.spec.RGBi.green, currentcolor.spec.RGBi.blue,
1404           psc[PSrgb].command);
1405 
1406         previouscolor=item->kind.any.color;
1407 
1408       }
1409 
1410       switch (item->type) {
1411       case SciPlotLine:
1412 	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
1413 	  item->kind.line.x1, yflip - item->kind.line.y1,
1414 	  psc[PSmoveto].command,
1415 	  item->kind.line.x2, yflip - item->kind.line.y2,
1416 	  psc[PSlineto].command);
1417 	break;
1418       case SciPlotRect:
1419 	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
1420 	  item->kind.rect.x,
1421 	  yflip - item->kind.rect.y - (item->kind.rect.h - 1.0),
1422 	  psc[PSmoveto].command,
1423 	  item->kind.rect.w - 1.0, item->kind.rect.h - 1.0,
1424 	  psc[PSbox].command);
1425 	break;
1426       case SciPlotFRect:
1427 	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
1428 	  item->kind.rect.x,
1429 	  yflip - item->kind.rect.y - (item->kind.rect.h - 1.0),
1430 	  psc[PSmoveto].command,
1431 	  item->kind.rect.w - 1.0, item->kind.rect.h - 1.0,
1432 	  psc[PSfbox].command);
1433 	break;
1434       case SciPlotPoly:
1435 	fprintf(fd, "%.2f %.2f %s ",
1436 	  item->kind.poly.x[0], yflip - item->kind.poly.y[0],
1437 	  psc[PSmoveto].command);
1438 	for (i = 1; i < item->kind.poly.count; i++) {
1439 	  fprintf(fd, "%.2f %.2f %s ",
1440 	    item->kind.poly.x[i],
1441 	    yflip - item->kind.poly.y[i],
1442 	    psc[PSpolyline].command);
1443 	}
1444 	fprintf(fd, "%s\n", psc[PSendpoly].command);
1445 	break;
1446       case SciPlotFPoly:
1447 	fprintf(fd, "%.2f %.2f %s ",
1448 	  item->kind.poly.x[0], yflip - item->kind.poly.y[0],
1449 	  psc[PSmoveto].command);
1450 	for (i = 1; i < item->kind.poly.count; i++) {
1451 	  fprintf(fd, "%.2f %.2f %s ",
1452 	    item->kind.poly.x[i],
1453 	    yflip - item->kind.poly.y[i],
1454 	    psc[PSpolyline].command);
1455 	}
1456 	fprintf(fd, "%s\n", psc[PSendfill].command);
1457 	break;
1458       case SciPlotCircle:
1459 	fprintf(fd, "%.2f %.2f %.2f %s\n",
1460 	  item->kind.circ.x, yflip - item->kind.circ.y,
1461 	  item->kind.circ.r,
1462 	  psc[PScircle].command);
1463 	break;
1464       case SciPlotFCircle:
1465 	fprintf(fd, "%.2f %.2f %.2f %s\n",
1466 	  item->kind.circ.x, yflip - item->kind.circ.y,
1467 	  item->kind.circ.r,
1468 	  psc[PSfcircle].command);
1469 	break;
1470       case SciPlotText:
1471 	fprintf(fd, "font-%d %.2f %.2f %s (%s) show\n",
1472 	  item->kind.text.font,
1473 	  item->kind.text.x, yflip - item->kind.text.y,
1474 	  psc[PSmoveto].command,
1475 	  item->kind.text.text);
1476 	break;
1477       case SciPlotVText:
1478 	fprintf(fd, "font-%d %.2f %.2f %s (%s) show %s\n",
1479 	  item->kind.text.font,
1480 	  item->kind.text.x, yflip - item->kind.text.y,
1481 	  psc[PSvmoveto].command,
1482 	  item->kind.text.text,
1483 	  psc[PSnormal].command);
1484 	break;
1485       case SciPlotClipRegion:
1486 	fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
1487 	  item->kind.line.x1,
1488 	  yflip - item->kind.line.y1 - item->kind.line.y2,
1489 	  psc[PSmoveto].command,
1490 	  item->kind.line.x2, item->kind.line.y2,
1491 	  psc[PSclipbox].command);
1492 	break;
1493       case SciPlotClipClear:
1494 	fprintf(fd, "%s\n", psc[PSunclip].command);
1495 	break;
1496       default:
1497 	break;
1498       }
1499     }
1500     loopcount++;
1501     item++;
1502   }
1503 }
1504 
1505 Boolean
SciPlotPSCreateFancy(SciPlotWidget w,char * filename,int drawborder,char * titles,Boolean usecolor)1506 SciPlotPSCreateFancy (SciPlotWidget w, char *filename, int drawborder, char *titles, Boolean usecolor)
1507 {
1508   FILE *fd;
1509   float scale, xoff, yoff, xmax, ymax, yflip, aspect, border, titlefontsize;
1510   int i;
1511   PScommands *p;
1512   char fontname[128];
1513 
1514   if (!(fd = fopen(filename, "w"))) {
1515     XtWarning("SciPlotPSCreate: Unable to open postscript file.");
1516     return False;
1517   }
1518   DrawAll(w);
1519 
1520   aspect = (float) w->core.width / (float) w->core.height;
1521   border = 36.0;
1522   if (aspect > (612.0 / 792.0)) {
1523     scale = (612.0 - (2 * border)) / (float) w->core.width;
1524     xoff = border;
1525     yoff = (792.0 - (2 * border) - scale * (float) w->core.height) / 2.0;
1526     xmax = xoff + scale * (float) w->core.width;
1527     ymax = yoff + scale * (float) w->core.height;
1528   }
1529   else {
1530     scale = (792.0 - (2 * border)) / (float) w->core.height;
1531     yoff = border;
1532     xoff = (612.0 - (2 * border) - scale * (float) w->core.width) / 2.0;
1533     xmax = xoff + scale * (float) w->core.width;
1534     ymax = yoff + scale * (float) w->core.height;
1535   }
1536   yflip = w->core.height;
1537   fprintf(fd, "%s\n%s %.2f  %s\n%s %f %f %f %f\n%s\n",
1538     "%!PS-ADOBE-3.0 EPSF-3.0",
1539     "%%Creator: SciPlot Widget",
1540     _SCIPLOT_WIDGET_VERSION,
1541     "Copyright (c) 1995 Robert W. McMullen",
1542     "%%BoundingBox:", xoff, yoff, xmax, ymax,
1543     "%%EndComments");
1544 
1545   p = psc;
1546   while (p->command) {
1547     fprintf(fd, "/%s {%s} bind def\n", p->command, p->prolog);
1548     p++;
1549   }
1550 
1551   for (i = 0; i < w->plot.num_fonts; i++) {
1552     FontnumPostScriptString(w, i, fontname);
1553     fprintf(fd, "/font-%d {%s setfont} bind def\n",
1554       i, fontname);
1555   }
1556   titlefontsize = 10.0;
1557   fprintf(fd, "/font-title {/%s findfont %f scalefont setfont} bind def\n",
1558     "Times-Roman", titlefontsize);
1559   fprintf(fd, "%f setlinewidth\n", 0.001);
1560   fprintf(fd, "newpath gsave\n%f %f translate %f %f scale\n",
1561     xoff, yoff, scale, scale);
1562 
1563   ItemPSDrawAll(w, fd, yflip, usecolor);
1564 
1565   fprintf(fd, "grestore\n");
1566 
1567   if (drawborder) {
1568     fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
1569       border, border,
1570       psc[PSmoveto].command,
1571       612.0 - 2.0 * border, 792.0 - 2.0 * border,
1572       psc[PSbox].command);
1573   }
1574   if (titles) {
1575     char *ptr;
1576     char buf[256];
1577     int len, i, j;
1578     float x, y;
1579 
1580     x = border + titlefontsize;
1581     y = 792.0 - border - (2.0 * titlefontsize);
1582     len = strlen(titles);
1583     ptr = titles;
1584     i = 0;
1585     while (i < len) {
1586       j = 0;
1587       while ((*ptr != '\n') && (i < len)) {
1588 	if ((*ptr == '(') || (*ptr == ')'))
1589 	  buf[j++] = '\\';
1590 	buf[j++] = *ptr;
1591 	ptr++;
1592 	i++;
1593       }
1594       buf[j] = '\0';
1595       ptr++;
1596       i++;
1597       fprintf(fd, "font-title %.2f %.2f %s (%s) show\n",
1598 	x, y, psc[PSmoveto].command, buf);
1599       y -= titlefontsize * 1.5;
1600     }
1601     if (border) {
1602       y += titlefontsize * 0.5;
1603       fprintf(fd, "%.2f %.2f %s %.2f %.2f %s\n",
1604 	border, y,
1605 	psc[PSmoveto].command,
1606 	612.0 - border, y,
1607 	psc[PSlineto].command);
1608     }
1609   }
1610 
1611   fprintf(fd, "showpage\n");
1612   fclose(fd);
1613   return True;
1614 }
1615 
1616 Boolean
SciPlotPSCreate(Widget wi,char * filename)1617 SciPlotPSCreate (Widget wi, char *filename)
1618 {
1619   SciPlotWidget w;
1620 
1621   if (!XtIsSciPlot(wi)) {
1622     XtWarning("SciPlotPSCreate: Not a SciPlot widget.");
1623     return False;
1624   }
1625 
1626   w = (SciPlotWidget) wi;
1627   return SciPlotPSCreateFancy(w, filename, False, NULL, False);
1628 }
1629 
1630 Boolean
SciPlotPSCreateColor(Widget wi,char * filename)1631 SciPlotPSCreateColor (Widget wi, char *filename)
1632 {
1633   SciPlotWidget w;
1634 
1635   if (!XtIsSciPlot(wi)) {
1636     XtWarning("SciPlotPSCreate: Not a SciPlot widget.");
1637     return False;
1638   }
1639 
1640   w = (SciPlotWidget) wi;
1641   return SciPlotPSCreateFancy(w, filename, False, NULL, True);
1642 }
1643 
1644 
1645 /*
1646  * Private device independent drawing functions
1647  */
1648 
1649 static void
EraseClassItems(SciPlotWidget w,SciPlotDrawingEnum drawing)1650 EraseClassItems (SciPlotWidget w, SciPlotDrawingEnum drawing)
1651 {
1652   SciPlotItem *item;
1653   int i;
1654 
1655   if (!XtIsRealized((Widget) w))
1656     return;
1657   item = w->plot.drawlist;
1658   i = 0;
1659   while (i < w->plot.num_drawlist) {
1660     if (item->drawing_class == drawing) {
1661       item->kind.any.color = 0;
1662       item->kind.any.style = XtLINE_SOLID;
1663       ItemDraw(w, item);
1664     }
1665     i++;
1666     item++;
1667   }
1668 }
1669 
1670 static void
EraseAllItems(SciPlotWidget w)1671 EraseAllItems (SciPlotWidget w)
1672 {
1673   SciPlotItem *item;
1674   int i;
1675 
1676   item = w->plot.drawlist;
1677   i = 0;
1678   while (i < w->plot.num_drawlist) {
1679     if ((item->type > SciPlotStartTextTypes) &&
1680       (item->type < SciPlotEndTextTypes))
1681       XtFree(item->kind.text.text);
1682     i++;
1683     item++;
1684   }
1685   w->plot.num_drawlist = 0;
1686 }
1687 
1688 static void
EraseAll(SciPlotWidget w)1689 EraseAll (SciPlotWidget w)
1690 {
1691   EraseAllItems(w);
1692   if (XtIsRealized((Widget) w))
1693     XClearWindow(XtDisplay(w), XtWindow(w));
1694 }
1695 
1696 static SciPlotItem *
ItemGetNew(SciPlotWidget w)1697 ItemGetNew (SciPlotWidget w)
1698 {
1699   SciPlotItem *item;
1700 
1701   w->plot.num_drawlist++;
1702   if (w->plot.num_drawlist >= w->plot.alloc_drawlist) {
1703     w->plot.alloc_drawlist += NUMPLOTITEMEXTRA;
1704     w->plot.drawlist = (SciPlotItem *) XtRealloc((char *) w->plot.drawlist,
1705       w->plot.alloc_drawlist * sizeof(SciPlotItem));
1706     if (!w->plot.drawlist) {
1707       printf("Can't realloc memory for SciPlotItem list\n");
1708       exit(1);
1709     }
1710 #ifdef DEBUG_SCIPLOT
1711     printf("Alloced #%d for drawlist\n", w->plot.alloc_drawlist);
1712 #endif
1713   }
1714   item = w->plot.drawlist + (w->plot.num_drawlist - 1);
1715   item->type = SciPlotFALSE;
1716   item->drawing_class = w->plot.current_id;
1717   return item;
1718 }
1719 
1720 
1721 static void
LineSet(SciPlotWidget w,real x1,real y1,real x2,real y2,int color,int style)1722 LineSet(SciPlotWidget w, real x1, real y1, real x2, real y2,
1723   int color, int style)
1724 {
1725   SciPlotItem *item;
1726 
1727   item = ItemGetNew(w);
1728   item->kind.any.color = (short) color;
1729   item->kind.any.style = (short) style;
1730   item->kind.line.x1 = (real) x1;
1731   item->kind.line.y1 = (real) y1;
1732   item->kind.line.x2 = (real) x2;
1733   item->kind.line.y2 = (real) y2;
1734   item->type = SciPlotLine;
1735   ItemDraw(w, item);
1736 }
1737 
1738 static void
RectSet(SciPlotWidget w,real x1,real y1,real x2,real y2,int color,int style)1739 RectSet(SciPlotWidget w, real x1, real y1, real x2, real y2,
1740   int color, int style)
1741 {
1742   SciPlotItem *item;
1743   real x, y, width, height;
1744 
1745   if (x1 < x2)
1746     x = x1, width = (x2 - x1 + 1);
1747   else
1748     x = x2, width = (x1 - x2 + 1);
1749   if (y1 < y2)
1750     y = y1, height = (y2 - y1 + 1);
1751   else
1752     y = y2, height = (y1 - y2 + 1);
1753 
1754   item = ItemGetNew(w);
1755   item->kind.any.color = (short) color;
1756   item->kind.any.style = (short) style;
1757   item->kind.rect.x = (real) x;
1758   item->kind.rect.y = (real) y;
1759   item->kind.rect.w = (real) width;
1760   item->kind.rect.h = (real) height;
1761   item->type = SciPlotRect;
1762   ItemDraw(w, item);
1763 }
1764 
1765 static void
FilledRectSet(SciPlotWidget w,real x1,real y1,real x2,real y2,int color,int style)1766 FilledRectSet (SciPlotWidget w, real x1, real y1, real x2, real y2, int color, int style)
1767 {
1768   SciPlotItem *item;
1769   real x, y, width, height;
1770 
1771   if (x1 < x2)
1772     x = x1, width = (x2 - x1 + 1);
1773   else
1774     x = x2, width = (x1 - x2 + 1);
1775   if (y1 < y2)
1776     y = y1, height = (y2 - y1 + 1);
1777   else
1778     y = y2, height = (y1 - y2 + 1);
1779 
1780   item = ItemGetNew(w);
1781   item->kind.any.color = (short) color;
1782   item->kind.any.style = (short) style;
1783   item->kind.rect.x = (real) x;
1784   item->kind.rect.y = (real) y;
1785   item->kind.rect.w = (real) width;
1786   item->kind.rect.h = (real) height;
1787   item->type = SciPlotFRect;
1788   ItemDraw(w, item);
1789 }
1790 
1791 static void
TriSet(SciPlotWidget w,real x1,real y1,real x2,real y2,real x3,real y3,int color,int style)1792 TriSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, int color, int style)
1793 {
1794   SciPlotItem *item;
1795 
1796   item = ItemGetNew(w);
1797   item->kind.any.color = (short) color;
1798   item->kind.any.style = (short) style;
1799   item->kind.poly.count = 3;
1800   item->kind.poly.x[0] = (real) x1;
1801   item->kind.poly.y[0] = (real) y1;
1802   item->kind.poly.x[1] = (real) x2;
1803   item->kind.poly.y[1] = (real) y2;
1804   item->kind.poly.x[2] = (real) x3;
1805   item->kind.poly.y[2] = (real) y3;
1806   item->type = SciPlotPoly;
1807   ItemDraw(w, item);
1808 }
1809 
1810 static void
FilledTriSet(SciPlotWidget w,real x1,real y1,real x2,real y2,real x3,real y3,int color,int style)1811 FilledTriSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, int color, int style)
1812 {
1813   SciPlotItem *item;
1814 
1815   item = ItemGetNew(w);
1816   item->kind.any.color = (short) color;
1817   item->kind.any.style = (short) style;
1818   item->kind.poly.count = 3;
1819   item->kind.poly.x[0] = (real) x1;
1820   item->kind.poly.y[0] = (real) y1;
1821   item->kind.poly.x[1] = (real) x2;
1822   item->kind.poly.y[1] = (real) y2;
1823   item->kind.poly.x[2] = (real) x3;
1824   item->kind.poly.y[2] = (real) y3;
1825   item->type = SciPlotFPoly;
1826   ItemDraw(w, item);
1827 }
1828 
1829 static void
QuadSet(SciPlotWidget w,real x1,real y1,real x2,real y2,real x3,real y3,real x4,real y4,int color,int style)1830 QuadSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, int color, int style)
1831 {
1832   SciPlotItem *item;
1833 
1834   item = ItemGetNew(w);
1835   item->kind.any.color = (short) color;
1836   item->kind.any.style = (short) style;
1837   item->kind.poly.count = 4;
1838   item->kind.poly.x[0] = (real) x1;
1839   item->kind.poly.y[0] = (real) y1;
1840   item->kind.poly.x[1] = (real) x2;
1841   item->kind.poly.y[1] = (real) y2;
1842   item->kind.poly.x[2] = (real) x3;
1843   item->kind.poly.y[2] = (real) y3;
1844   item->kind.poly.x[3] = (real) x4;
1845   item->kind.poly.y[3] = (real) y4;
1846   item->type = SciPlotPoly;
1847   ItemDraw(w, item);
1848 }
1849 
1850 static void
FilledQuadSet(SciPlotWidget w,real x1,real y1,real x2,real y2,real x3,real y3,real x4,real y4,int color,int style)1851 FilledQuadSet (SciPlotWidget w, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4, int color, int style)
1852 {
1853   SciPlotItem *item;
1854 
1855   item = ItemGetNew(w);
1856   item->kind.any.color = (short) color;
1857   item->kind.any.style = (short) style;
1858   item->kind.poly.count = 4;
1859   item->kind.poly.x[0] = (real) x1;
1860   item->kind.poly.y[0] = (real) y1;
1861   item->kind.poly.x[1] = (real) x2;
1862   item->kind.poly.y[1] = (real) y2;
1863   item->kind.poly.x[2] = (real) x3;
1864   item->kind.poly.y[2] = (real) y3;
1865   item->kind.poly.x[3] = (real) x4;
1866   item->kind.poly.y[3] = (real) y4;
1867   item->type = SciPlotFPoly;
1868   ItemDraw(w, item);
1869 }
1870 
1871 static void
CircleSet(SciPlotWidget w,real x,real y,real r,int color,int style)1872 CircleSet (SciPlotWidget w, real x, real y, real r, int color, int style)
1873 {
1874   SciPlotItem *item;
1875 
1876   item = ItemGetNew(w);
1877   item->kind.any.color = (short) color;
1878   item->kind.any.style = (short) style;
1879   item->kind.circ.x = (real) x;
1880   item->kind.circ.y = (real) y;
1881   item->kind.circ.r = (real) r;
1882   item->type = SciPlotCircle;
1883   ItemDraw(w, item);
1884 }
1885 
1886 static void
FilledCircleSet(SciPlotWidget w,real x,real y,real r,int color,int style)1887 FilledCircleSet (SciPlotWidget w, real x, real y, real r, int color, int style)
1888 {
1889   SciPlotItem *item;
1890 
1891   item = ItemGetNew(w);
1892   item->kind.any.color = (short) color;
1893   item->kind.any.style = (short) style;
1894   item->kind.circ.x = (real) x;
1895   item->kind.circ.y = (real) y;
1896   item->kind.circ.r = (real) r;
1897   item->type = SciPlotFCircle;
1898   ItemDraw(w, item);
1899 }
1900 
1901 static void
TextSet(SciPlotWidget w,real x,real y,char * text,int color,int font)1902 TextSet (SciPlotWidget w, real x, real y, char *text, int color, int font)
1903 {
1904   SciPlotItem *item;
1905 
1906   item = ItemGetNew(w);
1907   item->kind.any.color = (short) color;
1908   item->kind.any.style = 0;
1909   item->kind.text.x = (real) x;
1910   item->kind.text.y = (real) y;
1911   item->kind.text.length = strlen(text);
1912   item->kind.text.text = XtMalloc((int) item->kind.text.length + 1);
1913   item->kind.text.font = font;
1914   strcpy(item->kind.text.text, text);
1915   item->type = SciPlotText;
1916   ItemDraw(w, item);
1917 #ifdef DEBUG_SCIPLOT_TEXT
1918   if (1) {
1919     real x1, y1;
1920 
1921     y -= FontnumAscent(w, font);
1922     y1 = y + FontnumHeight(w, font) - 1.0;
1923     x1 = x + FontnumTextWidth(w, font, text) - 1.0;
1924     RectSet(w, x, y, x1, y1, color, XtLINE_SOLID);
1925   }
1926 #endif
1927 }
1928 
1929 static void
TextCenter(SciPlotWidget w,real x,real y,char * text,int color,int font)1930 TextCenter (SciPlotWidget w, real x, real y, char *text, int color, int font)
1931 {
1932   x -= FontnumTextWidth(w, font, text) / 2.0;
1933   y += FontnumHeight(w, font) / 2.0 - FontnumDescent(w, font);
1934   TextSet(w, x, y, text, color, font);
1935 }
1936 
1937 static void
VTextSet(SciPlotWidget w,real x,real y,char * text,int color,int font)1938 VTextSet (SciPlotWidget w, real x, real y, char *text, int color, int font)
1939 {
1940   SciPlotItem *item;
1941 
1942   item = ItemGetNew(w);
1943   item->kind.any.color = (short) color;
1944   item->kind.any.style = 0;
1945   item->kind.text.x = (real) x;
1946   item->kind.text.y = (real) y;
1947   item->kind.text.length = strlen(text);
1948   item->kind.text.text = XtMalloc((int) item->kind.text.length + 1);
1949   item->kind.text.font = font;
1950   strcpy(item->kind.text.text, text);
1951   item->type = SciPlotVText;
1952   ItemDraw(w, item);
1953 #ifdef DEBUG_SCIPLOT_TEXT
1954   if (1) {
1955     real x1, y1;
1956 
1957     x += FontnumDescent(w, font);
1958     x1 = x - FontnumHeight(w, font) - 1.0;
1959     y1 = y - FontnumTextWidth(w, font, text) - 1.0;
1960     RectSet(w, x, y, x1, y1, color, XtLINE_SOLID);
1961   }
1962 #endif
1963 }
1964 
1965 static void
VTextCenter(SciPlotWidget w,real x,real y,char * text,int color,int font)1966 VTextCenter (SciPlotWidget w, real x, real y, char *text, int color, int font)
1967 {
1968   x += FontnumHeight(w, font) / 2.0 - FontnumDescent(w, font);
1969   y += FontnumTextWidth(w, font, text) / 2.0;
1970   VTextSet(w, x, y, text, color, font);
1971 }
1972 
1973 static void
ClipSet(SciPlotWidget w)1974 ClipSet (SciPlotWidget w)
1975 {
1976   SciPlotItem *item;
1977 
1978   if (w->plot.ChartType == XtCARTESIAN) {
1979     item = ItemGetNew(w);
1980     item->kind.any.style = XtLINE_SOLID;
1981     item->kind.any.color = 1;
1982     item->kind.line.x1 = w->plot.x.Origin;
1983     item->kind.line.x2 = w->plot.x.Size;
1984     item->kind.line.y1 = w->plot.y.Origin;
1985     item->kind.line.y2 = w->plot.y.Size;
1986 #ifdef DEBUG_SCIPLOT
1987     printf("clipping region: x=%f y=%f w=%f h=%f\n",
1988       item->kind.line.x1,
1989       item->kind.line.y1,
1990       item->kind.line.x2,
1991       item->kind.line.y2
1992       );
1993 #endif
1994     item->type = SciPlotClipRegion;
1995     ItemDraw(w, item);
1996   }
1997 }
1998 
1999 static void
ClipClear(SciPlotWidget w)2000 ClipClear (SciPlotWidget w)
2001 {
2002   SciPlotItem *item;
2003 
2004   if (w->plot.ChartType == XtCARTESIAN) {
2005     item = ItemGetNew(w);
2006     item->kind.any.style = XtLINE_SOLID;
2007     item->kind.any.color = 1;
2008     item->type = SciPlotClipClear;
2009     ItemDraw(w, item);
2010   }
2011 }
2012 
2013 
2014 /*
2015  * Private data point to screen location converters
2016  */
2017 
2018 static real
PlotX(SciPlotWidget w,real xin)2019 PlotX (SciPlotWidget w, real xin)
2020 {
2021   real xout;
2022 
2023   if (w->plot.XLog)
2024     xout = w->plot.x.Origin +
2025       ((log10(xin) - log10(w->plot.x.DrawOrigin)) *
2026       (w->plot.x.Size / w->plot.x.DrawSize));
2027   else
2028     xout = w->plot.x.Origin +
2029       ((xin - w->plot.x.DrawOrigin) *
2030       (w->plot.x.Size / w->plot.x.DrawSize));
2031   return xout;
2032 }
2033 
2034 static real
PlotY(SciPlotWidget w,real yin)2035 PlotY (SciPlotWidget w, real yin)
2036 {
2037   real yout;
2038 
2039   if (w->plot.YLog)
2040     yout = w->plot.y.Origin + w->plot.y.Size -
2041       ((log10(yin) - log10(w->plot.y.DrawOrigin)) *
2042       (w->plot.y.Size / w->plot.y.DrawSize));
2043   else
2044     yout = w->plot.y.Origin + w->plot.y.Size -
2045       ((yin - w->plot.y.DrawOrigin) *
2046       (w->plot.y.Size / w->plot.y.DrawSize));
2047   return yout;
2048 }
2049 
2050 static void
PlotRTRadians(SciPlotWidget w,real r,real t,real * xout,real * yout)2051 PlotRTRadians (SciPlotWidget w, real r, real t, real *xout, real *yout)
2052 {
2053   *xout = w->plot.x.Center + (r * (real) cos(t) /
2054     w->plot.PolarScale * w->plot.x.Size / 2.0);
2055   *yout = w->plot.y.Center + (-r * (real) sin(t) /
2056     w->plot.PolarScale * w->plot.x.Size / 2.0);
2057 }
2058 
2059 static void
PlotRTDegrees(SciPlotWidget w,real r,real t,real * xout,real * yout)2060 PlotRTDegrees (SciPlotWidget w, real r, real t, real *xout, real *yout)
2061 {
2062   t *= DEG2RAD;
2063   PlotRTRadians(w, r, t, xout, yout);
2064 }
2065 
2066 static void
PlotRT(SciPlotWidget w,real r,real t,real * xout,real * yout)2067 PlotRT (SciPlotWidget w, real r, real t, real *xout, real *yout)
2068 {
2069   if (w->plot.Degrees)
2070     t *= DEG2RAD;
2071   PlotRTRadians(w, r, t, xout, yout);
2072 }
2073 
2074 
2075 /*
2076  * Private calculation utilities for axes
2077  */
2078 
2079 #define NUMBER_MINOR	8
2080 #define MAX_MAJOR	8
2081 static float CAdeltas[8] =
2082 {0.1, 0.2, 0.25, 0.5, 1.0, 2.0, 2.5, 5.0};
2083 static int CAdecimals[8] =
2084 {0, 0, 1, 0, 0, 0, 1, 0};
2085 static int CAminors[8] =
2086 {4, 4, 4, 5, 4, 4, 4, 5};
2087 
2088 static void
ComputeAxis(SciPlotAxis * axis,real min,real max,Boolean log)2089 ComputeAxis (SciPlotAxis *axis, real min, real max, Boolean log)
2090 {
2091   real range, rnorm, delta, calcmin, calcmax;
2092   int nexp, majornum, minornum, majordecimals, decimals, i;
2093 
2094   range = max - min;
2095   if (log) {
2096     if (range==0.0) {
2097       calcmin = powi(10.0, (int) floor(log10(min)));
2098       calcmax = 10.0*calcmin;
2099     }
2100     else {
2101       calcmin = powi(10.0, (int) floor(log10(min)));
2102       calcmax = powi(10.0, (int) ceil(log10(max)));
2103     }
2104 
2105 /*     printf("calcmin=%e min=%e   calcmax=%e max=%e\n",calcmin,min, */
2106 /*       calcmax,max); */
2107 
2108     delta = 10.0;
2109 
2110     axis->DrawOrigin = calcmin;
2111     axis->DrawMax = calcmax;
2112     axis->DrawSize = log10(calcmax) - log10(calcmin);
2113     axis->MajorInc = delta;
2114     axis->MajorNum = (int) (log10(calcmax) - log10(calcmin)) + 1;
2115     axis->MinorNum = 10;
2116     axis->Precision = -(int) (log10(calcmin) * 1.0001);
2117 #ifdef DEBUG_SCIPLOT
2118     printf("calcmin=%e log=%e (int)log=%d  Precision=%d\n",
2119       calcmin, log10(calcmin), (int) (log10(calcmin) * 1.0001), axis->Precision);
2120 #endif
2121     if (axis->Precision < 0)
2122       axis->Precision = 0;
2123   }
2124   else {
2125     if (range==0.0) nexp=0;
2126     else nexp = (int) floor(log10(range));
2127     rnorm = range / powi(10.0, nexp);
2128     for (i = 0; i < NUMBER_MINOR; i++) {
2129       delta = CAdeltas[i];
2130       minornum = CAminors[i];
2131       majornum = (int) ((rnorm + 0.9999 * delta) / delta);
2132       majordecimals = CAdecimals[i];
2133       if (majornum <= MAX_MAJOR)
2134 	break;
2135     }
2136     delta *= powi(10.0, nexp);
2137 #ifdef DEBUG_SCIPLOT
2138     printf("nexp=%d range=%f rnorm=%f delta=%f\n", nexp, range, rnorm, delta);
2139 #endif
2140 
2141     if (min < 0.0)
2142       calcmin = ((float) ((int) ((min - .9999 * delta) / delta))) * delta;
2143     else if ((min > 0.0) && (min < 1.0))
2144       calcmin = ((float) ((int) ((1.0001 * min) / delta))) * delta;
2145     else if (min >= 1.0)
2146       calcmin = ((float) ((int) ((.9999 * min) / delta))) * delta;
2147     else
2148       calcmin = min;
2149     if (max < 0.0)
2150       calcmax = ((float) ((int) ((.9999 * max) / delta))) * delta;
2151     else if (max > 0.0)
2152       calcmax = ((float) ((int) ((max + .9999 * delta) / delta))) * delta;
2153     else
2154       calcmax = max;
2155 
2156     axis->DrawOrigin = calcmin;
2157     axis->DrawMax = calcmax;
2158     axis->DrawSize = calcmax - calcmin;
2159     axis->MajorInc = delta;
2160     axis->MajorNum = majornum;
2161     axis->MinorNum = minornum;
2162 
2163     delta = log10(axis->MajorInc);
2164     if (delta > 0.0)
2165       decimals = -(int) floor(delta) + majordecimals;
2166     else
2167       decimals = (int) ceil(-delta) + majordecimals;
2168     if (decimals < 0)
2169       decimals = 0;
2170 #ifdef DEBUG_SCIPLOT
2171     printf("delta=%f majordecimals=%d decimals=%d\n",
2172       delta, majordecimals, decimals);
2173 #endif
2174     axis->Precision = decimals;
2175   }
2176 
2177 #ifdef DEBUG_SCIPLOT
2178   printf("Tics: min=%f max=%f size=%f  major inc=%f #major=%d #minor=%d decimals=%d\n",
2179     axis->DrawOrigin, axis->DrawMax, axis->DrawSize,
2180     axis->MajorInc, axis->MajorNum, axis->MinorNum, axis->Precision);
2181 #endif
2182 }
2183 
2184 static void
ComputeDrawingRange(SciPlotWidget w)2185 ComputeDrawingRange (SciPlotWidget w)
2186 {
2187   if (w->plot.ChartType == XtCARTESIAN) {
2188     ComputeAxis(&w->plot.x, w->plot.Min.x, w->plot.Max.x,
2189       w->plot.XLog);
2190     ComputeAxis(&w->plot.y, w->plot.Min.y, w->plot.Max.y,
2191       w->plot.YLog);
2192   }
2193   else {
2194     ComputeAxis(&w->plot.x, (real) 0.0, w->plot.Max.x,
2195       (Boolean) FALSE);
2196     w->plot.PolarScale = w->plot.x.DrawMax;
2197   }
2198 }
2199 
2200 static Boolean
CheckMinMax(SciPlotWidget w)2201 CheckMinMax (SciPlotWidget w)
2202 {
2203   register int i, j;
2204   register SciPlotList *p;
2205   register real val;
2206 
2207   if (w->plot.ChartType == XtCARTESIAN) {
2208     for (i = 0; i < w->plot.num_plotlist; i++) {
2209       p = w->plot.plotlist + i;
2210       if (p->draw) {
2211 	for (j = 0; j < p->number; j++) {
2212 
2213             /* Don't count the "break in line segment" flag for Min/Max */
2214           if (p->data[j].x > SCIPLOT_SKIP_VAL &&
2215               p->data[j].y > SCIPLOT_SKIP_VAL) {
2216 
2217             val = p->data[j].x;
2218             if (val > w->plot.x.DrawMax || val < w->plot.x.DrawOrigin)
2219               return True;
2220             val = p->data[j].y;
2221             if (val > w->plot.y.DrawMax || val < w->plot.y.DrawOrigin)
2222               return True;
2223           }
2224         }
2225       }
2226     }
2227   }
2228   else {
2229     for (i = 0; i < w->plot.num_plotlist; i++) {
2230       p = w->plot.plotlist + i;
2231       if (p->draw) {
2232 	for (j = 0; j < p->number; j++) {
2233 	  val = p->data[j].x;
2234 	  if (val > w->plot.Max.x || val < w->plot.Min.x)
2235 	    return True;
2236 	}
2237       }
2238     }
2239   }
2240   return False;
2241 }
2242 
2243 static void
ComputeMinMax(SciPlotWidget w)2244 ComputeMinMax (SciPlotWidget w)
2245 {
2246   register int i, j;
2247   register SciPlotList *p;
2248   register real val;
2249   Boolean firstx, firsty;
2250 
2251   w->plot.Min.x = w->plot.Min.y = w->plot.Max.x = w->plot.Max.y = 1.0;
2252   firstx = True;
2253   firsty = True;
2254 
2255   for (i = 0; i < w->plot.num_plotlist; i++) {
2256     p = w->plot.plotlist + i;
2257     if (p->draw) {
2258       for (j = 0; j < p->number; j++) {
2259 
2260           /* Don't count the "break in line segment" flag for Min/Max */
2261         if (p->data[j].x > SCIPLOT_SKIP_VAL &&
2262             p->data[j].y > SCIPLOT_SKIP_VAL) {
2263 
2264           val = p->data[j].x;
2265           if (!w->plot.XLog || (w->plot.XLog && (val > 0.0))) {
2266             if (firstx) {
2267               w->plot.Min.x = w->plot.Max.x = val;
2268               firstx = False;
2269             }
2270             else {
2271               if (val > w->plot.Max.x)
2272                 w->plot.Max.x = val;
2273               else if (val < w->plot.Min.x)
2274                 w->plot.Min.x = val;
2275             }
2276           }
2277 
2278           val = p->data[j].y;
2279           if (!w->plot.YLog || (w->plot.YLog && (val > 0.0))) {
2280             if (firsty) {
2281               w->plot.Min.y = w->plot.Max.y = val;
2282               firsty = False;
2283             }
2284             else {
2285               if (val > w->plot.Max.y)
2286                 w->plot.Max.y = val;
2287               else if (val < w->plot.Min.y)
2288                 w->plot.Min.y = val;
2289             }
2290           }
2291         }
2292 
2293       }
2294     }
2295   }
2296 
2297     /* fix defaults if there is only one point. */
2298   if (firstx) {
2299     if (w->plot.XLog) {
2300       w->plot.Min.x = 1.0;
2301       w->plot.Max.x = 10.0;
2302     }
2303     else {
2304       w->plot.Min.x = 0.0;
2305       w->plot.Max.x = 10.0;
2306     }
2307   }
2308   if (firsty) {
2309     if (w->plot.YLog) {
2310       w->plot.Min.y = 1.0;
2311       w->plot.Max.y = 10.0;
2312     }
2313     else {
2314       w->plot.Min.y = 0.0;
2315       w->plot.Max.y = 10.0;
2316     }
2317   }
2318   if (w->plot.ChartType == XtCARTESIAN) {
2319     if (!w->plot.XLog) {
2320       if (!w->plot.XAutoScale) {
2321 	w->plot.Min.x = w->plot.UserMin.x;
2322 	w->plot.Max.x = w->plot.UserMax.x;
2323       }
2324       else if (w->plot.XOrigin) {
2325 	if (w->plot.Min.x > 0.0)
2326 	  w->plot.Min.x = 0.0;
2327 	if (w->plot.Max.x < 0.0)
2328 	  w->plot.Max.x = 0.0;
2329       }
2330       if (fabs(w->plot.Min.x - w->plot.Max.x) < 1.e-10) {
2331 	w->plot.Min.x -= .5;
2332 	w->plot.Max.x += .5;
2333       }
2334     }
2335     if (!w->plot.YLog) {
2336       if (!w->plot.YAutoScale) {
2337 	w->plot.Min.y = w->plot.UserMin.y;
2338 	w->plot.Max.y = w->plot.UserMax.y;
2339       }
2340       else if (w->plot.YOrigin) {
2341 	if (w->plot.Min.y > 0.0)
2342 	  w->plot.Min.y = 0.0;
2343 	if (w->plot.Max.y < 0.0)
2344 	  w->plot.Max.y = 0.0;
2345       }
2346       if (fabs(w->plot.Min.y - w->plot.Max.y) < 1.e-10) {
2347 	w->plot.Min.y -= .5;
2348 	w->plot.Max.y += .5;
2349       }
2350     }
2351   }
2352   else {
2353     if (fabs(w->plot.Min.x) > fabs(w->plot.Max.x))
2354       w->plot.Max.x = fabs(w->plot.Min.x);
2355   }
2356 
2357 #ifdef DEBUG_SCIPLOT
2358   printf("Min: (%f,%f)\tMax: (%f,%f)\n",
2359     w->plot.Min.x, w->plot.Min.y,
2360     w->plot.Max.x, w->plot.Max.y);
2361 #endif
2362 }
2363 
2364 static void
ComputeLegendDimensions(SciPlotWidget w)2365 ComputeLegendDimensions (SciPlotWidget w)
2366 {
2367   real current, xmax, ymax;
2368   int i;
2369   SciPlotList *p;
2370 
2371   if (w->plot.ShowLegend) {
2372     xmax = 0.0;
2373     ymax = 2.0 * (real) w->plot.LegendMargin;
2374 
2375     for (i = 0; i < w->plot.num_plotlist; i++) {
2376       p = w->plot.plotlist + i;
2377       if (p->draw) {
2378 	current = (real) w->plot.Margin +
2379 	  (real) w->plot.LegendMargin * 3.0 +
2380 	  (real) w->plot.LegendLineSize +
2381 	  FontnumTextWidth(w, w->plot.axisFont, p->legend);
2382 	if (current > xmax)
2383 	  xmax = current;
2384 	ymax += FontnumHeight(w, w->plot.axisFont);
2385       }
2386     }
2387 
2388     w->plot.x.LegendSize = xmax;
2389     w->plot.x.LegendPos = (real) w->plot.Margin;
2390     w->plot.y.LegendSize = ymax;
2391     w->plot.y.LegendPos = 0.0;
2392   }
2393   else {
2394     w->plot.x.LegendSize =
2395       w->plot.x.LegendPos =
2396       w->plot.y.LegendSize =
2397       w->plot.y.LegendPos = 0.0;
2398   }
2399 }
2400 
2401 static void
ComputeDimensions(SciPlotWidget w)2402 ComputeDimensions (SciPlotWidget w)
2403 {
2404   real x, y, width, height, axisnumbersize, axisXlabelsize, axisYlabelsize;
2405 
2406 /* x,y is the origin of the upper left corner of the drawing area inside
2407  * the widget.  Doesn't necessarily have to be (Margin,Margin) as it is now.
2408  */
2409   x = (real) w->plot.Margin;
2410   y = (real) w->plot.Margin;
2411 
2412 /* width = (real)w->core.width - (real)w->plot.Margin - x -
2413  * **           legendwidth - AxisFontHeight
2414  */
2415   width = (real) w->core.width - (real) w->plot.Margin - x -
2416     w->plot.x.LegendSize;
2417 
2418 /* height = (real)w->core.height - (real)w->plot.Margin - y
2419  *           - Height of axis numbers (including margin)
2420  *           - Height of axis label (including margin)
2421  *           - Height of Title (including margin)
2422  */
2423   height = (real) w->core.height - (real) w->plot.Margin - y;
2424 
2425   w->plot.x.Origin = x;
2426   w->plot.y.Origin = y;
2427 
2428 /* Adjust the size depending upon what sorts of text are visible. */
2429   if (w->plot.ShowTitle)
2430     height -= (real) w->plot.TitleMargin +
2431       FontnumHeight(w, w->plot.titleFont);
2432 
2433   if (w->plot.ChartType == XtCARTESIAN) {
2434     axisnumbersize = (real) w->plot.Margin +
2435       FontnumHeight(w, w->plot.axisFont);
2436     if (w->plot.XAxisNumbers) {
2437       height -= axisnumbersize;
2438     }
2439     if (w->plot.YAxisNumbers) {
2440       width -= axisnumbersize;
2441       w->plot.x.Origin += axisnumbersize;
2442     }
2443 
2444     if (w->plot.ShowXLabel) {
2445       axisXlabelsize = (real) w->plot.Margin +
2446 	FontnumHeight(w, w->plot.labelFont);
2447       height -= axisXlabelsize;
2448     }
2449     if (w->plot.ShowYLabel) {
2450       axisYlabelsize = (real) w->plot.Margin +
2451 	FontnumHeight(w, w->plot.labelFont);
2452       width -= axisYlabelsize;
2453       w->plot.x.Origin += axisYlabelsize;
2454     }
2455   }
2456 
2457   w->plot.x.Size = width;
2458   w->plot.y.Size = height;
2459 
2460 /* Adjust parameters for polar plot */
2461   if (w->plot.ChartType == XtPOLAR) {
2462     if (height < width)
2463       w->plot.x.Size = height;
2464   }
2465   w->plot.x.Center = w->plot.x.Origin + (width / 2.0);
2466   w->plot.y.Center = w->plot.y.Origin + (height / 2.0);
2467 
2468 }
2469 
2470 static void
AdjustDimensionsCartesian(SciPlotWidget w)2471 AdjustDimensionsCartesian (SciPlotWidget w)
2472 {
2473   real xextra, yextra, val, xhorz;
2474   real x, y, width, height, axisnumbersize, axisXlabelsize, axisYlabelsize;
2475   char numberformat[16], label[16];
2476   int precision;
2477 
2478 /* Compute xextra and yextra, which are the extra distances that the text
2479  * labels on the axes stick outside of the graph.
2480  */
2481   xextra = yextra = 0.0;
2482   if (w->plot.XAxisNumbers) {
2483     precision = w->plot.x.Precision;
2484     if (w->plot.XLog) {
2485       val = w->plot.x.DrawMax;
2486       precision -= w->plot.x.MajorNum;
2487       if (precision < 0)
2488         precision = 0;
2489     }
2490     else
2491       val = w->plot.x.DrawOrigin + floor(w->plot.x.DrawSize /
2492         w->plot.x.MajorInc) * w->plot.x.MajorInc;
2493     x = PlotX(w, val);
2494     sprintf(numberformat, "%%.%df", precision);
2495     sprintf(label, numberformat, val);
2496     x += FontnumTextWidth(w, w->plot.axisFont, label);
2497     if ((int) x > w->core.width) {
2498       xextra = ceil(x - w->core.width + w->plot.Margin);
2499       if (xextra < 0.0)
2500         xextra = 0.0;
2501     }
2502   }
2503 
2504   yextra=xhorz=0.0;
2505   if (w->plot.YAxisNumbers) {
2506     precision = w->plot.y.Precision;
2507     if (w->plot.YLog) {
2508       int p1,p2;
2509 
2510       p1=precision;
2511       val = w->plot.y.DrawOrigin;
2512       if (p1 > 0)
2513         p1--;
2514 
2515       val = w->plot.y.DrawMax;
2516       p2 = precision - w->plot.y.MajorNum;
2517       if (p2 < 0)
2518         p2 = 0;
2519 
2520       if (p1>p2) precision=p1;
2521       else precision=p2;
2522     }
2523     else
2524       val = w->plot.y.DrawOrigin + floor(w->plot.y.DrawSize /
2525         w->plot.y.MajorInc * 1.0001) * w->plot.y.MajorInc;
2526     y = PlotY(w, val);
2527     sprintf(numberformat, "%%.%df", precision);
2528     sprintf(label, numberformat, val);
2529 #ifdef DEBUG_SCIPLOT
2530     printf("ylabel=%s\n", label);
2531 #endif
2532     if (w->plot.YNumHorz) {
2533       yextra=FontnumHeight(w, w->plot.axisFont)/2.0;
2534       xhorz=FontnumTextWidth(w, w->plot.axisFont, label) + (real)w->plot.Margin;
2535     }
2536     else {
2537       y -= FontnumTextWidth(w, w->plot.axisFont, label);
2538       if ((int) y <= 0) {
2539         yextra = ceil(w->plot.Margin - y);
2540         if (yextra < 0.0)
2541           yextra = 0.0;
2542       }
2543     }
2544   }
2545 
2546 /* x,y is the origin of the upper left corner of the drawing area inside
2547  * the widget.  Doesn't necessarily have to be (Margin,Margin) as it is now.
2548  */
2549   x = (real) w->plot.Margin + xhorz;
2550   y = (real) w->plot.Margin + yextra;
2551 
2552 /* width = (real)w->core.width - (real)w->plot.Margin - x -
2553  *          legendwidth - AxisFontHeight
2554  */
2555   width = (real) w->core.width - (real) w->plot.Margin - x - xextra;
2556 
2557 
2558 /* height = (real)w->core.height - (real)w->plot.Margin - y
2559  *           - Height of axis numbers (including margin)
2560  *           - Height of axis label (including margin)
2561  *           - Height of Title (including margin)
2562  */
2563   height = (real) w->core.height - (real) w->plot.Margin - y;
2564 
2565   w->plot.x.Origin = x;
2566   w->plot.y.Origin = y;
2567 
2568 /* Adjust the size depending upon what sorts of text are visible. */
2569   if (w->plot.ShowTitle)
2570     height -= (real) w->plot.TitleMargin +
2571       FontnumHeight(w, w->plot.titleFont);
2572 
2573   axisXlabelsize = 0.0;
2574   axisYlabelsize = 0.0;
2575   axisnumbersize = (real) w->plot.Margin +
2576     FontnumHeight(w, w->plot.axisFont);
2577   if (w->plot.XAxisNumbers) {
2578     height -= axisnumbersize;
2579   }
2580   if (w->plot.YAxisNumbers && !w->plot.YNumHorz) {
2581     width -= axisnumbersize;
2582     w->plot.x.Origin += axisnumbersize;
2583   }
2584 
2585   if (w->plot.ShowXLabel) {
2586     axisXlabelsize = (real) w->plot.Margin +
2587       FontnumHeight(w, w->plot.labelFont);
2588     height -= axisXlabelsize;
2589   }
2590   if (w->plot.ShowYLabel) {
2591     axisYlabelsize = (real) w->plot.Margin +
2592       FontnumHeight(w, w->plot.labelFont);
2593     width -= axisYlabelsize;
2594     w->plot.x.Origin += axisYlabelsize;
2595   }
2596 
2597 /* Move legend position to the right of the plot */
2598   if (w->plot.LegendThroughPlot) {
2599     w->plot.x.LegendPos += w->plot.x.Origin + width - w->plot.x.LegendSize;
2600     w->plot.y.LegendPos += w->plot.y.Origin;
2601   }
2602   else {
2603     width -= w->plot.x.LegendSize;
2604     w->plot.x.LegendPos += w->plot.x.Origin + width;
2605     w->plot.y.LegendPos += w->plot.y.Origin;
2606   }
2607 
2608   w->plot.x.Size = width;
2609   w->plot.y.Size = height;
2610 
2611   w->plot.y.AxisPos = w->plot.y.Origin + w->plot.y.Size +
2612     (real) w->plot.Margin +
2613     FontnumAscent(w, w->plot.axisFont);
2614   if (w->plot.YNumHorz) {
2615     w->plot.x.AxisPos = w->plot.x.Origin - (real) w->plot.Margin;
2616   }
2617   else {
2618     w->plot.x.AxisPos = w->plot.x.Origin -
2619       (real) w->plot.Margin -
2620       FontnumDescent(w, w->plot.axisFont);
2621   }
2622 
2623   w->plot.y.LabelPos = w->plot.y.Origin + w->plot.y.Size +
2624     (real) w->plot.Margin + (FontnumHeight(w, w->plot.labelFont) / 2.0);
2625   if (w->plot.XAxisNumbers)
2626     w->plot.y.LabelPos += axisnumbersize;
2627   if (w->plot.YAxisNumbers) {
2628     if (w->plot.YNumHorz) {
2629       w->plot.x.LabelPos = w->plot.x.Origin -
2630         xhorz - (real) w->plot.Margin -
2631         (FontnumHeight(w, w->plot.labelFont) / 2.0);
2632     }
2633     else {
2634       w->plot.x.LabelPos = w->plot.x.Origin -
2635         axisnumbersize - (real) w->plot.Margin -
2636         (FontnumHeight(w, w->plot.labelFont) / 2.0);
2637     }
2638   }
2639   else {
2640     w->plot.x.LabelPos = w->plot.x.Origin - (real) w->plot.Margin -
2641         (FontnumHeight(w, w->plot.labelFont) / 2.0);
2642   }
2643 
2644   w->plot.y.TitlePos = (real) w->core.height - (real) w->plot.Margin;
2645   w->plot.x.TitlePos = (real) w->plot.Margin;
2646 
2647 #ifdef DEBUG_SCIPLOT
2648   printf("y.Origin:		%f\n", w->plot.y.Origin);
2649   printf("y.Size:			%f\n", w->plot.y.Size);
2650   printf("axisnumbersize:		%f\n", axisnumbersize);
2651   printf("y.axisLabelSize:	%f\n", axisYlabelsize);
2652   printf("y.TitleSize:		%f\n",
2653     (real) w->plot.TitleMargin + FontnumHeight(w, w->plot.titleFont));
2654   printf("y.Margin:		%f\n", (real) w->plot.Margin);
2655   printf("total-------------------%f\n", w->plot.y.Origin + w->plot.y.Size +
2656     axisnumbersize + axisYlabelsize + (real) w->plot.Margin +
2657     (real) w->plot.TitleMargin + FontnumHeight(w, w->plot.titleFont));
2658   printf("total should be---------%f\n", (real) w->core.height);
2659 #endif
2660 }
2661 
2662 static void
AdjustDimensionsPolar(SciPlotWidget w)2663 AdjustDimensionsPolar (SciPlotWidget w)
2664 {
2665   real x, y, xextra, yextra, val;
2666   real width, height, size;
2667   char numberformat[16], label[16];
2668 
2669 /* Compute xextra and yextra, which are the extra distances that the text
2670  * labels on the axes stick outside of the graph.
2671  */
2672   xextra = yextra = 0.0;
2673   val = w->plot.PolarScale;
2674   PlotRTDegrees(w, val, 0.0, &x, &y);
2675   sprintf(numberformat, "%%.%df", w->plot.x.Precision);
2676   sprintf(label, numberformat, val);
2677   x += FontnumTextWidth(w, w->plot.axisFont, label);
2678   if ((int) x > w->core.width) {
2679     xextra = x - w->core.width + w->plot.Margin;
2680     if (xextra < 0.0)
2681       xextra = 0.0;
2682   }
2683   yextra = 0.0;
2684 
2685 
2686 /* x,y is the origin of the upper left corner of the drawing area inside
2687  * the widget.  Doesn't necessarily have to be (Margin,Margin) as it is now.
2688  */
2689   w->plot.x.Origin = (real) w->plot.Margin;
2690   w->plot.y.Origin = (real) w->plot.Margin;
2691 
2692 /* width = (real)w->core.width - (real)w->plot.Margin - x -
2693  *          legendwidth - AxisFontHeight
2694  */
2695   width = (real) w->core.width - (real) w->plot.Margin - w->plot.x.Origin - xextra;
2696 
2697 /* height = (real)w->core.height - (real)w->plot.Margin - y
2698  *           - Height of axis numbers (including margin)
2699  *           - Height of axis label (including margin)
2700  *           - Height of Title (including margin)
2701  */
2702   height = (real) w->core.height - (real) w->plot.Margin - w->plot.y.Origin - yextra;
2703 
2704 /* Adjust the size depending upon what sorts of text are visible. */
2705   if (w->plot.ShowTitle)
2706     height -= (real) w->plot.TitleMargin +
2707       FontnumHeight(w, w->plot.titleFont);
2708 
2709 /* Only need to carry one number for the size, (since it is a circle!) */
2710   if (height < width)
2711     size = height;
2712   else
2713     size = width;
2714 
2715 /* Assign some preliminary values */
2716   w->plot.x.Center = w->plot.x.Origin + (width / 2.0);
2717   w->plot.y.Center = w->plot.y.Origin + (height / 2.0);
2718   w->plot.x.LegendPos += width - w->plot.x.LegendSize;
2719   w->plot.y.LegendPos += w->plot.y.Origin;
2720 
2721 /*
2722  * Check and see if the legend can fit in the blank space in the upper right
2723  *
2724  * To fit, the legend must:
2725  *   1) be less than half the width/height of the plot
2726  *   2) hmmm.
2727  */
2728   if (!w->plot.LegendThroughPlot) {
2729     real radius = size / 2.0;
2730     real dist;
2731 
2732     x = w->plot.x.LegendPos - w->plot.x.Center;
2733     y = (w->plot.y.LegendPos + w->plot.y.LegendSize) - w->plot.y.Center;
2734 
2735     dist = sqrt(x * x + y * y);
2736 /*       printf("rad=%f dist=%f: legend=(%f,%f) center=(%f,%f)\n", */
2737 /*              radius,dist,w->plot.x.LegendPos,w->plot.y.LegendPos, */
2738 /*              w->plot.x.Center,w->plot.y.Center); */
2739 
2740     /* It doesn't fit if this check is true.  Make the plot smaller */
2741 
2742     /* This is a first cut horrible algorithm.  My calculus is a bit
2743      * rusty tonight--can't seem to figure out how to maximize a circle
2744      * in a rectangle with a rectangular chunk out of it. */
2745     if (dist < radius) {
2746       width -= w->plot.x.LegendSize;
2747       height -= w->plot.y.LegendSize;
2748 
2749       /* readjust some parameters */
2750       w->plot.x.Center = w->plot.x.Origin + width / 2.0;
2751       w->plot.y.Center = w->plot.y.Origin + w->plot.y.LegendSize + height / 2.0;
2752       if (height < width)
2753 	size = height;
2754       else
2755 	size = width;
2756     }
2757 
2758   }
2759 
2760 
2761 /* OK, customization is finished when we reach here. */
2762   w->plot.x.Size = w->plot.y.Size = size;
2763 
2764   w->plot.y.TitlePos = w->plot.y.Center + w->plot.y.Size / 2.0 +
2765     (real) w->plot.TitleMargin +
2766     FontnumAscent(w, w->plot.titleFont);
2767   w->plot.x.TitlePos = w->plot.x.Origin;
2768 }
2769 
2770 static void
AdjustDimensions(SciPlotWidget w)2771 AdjustDimensions (SciPlotWidget w)
2772 {
2773   if (w->plot.ChartType == XtCARTESIAN) {
2774     AdjustDimensionsCartesian(w);
2775   }
2776   else {
2777     AdjustDimensionsPolar(w);
2778   }
2779 }
2780 
2781 static void
ComputeAllDimensions(SciPlotWidget w)2782 ComputeAllDimensions (SciPlotWidget w)
2783 {
2784   ComputeLegendDimensions(w);
2785   ComputeDimensions(w);
2786   ComputeDrawingRange(w);
2787   AdjustDimensions(w);
2788 }
2789 
2790 static void
ComputeAll(SciPlotWidget w)2791 ComputeAll (SciPlotWidget w)
2792 {
2793   ComputeMinMax(w);
2794   ComputeAllDimensions(w);
2795 }
2796 
2797 
2798 /*
2799  * Private drawing routines
2800  */
2801 
2802 static void
DrawMarker(SciPlotWidget w,real xpaper,real ypaper,real size,int color,int style)2803 DrawMarker (SciPlotWidget w, real xpaper, real ypaper, real size, int color, int style)
2804 {
2805   real sizex, sizey;
2806 
2807   switch (style) {
2808   case XtMARKER_CIRCLE:
2809     CircleSet(w, xpaper, ypaper, size, color, XtLINE_SOLID);
2810     break;
2811   case XtMARKER_FCIRCLE:
2812     FilledCircleSet(w, xpaper, ypaper, size, color, XtLINE_SOLID);
2813     break;
2814   case XtMARKER_SQUARE:
2815     size -= .5;
2816     RectSet(w, xpaper - size, ypaper - size,
2817       xpaper + size, ypaper + size,
2818       color, XtLINE_SOLID);
2819     break;
2820   case XtMARKER_FSQUARE:
2821     size -= .5;
2822     FilledRectSet(w, xpaper - size, ypaper - size,
2823       xpaper + size, ypaper + size,
2824       color, XtLINE_SOLID);
2825     break;
2826   case XtMARKER_UTRIANGLE:
2827     sizex = size * .866;
2828     sizey = size / 2.0;
2829     TriSet(w, xpaper, ypaper - size,
2830       xpaper + sizex, ypaper + sizey,
2831       xpaper - sizex, ypaper + sizey,
2832       color, XtLINE_SOLID);
2833     break;
2834   case XtMARKER_FUTRIANGLE:
2835     sizex = size * .866;
2836     sizey = size / 2.0;
2837     FilledTriSet(w, xpaper, ypaper - size,
2838       xpaper + sizex, ypaper + sizey,
2839       xpaper - sizex, ypaper + sizey,
2840       color, XtLINE_SOLID);
2841     break;
2842   case XtMARKER_DTRIANGLE:
2843     sizex = size * .866;
2844     sizey = size / 2.0;
2845     TriSet(w, xpaper, ypaper + size,
2846       xpaper + sizex, ypaper - sizey,
2847       xpaper - sizex, ypaper - sizey,
2848       color, XtLINE_SOLID);
2849     break;
2850   case XtMARKER_FDTRIANGLE:
2851     sizex = size * .866;
2852     sizey = size / 2.0;
2853     FilledTriSet(w, xpaper, ypaper + size,
2854       xpaper + sizex, ypaper - sizey,
2855       xpaper - sizex, ypaper - sizey,
2856       color, XtLINE_SOLID);
2857     break;
2858   case XtMARKER_RTRIANGLE:
2859     sizey = size * .866;
2860     sizex = size / 2.0;
2861     TriSet(w, xpaper + size, ypaper,
2862       xpaper - sizex, ypaper + sizey,
2863       xpaper - sizex, ypaper - sizey,
2864       color, XtLINE_SOLID);
2865     break;
2866   case XtMARKER_FRTRIANGLE:
2867     sizey = size * .866;
2868     sizex = size / 2.0;
2869     FilledTriSet(w, xpaper + size, ypaper,
2870       xpaper - sizex, ypaper + sizey,
2871       xpaper - sizex, ypaper - sizey,
2872       color, XtLINE_SOLID);
2873     break;
2874   case XtMARKER_LTRIANGLE:
2875     sizey = size * .866;
2876     sizex = size / 2.0;
2877     TriSet(w, xpaper - size, ypaper,
2878       xpaper + sizex, ypaper + sizey,
2879       xpaper + sizex, ypaper - sizey,
2880       color, XtLINE_SOLID);
2881     break;
2882   case XtMARKER_FLTRIANGLE:
2883     sizey = size * .866;
2884     sizex = size / 2.0;
2885     FilledTriSet(w, xpaper - size, ypaper,
2886       xpaper + sizex, ypaper + sizey,
2887       xpaper + sizex, ypaper - sizey,
2888       color, XtLINE_SOLID);
2889     break;
2890   case XtMARKER_DIAMOND:
2891     QuadSet(w, xpaper, ypaper - size,
2892       xpaper + size, ypaper,
2893       xpaper, ypaper + size,
2894       xpaper - size, ypaper,
2895       color, XtLINE_SOLID);
2896     break;
2897   case XtMARKER_FDIAMOND:
2898     FilledQuadSet(w, xpaper, ypaper - size,
2899       xpaper + size, ypaper,
2900       xpaper, ypaper + size,
2901       xpaper - size, ypaper,
2902       color, XtLINE_SOLID);
2903     break;
2904   case XtMARKER_HOURGLASS:
2905     QuadSet(w, xpaper - size, ypaper - size,
2906       xpaper + size, ypaper - size,
2907       xpaper - size, ypaper + size,
2908       xpaper + size, ypaper + size,
2909       color, XtLINE_SOLID);
2910     break;
2911   case XtMARKER_FHOURGLASS:
2912     FilledQuadSet(w, xpaper - size, ypaper - size,
2913       xpaper + size, ypaper - size,
2914       xpaper - size, ypaper + size,
2915       xpaper + size, ypaper + size,
2916       color, XtLINE_SOLID);
2917     break;
2918   case XtMARKER_BOWTIE:
2919     QuadSet(w, xpaper - size, ypaper - size,
2920       xpaper - size, ypaper + size,
2921       xpaper + size, ypaper - size,
2922       xpaper + size, ypaper + size,
2923       color, XtLINE_SOLID);
2924     break;
2925   case XtMARKER_FBOWTIE:
2926     FilledQuadSet(w, xpaper - size, ypaper - size,
2927       xpaper - size, ypaper + size,
2928       xpaper + size, ypaper - size,
2929       xpaper + size, ypaper + size,
2930       color, XtLINE_SOLID);
2931     break;
2932   case XtMARKER_DOT:
2933     FilledCircleSet(w, xpaper, ypaper, 1.5, color, XtLINE_SOLID);
2934     break;
2935 
2936   default:
2937     break;
2938   }
2939 }
2940 
2941 static void
DrawLegend(SciPlotWidget w)2942 DrawLegend (SciPlotWidget w)
2943 {
2944   real x, y, len, height, height2, len2, ascent;
2945   int i;
2946   SciPlotList *p;
2947 
2948   w->plot.current_id = SciPlotDrawingLegend;
2949   if (w->plot.ShowLegend) {
2950     x = w->plot.x.LegendPos;
2951     y = w->plot.y.LegendPos;
2952     len = (real) w->plot.LegendLineSize;
2953     len2 = len / 2.0;
2954     height = FontnumHeight(w, w->plot.axisFont);
2955     height2 = height / 2.0;
2956     ascent = FontnumAscent(w, w->plot.axisFont);
2957     RectSet(w, x, y,
2958       x + w->plot.x.LegendSize - 1.0 - (real) w->plot.Margin,
2959       y + w->plot.y.LegendSize - 1.0,
2960       w->plot.ForegroundColor, XtLINE_SOLID);
2961     x += (real) w->plot.LegendMargin;
2962     y += (real) w->plot.LegendMargin;
2963 
2964     for (i = 0; i < w->plot.num_plotlist; i++) {
2965       p = w->plot.plotlist + i;
2966       if (p->draw) {
2967 	LineSet(w, x, y + height2, x + len, y + height2,
2968 	  p->LineColor, p->LineStyle);
2969 	DrawMarker(w, x + len2, y + height2, p->markersize,
2970 	  p->PointColor, p->PointStyle);
2971 	TextSet(w, x + len + (real) w->plot.LegendMargin,
2972 	  y + ascent,
2973 	  p->legend, w->plot.ForegroundColor,
2974 	  w->plot.axisFont);
2975 	y += height;
2976       }
2977     }
2978   }
2979 }
2980 
2981 static void
DrawCartesianAxes(SciPlotWidget w)2982 DrawCartesianAxes (SciPlotWidget w)
2983 {
2984   real x, y, x1, y1, x2, y2, tic, val, height, majorval;
2985   int j, precision;
2986   char numberformat[16], label[16];
2987 
2988   w->plot.current_id = SciPlotDrawingAxis;
2989   height = FontnumHeight(w, w->plot.labelFont);
2990   x1 = PlotX(w, w->plot.x.DrawOrigin);
2991   y1 = PlotY(w, w->plot.y.DrawOrigin);
2992   x2 = PlotX(w, w->plot.x.DrawMax);
2993   y2 = PlotY(w, w->plot.y.DrawMax);
2994   LineSet(w, x1, y1, x2, y1, w->plot.ForegroundColor, XtLINE_SOLID);
2995   LineSet(w, x1, y1, x1, y2, w->plot.ForegroundColor, XtLINE_SOLID);
2996 
2997   precision = w->plot.x.Precision;
2998   sprintf(numberformat, "%%.%df", precision);
2999   if (w->plot.XLog) {
3000     val = w->plot.x.DrawOrigin;
3001     if (precision > 0)
3002       precision--;
3003   }
3004   else {
3005     val = w->plot.x.DrawOrigin;
3006   }
3007   x = PlotX(w, val);
3008   if (w->plot.DrawMajorTics)
3009     LineSet(w, x, y1 + 5, x, y1 - 5, w->plot.ForegroundColor, XtLINE_SOLID);
3010   if (w->plot.XAxisNumbers) {
3011     sprintf(label, numberformat, val);
3012     TextSet(w, x, w->plot.y.AxisPos, label, w->plot.ForegroundColor,
3013       w->plot.axisFont);
3014   }
3015 
3016   majorval = val;
3017   while ((majorval * 1.0001) < w->plot.x.DrawMax) {
3018     if (w->plot.XLog) {
3019 
3020 /* Hack to make sure that 9.99999e? still gets interpreted as 10.0000e? */
3021       if (majorval * 1.1 > w->plot.x.DrawMax)
3022 	break;
3023       tic = majorval;
3024       if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
3025 	for (j = 2; j < w->plot.x.MinorNum; j++) {
3026 	  val = tic * (real) j;
3027 	  x = PlotX(w, val);
3028 	  if (w->plot.DrawMinor)
3029 	    LineSet(w, x, y1, x, y2,
3030 	      w->plot.ForegroundColor,
3031 	      XtLINE_WIDEDOT);
3032 	  if (w->plot.DrawMinorTics)
3033 	    LineSet(w, x, y1, x, y1 - 3,
3034 	      w->plot.ForegroundColor,
3035 	      XtLINE_SOLID);
3036 	}
3037       }
3038       val = tic * (real) w->plot.x.MinorNum;
3039       sprintf(numberformat, "%%.%df", precision);
3040       if (precision > 0)
3041 	precision--;
3042     }
3043     else {
3044       tic = majorval;
3045       if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
3046 	for (j = 1; j < w->plot.x.MinorNum; j++) {
3047 	  val = tic + w->plot.x.MajorInc * (real) j /
3048 	    w->plot.x.MinorNum;
3049 	  x = PlotX(w, val);
3050 	  if (w->plot.DrawMinor)
3051 	    LineSet(w, x, y1, x, y2,
3052 	      w->plot.ForegroundColor,
3053 	      XtLINE_WIDEDOT);
3054 	  if (w->plot.DrawMinorTics)
3055 	    LineSet(w, x, y1, x, y1 - 3,
3056 	      w->plot.ForegroundColor,
3057 	      XtLINE_SOLID);
3058 	}
3059       }
3060       val = tic + w->plot.x.MajorInc;
3061     }
3062     x = PlotX(w, val);
3063     if (w->plot.DrawMajor)
3064       LineSet(w, x, y1, x, y2, w->plot.ForegroundColor,
3065 	XtLINE_DOTTED);
3066     else if (w->plot.DrawMinor)
3067       LineSet(w, x, y1, x, y2, w->plot.ForegroundColor,
3068 	XtLINE_WIDEDOT);
3069     if (w->plot.DrawMajorTics)
3070       LineSet(w, x, y1 + 5, x, y1 - 5, w->plot.ForegroundColor,
3071 	XtLINE_SOLID);
3072     if (w->plot.XAxisNumbers) {
3073       sprintf(label, numberformat, val);
3074       TextSet(w, x, w->plot.y.AxisPos, label, w->plot.ForegroundColor,
3075         w->plot.axisFont);
3076     }
3077     majorval = val;
3078   }
3079 
3080   precision = w->plot.y.Precision;
3081   sprintf(numberformat, "%%.%df", precision);
3082   if (w->plot.YLog) {
3083     val = w->plot.y.DrawOrigin;
3084     if (precision > 0)
3085       precision--;
3086   }
3087   else {
3088     val = w->plot.y.DrawOrigin;
3089   }
3090   y = PlotY(w, val);
3091   if (w->plot.DrawMajorTics)
3092     LineSet(w, x1 + 5, y, x1 - 5, y, w->plot.ForegroundColor, XtLINE_SOLID);
3093   if (w->plot.YAxisNumbers) {
3094     sprintf(label, numberformat, val);
3095     if (w->plot.YNumHorz) {
3096       y+=FontnumHeight(w, w->plot.axisFont)/2.0 -
3097         FontnumDescent(w, w->plot.axisFont);
3098       TextSet(w,
3099         w->plot.x.AxisPos - FontnumTextWidth(w, w->plot.axisFont, label),
3100         y, label, w->plot.ForegroundColor,
3101         w->plot.axisFont);
3102     }
3103     else {
3104       VTextSet(w, w->plot.x.AxisPos, y, label, w->plot.ForegroundColor,
3105         w->plot.axisFont);
3106     }
3107   }
3108   majorval = val;
3109 
3110 /* majorval*1.0001 is a fudge to get rid of rounding errors that seem to
3111  * occur when continuing to add the major axis increment.
3112  */
3113   while ((majorval * 1.0001) < w->plot.y.DrawMax) {
3114     if (w->plot.YLog) {
3115 
3116 /* Hack to make sure that 9.99999e? still gets interpreted as 10.0000e? */
3117       if (majorval * 1.1 > w->plot.y.DrawMax)
3118 	break;
3119       tic = majorval;
3120       if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
3121 	for (j = 2; j < w->plot.y.MinorNum; j++) {
3122 	  val = tic * (real) j;
3123 	  y = PlotY(w, val);
3124 	  if (w->plot.DrawMinor)
3125 	    LineSet(w, x1, y, x2, y,
3126 	      w->plot.ForegroundColor,
3127 	      XtLINE_WIDEDOT);
3128 	  if (w->plot.DrawMinorTics)
3129 	    LineSet(w, x1, y, x1 + 3, y,
3130 	      w->plot.ForegroundColor,
3131 	      XtLINE_SOLID);
3132 	}
3133       }
3134       val = tic * (real) w->plot.y.MinorNum;
3135       sprintf(numberformat, "%%.%df", precision);
3136       if (precision > 0)
3137 	precision--;
3138     }
3139     else {
3140       tic = majorval;
3141       if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
3142 	for (j = 1; j < w->plot.y.MinorNum; j++) {
3143 	  val = tic + w->plot.y.MajorInc * (real) j /
3144 	    w->plot.y.MinorNum;
3145 	  y = PlotY(w, val);
3146 	  if (w->plot.DrawMinor)
3147 	    LineSet(w, x1, y, x2, y,
3148 	      w->plot.ForegroundColor,
3149 	      XtLINE_WIDEDOT);
3150 	  if (w->plot.DrawMinorTics)
3151 	    LineSet(w, x1, y, x1 + 3, y,
3152 	      w->plot.ForegroundColor,
3153 	      XtLINE_SOLID);
3154 	}
3155       }
3156       val = tic + w->plot.y.MajorInc;
3157     }
3158     y = PlotY(w, val);
3159     if (w->plot.DrawMajor)
3160       LineSet(w, x1, y, x2, y, w->plot.ForegroundColor,
3161 	XtLINE_DOTTED);
3162     else if (w->plot.DrawMinor)
3163       LineSet(w, x1, y, x2, y, w->plot.ForegroundColor,
3164 	XtLINE_WIDEDOT);
3165     if (w->plot.DrawMajorTics)
3166       LineSet(w, x1 - 5, y, x1 + 5, y, w->plot.ForegroundColor,
3167 	XtLINE_SOLID);
3168     if (w->plot.YAxisNumbers) {
3169       sprintf(label, numberformat, val);
3170       if (w->plot.YNumHorz) {
3171         y+=FontnumHeight(w, w->plot.axisFont)/2.0 -
3172           FontnumDescent(w, w->plot.axisFont);
3173         TextSet(w,
3174           w->plot.x.AxisPos - FontnumTextWidth(w, w->plot.axisFont, label),
3175           y, label, w->plot.ForegroundColor,
3176           w->plot.axisFont);
3177       }
3178       else {
3179         VTextSet(w, w->plot.x.AxisPos, y, label, w->plot.ForegroundColor,
3180           w->plot.axisFont);
3181       }
3182     }
3183     majorval = val;
3184   }
3185 
3186   if (w->plot.ShowTitle)
3187     TextSet(w, w->plot.x.TitlePos, w->plot.y.TitlePos,
3188       w->plot.plotTitle, w->plot.ForegroundColor,
3189       w->plot.titleFont);
3190   if (w->plot.ShowXLabel)
3191     TextCenter(w, w->plot.x.Origin + (w->plot.x.Size / 2.0),
3192       w->plot.y.LabelPos, w->plot.xlabel,
3193       w->plot.ForegroundColor, w->plot.labelFont);
3194   if (w->plot.ShowYLabel)
3195     VTextCenter(w, w->plot.x.LabelPos,
3196       w->plot.y.Origin + (w->plot.y.Size / 2.0),
3197       w->plot.ylabel, w->plot.ForegroundColor,
3198       w->plot.labelFont);
3199 }
3200 
3201 
3202 static void
DrawCartesianPlot(SciPlotWidget w)3203 DrawCartesianPlot (SciPlotWidget w)
3204 {
3205   int i, j, jstart;
3206   SciPlotList *p;
3207 
3208   w->plot.current_id = SciPlotDrawingAny;
3209   ClipSet(w);
3210   w->plot.current_id = SciPlotDrawingLine;
3211   for (i = 0; i < w->plot.num_plotlist; i++) {
3212     p = w->plot.plotlist + i;
3213     if (p->draw) {
3214       real x1, y1, x2, y2;
3215       Boolean skipnext=False;
3216 
3217       jstart = 0;
3218       while ((jstart < p->number) &&
3219         (((p->data[jstart].x <= SCIPLOT_SKIP_VAL ||
3220            p->data[jstart].y <= SCIPLOT_SKIP_VAL) ||
3221           (w->plot.XLog && (p->data[jstart].x <= 0.0)) ||
3222           (w->plot.YLog && (p->data[jstart].y <= 0.0)))))
3223         jstart++;
3224       if (jstart < p->number) {
3225         x1 = PlotX(w, p->data[jstart].x);
3226         y1 = PlotY(w, p->data[jstart].y);
3227       }
3228       for (j = jstart; j < p->number; j++) {
3229         if (p->data[j].x <= SCIPLOT_SKIP_VAL ||
3230             p->data[j].y <= SCIPLOT_SKIP_VAL) {
3231           skipnext=True;
3232           continue;
3233         }
3234 
3235 	if (!((w->plot.XLog && (p->data[j].x <= 0.0)) ||
3236 	    (w->plot.YLog && (p->data[j].y <= 0.0)))) {
3237 	  x2 = PlotX(w, p->data[j].x);
3238 	  y2 = PlotY(w, p->data[j].y);
3239           if (!skipnext)
3240             LineSet(w, x1, y1, x2, y2, p->LineColor, p->LineStyle);
3241 	  x1 = x2;
3242 	  y1 = y2;
3243 	}
3244 
3245         skipnext=False;
3246       }
3247     }
3248   }
3249   w->plot.current_id = SciPlotDrawingAny;
3250   ClipClear(w);
3251   w->plot.current_id = SciPlotDrawingLine;
3252   for (i = 0; i < w->plot.num_plotlist; i++) {
3253     p = w->plot.plotlist + i;
3254     if (p->draw) {
3255       real x2, y2;
3256 
3257       for (j = 0; j < p->number; j++) {
3258 	if (!((w->plot.XLog && (p->data[j].x <= 0.0)) ||
3259 	    (w->plot.YLog && (p->data[j].y <= 0.0)) ||
3260              p->data[j].x <= SCIPLOT_SKIP_VAL ||
3261              p->data[j].y <= SCIPLOT_SKIP_VAL )) {
3262 	  x2 = PlotX(w, p->data[j].x);
3263 	  y2 = PlotY(w, p->data[j].y);
3264 	  if ((x2 >= w->plot.x.Origin) &&
3265 	    (x2 <= w->plot.x.Origin + w->plot.x.Size) &&
3266 	    (y2 >= w->plot.y.Origin) &&
3267 	    (y2 <= w->plot.y.Origin + w->plot.y.Size)) {
3268 
3269 	    DrawMarker(w, x2, y2,
3270 	      p->markersize,
3271 	      p->PointColor,
3272 	      p->PointStyle);
3273 	  }
3274 
3275 	}
3276       }
3277     }
3278   }
3279 }
3280 
3281 static void
DrawPolarAxes(SciPlotWidget w)3282 DrawPolarAxes (SciPlotWidget w)
3283 {
3284   real x1, y1, x2, y2, max, tic, val, height;
3285   int i, j;
3286   char numberformat[16], label[16];
3287 
3288   w->plot.current_id = SciPlotDrawingAxis;
3289   sprintf(numberformat, "%%.%df", w->plot.x.Precision);
3290   height = FontnumHeight(w, w->plot.labelFont);
3291   max = w->plot.PolarScale;
3292   PlotRTDegrees(w, 0.0, 0.0, &x1, &y1);
3293   PlotRTDegrees(w, max, 0.0, &x2, &y2);
3294   LineSet(w, x1, y1, x2, y2, 1, XtLINE_SOLID);
3295   for (i = 45; i < 360; i += 45) {
3296     PlotRTDegrees(w, max, (real) i, &x2, &y2);
3297     LineSet(w, x1, y1, x2, y2, w->plot.ForegroundColor, XtLINE_DOTTED);
3298   }
3299   for (i = 1; i <= w->plot.x.MajorNum; i++) {
3300     tic = w->plot.PolarScale *
3301       (real) i / (real) w->plot.x.MajorNum;
3302     if (w->plot.DrawMinor || w->plot.DrawMinorTics) {
3303       for (j = 1; j < w->plot.x.MinorNum; j++) {
3304 	val = tic - w->plot.x.MajorInc * (real) j /
3305 	  w->plot.x.MinorNum;
3306 	PlotRTDegrees(w, val, 0.0, &x2, &y2);
3307 	if (w->plot.DrawMinor)
3308 	  CircleSet(w, x1, y1, x2 - x1,
3309 	    w->plot.ForegroundColor, XtLINE_WIDEDOT);
3310 	if (w->plot.DrawMinorTics)
3311 	  LineSet(w, x2, y2 - 2.5, x2, y2 + 2.5,
3312 	    w->plot.ForegroundColor, XtLINE_SOLID);
3313       }
3314     }
3315     PlotRTDegrees(w, tic, 0.0, &x2, &y2);
3316     if (w->plot.DrawMajor)
3317       CircleSet(w, x1, y1, x2 - x1, w->plot.ForegroundColor, XtLINE_DOTTED);
3318     if (w->plot.DrawMajorTics)
3319       LineSet(w, x2, y2 - 5.0, x2, y2 + 5.0, w->plot.ForegroundColor, XtLINE_SOLID);
3320     if (w->plot.XAxisNumbers) {
3321       sprintf(label, numberformat, tic);
3322       TextSet(w, x2, y2 + height, label, w->plot.ForegroundColor, w->plot.axisFont);
3323     }
3324   }
3325 
3326   if (w->plot.ShowTitle)
3327     TextSet(w, w->plot.x.TitlePos, w->plot.y.TitlePos,
3328       w->plot.plotTitle, w->plot.ForegroundColor, w->plot.titleFont);
3329 }
3330 
3331 static void
DrawPolarPlot(SciPlotWidget w)3332 DrawPolarPlot (SciPlotWidget w)
3333 {
3334   int i, j;
3335   SciPlotList *p;
3336 
3337   w->plot.current_id = SciPlotDrawingLine;
3338   for (i = 0; i < w->plot.num_plotlist; i++) {
3339     p = w->plot.plotlist + i;
3340     if (p->draw) {
3341       int jstart;
3342       real x1, y1, x2, y2;
3343       Boolean skipnext=False;
3344 
3345       jstart = 0;
3346       while ((jstart < p->number) &&
3347         (p->data[jstart].x <= SCIPLOT_SKIP_VAL ||
3348           p->data[jstart].y <= SCIPLOT_SKIP_VAL))
3349         jstart++;
3350       if (jstart < p->number) {
3351         PlotRT(w, p->data[0].x, p->data[0].y, &x1, &y1);
3352       }
3353       for (j = jstart; j < p->number; j++) {
3354         if (p->data[j].x <= SCIPLOT_SKIP_VAL ||
3355             p->data[j].y <= SCIPLOT_SKIP_VAL) {
3356           skipnext=True;
3357           continue;
3358         }
3359 
3360 	PlotRT(w, p->data[j].x, p->data[j].y, &x2, &y2);
3361         if (!skipnext) {
3362           LineSet(w, x1, y1, x2, y2,
3363             p->LineColor, p->LineStyle);
3364           DrawMarker(w, x1, y1, p->markersize,
3365             p->PointColor, p->PointStyle);
3366           DrawMarker(w, x2, y2, p->markersize,
3367             p->PointColor, p->PointStyle);
3368         }
3369 	x1 = x2;
3370 	y1 = y2;
3371 
3372         skipnext=False;
3373       }
3374     }
3375   }
3376 }
3377 
3378 static void
DrawAll(SciPlotWidget w)3379 DrawAll (SciPlotWidget w)
3380 {
3381   if (w->plot.ChartType == XtCARTESIAN) {
3382     DrawCartesianAxes(w);
3383     DrawLegend(w);
3384     DrawCartesianPlot(w);
3385   }
3386   else {
3387     DrawPolarAxes(w);
3388     DrawLegend(w);
3389     DrawPolarPlot(w);
3390   }
3391 }
3392 
3393 static Boolean
DrawQuick(SciPlotWidget w)3394 DrawQuick (SciPlotWidget w)
3395 {
3396   Boolean range_check;
3397 
3398   range_check = CheckMinMax(w);
3399   EraseClassItems(w, SciPlotDrawingLine);
3400   EraseAllItems(w);
3401   DrawAll(w);
3402 
3403   return range_check;
3404 }
3405 
3406 
3407 /*
3408  * Public Plot functions
3409  */
3410 
3411 int
SciPlotAllocNamedColor(Widget wi,char * name)3412 SciPlotAllocNamedColor (Widget wi, char *name)
3413 {
3414   XColor used, exact;
3415   SciPlotWidget w;
3416 
3417   if (!XtIsSciPlot(wi))
3418     return -1;
3419 
3420   w = (SciPlotWidget) wi;
3421 
3422   if (!XAllocNamedColor(XtDisplay(w), w->plot.cmap, name, &used, &exact))
3423     return 1;
3424   return ColorStore(w, used.pixel);
3425 }
3426 
3427 int
SciPlotAllocRGBColor(Widget wi,int r,int g,int b)3428 SciPlotAllocRGBColor (Widget wi, int r, int g, int b)
3429 {
3430   XColor used;
3431   SciPlotWidget w;
3432 
3433   if (!XtIsSciPlot(wi))
3434     return -1;
3435 
3436   w = (SciPlotWidget) wi;
3437 
3438   used.pixel = 0;
3439   r *= 256;
3440   g *= 256;
3441   b *= 256;
3442   if (r > 65535)
3443     r = 65535;
3444   if (g > 65535)
3445     g = 65535;
3446   if (b > 65535)
3447     b = 65535;
3448   used.red = (unsigned short) r;
3449   used.green = (unsigned short) g;
3450   used.blue = (unsigned short) b;
3451   if (!XAllocColor(XtDisplay(w), w->plot.cmap, &used))
3452     return 1;
3453   return ColorStore(w, used.pixel);
3454 }
3455 
3456 void
SciPlotSetBackgroundColor(Widget wi,int color)3457 SciPlotSetBackgroundColor (Widget wi, int color)
3458 {
3459   SciPlotWidget w;
3460 
3461   if (!XtIsSciPlot(wi))
3462     return;
3463 
3464   w = (SciPlotWidget) wi;
3465   if (color < w->plot.num_colors) {
3466     w->plot.BackgroundColor = color;
3467     w->core.background_pixel = w->plot.colors[color];
3468     XSetWindowBackground( XtDisplay(w), XtWindow(w), w->core.background_pixel);
3469   }
3470 }
3471 
3472 void
SciPlotSetForegroundColor(Widget wi,int color)3473 SciPlotSetForegroundColor (Widget wi, int color)
3474 {
3475   SciPlotWidget w;
3476 
3477   if (!XtIsSciPlot(wi))
3478     return;
3479 
3480   w = (SciPlotWidget) wi;
3481   if (color < w->plot.num_colors)
3482     w->plot.ForegroundColor = color;
3483 }
3484 
3485 void
SciPlotListDelete(Widget wi,int idnum)3486 SciPlotListDelete (Widget wi, int idnum)
3487 {
3488   SciPlotList *p;
3489   SciPlotWidget w;
3490 
3491   if (!XtIsSciPlot(wi))
3492     return;
3493 
3494   w = (SciPlotWidget) wi;
3495 
3496   p = _ListFind(w, idnum);
3497   if (p)
3498     _ListDelete(p);
3499 }
3500 
3501 int
SciPlotListCreateFromData(Widget wi,int num,real * xlist,real * ylist,char * legend,int pcolor,int pstyle,int lcolor,int lstyle)3502 SciPlotListCreateFromData (Widget wi, int num, real *xlist, real *ylist, char *legend, int pcolor, int pstyle, int lcolor, int lstyle)
3503 {
3504   int idnum;
3505   SciPlotList *p;
3506   SciPlotWidget w;
3507 
3508   if (!XtIsSciPlot(wi))
3509     return -1;
3510 
3511   w = (SciPlotWidget) wi;
3512 
3513   idnum = _ListNew(w);
3514   p = w->plot.plotlist + idnum;
3515   _ListSetReal(p, num, xlist, ylist);
3516   _ListSetLegend(p, legend);
3517   _ListSetStyle(p, pcolor, pstyle, lcolor, lstyle);
3518   return idnum;
3519 }
3520 
3521 int
SciPlotListCreateFloat(Widget wi,int num,float * xlist,float * ylist,char * legend)3522 SciPlotListCreateFloat (Widget wi, int num, float *xlist, float *ylist, char *legend)
3523 {
3524   int idnum;
3525   SciPlotList *p;
3526   SciPlotWidget w;
3527 
3528   if (!XtIsSciPlot(wi))
3529     return -1;
3530 
3531   w = (SciPlotWidget) wi;
3532 
3533   idnum = _ListNew(w);
3534   p = w->plot.plotlist + idnum;
3535   _ListSetFloat(p, num, xlist, ylist);
3536   _ListSetLegend(p, legend);
3537   _ListSetStyle(p, 1, XtMARKER_CIRCLE, 1, XtLINE_SOLID);
3538   return idnum;
3539 }
3540 
3541 void
SciPlotListUpdateFloat(Widget wi,int idnum,int num,float * xlist,float * ylist)3542 SciPlotListUpdateFloat (Widget wi, int idnum, int num, float *xlist, float *ylist)
3543 {
3544   SciPlotList *p;
3545   SciPlotWidget w;
3546 
3547   if (!XtIsSciPlot(wi))
3548     return;
3549 
3550   w = (SciPlotWidget) wi;
3551 
3552   p = _ListFind(w, idnum);
3553   if (p)
3554     _ListSetFloat(p, num, xlist, ylist);
3555 }
3556 
3557 void
SciPlotListAddFloat(Widget wi,int idnum,int num,float * xlist,float * ylist)3558 SciPlotListAddFloat (Widget wi, int idnum, int num, float *xlist, float *ylist)
3559 {
3560   SciPlotList *p;
3561   SciPlotWidget w;
3562 
3563   if (!XtIsSciPlot(wi))
3564     return;
3565 
3566   w = (SciPlotWidget) wi;
3567 
3568   p = _ListFind(w, idnum);
3569   if (p)
3570     _ListAddFloat(p, num, xlist, ylist);
3571 }
3572 
3573 int
SciPlotListCreateDouble(Widget wi,int num,double * xlist,double * ylist,char * legend)3574 SciPlotListCreateDouble (Widget wi, int num, double *xlist, double *ylist, char *legend)
3575 {
3576   int idnum;
3577   SciPlotList *p;
3578   SciPlotWidget w;
3579 
3580   if (!XtIsSciPlot(wi))
3581     return -1;
3582 
3583   w = (SciPlotWidget) wi;
3584 
3585   idnum = _ListNew(w);
3586   p = w->plot.plotlist + idnum;
3587   _ListSetDouble(p, num, xlist, ylist);
3588   _ListSetLegend(p, legend);
3589   _ListSetStyle(p, 1, XtMARKER_CIRCLE, 1, XtLINE_SOLID);
3590   return idnum;
3591 }
3592 
3593 void
SciPlotListUpdateDouble(Widget wi,int idnum,int num,double * xlist,double * ylist)3594 SciPlotListUpdateDouble (Widget wi, int idnum, int num, double *xlist, double *ylist)
3595 {
3596   SciPlotList *p;
3597   SciPlotWidget w;
3598 
3599   if (!XtIsSciPlot(wi))
3600     return;
3601 
3602   w = (SciPlotWidget) wi;
3603 
3604   p = _ListFind(w, idnum);
3605   if (p)
3606     _ListSetDouble(p, num, xlist, ylist);
3607 }
3608 
3609 void
SciPlotListAddDouble(Widget wi,int idnum,int num,double * xlist,double * ylist)3610 SciPlotListAddDouble (Widget wi, int idnum, int num, double *xlist, double *ylist)
3611 {
3612   SciPlotList *p;
3613   SciPlotWidget w;
3614 
3615   if (!XtIsSciPlot(wi))
3616     return;
3617 
3618   w = (SciPlotWidget) wi;
3619 
3620   p = _ListFind(w, idnum);
3621   if (p)
3622     _ListAddDouble(p, num, xlist, ylist);
3623 }
3624 
3625 void
SciPlotListSetStyle(Widget wi,int idnum,int pcolor,int pstyle,int lcolor,int lstyle)3626 SciPlotListSetStyle (Widget wi, int idnum, int pcolor, int pstyle, int lcolor, int lstyle)
3627 {
3628   SciPlotList *p;
3629   SciPlotWidget w;
3630 
3631   if (!XtIsSciPlot(wi))
3632     return;
3633 
3634   w = (SciPlotWidget) wi;
3635 
3636   p = _ListFind(w, idnum);
3637   if (p)
3638     _ListSetStyle(p, pcolor, pstyle, lcolor, lstyle);
3639 }
3640 
3641 void
SciPlotListSetMarkerSize(Widget wi,int idnum,float size)3642 SciPlotListSetMarkerSize (Widget wi, int idnum, float size)
3643 {
3644   SciPlotList *p;
3645   SciPlotWidget w;
3646 
3647   if (!XtIsSciPlot(wi))
3648     return;
3649 
3650   w = (SciPlotWidget) wi;
3651 
3652   p = _ListFind(w, idnum);
3653   if (p)
3654     p->markersize=size;
3655 }
3656 
3657 void
SciPlotSetXAutoScale(Widget wi)3658 SciPlotSetXAutoScale (Widget wi)
3659 {
3660   SciPlotWidget w;
3661 
3662   if (!XtIsSciPlot(wi))
3663     return;
3664 
3665   w = (SciPlotWidget) wi;
3666   w->plot.XAutoScale = True;
3667 }
3668 
3669 void
SciPlotSetXUserScale(Widget wi,double min,double max)3670 SciPlotSetXUserScale (Widget wi, double min, double max)
3671 {
3672   SciPlotWidget w;
3673 
3674   if (!XtIsSciPlot(wi))
3675     return;
3676 
3677   w = (SciPlotWidget) wi;
3678   if (min < max) {
3679     w->plot.XAutoScale = False;
3680     w->plot.UserMin.x = (real) min;
3681     w->plot.UserMax.x = (real) max;
3682   }
3683 }
3684 
3685 void
SciPlotSetYAutoScale(Widget wi)3686 SciPlotSetYAutoScale (Widget wi)
3687 {
3688   SciPlotWidget w;
3689 
3690   if (!XtIsSciPlot(wi))
3691     return;
3692 
3693   w = (SciPlotWidget) wi;
3694   w->plot.YAutoScale = True;
3695 }
3696 
3697 void
SciPlotSetYUserScale(Widget wi,double min,double max)3698 SciPlotSetYUserScale (Widget wi, double min, double max)
3699 {
3700   SciPlotWidget w;
3701 
3702   if (!XtIsSciPlot(wi))
3703     return;
3704 
3705   w = (SciPlotWidget) wi;
3706   if (min < max) {
3707     w->plot.YAutoScale = False;
3708     w->plot.UserMin.y = (real) min;
3709     w->plot.UserMax.y = (real) max;
3710   }
3711 }
3712 
3713 void
SciPlotPrintStatistics(Widget wi)3714 SciPlotPrintStatistics (Widget wi)
3715 {
3716   int i, j;
3717   SciPlotList *p;
3718   SciPlotWidget w;
3719 
3720   if (!XtIsSciPlot(wi))
3721     return;
3722 
3723   w = (SciPlotWidget) wi;
3724 
3725   printf("Title=%s\nxlabel=%s\tylabel=%s\n",
3726     w->plot.plotTitle, w->plot.xlabel, w->plot.ylabel);
3727   printf("ChartType=%d\n", w->plot.ChartType);
3728   printf("Degrees=%d\n", w->plot.Degrees);
3729   printf("XLog=%d\tYLog=%d\n", w->plot.XLog, w->plot.YLog);
3730   printf("XAutoScale=%d\tYAutoScale=%d\n",
3731     w->plot.XAutoScale, w->plot.YAutoScale);
3732   for (i = 0; i < w->plot.num_plotlist; i++) {
3733     p = w->plot.plotlist + i;
3734     if (p->draw) {
3735       printf("\nLegend=%s\n", p->legend);
3736       printf("Styles: point=%d line=%d  Color: point=%d line=%d\n",
3737 	p->PointStyle, p->LineStyle, p->PointColor, p->LineColor);
3738       for (j = 0; j < p->number; j++)
3739 	printf("%f\t%f\n", p->data[j].x, p->data[j].y);
3740       printf("\n");
3741     }
3742   }
3743 }
3744 
3745 void
SciPlotExportData(Widget wi,FILE * fd)3746 SciPlotExportData (Widget wi, FILE *fd)
3747 {
3748   int i, j;
3749   SciPlotList *p;
3750   SciPlotWidget w;
3751 
3752   if (!XtIsSciPlot(wi))
3753     return;
3754 
3755   w = (SciPlotWidget) wi;
3756 
3757   fprintf(fd, "Title=\"%s\"\n", w->plot.plotTitle);
3758   fprintf(fd, "Xaxis=\"%s\"\n", w->plot.xlabel);
3759   fprintf(fd, "Yaxis=\"%s\"\n\n", w->plot.ylabel);
3760   for (i = 0; i < w->plot.num_plotlist; i++) {
3761     p = w->plot.plotlist + i;
3762     if (p->draw) {
3763       fprintf(fd, "Line=\"%s\"\n",p->legend);
3764       for (j = 0; j < p->number; j++)
3765 	fprintf(fd, "%e\t%e\n", p->data[j].x, p->data[j].y);
3766       fprintf(fd, "\n");
3767     }
3768   }
3769 }
3770 
3771 int
SciPlotStoreAllocatedColor(Widget wi,Pixel p)3772 SciPlotStoreAllocatedColor(Widget wi, Pixel p)
3773 {
3774   SciPlotWidget w;
3775 
3776   if (!XtIsSciPlot(wi))
3777     return -1;
3778 
3779   w = (SciPlotWidget) wi;
3780 
3781   return ColorStore(w, p);
3782 }
3783 
3784 void
SciPlotUpdate(Widget wi)3785 SciPlotUpdate (Widget wi)
3786 {
3787   SciPlotWidget w;
3788 
3789   if (!XtIsSciPlot(wi))
3790     return;
3791 
3792   w = (SciPlotWidget) wi;
3793   EraseAll(w);
3794 #ifdef DEBUG_SCIPLOT
3795   SciPlotPrintStatistics(w);
3796 #endif
3797   ComputeAll(w);
3798   DrawAll(w);
3799 }
3800 
3801 Boolean
SciPlotQuickUpdate(Widget wi)3802 SciPlotQuickUpdate (Widget wi)
3803 {
3804   SciPlotWidget w;
3805 
3806   if (!XtIsSciPlot(wi))
3807     return False;
3808 
3809   w = (SciPlotWidget) wi;
3810   return DrawQuick(w);
3811 }
3812