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