Actual source code: axis.c

  1: /*$Id: axis.c,v 1.76 2001/08/07 21:28:45 bsmith Exp $*/
  2: /*
  3:    This file contains a simple routine for generating a 2-d axis.
  4: */

 6:  #include petsc.h

  8: int DRAWAXIS_COOKIE;

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

 23: #define MAXSEGS 20

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

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

 38: /*@C
 39:    PetscDrawAxisCreate - Generate the axis data structure.

 41:    Collective over PetscDraw

 43:    Input Parameters:
 44: .  win - PetscDraw object where axis to to be made

 46:    Ouput Parameters:
 47: .  axis - the axis datastructure

 49:    Level: advanced

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

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

 83:   *axis = ad;
 84:   return(0);
 85: }

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

 90:     Collective over PetscDrawAxis

 92:     Input Parameters:
 93: .   axis - the axis context
 94:  
 95:     Level: advanced

 97: @*/
 98: int PetscDrawAxisDestroy(PetscDrawAxis axis)
 99: {
101:   if (!axis) return(0);
102:   if (--axis->refct > 0) return(0);

104:   PetscLogObjectDestroy(axis);
105:   PetscHeaderDestroy(axis);
106:   return(0);
107: }

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

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

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

121:     Level: advanced

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

132: /*@C
133:     PetscDrawAxisSetLabels -  Sets the x and y axis labels.

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

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

142:     Level: advanced

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

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

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

165:     Level: advanced

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

179: /*@
180:     PetscDrawAxisDraw - PetscDraws an axis.

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

184:     Input Parameter:
185: .   axis - Axis structure

187:     Level: advanced

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

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

220:   PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac);
221:   PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

481:   /*  if (PetscAbsReal(low-high) < 1.e-8) {
482:     low  -= .01;
483:     high += .01;
484:   } */

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

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

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

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

506: #define EPS 1.e-6

508: static int PetscExp10(PetscReal d,PetscReal *result)
509: {
511:   *result = pow(10.0,d);
512:   return(0);
513: }

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

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

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

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

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

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

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

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