Actual source code: axis.c

  1: /*$Id: axis.c,v 1.74 2001/04/10 19:34:23 bsmith Exp $*/
  2: /*
  3:    This file contains a simple routine for generating a 2-d axis.
  4: */

  6: #include "petsc.h"              /*I "petsc.h" I*/

  8: struct _p_DrawAxis {
  9:     PETSCHEADER(int)
 10:     PetscReal  xlow,ylow,xhigh,yhigh;     /* User - coord limits */
 11:     int     (*ylabelstr)(PetscReal,PetscReal,char **),/* routines to generate labels */
 12:             (*xlabelstr)(PetscReal,PetscReal,char **);
 13:     int     (*xticks)(PetscReal,PetscReal,int,int*,PetscReal*,int),
 14:             (*yticks)(PetscReal,PetscReal,int,int*,PetscReal*,int);
 15:                                           /* location and size of ticks */
 16:     PetscDraw    win;
 17:     int     ac,tc,cc;                     /* axis,tick, charactor color */
 18:     char    *xlabel,*ylabel,*toplabel;
 19: };

 21: #define MAXSEGS 20

 23: EXTERN int    PetscADefTicks(PetscReal,PetscReal,int,int*,PetscReal*,int);
 24: EXTERN int    PetscADefLabel(PetscReal,PetscReal,char**);
 25: static int    PetscAGetNice(PetscReal,PetscReal,int,PetscReal*);
 26: static int    PetscAGetBase(PetscReal,PetscReal,int,PetscReal*,int*);

 28: static int PetscRint(PetscReal x,PetscReal *result)
 29: {
 31:   if (x > 0) *result = floor(x + 0.5);
 32:   else       *result = floor(x - 0.5);
 33:   return(0);
 34: }

 36: /*@C
 37:    PetscDrawAxisCreate - Generate the axis data structure.

 39:    Collective over PetscDraw

 41:    Input Parameters:
 42: .  win - PetscDraw object where axis to to be made

 44:    Ouput Parameters:
 45: .  axis - the axis datastructure

 47:    Level: advanced

 49: @*/
 50: int PetscDrawAxisCreate(PetscDraw draw,PetscDrawAxis *axis)
 51: {
 52:   PetscDrawAxis ad;
 53:   PetscObject   obj = (PetscObject)draw;
 54:   int           ierr;
 55:   PetscTruth    isnull;

 60:   PetscTypeCompare(obj,PETSC_DRAW_NULL,&isnull);
 61:   if (isnull) {
 62:     PetscDrawOpenNull(obj->comm,(PetscDraw*)axis);
 63:     (*axis)->win = draw;
 64:     return(0);
 65:   }
 66:   PetscHeaderCreate(ad,_p_DrawAxis,int,DRAWAXIS_COOKIE,0,"PetscDrawAxis",obj->comm,PetscDrawAxisDestroy,0);
 67:   PetscLogObjectCreate(ad);
 68:   PetscLogObjectParent(draw,ad);
 69:   ad->xticks    = PetscADefTicks;
 70:   ad->yticks    = PetscADefTicks;
 71:   ad->xlabelstr = PetscADefLabel;
 72:   ad->ylabelstr = PetscADefLabel;
 73:   ad->win       = draw;
 74:   ad->ac        = PETSC_DRAW_BLACK;
 75:   ad->tc        = PETSC_DRAW_BLACK;
 76:   ad->cc        = PETSC_DRAW_BLACK;
 77:   ad->xlabel    = 0;
 78:   ad->ylabel    = 0;
 79:   ad->toplabel  = 0;

 81:   *axis = ad;
 82:   return(0);
 83: }

 85: /*@C
 86:     PetscDrawAxisDestroy - Frees the space used by an axis structure.

 88:     Collective over PetscDrawAxis

 90:     Input Parameters:
 91: .   axis - the axis context
 92:  
 93:     Level: advanced

 95: @*/
 96: int PetscDrawAxisDestroy(PetscDrawAxis axis)
 97: {
 99:   if (!axis) return(0);
100:   if (--axis->refct > 0) return(0);

102:   PetscLogObjectDestroy(axis);
103:   PetscHeaderDestroy(axis);
104:   return(0);
105: }

107: /*@
108:     PetscDrawAxisSetColors -  Sets the colors to be used for the axis,       
109:                          tickmarks, and text.

111:     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)

113:     Input Parameters:
114: +   axis - the axis
115: .   ac - the color of the axis lines
116: .   tc - the color of the tick marks
117: -   cc - the color of the text strings

119:     Level: advanced

121: @*/
122: int PetscDrawAxisSetColors(PetscDrawAxis axis,int ac,int tc,int cc)
123: {
125:   if (!axis) return(0);
126:   axis->ac = ac; axis->tc = tc; axis->cc = cc;
127:   return(0);
128: }

130: /*@C
131:     PetscDrawAxisSetLabels -  Sets the x and y axis labels.

133:     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)

135:     Input Parameters:
136: +   axis - the axis
137: .   top - the label at the top of the image
138: -   xlabel,ylabel - the labes for the x and y axis

140:     Level: advanced

142: @*/
143: int PetscDrawAxisSetLabels(PetscDrawAxis axis,char* top,char *xlabel,char *ylabel)
144: {
146:   if (!axis) return(0);
147:   axis->xlabel   = xlabel;
148:   axis->ylabel   = ylabel;
149:   axis->toplabel = top;
150:   return(0);
151: }

153: /*@
154:     PetscDrawAxisSetLimits -  Sets the limits (in user coords) of the axis
155:     
156:     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)

158:     Input Parameters:
159: +   axis - the axis
160: .   xmin,xmax - limits in x
161: -   ymin,ymax - limits in y

163:     Level: advanced

165: @*/
166: int PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
167: {
169:   if (!axis) return(0);
170:   axis->xlow = xmin;
171:   axis->xhigh= xmax;
172:   axis->ylow = ymin;
173:   axis->yhigh= ymax;
174:   return(0);
175: }

177: /*@
178:     PetscDrawAxisDraw - PetscDraws an axis.

180:     Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)

182:     Input Parameter:
183: .   axis - Axis structure

185:     Level: advanced

187:     Note:
188:     This draws the actual axis.  The limits etc have already been set.
189:     By picking special routines for the ticks and labels, special
190:     effects may be generated.  These routines are part of the Axis
191:     structure (axis).
192: @*/
193: int PetscDrawAxisDraw(PetscDrawAxis axis)
194: {
195:   int       i,ierr,ntick,numx,numy,ac = axis->ac,tc = axis->tc,cc = axis->cc,rank,len;
196:   PetscReal tickloc[MAXSEGS],sep,h,w,tw,th,xl,xr,yl,yr;
197:   char      *p;
198:   PetscDraw draw = axis->win;
199: 
201:   if (!axis) return(0);
202:   MPI_Comm_rank(axis->comm,&rank);
203:   if (rank) return(0);

205:   if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;}
206:   if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;}
207:   xl = axis->xlow; xr = axis->xhigh; yl = axis->ylow; yr = axis->yhigh;
208:   PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
209:   PetscDrawStringGetSize(draw,&tw,&th);
210:   numx = (int)(.15*(xr-xl)/tw); if (numx > 6) numx = 6; if (numx< 2) numx = 2;
211:   numy = (int)(.5*(yr-yl)/th); if (numy > 6) numy = 6; if (numy< 2) numy = 2;
212:   xl -= 8*tw; xr += 2*tw; yl -= 2.5*th; yr += 2*th;
213:   if (axis->xlabel) yl -= 2*th;
214:   if (axis->ylabel) xl -= 2*tw;
215:   PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
216:   PetscDrawStringGetSize(draw,&tw,&th);

218:   PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac);
219:   PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac);

221:   if (axis->toplabel) {
222:      PetscStrlen(axis->toplabel,&len);
223:     w    = xl + .5*(xr - xl) - .5*len*tw;
224:     h    = axis->yhigh;
225:     PetscDrawString(draw,w,h,cc,axis->toplabel);
226:   }

228:   /* PetscDraw the ticks and labels */
229:   if (axis->xticks) {
230:     (*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,MAXSEGS);
231:     /* PetscDraw in tick marks */
232:     for (i=0; i<ntick; i++) {
233:       PetscDrawLine(draw,tickloc[i],axis->ylow-.5*th,tickloc[i],axis->ylow+.5*th,tc);
234:     }
235:     /* label ticks */
236:     for (i=0; i<ntick; i++) {
237:         if (axis->xlabelstr) {
238:             if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
239:             else if (i > 0)    sep = tickloc[i]   - tickloc[i-1];
240:             else               sep = 0.0;
241:             (*axis->xlabelstr)(tickloc[i],sep,&p);
242:             PetscStrlen(p,&len);
243:             w    = .5*len*tw;
244:             PetscDrawString(draw,tickloc[i]-w,axis->ylow-1.2*th,cc,p);
245:         }
246:     }
247:   }
248:   if (axis->xlabel) {
249:     PetscStrlen(axis->xlabel,&len);
250:     w    = xl + .5*(xr - xl) - .5*len*tw;
251:     h    = axis->ylow - 2.5*th;
252:     PetscDrawString(draw,w,h,cc,axis->xlabel);
253:   }
254:   if (axis->yticks) {
255:     (*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,MAXSEGS);
256:     /* PetscDraw in tick marks */
257:     for (i=0; i<ntick; i++) {
258:       PetscDrawLine(draw,axis->xlow -.5*tw,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc);
259:     }
260:     /* label ticks */
261:     for (i=0; i<ntick; i++) {
262:         if (axis->ylabelstr) {
263:             if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
264:             else if (i > 0)    sep = tickloc[i]   - tickloc[i-1];
265:             else               sep = 0.0;
266:             (*axis->xlabelstr)(tickloc[i],sep,&p);
267:             PetscStrlen(p,&len);
268:             w    = axis->xlow - len * tw - 1.2*tw;
269:             PetscDrawString(draw,w,tickloc[i]-.5*th,cc,p);
270:         }
271:     }
272:   }
273:   if (axis->ylabel) {
274:     PetscStrlen(axis->ylabel,&len);
275:     h    = yl + .5*(yr - yl) + .5*len*th;
276:     w    = xl + .5*tw;
277:     PetscDrawStringVertical(draw,w,h,cc,axis->ylabel);
278:   }
279:   return(0);
280: }

282: /*
283:     Removes all zeros but one from .0000 
284: */
285: static int PetscStripAllZeros(char *buf)
286: {
287:   int i,n,ierr;

290:   PetscStrlen(buf,&n);
291:   if (buf[0] != '.') return(0);
292:   for (i=1; i<n; i++) {
293:     if (buf[i] != '0') return(0);
294:   }
295:   buf[0] = '0';
296:   buf[1] = 0;
297:   return(0);
298: }

300: /*
301:     Removes trailing zeros
302: */
303: static int PetscStripTrailingZeros(char *buf)
304: {
305:   int  ierr,i,n,m = -1;
306:   char *found;

309:   /* if there is an e in string DO NOT strip trailing zeros */
310:   PetscStrchr(buf,'e',&found);
311:   if (found) return(0);

313:   PetscStrlen(buf,&n);
314:   /* locate decimal point */
315:   for (i=0; i<n; i++) {
316:     if (buf[i] == '.') {m = i; break;}
317:   }
318:   /* if not decimal point then no zeros to remove */
319:   if (m == -1) return(0);
320:   /* start at right end of string removing 0s */
321:   for (i=n-1; i>m; i++) {
322:     if (buf[i] != '0') return(0);
323:     buf[i] = 0;
324:   }
325:   return(0);
326: }

328: /*
329:     Removes leading 0 from 0.22 or -0.22
330: */
331: static int PetscStripInitialZero(char *buf)
332: {
333:   int i,n,ierr;

336:   PetscStrlen(buf,&n);
337:   if (buf[0] == '0') {
338:     for (i=0; i<n; i++) {
339:       buf[i] = buf[i+1];
340:     }
341:   } else if (buf[0] == '-' && buf[1] == '0') {
342:     for (i=1; i<n; i++) {
343:       buf[i] = buf[i+1];
344:     }
345:   }
346:   return(0);
347: }

349: /*
350:      Removes the extraneous zeros in numbers like 1.10000e6
351: */
352: static int PetscStripZeros(char *buf)
353: {
354:   int i,j,n,ierr;

357:   PetscStrlen(buf,&n);
358:   if (n<5) return(0);
359:   for (i=1; i<n-1; i++) {
360:     if (buf[i] == 'e' && buf[i-1] == '0') {
361:       for (j=i; j<n+1; j++) buf[j-1] = buf[j];
362:       PetscStripZeros(buf);
363:       return(0);
364:     }
365:   }
366:   return(0);
367: }

369: /*
370:       Removes the plus in something like 1.1e+2
371: */
372: static int PetscStripZerosPlus(char *buf)
373: {
374:   int i,j,n,ierr;

377:   PetscStrlen(buf,&n);
378:   if (n<5) return(0);
379:   for (i=1; i<n-2; i++) {
380:     if (buf[i] == '+') {
381:       if (buf[i+1] == '0') {
382:         for (j=i+1; j<n+1; j++) buf[j-1] = buf[j+1];
383:         return(0);
384:       } else {
385:         for (j=i+1; j<n+1; j++) buf[j] = buf[j+1];
386:         return(0);
387:       }
388:     } else if (buf[i] == '-') {
389:       if (buf[i+1] == '0') {
390:         for (j=i+1; j<n+1; j++) buf[j] = buf[j+1];
391:         return(0);
392:       }
393:     }
394:   }
395:   return(0);
396: }

398: /*
399:    val is the label value.  sep is the separation to the next (or previous)
400:    label; this is useful in determining how many significant figures to   
401:    keep.
402:  */
403: int PetscADefLabel(PetscReal val,PetscReal sep,char **p)
404: {
405:   static char buf[40];
406:   char        fmat[10];
407:   int         ierr,w,d;
408:   PetscReal   rval;

411:   /* Find the string */
412:   if (PetscAbsDouble(val)/sep <  1.e-6) {
413:     buf[0] = '0'; buf[1] = 0;
414:   } else if (PetscAbsDouble(val) < 1.0e6 && PetscAbsDouble(val) > 1.e-4) {
415:     /* Compute the number of digits */
416:     w = 0;
417:     d = 0;
418:     if (sep > 0.0) {
419:         d = (int)ceil(- log10 (sep));
420:         if (d < 0) d = 0;
421:         if (PetscAbsDouble(val) < 1.0e-6*sep) {
422:             /* This is the case where we are near zero and less than a small
423:                fraction of the sep.  In this case, we use 0 as the value */
424:             val = 0.0;
425:             w   = d;
426:         }
427:         else if (val == 0.0) w   = d;
428:         else w = (int)(ceil(log10(PetscAbsDouble(val))) + d);
429:         if (w < 1)   w ++;
430:         if (val < 0) w ++;
431:     }

433:     PetscRint(val,&rval);
434:     if (rval == val) {
435:         if (w > 0) sprintf(fmat,"%%%dd",w);
436:         else {PetscStrcpy(fmat,"%d");}
437:         sprintf(buf,fmat,(int)val);
438:         PetscStripInitialZero(buf);
439:         PetscStripAllZeros(buf);
440:         PetscStripTrailingZeros(buf);
441:     } else {
442:         /* The code used here is inappropriate for a val of 0, which
443:            tends to print with an excessive numer of digits.  In this
444:            case, we should look at the next/previous values and 
445:            use those widths */
446:         if (w > 0) sprintf(fmat,"%%%d.%dlf",w + 1,d);
447:         else {PetscStrcpy(fmat,"%lf");}
448:         sprintf(buf,fmat,val);
449:         PetscStripInitialZero(buf);
450:         PetscStripAllZeros(buf);
451:         PetscStripTrailingZeros(buf);
452:     }
453:   } else {
454:     sprintf(buf,"%e",val);
455:     /* remove the extraneous 0 before the e */
456:     PetscStripZeros(buf);
457:     PetscStripZerosPlus(buf);
458:     PetscStripInitialZero(buf);
459:     PetscStripAllZeros(buf);
460:     PetscStripTrailingZeros(buf);
461:   }
462:   *p =buf;
463:   return(0);
464: }

466: /* Finds "nice" locations for the ticks */
467: int PetscADefTicks(PetscReal low,PetscReal high,int num,int *ntick,PetscReal * tickloc,int  maxtick)
468: {
469:   int       i,power,ierr;
470:   PetscReal x,base;

473:   /* patch if low == high */
474:   if (low == high) {
475:     low  -= .01;
476:     high += .01;
477:   }

479:   /*  if (PetscAbsDouble(low-high) < 1.e-8) {
480:     low  -= .01;
481:     high += .01;
482:   } */

484:   PetscAGetBase(low,high,num,&base,&power);
485:   PetscAGetNice(low,base,-1,&x);

487:   /* Values are of the form j * base */
488:   /* Find the starting value */
489:   if (x < low) x += base;

491:   i = 0;
492:   while (i < maxtick && x <= high) {
493:     tickloc[i++] = x;
494:     x += base;
495:   }
496:   *ntick = i;

498:   if (i < 2 && num < 10) {
499:     PetscADefTicks(low,high,num+1,ntick,tickloc,maxtick);
500:   }
501:   return(0);
502: }

504: #define EPS 1.e-6

506: static int PetscExp10(PetscReal d,PetscReal *result)
507: {
509:   *result = pow(10.0,d);
510:   return(0);
511: }

513: static int PetscMod(PetscReal x,PetscReal y,PetscReal *result)
514: {
515:   int     i;

518:   i   = ((int)x) / ((int)y);
519:   x   = x - i * y;
520:   while (x > y) x -= y;
521:   *result = x;
522:   return(0);
523: }

525: static int PetscCopysign(PetscReal a,PetscReal b,PetscReal *result)
526: {
528:   if (b >= 0) *result = a;
529:   else        *result = -a;
530:   return(0);
531: }

533: /*
534:     Given a value "in" and a "base", return a nice value.
535:     based on "sign", extend up (+1) or down (-1)
536:  */
537: static int PetscAGetNice(PetscReal in,PetscReal base,int sign,PetscReal *result)
538: {
539:   PetscReal  etmp,s,s2,m;
540:   int     ierr;

543:   ierr    = PetscCopysign (0.5,(double)sign,&s);
544:   etmp    = in / base + 0.5 + s;
545:   ierr    = PetscCopysign (0.5,etmp,&s);
546:   ierr    = PetscCopysign (EPS * etmp,(double)sign,&s2);
547:   etmp    = etmp - 0.5 + s - s2;
548:   ierr    = PetscMod(etmp,1.0,&m);
549:   etmp    = base * (etmp -  m);
550:   *result = etmp;
551:   return(0);
552: }

554: static int PetscAGetBase(PetscReal vmin,PetscReal vmax,int num,PetscReal*Base,int*power)
555: {
556:   PetscReal        base,ftemp,e10;
557:   static PetscReal base_try[5] = {10.0,5.0,2.0,1.0,0.5};
558:   int              i,ierr;

561:   /* labels of the form n * BASE */
562:   /* get an approximate value for BASE */
563:   base    = (vmax - vmin) / (double)(num + 1);

565:   /* make it of form   m x 10^power,  m in [1.0, 10) */
566:   if (base <= 0.0) {
567:     base    = PetscAbsDouble(vmin);
568:     if (base < 1.0) base = 1.0;
569:   }
570:   ftemp   = log10((1.0 + EPS) * base);
571:   if (ftemp < 0.0)  ftemp   -= 1.0;
572:   *power  = (int)ftemp;
573:   PetscExp10((double)- *power,&e10);
574:   base    = base * e10;
575:   if (base < 1.0) base    = 1.0;
576:   /* now reduce it to one of 1, 2, or 5 */
577:   for (i=1; i<5; i++) {
578:     if (base >= base_try[i]) {
579:       PetscExp10((double)*power,&e10);
580:       base = base_try[i-1] * e10;
581:       if (i == 1) *power    = *power + 1;
582:       break;
583:     }
584:   }
585:   *Base   = base;
586:   return(0);
587: }