Actual source code: axis.c
1: #define PETSC_DLL
2: /*
3: This file contains a simple routine for generating a 2-d axis.
4: */
6: #include petsc.h
8: PetscCookie DRAWAXIS_COOKIE = 0;
10: struct _p_DrawAxis {
11: PETSCHEADER(int);
12: PetscReal xlow,ylow,xhigh,yhigh; /* User - coord limits */
13: PetscErrorCode (*ylabelstr)(PetscReal,PetscReal,char **);/* routines to generate labels */
14: PetscErrorCode (*xlabelstr)(PetscReal,PetscReal,char **);
15: PetscErrorCode (*xticks)(PetscReal,PetscReal,int,int*,PetscReal*,int);
16: PetscErrorCode (*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: PetscTruth hold;
22: };
24: #define MAXSEGS 20
26: EXTERN PetscErrorCode PetscADefTicks(PetscReal,PetscReal,int,int*,PetscReal*,int);
27: EXTERN PetscErrorCode PetscADefLabel(PetscReal,PetscReal,char**);
28: static PetscErrorCode PetscAGetNice(PetscReal,PetscReal,int,PetscReal*);
29: static PetscErrorCode PetscAGetBase(PetscReal,PetscReal,int,PetscReal*,int*);
33: static PetscErrorCode PetscRint(PetscReal x,PetscReal *result)
34: {
36: if (x > 0) *result = floor(x + 0.5);
37: else *result = floor(x - 0.5);
38: return(0);
39: }
43: /*@
44: PetscDrawAxisCreate - Generate the axis data structure.
46: Collective over PetscDraw
48: Input Parameters:
49: . win - PetscDraw object where axis to to be made
51: Ouput Parameters:
52: . axis - the axis datastructure
54: Level: advanced
56: @*/
57: PetscErrorCode PetscDrawAxisCreate(PetscDraw draw,PetscDrawAxis *axis)
58: {
59: PetscDrawAxis ad;
60: PetscObject obj = (PetscObject)draw;
62: PetscTruth isnull;
67: PetscTypeCompare(obj,PETSC_DRAW_NULL,&isnull);
68: if (isnull) {
69: PetscDrawOpenNull(obj->comm,(PetscDraw*)axis);
70: (*axis)->win = draw;
71: return(0);
72: }
73: PetscHeaderCreate(ad,_p_DrawAxis,int,DRAWAXIS_COOKIE,0,"PetscDrawAxis",obj->comm,PetscDrawAxisDestroy,0);
74: PetscLogObjectParent(draw,ad);
75: ad->xticks = PetscADefTicks;
76: ad->yticks = PetscADefTicks;
77: ad->xlabelstr = PetscADefLabel;
78: ad->ylabelstr = PetscADefLabel;
79: ad->win = draw;
80: ad->ac = PETSC_DRAW_BLACK;
81: ad->tc = PETSC_DRAW_BLACK;
82: ad->cc = PETSC_DRAW_BLACK;
83: ad->xlabel = 0;
84: ad->ylabel = 0;
85: ad->toplabel = 0;
87: *axis = ad;
88: return(0);
89: }
93: /*@
94: PetscDrawAxisDestroy - Frees the space used by an axis structure.
96: Collective over PetscDrawAxis
98: Input Parameters:
99: . axis - the axis context
100:
101: Level: advanced
103: @*/
104: PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis axis)
105: {
109: if (!axis) return(0);
110: if (--axis->refct > 0) return(0);
112: PetscStrfree(axis->toplabel);
113: PetscStrfree(axis->xlabel);
114: PetscStrfree(axis->ylabel);
115: PetscHeaderDestroy(axis);
116: return(0);
117: }
121: /*@
122: PetscDrawAxisSetColors - Sets the colors to be used for the axis,
123: tickmarks, and text.
125: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
127: Input Parameters:
128: + axis - the axis
129: . ac - the color of the axis lines
130: . tc - the color of the tick marks
131: - cc - the color of the text strings
133: Level: advanced
135: @*/
136: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis,int ac,int tc,int cc)
137: {
139: if (!axis) return(0);
140: axis->ac = ac; axis->tc = tc; axis->cc = cc;
141: return(0);
142: }
146: /*@C
147: PetscDrawAxisSetLabels - Sets the x and y axis labels.
149: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
151: Input Parameters:
152: + axis - the axis
153: . top - the label at the top of the image
154: - xlabel,ylabel - the labes for the x and y axis
156: Level: advanced
158: @*/
159: PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis,const char top[],const char xlabel[],const char ylabel[])
160: {
164: if (!axis) return(0);
165: PetscStrallocpy(xlabel,&axis->xlabel);
166: PetscStrallocpy(ylabel,&axis->ylabel);
167: PetscStrallocpy(top,&axis->toplabel);
168: return(0);
169: }
173: /*@
174: PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called
175: again
176:
177: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
179: Input Parameters:
180: + axis - the axis
181: - hold - PETSC_TRUE - hold current limits, PETSC_FALSE allow limits to be changed
183: Level: advanced
185: Notes:
186: Once this has been called with PETSC_TRUE the limits will not change if you call
187: PetscDrawAxisSetLimits() until you call this with PETSC_FALSE
188:
189: .seealso: PetscDrawAxisSetLimits()
191: @*/
192: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis,PetscTruth hold)
193: {
195: if (!axis) return(0);
196: axis->hold = hold;
197: return(0);
198: }
202: /*@
203: PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis
204:
205: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
207: Input Parameters:
208: + axis - the axis
209: . xmin,xmax - limits in x
210: - ymin,ymax - limits in y
212: Level: advanced
214: .seealso: PetscDrawAxisSetHoldLimits()
216: @*/
217: PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
218: {
220: if (!axis) return(0);
221: if (axis->hold) return(0);
222: axis->xlow = xmin;
223: axis->xhigh= xmax;
224: axis->ylow = ymin;
225: axis->yhigh= ymax;
226: return(0);
227: }
231: /*@
232: PetscDrawAxisDraw - PetscDraws an axis.
234: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
236: Input Parameter:
237: . axis - Axis structure
239: Level: advanced
241: Note:
242: This draws the actual axis. The limits etc have already been set.
243: By picking special routines for the ticks and labels, special
244: effects may be generated. These routines are part of the Axis
245: structure (axis).
246: @*/
247: PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
248: {
249: int i,ntick,numx,numy,ac = axis->ac,tc = axis->tc,cc = axis->cc,rank;
250: size_t len;
251: PetscReal tickloc[MAXSEGS],sep,h,w,tw,th,xl,xr,yl,yr;
252: char *p;
253: PetscDraw draw = axis->win;
257: if (!axis) return(0);
258: MPI_Comm_rank(axis->comm,&rank);
259: if (rank) return(0);
261: if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;}
262: if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;}
263: xl = axis->xlow; xr = axis->xhigh; yl = axis->ylow; yr = axis->yhigh;
264: PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
265: PetscDrawStringGetSize(draw,&tw,&th);
266: numx = (int)(.15*(xr-xl)/tw); if (numx > 6) numx = 6; if (numx< 2) numx = 2;
267: numy = (int)(.5*(yr-yl)/th); if (numy > 6) numy = 6; if (numy< 2) numy = 2;
268: xl -= 8*tw; xr += 2*tw; yl -= 2.5*th; yr += 2*th;
269: if (axis->xlabel) yl -= 2*th;
270: if (axis->ylabel) xl -= 2*tw;
271: PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
272: PetscDrawStringGetSize(draw,&tw,&th);
274: PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac);
275: PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac);
277: if (axis->toplabel) {
278: PetscStrlen(axis->toplabel,&len);
279: w = xl + .5*(xr - xl) - .5*len*tw;
280: h = axis->yhigh;
281: PetscDrawString(draw,w,h,cc,axis->toplabel);
282: }
284: /* PetscDraw the ticks and labels */
285: if (axis->xticks) {
286: (*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,MAXSEGS);
287: /* PetscDraw in tick marks */
288: for (i=0; i<ntick; i++) {
289: PetscDrawLine(draw,tickloc[i],axis->ylow-.5*th,tickloc[i],axis->ylow+.5*th,tc);
290: }
291: /* label ticks */
292: for (i=0; i<ntick; i++) {
293: if (axis->xlabelstr) {
294: if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
295: else if (i > 0) sep = tickloc[i] - tickloc[i-1];
296: else sep = 0.0;
297: (*axis->xlabelstr)(tickloc[i],sep,&p);
298: PetscStrlen(p,&len);
299: w = .5*len*tw;
300: PetscDrawString(draw,tickloc[i]-w,axis->ylow-1.2*th,cc,p);
301: }
302: }
303: }
304: if (axis->xlabel) {
305: PetscStrlen(axis->xlabel,&len);
306: w = xl + .5*(xr - xl) - .5*len*tw;
307: h = axis->ylow - 2.5*th;
308: PetscDrawString(draw,w,h,cc,axis->xlabel);
309: }
310: if (axis->yticks) {
311: (*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,MAXSEGS);
312: /* PetscDraw in tick marks */
313: for (i=0; i<ntick; i++) {
314: PetscDrawLine(draw,axis->xlow -.5*tw,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc);
315: }
316: /* label ticks */
317: for (i=0; i<ntick; i++) {
318: if (axis->ylabelstr) {
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: (*axis->xlabelstr)(tickloc[i],sep,&p);
323: PetscStrlen(p,&len);
324: w = axis->xlow - len * tw - 1.2*tw;
325: PetscDrawString(draw,w,tickloc[i]-.5*th,cc,p);
326: }
327: }
328: }
329: if (axis->ylabel) {
330: PetscStrlen(axis->ylabel,&len);
331: h = yl + .5*(yr - yl) + .5*len*th;
332: w = xl + .5*tw;
333: PetscDrawStringVertical(draw,w,h,cc,axis->ylabel);
334: }
335: return(0);
336: }
340: /*
341: Removes all zeros but one from .0000
342: */
343: static PetscErrorCode PetscStripAllZeros(char *buf)
344: {
346: size_t i,n;
349: PetscStrlen(buf,&n);
350: if (buf[0] != '.') return(0);
351: for (i=1; i<n; i++) {
352: if (buf[i] != '0') return(0);
353: }
354: buf[0] = '0';
355: buf[1] = 0;
356: return(0);
357: }
361: /*
362: Removes trailing zeros
363: */
364: static PetscErrorCode PetscStripTrailingZeros(char *buf)
365: {
367: char *found;
368: size_t i,n,m = PETSC_MAX_INT;
371: /* if there is an e in string DO NOT strip trailing zeros */
372: PetscStrchr(buf,'e',&found);
373: if (found) return(0);
375: PetscStrlen(buf,&n);
376: /* locate decimal point */
377: for (i=0; i<n; i++) {
378: if (buf[i] == '.') {m = i; break;}
379: }
380: /* if not decimal point then no zeros to remove */
381: if (m == PETSC_MAX_INT) return(0);
382: /* start at right end of string removing 0s */
383: for (i=n-1; i>m; i++) {
384: if (buf[i] != '0') return(0);
385: buf[i] = 0;
386: }
387: return(0);
388: }
392: /*
393: Removes leading 0 from 0.22 or -0.22
394: */
395: static PetscErrorCode PetscStripInitialZero(char *buf)
396: {
398: size_t i,n;
401: PetscStrlen(buf,&n);
402: if (buf[0] == '0') {
403: for (i=0; i<n; i++) {
404: buf[i] = buf[i+1];
405: }
406: } else if (buf[0] == '-' && buf[1] == '0') {
407: for (i=1; i<n; i++) {
408: buf[i] = buf[i+1];
409: }
410: }
411: return(0);
412: }
416: /*
417: Removes the extraneous zeros in numbers like 1.10000e6
418: */
419: static PetscErrorCode PetscStripZeros(char *buf)
420: {
422: size_t i,j,n;
425: PetscStrlen(buf,&n);
426: if (n<5) return(0);
427: for (i=1; i<n-1; i++) {
428: if (buf[i] == 'e' && buf[i-1] == '0') {
429: for (j=i; j<n+1; j++) buf[j-1] = buf[j];
430: PetscStripZeros(buf);
431: return(0);
432: }
433: }
434: return(0);
435: }
439: /*
440: Removes the plus in something like 1.1e+2
441: */
442: static PetscErrorCode PetscStripZerosPlus(char *buf)
443: {
445: size_t i,j,n;
448: PetscStrlen(buf,&n);
449: if (n<5) return(0);
450: for (i=1; i<n-2; i++) {
451: if (buf[i] == '+') {
452: if (buf[i+1] == '0') {
453: for (j=i+1; j<n+1; j++) buf[j-1] = buf[j+1];
454: return(0);
455: } else {
456: for (j=i+1; j<n+1; j++) buf[j] = buf[j+1];
457: return(0);
458: }
459: } else if (buf[i] == '-') {
460: if (buf[i+1] == '0') {
461: for (j=i+1; j<n+1; j++) buf[j] = buf[j+1];
462: return(0);
463: }
464: }
465: }
466: return(0);
467: }
471: /*
472: val is the label value. sep is the separation to the next (or previous)
473: label; this is useful in determining how many significant figures to
474: keep.
475: */
476: PetscErrorCode PetscADefLabel(PetscReal val,PetscReal sep,char **p)
477: {
478: static char buf[40];
479: char fmat[10];
481: int w,d;
482: PetscReal rval;
485: /* Find the string */
486: if (PetscAbsReal(val)/sep < 1.e-6) {
487: buf[0] = '0'; buf[1] = 0;
488: } else if (PetscAbsReal(val) < 1.0e6 && PetscAbsReal(val) > 1.e-4) {
489: /* Compute the number of digits */
490: w = 0;
491: d = 0;
492: if (sep > 0.0) {
493: d = (int)ceil(- log10 (sep));
494: if (d < 0) d = 0;
495: if (PetscAbsReal(val) < 1.0e-6*sep) {
496: /* This is the case where we are near zero and less than a small
497: fraction of the sep. In this case, we use 0 as the value */
498: val = 0.0;
499: w = d;
500: }
501: else if (!val) w = d;
502: else w = (int)(ceil(log10(PetscAbsReal(val))) + d);
503: if (w < 1) w ++;
504: if (val < 0) w ++;
505: }
507: PetscRint(val,&rval);
508: if (rval == val) {
509: if (w > 0) sprintf(fmat,"%%%dd",w);
510: else {PetscStrcpy(fmat,"%d");}
511: sprintf(buf,fmat,(int)val);
512: PetscStripInitialZero(buf);
513: PetscStripAllZeros(buf);
514: PetscStripTrailingZeros(buf);
515: } else {
516: /* The code used here is inappropriate for a val of 0, which
517: tends to print with an excessive numer of digits. In this
518: case, we should look at the next/previous values and
519: use those widths */
520: if (w > 0) sprintf(fmat,"%%%d.%dlf",w + 1,d);
521: else {PetscStrcpy(fmat,"%lf");}
522: sprintf(buf,fmat,val);
523: PetscStripInitialZero(buf);
524: PetscStripAllZeros(buf);
525: PetscStripTrailingZeros(buf);
526: }
527: } else {
528: sprintf(buf,"%e",val);
529: /* remove the extraneous 0 before the e */
530: PetscStripZeros(buf);
531: PetscStripZerosPlus(buf);
532: PetscStripInitialZero(buf);
533: PetscStripAllZeros(buf);
534: PetscStripTrailingZeros(buf);
535: }
536: *p =buf;
537: return(0);
538: }
542: /* Finds "nice" locations for the ticks */
543: PetscErrorCode PetscADefTicks(PetscReal low,PetscReal high,int num,int *ntick,PetscReal * tickloc,int maxtick)
544: {
546: int i,power;
547: PetscReal x = 0.0,base;
550: /* patch if low == high */
551: if (low == high) {
552: low -= .01;
553: high += .01;
554: }
556: /* if (PetscAbsReal(low-high) < 1.e-8) {
557: low -= .01;
558: high += .01;
559: } */
561: PetscAGetBase(low,high,num,&base,&power);
562: PetscAGetNice(low,base,-1,&x);
564: /* Values are of the form j * base */
565: /* Find the starting value */
566: if (x < low) x += base;
568: i = 0;
569: while (i < maxtick && x <= high) {
570: tickloc[i++] = x;
571: x += base;
572: }
573: *ntick = i;
575: if (i < 2 && num < 10) {
576: PetscADefTicks(low,high,num+1,ntick,tickloc,maxtick);
577: }
578: return(0);
579: }
581: #define EPS 1.e-6
585: static PetscErrorCode PetscExp10(PetscReal d,PetscReal *result)
586: {
588: *result = pow(10.0,d);
589: return(0);
590: }
594: static PetscErrorCode PetscMod(PetscReal x,PetscReal y,PetscReal *result)
595: {
596: int i;
599: i = ((int)x) / ((int)y);
600: x = x - i * y;
601: while (x > y) x -= y;
602: *result = x;
603: return(0);
604: }
608: static PetscErrorCode PetscCopysign(PetscReal a,PetscReal b,PetscReal *result)
609: {
611: if (b >= 0) *result = a;
612: else *result = -a;
613: return(0);
614: }
618: /*
619: Given a value "in" and a "base", return a nice value.
620: based on "sign", extend up (+1) or down (-1)
621: */
622: static PetscErrorCode PetscAGetNice(PetscReal in,PetscReal base,int sign,PetscReal *result)
623: {
624: PetscReal etmp,s,s2,m;
628: PetscCopysign (0.5,(double)sign,&s);
629: etmp = in / base + 0.5 + s;
630: PetscCopysign (0.5,etmp,&s);
631: PetscCopysign (EPS * etmp,(double)sign,&s2);
632: etmp = etmp - 0.5 + s - s2;
633: PetscMod(etmp,1.0,&m);
634: etmp = base * (etmp - m);
635: *result = etmp;
636: return(0);
637: }
641: static PetscErrorCode PetscAGetBase(PetscReal vmin,PetscReal vmax,int num,PetscReal*Base,int*power)
642: {
643: PetscReal base,ftemp,e10;
644: static PetscReal base_try[5] = {10.0,5.0,2.0,1.0,0.5};
645: PetscErrorCode ierr;
646: int i;
649: /* labels of the form n * BASE */
650: /* get an approximate value for BASE */
651: base = (vmax - vmin) / (double)(num + 1);
653: /* make it of form m x 10^power, m in [1.0, 10) */
654: if (base <= 0.0) {
655: base = PetscAbsReal(vmin);
656: if (base < 1.0) base = 1.0;
657: }
658: ftemp = log10((1.0 + EPS) * base);
659: if (ftemp < 0.0) ftemp -= 1.0;
660: *power = (int)ftemp;
661: PetscExp10((double)- *power,&e10);
662: base = base * e10;
663: if (base < 1.0) base = 1.0;
664: /* now reduce it to one of 1, 2, or 5 */
665: for (i=1; i<5; i++) {
666: if (base >= base_try[i]) {
667: PetscExp10((double)*power,&e10);
668: base = base_try[i-1] * e10;
669: if (i == 1) *power = *power + 1;
670: break;
671: }
672: }
673: *Base = base;
674: return(0);
675: }