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: . 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;
31: PetscFunctionBegin;
35: PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL));
37: PetscCall(PetscObjectReference((PetscObject)draw));
38: ad->win = draw;
40: ad->xticks = PetscADefTicks;
41: ad->yticks = PetscADefTicks;
42: ad->xlabelstr = PetscADefLabel;
43: ad->ylabelstr = PetscADefLabel;
44: ad->ac = PETSC_DRAW_BLACK;
45: ad->tc = PETSC_DRAW_BLACK;
46: ad->cc = PETSC_DRAW_BLACK;
47: ad->xlabel = NULL;
48: ad->ylabel = NULL;
49: ad->toplabel = NULL;
51: *axis = ad;
52: PetscFunctionReturn(PETSC_SUCCESS);
53: }
55: /*@
56: PetscDrawAxisDestroy - Frees the space used by an axis structure.
58: Collective
60: Input Parameter:
61: . axis - the axis context
63: Level: advanced
65: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`
66: @*/
67: PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis)
68: {
69: PetscFunctionBegin;
70: if (!*axis) PetscFunctionReturn(PETSC_SUCCESS);
72: if (--((PetscObject)(*axis))->refct > 0) {
73: *axis = NULL;
74: PetscFunctionReturn(PETSC_SUCCESS);
75: }
77: PetscCall(PetscFree((*axis)->toplabel));
78: PetscCall(PetscFree((*axis)->xlabel));
79: PetscCall(PetscFree((*axis)->ylabel));
80: PetscCall(PetscDrawDestroy(&(*axis)->win));
81: PetscCall(PetscHeaderDestroy(axis));
82: PetscFunctionReturn(PETSC_SUCCESS);
83: }
85: /*@
86: PetscDrawAxisSetColors - Sets the colors to be used for the axis,
87: tickmarks, and text.
89: Logically Collective
91: Input Parameters:
92: + axis - the axis
93: . ac - the color of the axis lines
94: . tc - the color of the tick marks
95: - cc - the color of the text strings
97: Level: advanced
99: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
100: @*/
101: PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc)
102: {
103: PetscFunctionBegin;
108: axis->ac = ac;
109: axis->tc = tc;
110: axis->cc = cc;
111: PetscFunctionReturn(PETSC_SUCCESS);
112: }
114: /*@C
115: PetscDrawAxisSetLabels - Sets the x and y axis labels.
117: Logically Collective
119: Input Parameters:
120: + axis - the axis
121: . top - the label at the top of the image
122: - xlabel,ylabel - the labes for the x and y axis
124: Level: advanced
126: Notes:
127: Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`
129: There should be no newlines in the arguments
131: .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
132: @*/
133: PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[])
134: {
135: PetscFunctionBegin;
137: PetscCall(PetscFree(axis->xlabel));
138: PetscCall(PetscFree(axis->ylabel));
139: PetscCall(PetscFree(axis->toplabel));
140: PetscCall(PetscStrallocpy(xlabel, &axis->xlabel));
141: PetscCall(PetscStrallocpy(ylabel, &axis->ylabel));
142: PetscCall(PetscStrallocpy(top, &axis->toplabel));
143: PetscFunctionReturn(PETSC_SUCCESS);
144: }
146: /*@
147: PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis
149: Logically Collective
151: Input Parameters:
152: + axis - the axis
153: . xmin,xmax - limits in x
154: - ymin,ymax - limits in y
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,xmax - limits in x
184: - ymin,ymax - limits in y
186: Level: advanced
188: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
189: @*/
190: PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax)
191: {
192: PetscFunctionBegin;
194: if (xmin) *xmin = axis->xlow;
195: if (xmax) *xmax = axis->xhigh;
196: if (ymin) *ymin = axis->ylow;
197: if (ymax) *ymax = axis->yhigh;
198: PetscFunctionReturn(PETSC_SUCCESS);
199: }
201: /*@
202: PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called
203: again
205: Logically Collective
207: Input Parameters:
208: + axis - the axis
209: - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed
211: Level: advanced
213: Note:
214: Once this has been called with `PETSC_TRUE` the limits will not change if you call
215: `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE`
217: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
218: @*/
219: PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold)
220: {
221: PetscFunctionBegin;
224: axis->hold = hold;
225: PetscFunctionReturn(PETSC_SUCCESS);
226: }
228: /*@
229: PetscDrawAxisDraw - draws an axis.
231: Collective
233: Input Parameter:
234: . axis - `PetscDrawAxis` structure
236: Level: advanced
238: Note:
239: This draws the actual axis. The limits etc have already been set.
240: By picking special routines for the ticks and labels, special
241: effects may be generated. These routines are part of the Axis
242: structure (axis).
244: .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
245: @*/
246: PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
247: {
248: int i, ntick, numx, numy, ac, tc, cc;
249: PetscMPIInt rank;
250: size_t len, ytlen = 0;
251: PetscReal coors[4], tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th;
252: PetscReal xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0;
253: char *p;
254: PetscDraw draw;
255: PetscBool isnull;
257: PetscFunctionBegin;
259: PetscCall(PetscDrawIsNull(axis->win, &isnull));
260: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
261: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank));
263: draw = axis->win;
265: ac = axis->ac;
266: tc = axis->tc;
267: cc = axis->cc;
268: if (axis->xlow == axis->xhigh) {
269: axis->xlow -= .5;
270: axis->xhigh += .5;
271: }
272: if (axis->ylow == axis->yhigh) {
273: axis->ylow -= .5;
274: axis->yhigh += .5;
275: }
277: PetscDrawCollectiveBegin(draw);
278: if (rank) goto finally;
280: /* get canonical string size */
281: PetscCall(PetscDrawSetCoordinates(draw, 0, 0, 1, 1));
282: PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
283: /* lower spacing */
284: if (axis->xlabelstr) dyl += 1.5 * th;
285: if (axis->xlabel) dyl += 1.5 * th;
286: /* left spacing */
287: if (axis->ylabelstr) dxl += 7.5 * tw;
288: if (axis->ylabel) dxl += 2.0 * tw;
289: /* right and top spacing */
290: if (axis->xlabelstr) dxr = 2.5 * tw;
291: if (axis->ylabelstr) dyr = 0.5 * th;
292: if (axis->toplabel) dyr = 1.5 * th;
293: /* extra spacing */
294: dxl += 0.7 * tw;
295: dxr += 0.5 * tw;
296: dyl += 0.2 * th;
297: dyr += 0.2 * th;
298: /* determine coordinates */
299: xl = (dxl * axis->xhigh + dxr * axis->xlow - axis->xlow) / (dxl + dxr - 1);
300: xr = (dxl * axis->xhigh + dxr * axis->xlow - axis->xhigh) / (dxl + dxr - 1);
301: yl = (dyl * axis->yhigh + dyr * axis->ylow - axis->ylow) / (dyl + dyr - 1);
302: yr = (dyl * axis->yhigh + dyr * axis->ylow - axis->yhigh) / (dyl + dyr - 1);
303: PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr));
304: PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
306: /* PetscDraw the axis lines */
307: PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac));
308: PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac));
309: PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac));
310: PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac));
312: /* PetscDraw the top label */
313: if (axis->toplabel) {
314: PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;
315: PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel));
316: }
318: /* PetscDraw the X ticks and labels */
319: if (axis->xticks) {
320: numx = (int)(.15 * (axis->xhigh - axis->xlow) / tw);
321: numx = PetscClipInterval(numx, 2, 6);
322: PetscCall((*axis->xticks)(axis->xlow, axis->xhigh, numx, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
323: /* PetscDraw in tick marks */
324: for (i = 0; i < ntick; i++) {
325: PetscCall(PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc));
326: PetscCall(PetscDrawLine(draw, tickloc[i], axis->yhigh, tickloc[i], axis->yhigh - .5 * th, tc));
327: }
328: /* label ticks */
329: if (axis->xlabelstr) {
330: for (i = 0; i < ntick; i++) {
331: if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
332: else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
333: else sep = 0.0;
334: PetscCall((*axis->xlabelstr)(tickloc[i], sep, &p));
335: PetscCall(PetscDrawStringCentered(draw, tickloc[i], axis->ylow - 1.5 * th, cc, p));
336: }
337: }
338: }
339: if (axis->xlabel) {
340: PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->ylow - 1.5 * th;
341: if (axis->xlabelstr) y -= 1.5 * th;
342: PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel));
343: }
345: /* PetscDraw the Y ticks and labels */
346: if (axis->yticks) {
347: numy = (int)(.50 * (axis->yhigh - axis->ylow) / th);
348: numy = PetscClipInterval(numy, 2, 6);
349: PetscCall((*axis->yticks)(axis->ylow, axis->yhigh, numy, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
350: /* PetscDraw in tick marks */
351: for (i = 0; i < ntick; i++) {
352: PetscCall(PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc));
353: PetscCall(PetscDrawLine(draw, axis->xhigh, tickloc[i], axis->xhigh - .5 * tw, tickloc[i], tc));
354: }
355: /* label ticks */
356: if (axis->ylabelstr) {
357: for (i = 0; i < ntick; i++) {
358: if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
359: else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
360: else sep = 0.0;
361: PetscCall((*axis->ylabelstr)(tickloc[i], sep, &p));
362: PetscCall(PetscStrlen(p, &len));
363: ytlen = PetscMax(ytlen, len);
364: PetscCall(PetscDrawString(draw, axis->xlow - (len + .5) * tw, tickloc[i] - .5 * th, cc, p));
365: }
366: }
367: }
368: if (axis->ylabel) {
369: PetscReal x = axis->xlow - 2.0 * tw, y = (axis->ylow + axis->yhigh) / 2;
370: if (axis->ylabelstr) x -= (ytlen + .5) * tw;
371: PetscCall(PetscStrlen(axis->ylabel, &len));
372: PetscCall(PetscDrawStringVertical(draw, x, y + len * th / 2, cc, axis->ylabel));
373: }
375: PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]));
376: finally:
377: PetscDrawCollectiveEnd(draw);
378: PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw)));
379: PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]));
380: PetscFunctionReturn(PETSC_SUCCESS);
381: }
383: /*
384: Removes all zeros but one from .0000
385: */
386: PetscErrorCode PetscStripe0(char *buf)
387: {
388: size_t n;
389: PetscBool flg;
390: char *str = NULL;
392: PetscFunctionBegin;
393: PetscCall(PetscStrlen(buf, &n));
394: PetscCall(PetscStrendswith(buf, "e00", &flg));
395: if (flg) buf[n - 3] = 0;
396: PetscCall(PetscStrstr(buf, "e0", &str));
397: if (str) {
398: buf[n - 2] = buf[n - 1];
399: buf[n - 1] = 0;
400: }
401: PetscCall(PetscStrstr(buf, "e-0", &str));
402: if (str) {
403: buf[n - 2] = buf[n - 1];
404: buf[n - 1] = 0;
405: }
406: PetscFunctionReturn(PETSC_SUCCESS);
407: }
409: /*
410: Removes all zeros but one from .0000
411: */
412: PetscErrorCode PetscStripAllZeros(char *buf)
413: {
414: size_t i, n;
416: PetscFunctionBegin;
417: PetscCall(PetscStrlen(buf, &n));
418: if (buf[0] != '.') PetscFunctionReturn(PETSC_SUCCESS);
419: for (i = 1; i < n; i++) {
420: if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
421: }
422: buf[0] = '0';
423: buf[1] = 0;
424: PetscFunctionReturn(PETSC_SUCCESS);
425: }
427: /*
428: Removes trailing zeros
429: */
430: #if (PETSC_SIZEOF_SIZE_T == 8)
431: #define MAX_SIZE_T PETSC_INT64_MAX
432: #else
433: #define MAX_SIZE_T INT_MAX
434: #endif
435: PetscErrorCode PetscStripTrailingZeros(char *buf)
436: {
437: char *found = NULL;
438: size_t i, n, m = MAX_SIZE_T;
440: PetscFunctionBegin;
441: /* if there is an e in string DO NOT strip trailing zeros */
442: PetscCall(PetscStrchr(buf, 'e', &found));
443: if (found) PetscFunctionReturn(PETSC_SUCCESS);
445: PetscCall(PetscStrlen(buf, &n));
446: /* locate decimal point */
447: for (i = 0; i < n; i++) {
448: if (buf[i] == '.') {
449: m = i;
450: break;
451: }
452: }
453: /* if not decimal point then no zeros to remove */
454: if (m == MAX_SIZE_T) PetscFunctionReturn(PETSC_SUCCESS);
455: /* start at right end of string removing 0s */
456: for (i = n - 1; i > m; i++) {
457: if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
458: buf[i] = 0;
459: }
460: PetscFunctionReturn(PETSC_SUCCESS);
461: }
463: /*
464: Removes leading 0 from 0.22 or -0.22
465: */
466: PetscErrorCode PetscStripInitialZero(char *buf)
467: {
468: size_t i, n;
470: PetscFunctionBegin;
471: PetscCall(PetscStrlen(buf, &n));
472: if (buf[0] == '0') {
473: for (i = 0; i < n; i++) buf[i] = buf[i + 1];
474: } else if (buf[0] == '-' && buf[1] == '0') {
475: for (i = 1; i < n; i++) buf[i] = buf[i + 1];
476: }
477: PetscFunctionReturn(PETSC_SUCCESS);
478: }
480: /*
481: Removes the extraneous zeros in numbers like 1.10000e6
482: */
483: PetscErrorCode PetscStripZeros(char *buf)
484: {
485: size_t i, j, n;
487: PetscFunctionBegin;
488: PetscCall(PetscStrlen(buf, &n));
489: if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
490: for (i = 1; i < n - 1; i++) {
491: if (buf[i] == 'e' && buf[i - 1] == '0') {
492: for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
493: PetscCall(PetscStripZeros(buf));
494: PetscFunctionReturn(PETSC_SUCCESS);
495: }
496: }
497: PetscFunctionReturn(PETSC_SUCCESS);
498: }
500: /*
501: Removes the plus in something like 1.1e+2 or 1.1e+02
502: */
503: PetscErrorCode PetscStripZerosPlus(char *buf)
504: {
505: size_t i, j, n;
507: PetscFunctionBegin;
508: PetscCall(PetscStrlen(buf, &n));
509: if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
510: for (i = 1; i < n - 2; i++) {
511: if (buf[i] == '+') {
512: if (buf[i + 1] == '0') {
513: for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
514: PetscFunctionReturn(PETSC_SUCCESS);
515: } else {
516: for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
517: PetscFunctionReturn(PETSC_SUCCESS);
518: }
519: } else if (buf[i] == '-') {
520: if (buf[i + 1] == '0') {
521: for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
522: PetscFunctionReturn(PETSC_SUCCESS);
523: }
524: }
525: }
526: PetscFunctionReturn(PETSC_SUCCESS);
527: }