Actual source code: axis.c
1: /*
2: This file contains a simple routine for generating a 2-d axis.
3: */
5: #include petsc.h
7: PetscCookie DRAWAXIS_COOKIE = 0;
9: struct _p_DrawAxis {
10: PETSCHEADER(int)
11: PetscReal xlow,ylow,xhigh,yhigh; /* User - coord limits */
12: PetscErrorCode (*ylabelstr)(PetscReal,PetscReal,char **);/* routines to generate labels */
13: PetscErrorCode (*xlabelstr)(PetscReal,PetscReal,char **);
14: PetscErrorCode (*xticks)(PetscReal,PetscReal,int,int*,PetscReal*,int);
15: PetscErrorCode (*yticks)(PetscReal,PetscReal,int,int*,PetscReal*,int);
16: /* location and size of ticks */
17: PetscDraw win;
18: int ac,tc,cc; /* axis,tick, character color */
19: char *xlabel,*ylabel,*toplabel;
20: PetscTruth hold;
21: };
23: #define MAXSEGS 20
25: EXTERN PetscErrorCode PetscADefTicks(PetscReal,PetscReal,int,int*,PetscReal*,int);
26: EXTERN PetscErrorCode PetscADefLabel(PetscReal,PetscReal,char**);
27: static PetscErrorCode PetscAGetNice(PetscReal,PetscReal,int,PetscReal*);
28: static PetscErrorCode PetscAGetBase(PetscReal,PetscReal,int,PetscReal*,int*);
32: static PetscErrorCode PetscRint(PetscReal x,PetscReal *result)
33: {
35: if (x > 0) *result = floor(x + 0.5);
36: else *result = floor(x - 0.5);
37: return(0);
38: }
42: /*@C
43: PetscDrawAxisCreate - Generate the axis data structure.
45: Collective over PetscDraw
47: Input Parameters:
48: . win - PetscDraw object where axis to to be made
50: Ouput Parameters:
51: . axis - the axis datastructure
53: Level: advanced
55: @*/
56: PetscErrorCode PetscDrawAxisCreate(PetscDraw draw,PetscDrawAxis *axis)
57: {
58: PetscDrawAxis ad;
59: PetscObject obj = (PetscObject)draw;
61: PetscTruth isnull;
66: PetscTypeCompare(obj,PETSC_DRAW_NULL,&isnull);
67: if (isnull) {
68: PetscDrawOpenNull(obj->comm,(PetscDraw*)axis);
69: (*axis)->win = draw;
70: return(0);
71: }
72: PetscHeaderCreate(ad,_p_DrawAxis,int,DRAWAXIS_COOKIE,0,"PetscDrawAxis",obj->comm,PetscDrawAxisDestroy,0);
73: PetscLogObjectCreate(ad);
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: /*@C
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: PetscLogObjectDestroy(axis);
116: PetscHeaderDestroy(axis);
117: return(0);
118: }
122: /*@
123: PetscDrawAxisSetColors - Sets the colors to be used for the axis,
124: tickmarks, and text.
126: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
128: Input Parameters:
129: + axis - the axis
130: . ac - the color of the axis lines
131: . tc - the color of the tick marks
132: - cc - the color of the text strings
134: Level: advanced
136: @*/
137: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis,int ac,int tc,int cc)
138: {
140: if (!axis) return(0);
141: axis->ac = ac; axis->tc = tc; axis->cc = cc;
142: return(0);
143: }
147: /*@C
148: PetscDrawAxisSetLabels - Sets the x and y axis labels.
150: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
152: Input Parameters:
153: + axis - the axis
154: . top - the label at the top of the image
155: - xlabel,ylabel - the labes for the x and y axis
157: Level: advanced
159: @*/
160: PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis,const char top[],const char xlabel[],const char ylabel[])
161: {
165: if (!axis) return(0);
166: PetscStrallocpy(xlabel,&axis->xlabel);
167: PetscStrallocpy(ylabel,&axis->ylabel);
168: PetscStrallocpy(top,&axis->toplabel);
169: return(0);
170: }
174: /*@
175: PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called
176: again
177:
178: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
180: Input Parameters:
181: + axis - the axis
182: - hold - PETSC_TRUE - hold current limits, PETSC_FALSE allow limits to be changed
184: Level: advanced
186: Notes:
187: Once this has been called with PETSC_TRUE the limits will not change if you call
188: PetscDrawAxisSetLimits() until you call this with PETSC_FALSE
189:
190: .seealso: PetscDrawAxisSetLimits()
192: @*/
193: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis,PetscTruth hold)
194: {
196: if (!axis) return(0);
197: axis->hold = hold;
198: return(0);
199: }
203: /*@
204: PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis
205:
206: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
208: Input Parameters:
209: + axis - the axis
210: . xmin,xmax - limits in x
211: - ymin,ymax - limits in y
213: Level: advanced
215: .seealso: PetscDrawAxisSetHoldLimits()
217: @*/
218: PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis,PetscReal xmin,PetscReal xmax,PetscReal ymin,PetscReal ymax)
219: {
221: if (!axis) return(0);
222: if (axis->hold) return(0);
223: axis->xlow = xmin;
224: axis->xhigh= xmax;
225: axis->ylow = ymin;
226: axis->yhigh= ymax;
227: return(0);
228: }
232: /*@
233: PetscDrawAxisDraw - PetscDraws an axis.
235: Not Collective (ignored on all processors except processor 0 of PetscDrawAxis)
237: Input Parameter:
238: . axis - Axis structure
240: Level: advanced
242: Note:
243: This draws the actual axis. The limits etc have already been set.
244: By picking special routines for the ticks and labels, special
245: effects may be generated. These routines are part of the Axis
246: structure (axis).
247: @*/
248: PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
249: {
250: int i,ntick,numx,numy,ac = axis->ac,tc = axis->tc,cc = axis->cc,rank;
251: size_t len;
252: PetscReal tickloc[MAXSEGS],sep,h,w,tw,th,xl,xr,yl,yr;
253: char *p;
254: PetscDraw draw = axis->win;
258: if (!axis) return(0);
259: MPI_Comm_rank(axis->comm,&rank);
260: if (rank) return(0);
262: if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;}
263: if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;}
264: xl = axis->xlow; xr = axis->xhigh; yl = axis->ylow; yr = axis->yhigh;
265: PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
266: PetscDrawStringGetSize(draw,&tw,&th);
267: numx = (int)(.15*(xr-xl)/tw); if (numx > 6) numx = 6; if (numx< 2) numx = 2;
268: numy = (int)(.5*(yr-yl)/th); if (numy > 6) numy = 6; if (numy< 2) numy = 2;
269: xl -= 8*tw; xr += 2*tw; yl -= 2.5*th; yr += 2*th;
270: if (axis->xlabel) yl -= 2*th;
271: if (axis->ylabel) xl -= 2*tw;
272: PetscDrawSetCoordinates(draw,xl,yl,xr,yr);
273: PetscDrawStringGetSize(draw,&tw,&th);
275: PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac);
276: PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac);
278: if (axis->toplabel) {
279: PetscStrlen(axis->toplabel,&len);
280: w = xl + .5*(xr - xl) - .5*len*tw;
281: h = axis->yhigh;
282: PetscDrawString(draw,w,h,cc,axis->toplabel);
283: }
285: /* PetscDraw the ticks and labels */
286: if (axis->xticks) {
287: (*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,MAXSEGS);
288: /* PetscDraw in tick marks */
289: for (i=0; i<ntick; i++) {
290: PetscDrawLine(draw,tickloc[i],axis->ylow-.5*th,tickloc[i],axis->ylow+.5*th,tc);
291: }
292: /* label ticks */
293: for (i=0; i<ntick; i++) {
294: if (axis->xlabelstr) {
295: if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i];
296: else if (i > 0) sep = tickloc[i] - tickloc[i-1];
297: else sep = 0.0;
298: (*axis->xlabelstr)(tickloc[i],sep,&p);
299: PetscStrlen(p,&len);
300: w = .5*len*tw;
301: PetscDrawString(draw,tickloc[i]-w,axis->ylow-1.2*th,cc,p);
302: }
303: }
304: }
305: if (axis->xlabel) {
306: PetscStrlen(axis->xlabel,&len);
307: w = xl + .5*(xr - xl) - .5*len*tw;
308: h = axis->ylow - 2.5*th;
309: PetscDrawString(draw,w,h,cc,axis->xlabel);
310: }
311: if (axis->yticks) {
312: (*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,MAXSEGS);
313: /* PetscDraw in tick marks */
314: for (i=0; i<ntick; i++) {
315: PetscDrawLine(draw,axis->xlow -.5*tw,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc);
316: }
317: /* label ticks */
318: for (i=0; i<ntick; i++) {
319: if (axis->ylabelstr) {
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: (*axis->xlabelstr)(tickloc[i],sep,&p);
324: PetscStrlen(p,&len);
325: w = axis->xlow - len * tw - 1.2*tw;
326: PetscDrawString(draw,w,tickloc[i]-.5*th,cc,p);
327: }
328: }
329: }
330: if (axis->ylabel) {
331: PetscStrlen(axis->ylabel,&len);
332: h = yl + .5*(yr - yl) + .5*len*th;
333: w = xl + .5*tw;
334: PetscDrawStringVertical(draw,w,h,cc,axis->ylabel);
335: }
336: return(0);
337: }
341: /*
342: Removes all zeros but one from .0000
343: */
344: static PetscErrorCode PetscStripAllZeros(char *buf)
345: {
347: size_t i,n;
350: PetscStrlen(buf,&n);
351: if (buf[0] != '.') return(0);
352: for (i=1; i<n; i++) {
353: if (buf[i] != '0') return(0);
354: }
355: buf[0] = '0';
356: buf[1] = 0;
357: return(0);
358: }
362: /*
363: Removes trailing zeros
364: */
365: static PetscErrorCode PetscStripTrailingZeros(char *buf)
366: {
368: char *found;
369: size_t i,n,m = PETSC_MAX_INT;
372: /* if there is an e in string DO NOT strip trailing zeros */
373: PetscStrchr(buf,'e',&found);
374: if (found) return(0);
376: PetscStrlen(buf,&n);
377: /* locate decimal point */
378: for (i=0; i<n; i++) {
379: if (buf[i] == '.') {m = i; break;}
380: }
381: /* if not decimal point then no zeros to remove */
382: if (m == PETSC_MAX_INT) return(0);
383: /* start at right end of string removing 0s */
384: for (i=n-1; i>m; i++) {
385: if (buf[i] != '0') return(0);
386: buf[i] = 0;
387: }
388: return(0);
389: }
393: /*
394: Removes leading 0 from 0.22 or -0.22
395: */
396: static PetscErrorCode PetscStripInitialZero(char *buf)
397: {
399: size_t i,n;
402: PetscStrlen(buf,&n);
403: if (buf[0] == '0') {
404: for (i=0; i<n; i++) {
405: buf[i] = buf[i+1];
406: }
407: } else if (buf[0] == '-' && buf[1] == '0') {
408: for (i=1; i<n; i++) {
409: buf[i] = buf[i+1];
410: }
411: }
412: return(0);
413: }
417: /*
418: Removes the extraneous zeros in numbers like 1.10000e6
419: */
420: static PetscErrorCode PetscStripZeros(char *buf)
421: {
423: size_t i,j,n;
426: PetscStrlen(buf,&n);
427: if (n<5) return(0);
428: for (i=1; i<n-1; i++) {
429: if (buf[i] == 'e' && buf[i-1] == '0') {
430: for (j=i; j<n+1; j++) buf[j-1] = buf[j];
431: PetscStripZeros(buf);
432: return(0);
433: }
434: }
435: return(0);
436: }
440: /*
441: Removes the plus in something like 1.1e+2
442: */
443: static PetscErrorCode PetscStripZerosPlus(char *buf)
444: {
446: size_t i,j,n;
449: PetscStrlen(buf,&n);
450: if (n<5) return(0);
451: for (i=1; i<n-2; i++) {
452: if (buf[i] == '+') {
453: if (buf[i+1] == '0') {
454: for (j=i+1; j<n+1; j++) buf[j-1] = buf[j+1];
455: return(0);
456: } else {
457: for (j=i+1; j<n+1; j++) buf[j] = buf[j+1];
458: return(0);
459: }
460: } else if (buf[i] == '-') {
461: if (buf[i+1] == '0') {
462: for (j=i+1; j<n+1; j++) buf[j] = buf[j+1];
463: return(0);
464: }
465: }
466: }
467: return(0);
468: }
472: /*
473: val is the label value. sep is the separation to the next (or previous)
474: label; this is useful in determining how many significant figures to
475: keep.
476: */
477: PetscErrorCode PetscADefLabel(PetscReal val,PetscReal sep,char **p)
478: {
479: static char buf[40];
480: char fmat[10];
482: int w,d;
483: PetscReal rval;
486: /* Find the string */
487: if (PetscAbsReal(val)/sep < 1.e-6) {
488: buf[0] = '0'; buf[1] = 0;
489: } else if (PetscAbsReal(val) < 1.0e6 && PetscAbsReal(val) > 1.e-4) {
490: /* Compute the number of digits */
491: w = 0;
492: d = 0;
493: if (sep > 0.0) {
494: d = (int)ceil(- log10 (sep));
495: if (d < 0) d = 0;
496: if (PetscAbsReal(val) < 1.0e-6*sep) {
497: /* This is the case where we are near zero and less than a small
498: fraction of the sep. In this case, we use 0 as the value */
499: val = 0.0;
500: w = d;
501: }
502: else if (!val) w = d;
503: else w = (int)(ceil(log10(PetscAbsReal(val))) + d);
504: if (w < 1) w ++;
505: if (val < 0) w ++;
506: }
508: PetscRint(val,&rval);
509: if (rval == val) {
510: if (w > 0) sprintf(fmat,"%%%dd",w);
511: else {PetscStrcpy(fmat,"%d");}
512: sprintf(buf,fmat,(int)val);
513: PetscStripInitialZero(buf);
514: PetscStripAllZeros(buf);
515: PetscStripTrailingZeros(buf);
516: } else {
517: /* The code used here is inappropriate for a val of 0, which
518: tends to print with an excessive numer of digits. In this
519: case, we should look at the next/previous values and
520: use those widths */
521: if (w > 0) sprintf(fmat,"%%%d.%dlf",w + 1,d);
522: else {PetscStrcpy(fmat,"%lf");}
523: sprintf(buf,fmat,val);
524: PetscStripInitialZero(buf);
525: PetscStripAllZeros(buf);
526: PetscStripTrailingZeros(buf);
527: }
528: } else {
529: sprintf(buf,"%e",val);
530: /* remove the extraneous 0 before the e */
531: PetscStripZeros(buf);
532: PetscStripZerosPlus(buf);
533: PetscStripInitialZero(buf);
534: PetscStripAllZeros(buf);
535: PetscStripTrailingZeros(buf);
536: }
537: *p =buf;
538: return(0);
539: }
543: /* Finds "nice" locations for the ticks */
544: PetscErrorCode PetscADefTicks(PetscReal low,PetscReal high,int num,int *ntick,PetscReal * tickloc,int maxtick)
545: {
547: int i,power;
548: PetscReal x,base;
551: /* patch if low == high */
552: if (low == high) {
553: low -= .01;
554: high += .01;
555: }
557: /* if (PetscAbsReal(low-high) < 1.e-8) {
558: low -= .01;
559: high += .01;
560: } */
562: PetscAGetBase(low,high,num,&base,&power);
563: PetscAGetNice(low,base,-1,&x);
565: /* Values are of the form j * base */
566: /* Find the starting value */
567: if (x < low) x += base;
569: i = 0;
570: while (i < maxtick && x <= high) {
571: tickloc[i++] = x;
572: x += base;
573: }
574: *ntick = i;
576: if (i < 2 && num < 10) {
577: PetscADefTicks(low,high,num+1,ntick,tickloc,maxtick);
578: }
579: return(0);
580: }
582: #define EPS 1.e-6
586: static PetscErrorCode PetscExp10(PetscReal d,PetscReal *result)
587: {
589: *result = pow(10.0,d);
590: return(0);
591: }
595: static PetscErrorCode PetscMod(PetscReal x,PetscReal y,PetscReal *result)
596: {
597: int i;
600: i = ((int)x) / ((int)y);
601: x = x - i * y;
602: while (x > y) x -= y;
603: *result = x;
604: return(0);
605: }
609: static PetscErrorCode PetscCopysign(PetscReal a,PetscReal b,PetscReal *result)
610: {
612: if (b >= 0) *result = a;
613: else *result = -a;
614: return(0);
615: }
619: /*
620: Given a value "in" and a "base", return a nice value.
621: based on "sign", extend up (+1) or down (-1)
622: */
623: static PetscErrorCode PetscAGetNice(PetscReal in,PetscReal base,int sign,PetscReal *result)
624: {
625: PetscReal etmp,s,s2,m;
629: PetscCopysign (0.5,(double)sign,&s);
630: etmp = in / base + 0.5 + s;
631: PetscCopysign (0.5,etmp,&s);
632: PetscCopysign (EPS * etmp,(double)sign,&s2);
633: etmp = etmp - 0.5 + s - s2;
634: PetscMod(etmp,1.0,&m);
635: etmp = base * (etmp - m);
636: *result = etmp;
637: return(0);
638: }
642: static PetscErrorCode PetscAGetBase(PetscReal vmin,PetscReal vmax,int num,PetscReal*Base,int*power)
643: {
644: PetscReal base,ftemp,e10;
645: static PetscReal base_try[5] = {10.0,5.0,2.0,1.0,0.5};
646: PetscErrorCode ierr;
647: int i;
650: /* labels of the form n * BASE */
651: /* get an approximate value for BASE */
652: base = (vmax - vmin) / (double)(num + 1);
654: /* make it of form m x 10^power, m in [1.0, 10) */
655: if (base <= 0.0) {
656: base = PetscAbsReal(vmin);
657: if (base < 1.0) base = 1.0;
658: }
659: ftemp = log10((1.0 + EPS) * base);
660: if (ftemp < 0.0) ftemp -= 1.0;
661: *power = (int)ftemp;
662: PetscExp10((double)- *power,&e10);
663: base = base * e10;
664: if (base < 1.0) base = 1.0;
665: /* now reduce it to one of 1, 2, or 5 */
666: for (i=1; i<5; i++) {
667: if (base >= base_try[i]) {
668: PetscExp10((double)*power,&e10);
669: base = base_try[i-1] * e10;
670: if (i == 1) *power = *power + 1;
671: break;
672: }
673: }
674: *Base = base;
675: return(0);
676: }