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 { 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(0); 53 } 54 55 /*@ 56 PetscDrawAxisDestroy - Frees the space used by an axis structure. 57 58 Collective on axis 59 60 Input Parameters: 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(0); 71 PetscValidHeaderSpecific(*axis, PETSC_DRAWAXIS_CLASSID, 1); 72 if (--((PetscObject)(*axis))->refct > 0) { 73 *axis = NULL; 74 PetscFunctionReturn(0); 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(0); 83 } 84 85 /*@ 86 PetscDrawAxisSetColors - Sets the colors to be used for the axis, 87 tickmarks, and text. 88 89 Logically Collective on axis 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(0); 112 } 113 114 /*@C 115 PetscDrawAxisSetLabels - Sets the x and y axis labels. 116 117 Logically Collective on axis 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 Notes: 125 Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()` 126 127 There should be no newlines in the arguments 128 129 Level: advanced 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(0); 144 } 145 146 /*@ 147 PetscDrawAxisSetLimits - Sets the limits (in user coords) of the axis 148 149 Logically Collective on axis 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(0); 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(0); 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(0); 199 } 200 201 /*@ 202 PetscDrawAxisSetHoldLimits - Causes an axis to keep the same limits until this is called 203 again 204 205 Logically Collective on axis 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(0); 226 } 227 228 /*@ 229 PetscDrawAxisDraw - draws an axis. 230 231 Collective on axis 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(0); 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 cannonical 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(0); 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; 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(0); 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(0); 419 for (i = 1; i < n; i++) { 420 if (buf[i] != '0') PetscFunctionReturn(0); 421 } 422 buf[0] = '0'; 423 buf[1] = 0; 424 PetscFunctionReturn(0); 425 } 426 427 /* 428 Removes trailing zeros 429 */ 430 PetscErrorCode PetscStripTrailingZeros(char *buf) 431 { 432 char *found; 433 size_t i, n, m = PETSC_MAX_INT; 434 435 PetscFunctionBegin; 436 /* if there is an e in string DO NOT strip trailing zeros */ 437 PetscCall(PetscStrchr(buf, 'e', &found)); 438 if (found) PetscFunctionReturn(0); 439 440 PetscCall(PetscStrlen(buf, &n)); 441 /* locate decimal point */ 442 for (i = 0; i < n; i++) { 443 if (buf[i] == '.') { 444 m = i; 445 break; 446 } 447 } 448 /* if not decimal point then no zeros to remove */ 449 if (m == PETSC_MAX_INT) PetscFunctionReturn(0); 450 /* start at right end of string removing 0s */ 451 for (i = n - 1; i > m; i++) { 452 if (buf[i] != '0') PetscFunctionReturn(0); 453 buf[i] = 0; 454 } 455 PetscFunctionReturn(0); 456 } 457 458 /* 459 Removes leading 0 from 0.22 or -0.22 460 */ 461 PetscErrorCode PetscStripInitialZero(char *buf) 462 { 463 size_t i, n; 464 465 PetscFunctionBegin; 466 PetscCall(PetscStrlen(buf, &n)); 467 if (buf[0] == '0') { 468 for (i = 0; i < n; i++) buf[i] = buf[i + 1]; 469 } else if (buf[0] == '-' && buf[1] == '0') { 470 for (i = 1; i < n; i++) buf[i] = buf[i + 1]; 471 } 472 PetscFunctionReturn(0); 473 } 474 475 /* 476 Removes the extraneous zeros in numbers like 1.10000e6 477 */ 478 PetscErrorCode PetscStripZeros(char *buf) 479 { 480 size_t i, j, n; 481 482 PetscFunctionBegin; 483 PetscCall(PetscStrlen(buf, &n)); 484 if (n < 5) PetscFunctionReturn(0); 485 for (i = 1; i < n - 1; i++) { 486 if (buf[i] == 'e' && buf[i - 1] == '0') { 487 for (j = i; j < n + 1; j++) buf[j - 1] = buf[j]; 488 PetscCall(PetscStripZeros(buf)); 489 PetscFunctionReturn(0); 490 } 491 } 492 PetscFunctionReturn(0); 493 } 494 495 /* 496 Removes the plus in something like 1.1e+2 or 1.1e+02 497 */ 498 PetscErrorCode PetscStripZerosPlus(char *buf) 499 { 500 size_t i, j, n; 501 502 PetscFunctionBegin; 503 PetscCall(PetscStrlen(buf, &n)); 504 if (n < 5) PetscFunctionReturn(0); 505 for (i = 1; i < n - 2; i++) { 506 if (buf[i] == '+') { 507 if (buf[i + 1] == '0') { 508 for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1]; 509 PetscFunctionReturn(0); 510 } else { 511 for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j]; 512 PetscFunctionReturn(0); 513 } 514 } else if (buf[i] == '-') { 515 if (buf[i + 1] == '0') { 516 for (j = i + 1; j < n; j++) buf[j] = buf[j + 1]; 517 PetscFunctionReturn(0); 518 } 519 } 520 } 521 PetscFunctionReturn(0); 522 } 523