xref: /petsc/src/sys/classes/draw/utils/axisc.c (revision 6a5217c03994f2d95bb2e6dbd8bed42381aeb015)
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   PetscErrorCode ierr;
256 
257   PetscFunctionBegin;
258   PetscValidHeaderSpecific(axis,PETSC_DRAWAXIS_CLASSID,1);
259   PetscCall(PetscDrawIsNull(axis->win,&isnull));
260   if (isnull) PetscFunctionReturn(0);
261   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis),&rank));
262 
263   draw = axis->win;
264 
265   ac = axis->ac; tc = axis->tc; cc = axis->cc;
266   if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;}
267   if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;}
268 
269   ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr);
270   if (rank) goto finally;
271 
272   /* get cannonical string size */
273   PetscCall(PetscDrawSetCoordinates(draw,0,0,1,1));
274   PetscCall(PetscDrawStringGetSize(draw,&tw,&th));
275   /* lower spacing */
276   if (axis->xlabelstr) dyl += 1.5*th;
277   if (axis->xlabel)    dyl += 1.5*th;
278   /* left spacing */
279   if (axis->ylabelstr) dxl += 7.5*tw;
280   if (axis->ylabel)    dxl += 2.0*tw;
281   /* right and top spacing */
282   if (axis->xlabelstr) dxr = 2.5*tw;
283   if (axis->ylabelstr) dyr = 0.5*th;
284   if (axis->toplabel)  dyr = 1.5*th;
285   /* extra spacing */
286   dxl += 0.7*tw; dxr += 0.5*tw;
287   dyl += 0.2*th; dyr += 0.2*th;
288   /* determine coordinates */
289   xl = (dxl*axis->xhigh + dxr*axis->xlow - axis->xlow)  / (dxl + dxr - 1);
290   xr = (dxl*axis->xhigh + dxr*axis->xlow - axis->xhigh) / (dxl + dxr - 1);
291   yl = (dyl*axis->yhigh + dyr*axis->ylow - axis->ylow)  / (dyl + dyr - 1);
292   yr = (dyl*axis->yhigh + dyr*axis->ylow - axis->yhigh) / (dyl + dyr - 1);
293   PetscCall(PetscDrawSetCoordinates(draw,xl,yl,xr,yr));
294   PetscCall(PetscDrawStringGetSize(draw,&tw,&th));
295 
296   /* PetscDraw the axis lines */
297   PetscCall(PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac));
298   PetscCall(PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac));
299   PetscCall(PetscDrawLine(draw,axis->xlow,axis->yhigh,axis->xhigh,axis->yhigh,ac));
300   PetscCall(PetscDrawLine(draw,axis->xhigh,axis->ylow,axis->xhigh,axis->yhigh,ac));
301 
302   /* PetscDraw the top label */
303   if (axis->toplabel) {
304     PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->yhigh + 0.5*th;
305     PetscCall(PetscDrawStringCentered(draw,x,y,cc,axis->toplabel));
306   }
307 
308   /* PetscDraw the X ticks and labels */
309   if (axis->xticks) {
310     numx = (int)(.15*(axis->xhigh-axis->xlow)/tw); numx = PetscClipInterval(numx,2,6);
311     PetscCall((*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS));
312     /* PetscDraw in tick marks */
313     for (i=0; i<ntick; i++) {
314       PetscCall(PetscDrawLine(draw,tickloc[i],axis->ylow,tickloc[i],axis->ylow+.5*th,tc));
315       PetscCall(PetscDrawLine(draw,tickloc[i],axis->yhigh,tickloc[i],axis->yhigh-.5*th,tc));
316     }
317     /* label ticks */
318     if (axis->xlabelstr) {
319       for (i=0; i<ntick; i++) {
320         if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
321         else if (i > 0)    sep = tickloc[i]   - tickloc[i-1];
322         else               sep = 0.0;
323         PetscCall((*axis->xlabelstr)(tickloc[i],sep,&p));
324         PetscCall(PetscDrawStringCentered(draw,tickloc[i],axis->ylow-1.5*th,cc,p));
325       }
326     }
327   }
328   if (axis->xlabel) {
329     PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->ylow - 1.5*th;
330     if (axis->xlabelstr) y -= 1.5*th;
331     PetscCall(PetscDrawStringCentered(draw,x,y,cc,axis->xlabel));
332   }
333 
334   /* PetscDraw the Y ticks and labels */
335   if (axis->yticks) {
336     numy = (int)(.50*(axis->yhigh-axis->ylow)/th); numy = PetscClipInterval(numy,2,6);
337     PetscCall((*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS));
338     /* PetscDraw in tick marks */
339     for (i=0; i<ntick; i++) {
340       PetscCall(PetscDrawLine(draw,axis->xlow,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc));
341       PetscCall(PetscDrawLine(draw,axis->xhigh,tickloc[i],axis->xhigh-.5*tw,tickloc[i],tc));
342     }
343     /* label ticks */
344     if (axis->ylabelstr) {
345       for (i=0; i<ntick; i++) {
346         if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
347         else if (i > 0)    sep = tickloc[i]   - tickloc[i-1];
348         else               sep = 0.0;
349         PetscCall((*axis->ylabelstr)(tickloc[i],sep,&p));
350         PetscCall(PetscStrlen(p,&len)); ytlen = PetscMax(ytlen,len);
351         PetscCall(PetscDrawString(draw,axis->xlow-(len+.5)*tw,tickloc[i]-.5*th,cc,p));
352       }
353     }
354   }
355   if (axis->ylabel) {
356     PetscReal x = axis->xlow - 2.0*tw, y = (axis->ylow + axis->yhigh)/2;
357     if (axis->ylabelstr) x -= (ytlen+.5)*tw;
358     PetscCall(PetscStrlen(axis->ylabel,&len));
359     PetscCall(PetscDrawStringVertical(draw,x,y+len*th/2,cc,axis->ylabel));
360   }
361 
362   PetscCall(PetscDrawGetCoordinates(draw,&coors[0],&coors[1],&coors[2],&coors[3]));
363 finally:
364   ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr);
365   PetscCallMPI(MPI_Bcast(coors,4,MPIU_REAL,0,PetscObjectComm((PetscObject)draw)));
366   PetscCall(PetscDrawSetCoordinates(draw,coors[0],coors[1],coors[2],coors[3]));
367   PetscFunctionReturn(0);
368 }
369 
370 /*
371     Removes all zeros but one from .0000
372 */
373 PetscErrorCode PetscStripe0(char *buf)
374 {
375   size_t         n;
376   PetscBool      flg;
377   char           *str;
378 
379   PetscFunctionBegin;
380   PetscCall(PetscStrlen(buf,&n));
381   PetscCall(PetscStrendswith(buf,"e00",&flg));
382   if (flg) buf[n-3] = 0;
383   PetscCall(PetscStrstr(buf,"e0",&str));
384   if (str) {
385     buf[n-2] = buf[n-1];
386     buf[n-1] = 0;
387   }
388   PetscCall(PetscStrstr(buf,"e-0",&str));
389   if (str) {
390     buf[n-2] = buf[n-1];
391     buf[n-1] = 0;
392   }
393   PetscFunctionReturn(0);
394 }
395 
396 /*
397     Removes all zeros but one from .0000
398 */
399 PetscErrorCode PetscStripAllZeros(char *buf)
400 {
401   size_t         i,n;
402 
403   PetscFunctionBegin;
404   PetscCall(PetscStrlen(buf,&n));
405   if (buf[0] != '.') PetscFunctionReturn(0);
406   for (i=1; i<n; i++) {
407     if (buf[i] != '0') PetscFunctionReturn(0);
408   }
409   buf[0] = '0';
410   buf[1] = 0;
411   PetscFunctionReturn(0);
412 }
413 
414 /*
415     Removes trailing zeros
416 */
417 PetscErrorCode PetscStripTrailingZeros(char *buf)
418 {
419   char           *found;
420   size_t         i,n,m = PETSC_MAX_INT;
421 
422   PetscFunctionBegin;
423   /* if there is an e in string DO NOT strip trailing zeros */
424   PetscCall(PetscStrchr(buf,'e',&found));
425   if (found) PetscFunctionReturn(0);
426 
427   PetscCall(PetscStrlen(buf,&n));
428   /* locate decimal point */
429   for (i=0; i<n; i++) {
430     if (buf[i] == '.') {m = i; break;}
431   }
432   /* if not decimal point then no zeros to remove */
433   if (m == PETSC_MAX_INT) PetscFunctionReturn(0);
434   /* start at right end of string removing 0s */
435   for (i=n-1; i>m; i++) {
436     if (buf[i] != '0') PetscFunctionReturn(0);
437     buf[i] = 0;
438   }
439   PetscFunctionReturn(0);
440 }
441 
442 /*
443     Removes leading 0 from 0.22 or -0.22
444 */
445 PetscErrorCode PetscStripInitialZero(char *buf)
446 {
447   size_t         i,n;
448 
449   PetscFunctionBegin;
450   PetscCall(PetscStrlen(buf,&n));
451   if (buf[0] == '0') {
452     for (i=0; i<n; i++) buf[i] = buf[i+1];
453   } else if (buf[0] == '-' && buf[1] == '0') {
454     for (i=1; i<n; i++) buf[i] = buf[i+1];
455   }
456   PetscFunctionReturn(0);
457 }
458 
459 /*
460      Removes the extraneous zeros in numbers like 1.10000e6
461 */
462 PetscErrorCode PetscStripZeros(char *buf)
463 {
464   size_t         i,j,n;
465 
466   PetscFunctionBegin;
467   PetscCall(PetscStrlen(buf,&n));
468   if (n<5) PetscFunctionReturn(0);
469   for (i=1; i<n-1; i++) {
470     if (buf[i] == 'e' && buf[i-1] == '0') {
471       for (j=i; j<n+1; j++) buf[j-1] = buf[j];
472       PetscCall(PetscStripZeros(buf));
473       PetscFunctionReturn(0);
474     }
475   }
476   PetscFunctionReturn(0);
477 }
478 
479 /*
480       Removes the plus in something like 1.1e+2 or 1.1e+02
481 */
482 PetscErrorCode PetscStripZerosPlus(char *buf)
483 {
484   size_t         i,j,n;
485 
486   PetscFunctionBegin;
487   PetscCall(PetscStrlen(buf,&n));
488   if (n<5) PetscFunctionReturn(0);
489   for (i=1; i<n-2; i++) {
490     if (buf[i] == '+') {
491       if (buf[i+1] == '0') {
492         for (j=i+1; j<n; j++) buf[j-1] = buf[j+1];
493         PetscFunctionReturn(0);
494       } else {
495         for (j=i+1; j<n+1; j++) buf[j-1] = buf[j];
496         PetscFunctionReturn(0);
497       }
498     } else if (buf[i] == '-') {
499       if (buf[i+1] == '0') {
500         for (j=i+1; j<n; j++) buf[j] = buf[j+1];
501         PetscFunctionReturn(0);
502       }
503     }
504   }
505   PetscFunctionReturn(0);
506 }
507