1 #include <petsc/private/drawimpl.h> /*I "petscdraw.h" I*/ 2 3 #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20 4 PetscClassId PETSC_DRAWAXIS_CLASSID = 0; 5 6 /*@ 7 PetscDrawAxisCreate - Generate the axis data structure. 8 9 Collective on draw 10 11 Input Parameters: 12 . win - `PetscDraw` object where axis to to be made 13 14 Output Parameter: 15 . axis - the axis datastructure 16 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 20 21 Level: advanced 22 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 PetscDrawAxis ad; 29 30 PetscFunctionBegin; 31 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 32 PetscValidPointer(axis, 2); 33 34 PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL)); 35 36 PetscCall(PetscObjectReference((PetscObject)draw)); 37 ad->win = draw; 38 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; 49 50 *axis = ad; 51 PetscFunctionReturn(0); 52 } 53 54 /*@ 55 PetscDrawAxisDestroy - Frees the space used by an axis structure. 56 57 Collective on axis 58 59 Input Parameters: 60 . axis - the axis context 61 62 Level: advanced 63 64 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis` 65 @*/ 66 PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis) { 67 PetscFunctionBegin; 68 if (!*axis) PetscFunctionReturn(0); 69 PetscValidHeaderSpecific(*axis, PETSC_DRAWAXIS_CLASSID, 1); 70 if (--((PetscObject)(*axis))->refct > 0) { 71 *axis = NULL; 72 PetscFunctionReturn(0); 73 } 74 75 PetscCall(PetscFree((*axis)->toplabel)); 76 PetscCall(PetscFree((*axis)->xlabel)); 77 PetscCall(PetscFree((*axis)->ylabel)); 78 PetscCall(PetscDrawDestroy(&(*axis)->win)); 79 PetscCall(PetscHeaderDestroy(axis)); 80 PetscFunctionReturn(0); 81 } 82 83 /*@ 84 PetscDrawAxisSetColors - Sets the colors to be used for the axis, 85 tickmarks, and text. 86 87 Logically Collective on axis 88 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 94 95 Level: advanced 96 97 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()` 98 @*/ 99 PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc) { 100 PetscFunctionBegin; 101 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 102 PetscValidLogicalCollectiveInt(axis, ac, 2); 103 PetscValidLogicalCollectiveInt(axis, tc, 3); 104 PetscValidLogicalCollectiveInt(axis, cc, 4); 105 axis->ac = ac; 106 axis->tc = tc; 107 axis->cc = cc; 108 PetscFunctionReturn(0); 109 } 110 111 /*@C 112 PetscDrawAxisSetLabels - Sets the x and y axis labels. 113 114 Logically Collective on axis 115 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 120 121 Notes: 122 Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()` 123 124 There should be no newlines in the arguments 125 126 Level: advanced 127 128 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()` 129 @*/ 130 PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[]) { 131 PetscFunctionBegin; 132 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 133 PetscCall(PetscFree(axis->xlabel)); 134 PetscCall(PetscFree(axis->ylabel)); 135 PetscCall(PetscFree(axis->toplabel)); 136 PetscCall(PetscStrallocpy(xlabel, &axis->xlabel)); 137 PetscCall(PetscStrallocpy(ylabel, &axis->ylabel)); 138 PetscCall(PetscStrallocpy(top, &axis->toplabel)); 139 PetscFunctionReturn(0); 140 } 141 142 /*@ 143 PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis 144 145 Logically Collective on axis 146 147 Input Parameters: 148 + axis - the axis 149 . xmin,xmax - limits in x 150 - ymin,ymax - limits in y 151 152 Options Database Key: 153 . -drawaxis_hold - hold the initial set of axis limits for future plotting 154 155 Level: advanced 156 157 .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 158 @*/ 159 PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax) { 160 PetscFunctionBegin; 161 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 162 if (axis->hold) PetscFunctionReturn(0); 163 axis->xlow = xmin; 164 axis->xhigh = xmax; 165 axis->ylow = ymin; 166 axis->yhigh = ymax; 167 PetscCall(PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold)); 168 PetscFunctionReturn(0); 169 } 170 171 /*@ 172 PetscDrawAxisGetLimits - Gets the limits (in user coords) of the axis 173 174 Not Collective 175 176 Input Parameters: 177 + axis - the axis 178 . xmin,xmax - limits in x 179 - ymin,ymax - limits in y 180 181 Level: advanced 182 183 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 184 @*/ 185 PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax) { 186 PetscFunctionBegin; 187 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 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 PetscFunctionReturn(0); 193 } 194 195 /*@ 196 PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called 197 again 198 199 Logically Collective on axis 200 201 Input Parameters: 202 + axis - the axis 203 - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed 204 205 Level: advanced 206 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` 210 211 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 212 @*/ 213 PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold) { 214 PetscFunctionBegin; 215 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 216 PetscValidLogicalCollectiveBool(axis, hold, 2); 217 axis->hold = hold; 218 PetscFunctionReturn(0); 219 } 220 221 /*@ 222 PetscDrawAxisDraw - draws an axis. 223 224 Collective on axis 225 226 Input Parameter: 227 . axis - `PetscDrawAxis` structure 228 229 Level: advanced 230 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). 236 237 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 238 @*/ 239 PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis) { 240 int i, ntick, numx, numy, ac, tc, cc; 241 PetscMPIInt rank; 242 size_t len, ytlen = 0; 243 PetscReal coors[4], tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th; 244 PetscReal xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0; 245 char *p; 246 PetscDraw draw; 247 PetscBool isnull; 248 249 PetscFunctionBegin; 250 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 251 PetscCall(PetscDrawIsNull(axis->win, &isnull)); 252 if (isnull) PetscFunctionReturn(0); 253 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank)); 254 255 draw = axis->win; 256 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 } 268 269 PetscDrawCollectiveBegin(draw); 270 if (rank) goto finally; 271 272 /* get cannonical string size */ 273 PetscCall(PetscDrawSetCoordinates(draw, 0, 0, 1, 1)); 274 PetscCall(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 PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr)); 296 PetscCall(PetscDrawStringGetSize(draw, &tw, &th)); 297 298 /* PetscDraw the axis lines */ 299 PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac)); 300 PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac)); 301 PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac)); 302 PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac)); 303 304 /* PetscDraw the top label */ 305 if (axis->toplabel) { 306 PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th; 307 PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel)); 308 } 309 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 PetscCall((*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 PetscCall(PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc)); 318 PetscCall(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 PetscCall((*axis->xlabelstr)(tickloc[i], sep, &p)); 327 PetscCall(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 PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel)); 335 } 336 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 PetscCall((*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 PetscCall(PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc)); 345 PetscCall(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 PetscCall((*axis->ylabelstr)(tickloc[i], sep, &p)); 354 PetscCall(PetscStrlen(p, &len)); 355 ytlen = PetscMax(ytlen, len); 356 PetscCall(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 PetscCall(PetscStrlen(axis->ylabel, &len)); 364 PetscCall(PetscDrawStringVertical(draw, x, y + len * th / 2, cc, axis->ylabel)); 365 } 366 367 PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3])); 368 finally: 369 PetscDrawCollectiveEnd(draw); 370 PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw))); 371 PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3])); 372 PetscFunctionReturn(0); 373 } 374 375 /* 376 Removes all zeros but one from .0000 377 */ 378 PetscErrorCode PetscStripe0(char *buf) { 379 size_t n; 380 PetscBool flg; 381 char *str; 382 383 PetscFunctionBegin; 384 PetscCall(PetscStrlen(buf, &n)); 385 PetscCall(PetscStrendswith(buf, "e00", &flg)); 386 if (flg) buf[n - 3] = 0; 387 PetscCall(PetscStrstr(buf, "e0", &str)); 388 if (str) { 389 buf[n - 2] = buf[n - 1]; 390 buf[n - 1] = 0; 391 } 392 PetscCall(PetscStrstr(buf, "e-0", &str)); 393 if (str) { 394 buf[n - 2] = buf[n - 1]; 395 buf[n - 1] = 0; 396 } 397 PetscFunctionReturn(0); 398 } 399 400 /* 401 Removes all zeros but one from .0000 402 */ 403 PetscErrorCode PetscStripAllZeros(char *buf) { 404 size_t i, n; 405 406 PetscFunctionBegin; 407 PetscCall(PetscStrlen(buf, &n)); 408 if (buf[0] != '.') PetscFunctionReturn(0); 409 for (i = 1; i < n; i++) { 410 if (buf[i] != '0') PetscFunctionReturn(0); 411 } 412 buf[0] = '0'; 413 buf[1] = 0; 414 PetscFunctionReturn(0); 415 } 416 417 /* 418 Removes trailing zeros 419 */ 420 PetscErrorCode PetscStripTrailingZeros(char *buf) { 421 char *found; 422 size_t i, n, m = PETSC_MAX_INT; 423 424 PetscFunctionBegin; 425 /* if there is an e in string DO NOT strip trailing zeros */ 426 PetscCall(PetscStrchr(buf, 'e', &found)); 427 if (found) PetscFunctionReturn(0); 428 429 PetscCall(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) PetscFunctionReturn(0); 439 /* start at right end of string removing 0s */ 440 for (i = n - 1; i > m; i++) { 441 if (buf[i] != '0') PetscFunctionReturn(0); 442 buf[i] = 0; 443 } 444 PetscFunctionReturn(0); 445 } 446 447 /* 448 Removes leading 0 from 0.22 or -0.22 449 */ 450 PetscErrorCode PetscStripInitialZero(char *buf) { 451 size_t i, n; 452 453 PetscFunctionBegin; 454 PetscCall(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 PetscFunctionReturn(0); 461 } 462 463 /* 464 Removes the extraneous zeros in numbers like 1.10000e6 465 */ 466 PetscErrorCode PetscStripZeros(char *buf) { 467 size_t i, j, n; 468 469 PetscFunctionBegin; 470 PetscCall(PetscStrlen(buf, &n)); 471 if (n < 5) PetscFunctionReturn(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 PetscCall(PetscStripZeros(buf)); 476 PetscFunctionReturn(0); 477 } 478 } 479 PetscFunctionReturn(0); 480 } 481 482 /* 483 Removes the plus in something like 1.1e+2 or 1.1e+02 484 */ 485 PetscErrorCode PetscStripZerosPlus(char *buf) { 486 size_t i, j, n; 487 488 PetscFunctionBegin; 489 PetscCall(PetscStrlen(buf, &n)); 490 if (n < 5) PetscFunctionReturn(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 PetscFunctionReturn(0); 496 } else { 497 for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j]; 498 PetscFunctionReturn(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 PetscFunctionReturn(0); 504 } 505 } 506 } 507 PetscFunctionReturn(0); 508 } 509