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: }