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