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 Parameter:
12: . draw - `PetscDraw` object where axis 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;
31: PetscFunctionBegin;
33: PetscAssertPointer(axis, 2);
35: PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL));
36: PetscCall(PetscObjectReference((PetscObject)draw));
37: ad->win = draw;
38: ad->xticks = PetscADefTicks;
39: ad->yticks = PetscADefTicks;
40: ad->xlabelstr = PetscADefLabel;
41: ad->ylabelstr = PetscADefLabel;
42: ad->ac = PETSC_DRAW_BLACK;
43: ad->tc = PETSC_DRAW_BLACK;
44: ad->cc = PETSC_DRAW_BLACK;
45: ad->xlabel = NULL;
46: ad->ylabel = NULL;
47: ad->toplabel = NULL;
48: *axis = ad;
49: PetscFunctionReturn(PETSC_SUCCESS);
50: }
52: /*@
53: PetscDrawAxisDestroy - Frees the space used by an axis structure.
55: Collective
57: Input Parameter:
58: . axis - the axis context
60: Level: advanced
62: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`
63: @*/
64: PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis)
65: {
66: PetscFunctionBegin;
67: if (!*axis) PetscFunctionReturn(PETSC_SUCCESS);
69: if (--((PetscObject)*axis)->refct > 0) {
70: *axis = NULL;
71: PetscFunctionReturn(PETSC_SUCCESS);
72: }
74: PetscCall(PetscFree((*axis)->toplabel));
75: PetscCall(PetscFree((*axis)->xlabel));
76: PetscCall(PetscFree((*axis)->ylabel));
77: PetscCall(PetscDrawDestroy(&(*axis)->win));
78: PetscCall(PetscHeaderDestroy(axis));
79: PetscFunctionReturn(PETSC_SUCCESS);
80: }
82: /*@
83: PetscDrawAxisSetColors - Sets the colors to be used for the axis,
84: tickmarks, and text.
86: Logically Collective
88: Input Parameters:
89: + axis - the axis
90: . ac - the color of the axis lines
91: . tc - the color of the tick marks
92: - cc - the color of the text strings
94: Level: advanced
96: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
97: @*/
98: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc)
99: {
100: PetscFunctionBegin;
105: axis->ac = ac;
106: axis->tc = tc;
107: axis->cc = cc;
108: PetscFunctionReturn(PETSC_SUCCESS);
109: }
111: /*@
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 - the x axis label
120: - ylabel - the y axis label
122: Level: advanced
124: Notes:
125: Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`
127: There should be no newlines in the arguments
129: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
130: @*/
131: PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[])
132: {
133: PetscFunctionBegin;
135: PetscCall(PetscFree(axis->xlabel));
136: PetscCall(PetscFree(axis->ylabel));
137: PetscCall(PetscFree(axis->toplabel));
138: PetscCall(PetscStrallocpy(xlabel, &axis->xlabel));
139: PetscCall(PetscStrallocpy(ylabel, &axis->ylabel));
140: PetscCall(PetscStrallocpy(top, &axis->toplabel));
141: PetscFunctionReturn(PETSC_SUCCESS);
142: }
144: /*@
145: PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis
147: Logically Collective
149: Input Parameters:
150: + axis - the axis
151: . xmin - the lower x limit
152: . xmax - the upper x limit
153: . ymin - the lower y limit
154: - ymax - the upper y limit
156: Options Database Key:
157: . -drawaxis_hold - hold the initial set of axis limits for future plotting
159: Level: advanced
161: .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
162: @*/
163: PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax)
164: {
165: PetscFunctionBegin;
167: if (axis->hold) PetscFunctionReturn(PETSC_SUCCESS);
168: axis->xlow = xmin;
169: axis->xhigh = xmax;
170: axis->ylow = ymin;
171: axis->yhigh = ymax;
172: PetscCall(PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold));
173: PetscFunctionReturn(PETSC_SUCCESS);
174: }
176: /*@
177: PetscDrawAxisGetLimits - Gets the limits (in user coords) of the axis
179: Not Collective
181: Input Parameters:
182: + axis - the axis
183: . xmin - the lower x limit
184: . xmax - the upper x limit
185: . ymin - the lower y limit
186: - ymax - the upper y limit
188: Level: advanced
190: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
191: @*/
192: PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax)
193: {
194: PetscFunctionBegin;
196: if (xmin) *xmin = axis->xlow;
197: if (xmax) *xmax = axis->xhigh;
198: if (ymin) *ymin = axis->ylow;
199: if (ymax) *ymax = axis->yhigh;
200: PetscFunctionReturn(PETSC_SUCCESS);
201: }
203: /*@
204: PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called
205: again
207: Logically Collective
209: Input Parameters:
210: + axis - the axis
211: - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed
213: Level: advanced
215: Note:
216: Once this has been called with `PETSC_TRUE` the limits will not change if you call
217: `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE`
219: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
220: @*/
221: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold)
222: {
223: PetscFunctionBegin;
226: axis->hold = hold;
227: PetscFunctionReturn(PETSC_SUCCESS);
228: }
230: #if defined(__GNUC__) && !defined(__clang__)
231: #pragma GCC diagnostic push
232: #pragma GCC diagnostic ignored "-Wclobbered"
233: #endif
234: /*@
235: PetscDrawAxisDraw - draws an axis.
237: Collective
239: Input Parameter:
240: . axis - `PetscDrawAxis` structure
242: Level: advanced
244: Note:
245: This draws the actual axis. The limits etc have already been set.
246: By picking special routines for the ticks and labels, special
247: effects may be generated. These routines are part of the Axis
248: structure (axis).
250: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
251: @*/
252: PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
253: {
254: int i, ntick, numx, numy, ac, tc, cc;
255: PetscMPIInt rank;
256: size_t len, ytlen = 0;
257: PetscReal coors[4] = {0, 0, 0, 0}, tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th;
258: PetscReal xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0;
259: char *p;
260: PetscDraw draw;
261: PetscBool isnull;
263: PetscFunctionBegin;
265: PetscCall(PetscDrawIsNull(axis->win, &isnull));
266: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
267: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank));
269: draw = axis->win;
271: ac = axis->ac;
272: tc = axis->tc;
273: cc = axis->cc;
274: if (axis->xlow == axis->xhigh) {
275: axis->xlow -= .5;
276: axis->xhigh += .5;
277: }
278: if (axis->ylow == axis->yhigh) {
279: axis->ylow -= .5;
280: axis->yhigh += .5;
281: }
283: PetscDrawCollectiveBegin(draw);
284: if (rank) goto finally;
286: /* get canonical string size */
287: PetscCall(PetscDrawSetCoordinates(draw, 0, 0, 1, 1));
288: PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
289: /* lower spacing */
290: if (axis->xlabelstr) dyl += 1.5 * th;
291: if (axis->xlabel) dyl += 1.5 * th;
292: /* left spacing */
293: if (axis->ylabelstr) dxl += 7.5 * tw;
294: if (axis->ylabel) dxl += 2.0 * tw;
295: /* right and top spacing */
296: if (axis->xlabelstr) dxr = 2.5 * tw;
297: if (axis->ylabelstr) dyr = 0.5 * th;
298: if (axis->toplabel) dyr = 1.5 * th;
299: /* extra spacing */
300: dxl += 0.7 * tw;
301: dxr += 0.5 * tw;
302: dyl += 0.2 * th;
303: dyr += 0.2 * th;
304: /* determine coordinates */
305: xl = (dxl * axis->xhigh + dxr * axis->xlow - axis->xlow) / (dxl + dxr - 1);
306: xr = (dxl * axis->xhigh + dxr * axis->xlow - axis->xhigh) / (dxl + dxr - 1);
307: yl = (dyl * axis->yhigh + dyr * axis->ylow - axis->ylow) / (dyl + dyr - 1);
308: yr = (dyl * axis->yhigh + dyr * axis->ylow - axis->yhigh) / (dyl + dyr - 1);
309: PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr));
310: PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
312: /* PetscDraw the axis lines */
313: PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac));
314: PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac));
315: PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac));
316: PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac));
318: /* PetscDraw the top label */
319: if (axis->toplabel) {
320: PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;
322: PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel));
323: }
325: /* PetscDraw the X ticks and labels */
326: if (axis->xticks) {
327: numx = (int)(.15 * (axis->xhigh - axis->xlow) / tw);
328: numx = PetscClipInterval(numx, 2, 6);
329: PetscCall((*axis->xticks)(axis->xlow, axis->xhigh, numx, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
330: /* PetscDraw in tick marks */
331: for (i = 0; i < ntick; i++) {
332: PetscCall(PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc));
333: PetscCall(PetscDrawLine(draw, tickloc[i], axis->yhigh, tickloc[i], axis->yhigh - .5 * th, tc));
334: }
335: /* label ticks */
336: if (axis->xlabelstr) {
337: for (i = 0; i < ntick; i++) {
338: if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
339: else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
340: else sep = 0.0;
341: PetscCall((*axis->xlabelstr)(tickloc[i], sep, &p));
342: PetscCall(PetscDrawStringCentered(draw, tickloc[i], axis->ylow - 1.5 * th, cc, p));
343: }
344: }
345: }
346: if (axis->xlabel) {
347: PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->ylow - 1.5 * th;
349: if (axis->xlabelstr) y -= 1.5 * th;
350: PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel));
351: }
353: /* PetscDraw the Y ticks and labels */
354: if (axis->yticks) {
355: numy = (int)(.50 * (axis->yhigh - axis->ylow) / th);
356: numy = PetscClipInterval(numy, 2, 6);
357: PetscCall((*axis->yticks)(axis->ylow, axis->yhigh, numy, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
358: /* PetscDraw in tick marks */
359: for (i = 0; i < ntick; i++) {
360: PetscCall(PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc));
361: PetscCall(PetscDrawLine(draw, axis->xhigh, tickloc[i], axis->xhigh - .5 * tw, tickloc[i], tc));
362: }
363: /* label ticks */
364: if (axis->ylabelstr) {
365: for (i = 0; i < ntick; i++) {
366: if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
367: else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
368: else sep = 0.0;
369: PetscCall((*axis->ylabelstr)(tickloc[i], sep, &p));
370: PetscCall(PetscStrlen(p, &len));
371: ytlen = PetscMax(ytlen, len);
372: PetscCall(PetscDrawString(draw, axis->xlow - ((PetscReal)len + .5) * tw, tickloc[i] - .5 * th, cc, p));
373: }
374: }
375: }
376: if (axis->ylabel) {
377: PetscReal x = axis->xlow - 2.0 * tw, y = (axis->ylow + axis->yhigh) / 2;
379: if (axis->ylabelstr) x -= ((PetscReal)ytlen + .5) * tw;
380: PetscCall(PetscStrlen(axis->ylabel, &len));
381: PetscCall(PetscDrawStringVertical(draw, x, y + ((PetscReal)len) * th / 2, cc, axis->ylabel));
382: }
384: PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]));
385: finally:
386: PetscDrawCollectiveEnd(draw);
387: PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw)));
388: PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]));
389: PetscFunctionReturn(PETSC_SUCCESS);
390: }
391: #if defined(__GNUC__) && !defined(__clang__)
392: #pragma GCC diagnostic pop
393: #endif
395: /*
396: Removes all zeros but one from .0000
397: */
398: PetscErrorCode PetscStripe0(char *buf)
399: {
400: size_t n;
401: PetscBool flg;
402: char *str = NULL;
404: PetscFunctionBegin;
405: PetscCall(PetscStrlen(buf, &n));
406: PetscCall(PetscStrendswith(buf, "e00", &flg));
407: if (flg) buf[n - 3] = 0;
408: PetscCall(PetscStrstr(buf, "e0", &str));
409: if (str) {
410: buf[n - 2] = buf[n - 1];
411: buf[n - 1] = 0;
412: }
413: PetscCall(PetscStrstr(buf, "e-0", &str));
414: if (str) {
415: buf[n - 2] = buf[n - 1];
416: buf[n - 1] = 0;
417: }
418: PetscFunctionReturn(PETSC_SUCCESS);
419: }
421: /*
422: Removes all zeros but one from .0000
423: */
424: PetscErrorCode PetscStripAllZeros(char *buf)
425: {
426: size_t i, n;
428: PetscFunctionBegin;
429: PetscCall(PetscStrlen(buf, &n));
430: if (buf[0] != '.') PetscFunctionReturn(PETSC_SUCCESS);
431: for (i = 1; i < n; i++) {
432: if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
433: }
434: buf[0] = '0';
435: buf[1] = 0;
436: PetscFunctionReturn(PETSC_SUCCESS);
437: }
439: /*
440: Removes trailing zeros
441: */
442: #if (PETSC_SIZEOF_SIZE_T == 8)
443: #define MAX_SIZE_T PETSC_INT64_MAX
444: #else
445: #define MAX_SIZE_T INT_MAX
446: #endif
447: PetscErrorCode PetscStripTrailingZeros(char *buf)
448: {
449: char *found = NULL;
450: size_t i, n, m = MAX_SIZE_T;
452: PetscFunctionBegin;
453: /* if there is an e in string DO NOT strip trailing zeros */
454: PetscCall(PetscStrchr(buf, 'e', &found));
455: if (found) PetscFunctionReturn(PETSC_SUCCESS);
457: PetscCall(PetscStrlen(buf, &n));
458: /* locate decimal point */
459: for (i = 0; i < n; i++) {
460: if (buf[i] == '.') {
461: m = i;
462: break;
463: }
464: }
465: /* if not decimal point then no zeros to remove */
466: if (m == MAX_SIZE_T) PetscFunctionReturn(PETSC_SUCCESS);
467: /* start at right end of string removing 0s */
468: for (i = n - 1; i > m; i++) {
469: if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
470: buf[i] = 0;
471: }
472: PetscFunctionReturn(PETSC_SUCCESS);
473: }
475: /*
476: Removes leading 0 from 0.22 or -0.22
477: */
478: PetscErrorCode PetscStripInitialZero(char *buf)
479: {
480: size_t i, n;
482: PetscFunctionBegin;
483: PetscCall(PetscStrlen(buf, &n));
484: if (buf[0] == '0') {
485: for (i = 0; i < n; i++) buf[i] = buf[i + 1];
486: } else if (buf[0] == '-' && buf[1] == '0') {
487: for (i = 1; i < n; i++) buf[i] = buf[i + 1];
488: }
489: PetscFunctionReturn(PETSC_SUCCESS);
490: }
492: /*
493: Removes the extraneous zeros in numbers like 1.10000e6
494: */
495: PetscErrorCode PetscStripZeros(char *buf)
496: {
497: size_t i, j, n;
499: PetscFunctionBegin;
500: PetscCall(PetscStrlen(buf, &n));
501: if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
502: for (i = 1; i < n - 1; i++) {
503: if (buf[i] == 'e' && buf[i - 1] == '0') {
504: for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
505: PetscCall(PetscStripZeros(buf));
506: PetscFunctionReturn(PETSC_SUCCESS);
507: }
508: }
509: PetscFunctionReturn(PETSC_SUCCESS);
510: }
512: /*
513: Removes the plus in something like 1.1e+2 or 1.1e+02
514: */
515: PetscErrorCode PetscStripZerosPlus(char *buf)
516: {
517: size_t i, j, n;
519: PetscFunctionBegin;
520: PetscCall(PetscStrlen(buf, &n));
521: if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
522: for (i = 1; i < n - 2; i++) {
523: if (buf[i] == '+') {
524: if (buf[i + 1] == '0') {
525: for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
526: PetscFunctionReturn(PETSC_SUCCESS);
527: } else {
528: for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
529: PetscFunctionReturn(PETSC_SUCCESS);
530: }
531: } else if (buf[i] == '-') {
532: if (buf[i + 1] == '0') {
533: for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
534: PetscFunctionReturn(PETSC_SUCCESS);
535: }
536: }
537: }
538: PetscFunctionReturn(PETSC_SUCCESS);
539: }