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