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