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