xref: /petsc/src/sys/classes/draw/utils/axisc.c (revision 8da24d32403b711d95ab43313acc68d97deb82f3)
1 #include <petsc/private/drawimpl.h>  /*I   "petscdraw.h"  I*/
2 
3 #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20
4 PetscClassId PETSC_DRAWAXIS_CLASSID = 0;
5 
6 /*@
7    PetscDrawAxisCreate - Generate the axis data structure.
8 
9    Collective on PetscDraw
10 
11    Input Parameters:
12 .  win - PetscDraw object where axis to to be made
13 
14    Output Parameter:
15 .  axis - the axis datastructure
16 
17    Notes:
18     the MPI communicator that owns the underlying draw object owns the PetscDrawAxis object, but calls to set PetscDrawAxis options are ignored by all processes
19           except the first MPI process in the communicator
20 
21    Level: advanced
22 
23 .seealso: PetscDrawLGCreate(), PetscDrawLG, PetscDrawSPCreate(), PetscDrawSP, PetscDrawHGCreate(), PetscDrawHG, PetscDrawBarCreate(), PetscDrawBar, PetscDrawLGGetAxis(), PetscDrawSPGetAxis(),
24           PetscDrawHGGetAxis(), PetscDrawBarGetAxis(), PetscDrawAxis, PetscDrawAxisDestroy(), PetscDrawAxisSetColors(), PetscDrawAxisSetLabels(), PetscDrawAxisSetLimits(), PetscDrawAxisGetLimits(), PetscDrawAxisSetHoldLimits(),
25           PetscDrawAxisDraw()
26 @*/
27 PetscErrorCode  PetscDrawAxisCreate(PetscDraw draw,PetscDrawAxis *axis)
28 {
29   PetscDrawAxis  ad;
30 
31   PetscFunctionBegin;
32   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
33   PetscValidPointer(axis,2);
34 
35   PetscCall(PetscHeaderCreate(ad,PETSC_DRAWAXIS_CLASSID,"DrawAxis","Draw Axis","Draw",PetscObjectComm((PetscObject)draw),PetscDrawAxisDestroy,NULL));
36   PetscCall(PetscLogObjectParent((PetscObject)draw,(PetscObject)ad));
37 
38   PetscCall(PetscObjectReference((PetscObject)draw));
39   ad->win = draw;
40 
41   ad->xticks    = PetscADefTicks;
42   ad->yticks    = PetscADefTicks;
43   ad->xlabelstr = PetscADefLabel;
44   ad->ylabelstr = PetscADefLabel;
45   ad->ac        = PETSC_DRAW_BLACK;
46   ad->tc        = PETSC_DRAW_BLACK;
47   ad->cc        = PETSC_DRAW_BLACK;
48   ad->xlabel    = NULL;
49   ad->ylabel    = NULL;
50   ad->toplabel  = NULL;
51 
52   *axis = ad;
53   PetscFunctionReturn(0);
54 }
55 
56 /*@
57     PetscDrawAxisDestroy - Frees the space used by an axis structure.
58 
59     Collective on PetscDrawAxis
60 
61     Input Parameters:
62 .   axis - the axis context
63 
64     Level: advanced
65 
66 .seealso: PetscDrawAxisCreate(), PetscDrawAxis
67 @*/
68 PetscErrorCode  PetscDrawAxisDestroy(PetscDrawAxis *axis)
69 {
70   PetscFunctionBegin;
71   if (!*axis) PetscFunctionReturn(0);
72   PetscValidHeaderSpecific(*axis,PETSC_DRAWAXIS_CLASSID,1);
73   if (--((PetscObject)(*axis))->refct > 0) {*axis = NULL; PetscFunctionReturn(0);}
74 
75   PetscCall(PetscFree((*axis)->toplabel));
76   PetscCall(PetscFree((*axis)->xlabel));
77   PetscCall(PetscFree((*axis)->ylabel));
78   PetscCall(PetscDrawDestroy(&(*axis)->win));
79   PetscCall(PetscHeaderDestroy(axis));
80   PetscFunctionReturn(0);
81 }
82 
83 /*@
84     PetscDrawAxisSetColors -  Sets the colors to be used for the axis,
85                          tickmarks, and text.
86 
87     Logically Collective on PetscDrawAxis
88 
89     Input Parameters:
90 +   axis - the axis
91 .   ac - the color of the axis lines
92 .   tc - the color of the tick marks
93 -   cc - the color of the text strings
94 
95     Level: advanced
96 
97 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisSetLabels(), PetscDrawAxisDraw(), PetscDrawAxisSetLimits()
98 @*/
99 PetscErrorCode  PetscDrawAxisSetColors(PetscDrawAxis axis,int ac,int tc,int cc)
100 {
101   PetscFunctionBegin;
102   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
103   PetscValidLogicalCollectiveInt(axis,ac,2);
104   PetscValidLogicalCollectiveInt(axis,tc,3);
105   PetscValidLogicalCollectiveInt(axis,cc,4);
106   axis->ac = ac; axis->tc = tc; axis->cc = cc;
107   PetscFunctionReturn(0);
108 }
109 
110 /*@C
111     PetscDrawAxisSetLabels -  Sets the x and y axis labels.
112 
113     Logically Collective on PetscDrawAxis
114 
115     Input Parameters:
116 +   axis - the axis
117 .   top - the label at the top of the image
118 -   xlabel,ylabel - the labes for the x and y axis
119 
120     Notes:
121     Must be called before PetscDrawAxisDraw() or PetscDrawLGDraw()
122            There should be no newlines in the arguments
123 
124     Level: advanced
125 
126 .seealso: PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisSetColors(), PetscDrawAxisDraw(), PetscDrawAxisSetLimits()
127 @*/
128 PetscErrorCode  PetscDrawAxisSetLabels(PetscDrawAxis axis,const char top[],const char xlabel[],const char ylabel[])
129 {
130   PetscFunctionBegin;
131   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
132   PetscCall(PetscFree(axis->xlabel));
133   PetscCall(PetscFree(axis->ylabel));
134   PetscCall(PetscFree(axis->toplabel));
135   PetscCall(PetscStrallocpy(xlabel,&axis->xlabel));
136   PetscCall(PetscStrallocpy(ylabel,&axis->ylabel));
137   PetscCall(PetscStrallocpy(top,&axis->toplabel));
138   PetscFunctionReturn(0);
139 }
140 
141 /*@
142     PetscDrawAxisSetLimits -  Sets the limits (in user coords) of the axis
143 
144     Logically Collective on PetscDrawAxis
145 
146     Input Parameters:
147 +   axis - the axis
148 .   xmin,xmax - limits in x
149 -   ymin,ymax - limits in y
150 
151     Options Database:
152 .   -drawaxis_hold - hold the initial set of axis limits for future plotting
153 
154     Level: advanced
155 
156 .seealso:  PetscDrawAxisSetHoldLimits(), PetscDrawAxisGetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors()
157 
158 @*/
159 PetscErrorCode  PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
160 {
161   PetscFunctionBegin;
162   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
163   if (axis->hold) PetscFunctionReturn(0);
164   axis->xlow = xmin;
165   axis->xhigh= xmax;
166   axis->ylow = ymin;
167   axis->yhigh= ymax;
168   PetscCall(PetscOptionsHasName(((PetscObject)axis)->options,((PetscObject)axis)->prefix,"-drawaxis_hold",&axis->hold));
169   PetscFunctionReturn(0);
170 }
171 
172 /*@
173     PetscDrawAxisGetLimits -  Gets the limits (in user coords) of the axis
174 
175     Not Collective
176 
177     Input Parameters:
178 +   axis - the axis
179 .   xmin,xmax - limits in x
180 -   ymin,ymax - limits in y
181 
182     Level: advanced
183 
184 .seealso:  PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisSetHoldLimits(), PetscDrawAxisSetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors()
185 
186 @*/
187 PetscErrorCode  PetscDrawAxisGetLimits(PetscDrawAxis axis,PetscReal *xmin,PetscReal *xmax,PetscReal *ymin,PetscReal *ymax)
188 {
189   PetscFunctionBegin;
190   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
191   if (xmin) *xmin = axis->xlow;
192   if (xmax) *xmax = axis->xhigh;
193   if (ymin) *ymin = axis->ylow;
194   if (ymax) *ymax = axis->yhigh;
195   PetscFunctionReturn(0);
196 }
197 
198 /*@
199     PetscDrawAxisSetHoldLimits -  Causes an axis to keep the same limits until this is called
200         again
201 
202     Logically Collective on PetscDrawAxis
203 
204     Input Parameters:
205 +   axis - the axis
206 -   hold - PETSC_TRUE - hold current limits, PETSC_FALSE allow limits to be changed
207 
208     Level: advanced
209 
210     Notes:
211         Once this has been called with PETSC_TRUE the limits will not change if you call
212      PetscDrawAxisSetLimits() until you call this with PETSC_FALSE
213 
214 .seealso:  PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisGetLimits(), PetscDrawAxisSetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors()
215 
216 @*/
217 PetscErrorCode  PetscDrawAxisSetHoldLimits(PetscDrawAxis axis,PetscBool hold)
218 {
219   PetscFunctionBegin;
220   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
221   PetscValidLogicalCollectiveBool(axis,hold,2);
222   axis->hold = hold;
223   PetscFunctionReturn(0);
224 }
225 
226 /*@
227     PetscDrawAxisDraw - PetscDraws an axis.
228 
229     Collective on PetscDrawAxis
230 
231     Input Parameter:
232 .   axis - Axis structure
233 
234     Level: advanced
235 
236     Note:
237     This draws the actual axis.  The limits etc have already been set.
238     By picking special routines for the ticks and labels, special
239     effects may be generated.  These routines are part of the Axis
240     structure (axis).
241 
242 .seealso:  PetscDrawAxisCreate(), PetscDrawAxis, PetscDrawAxisGetLimits(), PetscDrawAxisSetLimits(), PetscDrawAxisSetLabels(), PetscDrawAxisSetColors()
243 
244 @*/
245 PetscErrorCode  PetscDrawAxisDraw(PetscDrawAxis axis)
246 {
247   int            i,ntick,numx,numy,ac,tc,cc;
248   PetscMPIInt    rank;
249   size_t         len,ytlen=0;
250   PetscReal      coors[4],tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS],sep,tw,th;
251   PetscReal      xl,xr,yl,yr,dxl=0,dyl=0,dxr=0,dyr=0;
252   char           *p;
253   PetscDraw      draw;
254   PetscBool      isnull;
255 
256   PetscFunctionBegin;
257   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
258   PetscCall(PetscDrawIsNull(axis->win,&isnull));
259   if (isnull) PetscFunctionReturn(0);
260   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis),&rank));
261 
262   draw = axis->win;
263 
264   ac = axis->ac; tc = axis->tc; cc = axis->cc;
265   if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;}
266   if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;}
267 
268   PetscDrawCollectiveBegin(draw);
269   if (rank) goto finally;
270 
271   /* get cannonical string size */
272   PetscCall(PetscDrawSetCoordinates(draw,0,0,1,1));
273   PetscCall(PetscDrawStringGetSize(draw,&tw,&th));
274   /* lower spacing */
275   if (axis->xlabelstr) dyl += 1.5*th;
276   if (axis->xlabel)    dyl += 1.5*th;
277   /* left spacing */
278   if (axis->ylabelstr) dxl += 7.5*tw;
279   if (axis->ylabel)    dxl += 2.0*tw;
280   /* right and top spacing */
281   if (axis->xlabelstr) dxr = 2.5*tw;
282   if (axis->ylabelstr) dyr = 0.5*th;
283   if (axis->toplabel)  dyr = 1.5*th;
284   /* extra spacing */
285   dxl += 0.7*tw; dxr += 0.5*tw;
286   dyl += 0.2*th; dyr += 0.2*th;
287   /* determine coordinates */
288   xl = (dxl*axis->xhigh + dxr*axis->xlow - axis->xlow)  / (dxl + dxr - 1);
289   xr = (dxl*axis->xhigh + dxr*axis->xlow - axis->xhigh) / (dxl + dxr - 1);
290   yl = (dyl*axis->yhigh + dyr*axis->ylow - axis->ylow)  / (dyl + dyr - 1);
291   yr = (dyl*axis->yhigh + dyr*axis->ylow - axis->yhigh) / (dyl + dyr - 1);
292   PetscCall(PetscDrawSetCoordinates(draw,xl,yl,xr,yr));
293   PetscCall(PetscDrawStringGetSize(draw,&tw,&th));
294 
295   /* PetscDraw the axis lines */
296   PetscCall(PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac));
297   PetscCall(PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac));
298   PetscCall(PetscDrawLine(draw,axis->xlow,axis->yhigh,axis->xhigh,axis->yhigh,ac));
299   PetscCall(PetscDrawLine(draw,axis->xhigh,axis->ylow,axis->xhigh,axis->yhigh,ac));
300 
301   /* PetscDraw the top label */
302   if (axis->toplabel) {
303     PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->yhigh + 0.5*th;
304     PetscCall(PetscDrawStringCentered(draw,x,y,cc,axis->toplabel));
305   }
306 
307   /* PetscDraw the X ticks and labels */
308   if (axis->xticks) {
309     numx = (int)(.15*(axis->xhigh-axis->xlow)/tw); numx = PetscClipInterval(numx,2,6);
310     PetscCall((*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS));
311     /* PetscDraw in tick marks */
312     for (i=0; i<ntick; i++) {
313       PetscCall(PetscDrawLine(draw,tickloc[i],axis->ylow,tickloc[i],axis->ylow+.5*th,tc));
314       PetscCall(PetscDrawLine(draw,tickloc[i],axis->yhigh,tickloc[i],axis->yhigh-.5*th,tc));
315     }
316     /* label ticks */
317     if (axis->xlabelstr) {
318       for (i=0; i<ntick; i++) {
319         if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
320         else if (i > 0)    sep = tickloc[i]   - tickloc[i-1];
321         else               sep = 0.0;
322         PetscCall((*axis->xlabelstr)(tickloc[i],sep,&p));
323         PetscCall(PetscDrawStringCentered(draw,tickloc[i],axis->ylow-1.5*th,cc,p));
324       }
325     }
326   }
327   if (axis->xlabel) {
328     PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->ylow - 1.5*th;
329     if (axis->xlabelstr) y -= 1.5*th;
330     PetscCall(PetscDrawStringCentered(draw,x,y,cc,axis->xlabel));
331   }
332 
333   /* PetscDraw the Y ticks and labels */
334   if (axis->yticks) {
335     numy = (int)(.50*(axis->yhigh-axis->ylow)/th); numy = PetscClipInterval(numy,2,6);
336     PetscCall((*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS));
337     /* PetscDraw in tick marks */
338     for (i=0; i<ntick; i++) {
339       PetscCall(PetscDrawLine(draw,axis->xlow,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc));
340       PetscCall(PetscDrawLine(draw,axis->xhigh,tickloc[i],axis->xhigh-.5*tw,tickloc[i],tc));
341     }
342     /* label ticks */
343     if (axis->ylabelstr) {
344       for (i=0; i<ntick; i++) {
345         if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
346         else if (i > 0)    sep = tickloc[i]   - tickloc[i-1];
347         else               sep = 0.0;
348         PetscCall((*axis->ylabelstr)(tickloc[i],sep,&p));
349         PetscCall(PetscStrlen(p,&len)); ytlen = PetscMax(ytlen,len);
350         PetscCall(PetscDrawString(draw,axis->xlow-(len+.5)*tw,tickloc[i]-.5*th,cc,p));
351       }
352     }
353   }
354   if (axis->ylabel) {
355     PetscReal x = axis->xlow - 2.0*tw, y = (axis->ylow + axis->yhigh)/2;
356     if (axis->ylabelstr) x -= (ytlen+.5)*tw;
357     PetscCall(PetscStrlen(axis->ylabel,&len));
358     PetscCall(PetscDrawStringVertical(draw,x,y+len*th/2,cc,axis->ylabel));
359   }
360 
361   PetscCall(PetscDrawGetCoordinates(draw,&coors[0],&coors[1],&coors[2],&coors[3]));
362 finally:
363   PetscDrawCollectiveEnd(draw);
364   PetscCallMPI(MPI_Bcast(coors,4,MPIU_REAL,0,PetscObjectComm((PetscObject)draw)));
365   PetscCall(PetscDrawSetCoordinates(draw,coors[0],coors[1],coors[2],coors[3]));
366   PetscFunctionReturn(0);
367 }
368 
369 /*
370     Removes all zeros but one from .0000
371 */
372 PetscErrorCode PetscStripe0(char *buf)
373 {
374   size_t         n;
375   PetscBool      flg;
376   char           *str;
377 
378   PetscFunctionBegin;
379   PetscCall(PetscStrlen(buf,&n));
380   PetscCall(PetscStrendswith(buf,"e00",&flg));
381   if (flg) buf[n-3] = 0;
382   PetscCall(PetscStrstr(buf,"e0",&str));
383   if (str) {
384     buf[n-2] = buf[n-1];
385     buf[n-1] = 0;
386   }
387   PetscCall(PetscStrstr(buf,"e-0",&str));
388   if (str) {
389     buf[n-2] = buf[n-1];
390     buf[n-1] = 0;
391   }
392   PetscFunctionReturn(0);
393 }
394 
395 /*
396     Removes all zeros but one from .0000
397 */
398 PetscErrorCode PetscStripAllZeros(char *buf)
399 {
400   size_t         i,n;
401 
402   PetscFunctionBegin;
403   PetscCall(PetscStrlen(buf,&n));
404   if (buf[0] != '.') PetscFunctionReturn(0);
405   for (i=1; i<n; i++) {
406     if (buf[i] != '0') PetscFunctionReturn(0);
407   }
408   buf[0] = '0';
409   buf[1] = 0;
410   PetscFunctionReturn(0);
411 }
412 
413 /*
414     Removes trailing zeros
415 */
416 PetscErrorCode PetscStripTrailingZeros(char *buf)
417 {
418   char           *found;
419   size_t         i,n,m = PETSC_MAX_INT;
420 
421   PetscFunctionBegin;
422   /* if there is an e in string DO NOT strip trailing zeros */
423   PetscCall(PetscStrchr(buf,'e',&found));
424   if (found) PetscFunctionReturn(0);
425 
426   PetscCall(PetscStrlen(buf,&n));
427   /* locate decimal point */
428   for (i=0; i<n; i++) {
429     if (buf[i] == '.') {m = i; break;}
430   }
431   /* if not decimal point then no zeros to remove */
432   if (m == PETSC_MAX_INT) PetscFunctionReturn(0);
433   /* start at right end of string removing 0s */
434   for (i=n-1; i>m; i++) {
435     if (buf[i] != '0') PetscFunctionReturn(0);
436     buf[i] = 0;
437   }
438   PetscFunctionReturn(0);
439 }
440 
441 /*
442     Removes leading 0 from 0.22 or -0.22
443 */
444 PetscErrorCode PetscStripInitialZero(char *buf)
445 {
446   size_t         i,n;
447 
448   PetscFunctionBegin;
449   PetscCall(PetscStrlen(buf,&n));
450   if (buf[0] == '0') {
451     for (i=0; i<n; i++) buf[i] = buf[i+1];
452   } else if (buf[0] == '-' && buf[1] == '0') {
453     for (i=1; i<n; i++) buf[i] = buf[i+1];
454   }
455   PetscFunctionReturn(0);
456 }
457 
458 /*
459      Removes the extraneous zeros in numbers like 1.10000e6
460 */
461 PetscErrorCode PetscStripZeros(char *buf)
462 {
463   size_t         i,j,n;
464 
465   PetscFunctionBegin;
466   PetscCall(PetscStrlen(buf,&n));
467   if (n<5) PetscFunctionReturn(0);
468   for (i=1; i<n-1; i++) {
469     if (buf[i] == 'e' && buf[i-1] == '0') {
470       for (j=i; j<n+1; j++) buf[j-1] = buf[j];
471       PetscCall(PetscStripZeros(buf));
472       PetscFunctionReturn(0);
473     }
474   }
475   PetscFunctionReturn(0);
476 }
477 
478 /*
479       Removes the plus in something like 1.1e+2 or 1.1e+02
480 */
481 PetscErrorCode PetscStripZerosPlus(char *buf)
482 {
483   size_t         i,j,n;
484 
485   PetscFunctionBegin;
486   PetscCall(PetscStrlen(buf,&n));
487   if (n<5) PetscFunctionReturn(0);
488   for (i=1; i<n-2; i++) {
489     if (buf[i] == '+') {
490       if (buf[i+1] == '0') {
491         for (j=i+1; j<n; j++) buf[j-1] = buf[j+1];
492         PetscFunctionReturn(0);
493       } else {
494         for (j=i+1; j<n+1; j++) buf[j-1] = buf[j];
495         PetscFunctionReturn(0);
496       }
497     } else if (buf[i] == '-') {
498       if (buf[i+1] == '0') {
499         for (j=i+1; j<n; j++) buf[j] = buf[j+1];
500         PetscFunctionReturn(0);
501       }
502     }
503   }
504   PetscFunctionReturn(0);
505 }
506