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