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