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 10 11 Input Parameter: 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 { 29 PetscDrawAxis ad; 30 31 PetscFunctionBegin; 32 PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1); 33 PetscValidPointer(axis, 2); 34 35 PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL)); 36 37 PetscCall(PetscObjectReference((PetscObject)draw)); 38 ad->win = draw; 39 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; 50 51 *axis = ad; 52 PetscFunctionReturn(PETSC_SUCCESS); 53 } 54 55 /*@ 56 PetscDrawAxisDestroy - Frees the space used by an axis structure. 57 58 Collective 59 60 Input Parameter: 61 . axis - the axis context 62 63 Level: advanced 64 65 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis` 66 @*/ 67 PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis) 68 { 69 PetscFunctionBegin; 70 if (!*axis) PetscFunctionReturn(PETSC_SUCCESS); 71 PetscValidHeaderSpecific(*axis, PETSC_DRAWAXIS_CLASSID, 1); 72 if (--((PetscObject)(*axis))->refct > 0) { 73 *axis = NULL; 74 PetscFunctionReturn(PETSC_SUCCESS); 75 } 76 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 } 84 85 /*@ 86 PetscDrawAxisSetColors - Sets the colors to be used for the axis, 87 tickmarks, and text. 88 89 Logically Collective 90 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 96 97 Level: advanced 98 99 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()` 100 @*/ 101 PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc) 102 { 103 PetscFunctionBegin; 104 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 105 PetscValidLogicalCollectiveInt(axis, ac, 2); 106 PetscValidLogicalCollectiveInt(axis, tc, 3); 107 PetscValidLogicalCollectiveInt(axis, cc, 4); 108 axis->ac = ac; 109 axis->tc = tc; 110 axis->cc = cc; 111 PetscFunctionReturn(PETSC_SUCCESS); 112 } 113 114 /*@C 115 PetscDrawAxisSetLabels - Sets the x and y axis labels. 116 117 Logically Collective 118 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 123 124 Level: advanced 125 126 Notes: 127 Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()` 128 129 There should be no newlines in the arguments 130 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; 136 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 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 } 145 146 /*@ 147 PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis 148 149 Logically Collective 150 151 Input Parameters: 152 + axis - the axis 153 . xmin,xmax - limits in x 154 - ymin,ymax - limits in y 155 156 Options Database Key: 157 . -drawaxis_hold - hold the initial set of axis limits for future plotting 158 159 Level: advanced 160 161 .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 162 @*/ 163 PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax) 164 { 165 PetscFunctionBegin; 166 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 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 } 175 176 /*@ 177 PetscDrawAxisGetLimits - Gets the limits (in user coords) of the axis 178 179 Not Collective 180 181 Input Parameters: 182 + axis - the axis 183 . xmin,xmax - limits in x 184 - ymin,ymax - limits in y 185 186 Level: advanced 187 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; 193 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 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 } 200 201 /*@ 202 PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called 203 again 204 205 Logically Collective 206 207 Input Parameters: 208 + axis - the axis 209 - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed 210 211 Level: advanced 212 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` 216 217 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()` 218 @*/ 219 PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold) 220 { 221 PetscFunctionBegin; 222 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 223 PetscValidLogicalCollectiveBool(axis, hold, 2); 224 axis->hold = hold; 225 PetscFunctionReturn(PETSC_SUCCESS); 226 } 227 228 /*@ 229 PetscDrawAxisDraw - draws an axis. 230 231 Collective 232 233 Input Parameter: 234 . axis - `PetscDrawAxis` structure 235 236 Level: advanced 237 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). 243 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; 256 257 PetscFunctionBegin; 258 PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1); 259 PetscCall(PetscDrawIsNull(axis->win, &isnull)); 260 if (isnull) PetscFunctionReturn(PETSC_SUCCESS); 261 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank)); 262 263 draw = axis->win; 264 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 } 276 277 PetscDrawCollectiveBegin(draw); 278 if (rank) goto finally; 279 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)); 305 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)); 311 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 } 317 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 } 344 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 } 374 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 } 382 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; 391 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 } 408 409 /* 410 Removes all zeros but one from .0000 411 */ 412 PetscErrorCode PetscStripAllZeros(char *buf) 413 { 414 size_t i, n; 415 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 } 426 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; 439 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); 444 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 } 462 463 /* 464 Removes leading 0 from 0.22 or -0.22 465 */ 466 PetscErrorCode PetscStripInitialZero(char *buf) 467 { 468 size_t i, n; 469 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 } 479 480 /* 481 Removes the extraneous zeros in numbers like 1.10000e6 482 */ 483 PetscErrorCode PetscStripZeros(char *buf) 484 { 485 size_t i, j, n; 486 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 } 499 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; 506 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 } 528