Actual source code: axisc.c
1: #include <petsc/private/drawimpl.h>
3: #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20
4: PetscClassId PETSC_DRAWAXIS_CLASSID = 0;
6: /*@
7: PetscDrawAxisCreate - Generate the axis data structure.
9: Collective
11: Input Parameters:
12: . win - `PetscDraw` object where axis to to be made
14: Output Parameter:
15: . axis - the axis datastructure
17: Note:
18: The MPI communicator that owns the underlying draw object owns the `PetscDrawAxis` object, but calls to set `PetscDrawAxis` options are
19: ignored by all processes except the first MPI rank in the communicator
21: Level: advanced
23: .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawLGGetAxis()`, `PetscDrawSPGetAxis()`,
24: `PetscDrawHGGetAxis()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisDestroy()`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetHoldLimits()`,
25: `PetscDrawAxisDraw()`
26: @*/
27: PetscErrorCode PetscDrawAxisCreate(PetscDraw draw, PetscDrawAxis *axis)
28: {
29: PetscDrawAxis ad;
34: PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL);
36: PetscObjectReference((PetscObject)draw);
37: ad->win = draw;
39: ad->xticks = PetscADefTicks;
40: ad->yticks = PetscADefTicks;
41: ad->xlabelstr = PetscADefLabel;
42: ad->ylabelstr = PetscADefLabel;
43: ad->ac = PETSC_DRAW_BLACK;
44: ad->tc = PETSC_DRAW_BLACK;
45: ad->cc = PETSC_DRAW_BLACK;
46: ad->xlabel = NULL;
47: ad->ylabel = NULL;
48: ad->toplabel = NULL;
50: *axis = ad;
51: return 0;
52: }
54: /*@
55: PetscDrawAxisDestroy - Frees the space used by an axis structure.
57: Collective
59: Input Parameters:
60: . axis - the axis context
62: Level: advanced
64: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`
65: @*/
66: PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis)
67: {
68: if (!*axis) return 0;
70: if (--((PetscObject)(*axis))->refct > 0) {
71: *axis = NULL;
72: return 0;
73: }
75: PetscFree((*axis)->toplabel);
76: PetscFree((*axis)->xlabel);
77: PetscFree((*axis)->ylabel);
78: PetscDrawDestroy(&(*axis)->win);
79: PetscHeaderDestroy(axis);
80: return 0;
81: }
83: /*@
84: PetscDrawAxisSetColors - Sets the colors to be used for the axis,
85: tickmarks, and text.
87: Logically Collective
89: Input Parameters:
90: + axis - the axis
91: . ac - the color of the axis lines
92: . tc - the color of the tick marks
93: - cc - the color of the text strings
95: Level: advanced
97: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
98: @*/
99: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc)
100: {
105: axis->ac = ac;
106: axis->tc = tc;
107: axis->cc = cc;
108: return 0;
109: }
111: /*@C
112: PetscDrawAxisSetLabels - Sets the x and y axis labels.
114: Logically Collective
116: Input Parameters:
117: + axis - the axis
118: . top - the label at the top of the image
119: - xlabel,ylabel - the labes for the x and y axis
121: Notes:
122: Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`
124: There should be no newlines in the arguments
126: Level: advanced
128: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
129: @*/
130: PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[])
131: {
133: PetscFree(axis->xlabel);
134: PetscFree(axis->ylabel);
135: PetscFree(axis->toplabel);
136: PetscStrallocpy(xlabel, &axis->xlabel);
137: PetscStrallocpy(ylabel, &axis->ylabel);
138: PetscStrallocpy(top, &axis->toplabel);
139: return 0;
140: }
142: /*@
143: PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis
145: Logically Collective
147: Input Parameters:
148: + axis - the axis
149: . xmin,xmax - limits in x
150: - ymin,ymax - limits in y
152: Options Database Key:
153: . -drawaxis_hold - hold the initial set of axis limits for future plotting
155: Level: advanced
157: .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
158: @*/
159: PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax)
160: {
162: if (axis->hold) return 0;
163: axis->xlow = xmin;
164: axis->xhigh = xmax;
165: axis->ylow = ymin;
166: axis->yhigh = ymax;
167: PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold);
168: return 0;
169: }
171: /*@
172: PetscDrawAxisGetLimits - Gets the limits (in user coords) of the axis
174: Not Collective
176: Input Parameters:
177: + axis - the axis
178: . xmin,xmax - limits in x
179: - ymin,ymax - limits in y
181: Level: advanced
183: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
184: @*/
185: PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax)
186: {
188: if (xmin) *xmin = axis->xlow;
189: if (xmax) *xmax = axis->xhigh;
190: if (ymin) *ymin = axis->ylow;
191: if (ymax) *ymax = axis->yhigh;
192: return 0;
193: }
195: /*@
196: PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called
197: again
199: Logically Collective
201: Input Parameters:
202: + axis - the axis
203: - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed
205: Level: advanced
207: Note:
208: Once this has been called with `PETSC_TRUE` the limits will not change if you call
209: `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE`
211: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
212: @*/
213: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold)
214: {
217: axis->hold = hold;
218: return 0;
219: }
221: /*@
222: PetscDrawAxisDraw - draws an axis.
224: Collective
226: Input Parameter:
227: . axis - `PetscDrawAxis` structure
229: Level: advanced
231: Note:
232: This draws the actual axis. The limits etc have already been set.
233: By picking special routines for the ticks and labels, special
234: effects may be generated. These routines are part of the Axis
235: structure (axis).
237: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
238: @*/
239: PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
240: {
241: int i, ntick, numx, numy, ac, tc, cc;
242: PetscMPIInt rank;
243: size_t len, ytlen = 0;
244: PetscReal coors[4], tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th;
245: PetscReal xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0;
246: char *p;
247: PetscDraw draw;
248: PetscBool isnull;
251: PetscDrawIsNull(axis->win, &isnull);
252: if (isnull) return 0;
253: MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank);
255: draw = axis->win;
257: ac = axis->ac;
258: tc = axis->tc;
259: cc = axis->cc;
260: if (axis->xlow == axis->xhigh) {
261: axis->xlow -= .5;
262: axis->xhigh += .5;
263: }
264: if (axis->ylow == axis->yhigh) {
265: axis->ylow -= .5;
266: axis->yhigh += .5;
267: }
269: PetscDrawCollectiveBegin(draw);
270: if (rank) goto finally;
272: /* get canonical string size */
273: PetscDrawSetCoordinates(draw, 0, 0, 1, 1);
274: PetscDrawStringGetSize(draw, &tw, &th);
275: /* lower spacing */
276: if (axis->xlabelstr) dyl += 1.5 * th;
277: if (axis->xlabel) dyl += 1.5 * th;
278: /* left spacing */
279: if (axis->ylabelstr) dxl += 7.5 * tw;
280: if (axis->ylabel) dxl += 2.0 * tw;
281: /* right and top spacing */
282: if (axis->xlabelstr) dxr = 2.5 * tw;
283: if (axis->ylabelstr) dyr = 0.5 * th;
284: if (axis->toplabel) dyr = 1.5 * th;
285: /* extra spacing */
286: dxl += 0.7 * tw;
287: dxr += 0.5 * tw;
288: dyl += 0.2 * th;
289: dyr += 0.2 * th;
290: /* determine coordinates */
291: xl = (dxl * axis->xhigh + dxr * axis->xlow - axis->xlow) / (dxl + dxr - 1);
292: xr = (dxl * axis->xhigh + dxr * axis->xlow - axis->xhigh) / (dxl + dxr - 1);
293: yl = (dyl * axis->yhigh + dyr * axis->ylow - axis->ylow) / (dyl + dyr - 1);
294: yr = (dyl * axis->yhigh + dyr * axis->ylow - axis->yhigh) / (dyl + dyr - 1);
295: PetscDrawSetCoordinates(draw, xl, yl, xr, yr);
296: PetscDrawStringGetSize(draw, &tw, &th);
298: /* PetscDraw the axis lines */
299: PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac);
300: PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac);
301: PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac);
302: PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac);
304: /* PetscDraw the top label */
305: if (axis->toplabel) {
306: PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;
307: PetscDrawStringCentered(draw, x, y, cc, axis->toplabel);
308: }
310: /* PetscDraw the X ticks and labels */
311: if (axis->xticks) {
312: numx = (int)(.15 * (axis->xhigh - axis->xlow) / tw);
313: numx = PetscClipInterval(numx, 2, 6);
314: (*axis->xticks)(axis->xlow, axis->xhigh, numx, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS);
315: /* PetscDraw in tick marks */
316: for (i = 0; i < ntick; i++) {
317: PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc);
318: PetscDrawLine(draw, tickloc[i], axis->yhigh, tickloc[i], axis->yhigh - .5 * th, tc);
319: }
320: /* label ticks */
321: if (axis->xlabelstr) {
322: for (i = 0; i < ntick; i++) {
323: if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
324: else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
325: else sep = 0.0;
326: (*axis->xlabelstr)(tickloc[i], sep, &p);
327: PetscDrawStringCentered(draw, tickloc[i], axis->ylow - 1.5 * th, cc, p);
328: }
329: }
330: }
331: if (axis->xlabel) {
332: PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->ylow - 1.5 * th;
333: if (axis->xlabelstr) y -= 1.5 * th;
334: PetscDrawStringCentered(draw, x, y, cc, axis->xlabel);
335: }
337: /* PetscDraw the Y ticks and labels */
338: if (axis->yticks) {
339: numy = (int)(.50 * (axis->yhigh - axis->ylow) / th);
340: numy = PetscClipInterval(numy, 2, 6);
341: (*axis->yticks)(axis->ylow, axis->yhigh, numy, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS);
342: /* PetscDraw in tick marks */
343: for (i = 0; i < ntick; i++) {
344: PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc);
345: PetscDrawLine(draw, axis->xhigh, tickloc[i], axis->xhigh - .5 * tw, tickloc[i], tc);
346: }
347: /* label ticks */
348: if (axis->ylabelstr) {
349: for (i = 0; i < ntick; i++) {
350: if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
351: else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
352: else sep = 0.0;
353: (*axis->ylabelstr)(tickloc[i], sep, &p);
354: PetscStrlen(p, &len);
355: ytlen = PetscMax(ytlen, len);
356: PetscDrawString(draw, axis->xlow - (len + .5) * tw, tickloc[i] - .5 * th, cc, p);
357: }
358: }
359: }
360: if (axis->ylabel) {
361: PetscReal x = axis->xlow - 2.0 * tw, y = (axis->ylow + axis->yhigh) / 2;
362: if (axis->ylabelstr) x -= (ytlen + .5) * tw;
363: PetscStrlen(axis->ylabel, &len);
364: PetscDrawStringVertical(draw, x, y + len * th / 2, cc, axis->ylabel);
365: }
367: PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]);
368: finally:
369: PetscDrawCollectiveEnd(draw);
370: MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw));
371: PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]);
372: return 0;
373: }
375: /*
376: Removes all zeros but one from .0000
377: */
378: PetscErrorCode PetscStripe0(char *buf)
379: {
380: size_t n;
381: PetscBool flg;
382: char *str;
384: PetscStrlen(buf, &n);
385: PetscStrendswith(buf, "e00", &flg);
386: if (flg) buf[n - 3] = 0;
387: PetscStrstr(buf, "e0", &str);
388: if (str) {
389: buf[n - 2] = buf[n - 1];
390: buf[n - 1] = 0;
391: }
392: PetscStrstr(buf, "e-0", &str);
393: if (str) {
394: buf[n - 2] = buf[n - 1];
395: buf[n - 1] = 0;
396: }
397: return 0;
398: }
400: /*
401: Removes all zeros but one from .0000
402: */
403: PetscErrorCode PetscStripAllZeros(char *buf)
404: {
405: size_t i, n;
407: PetscStrlen(buf, &n);
408: if (buf[0] != '.') return 0;
409: for (i = 1; i < n; i++) {
410: if (buf[i] != '0') return 0;
411: }
412: buf[0] = '0';
413: buf[1] = 0;
414: return 0;
415: }
417: /*
418: Removes trailing zeros
419: */
420: PetscErrorCode PetscStripTrailingZeros(char *buf)
421: {
422: char *found;
423: size_t i, n, m = PETSC_MAX_INT;
425: /* if there is an e in string DO NOT strip trailing zeros */
426: PetscStrchr(buf, 'e', &found);
427: if (found) return 0;
429: PetscStrlen(buf, &n);
430: /* locate decimal point */
431: for (i = 0; i < n; i++) {
432: if (buf[i] == '.') {
433: m = i;
434: break;
435: }
436: }
437: /* if not decimal point then no zeros to remove */
438: if (m == PETSC_MAX_INT) return 0;
439: /* start at right end of string removing 0s */
440: for (i = n - 1; i > m; i++) {
441: if (buf[i] != '0') return 0;
442: buf[i] = 0;
443: }
444: return 0;
445: }
447: /*
448: Removes leading 0 from 0.22 or -0.22
449: */
450: PetscErrorCode PetscStripInitialZero(char *buf)
451: {
452: size_t i, n;
454: PetscStrlen(buf, &n);
455: if (buf[0] == '0') {
456: for (i = 0; i < n; i++) buf[i] = buf[i + 1];
457: } else if (buf[0] == '-' && buf[1] == '0') {
458: for (i = 1; i < n; i++) buf[i] = buf[i + 1];
459: }
460: return 0;
461: }
463: /*
464: Removes the extraneous zeros in numbers like 1.10000e6
465: */
466: PetscErrorCode PetscStripZeros(char *buf)
467: {
468: size_t i, j, n;
470: PetscStrlen(buf, &n);
471: if (n < 5) return 0;
472: for (i = 1; i < n - 1; i++) {
473: if (buf[i] == 'e' && buf[i - 1] == '0') {
474: for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
475: PetscStripZeros(buf);
476: return 0;
477: }
478: }
479: return 0;
480: }
482: /*
483: Removes the plus in something like 1.1e+2 or 1.1e+02
484: */
485: PetscErrorCode PetscStripZerosPlus(char *buf)
486: {
487: size_t i, j, n;
489: PetscStrlen(buf, &n);
490: if (n < 5) return 0;
491: for (i = 1; i < n - 2; i++) {
492: if (buf[i] == '+') {
493: if (buf[i + 1] == '0') {
494: for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
495: return 0;
496: } else {
497: for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
498: return 0;
499: }
500: } else if (buf[i] == '-') {
501: if (buf[i + 1] == '0') {
502: for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
503: return 0;
504: }
505: }
506: }
507: return 0;
508: }