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 PetscErrorCode ierr; 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; tc = axis->tc; cc = axis->cc; 266 if (axis->xlow == axis->xhigh) {axis->xlow -= .5; axis->xhigh += .5;} 267 if (axis->ylow == axis->yhigh) {axis->ylow -= .5; axis->yhigh += .5;} 268 269 ierr = PetscDrawCollectiveBegin(draw);PetscCall(ierr); 270 if (rank) goto finally; 271 272 /* get cannonical string size */ 273 PetscCall(PetscDrawSetCoordinates(draw,0,0,1,1)); 274 PetscCall(PetscDrawStringGetSize(draw,&tw,&th)); 275 /* lower spacing */ 276 if (axis->xlabelstr) dyl += 1.5*th; 277 if (axis->xlabel) dyl += 1.5*th; 278 /* left spacing */ 279 if (axis->ylabelstr) dxl += 7.5*tw; 280 if (axis->ylabel) dxl += 2.0*tw; 281 /* right and top spacing */ 282 if (axis->xlabelstr) dxr = 2.5*tw; 283 if (axis->ylabelstr) dyr = 0.5*th; 284 if (axis->toplabel) dyr = 1.5*th; 285 /* extra spacing */ 286 dxl += 0.7*tw; dxr += 0.5*tw; 287 dyl += 0.2*th; dyr += 0.2*th; 288 /* determine coordinates */ 289 xl = (dxl*axis->xhigh + dxr*axis->xlow - axis->xlow) / (dxl + dxr - 1); 290 xr = (dxl*axis->xhigh + dxr*axis->xlow - axis->xhigh) / (dxl + dxr - 1); 291 yl = (dyl*axis->yhigh + dyr*axis->ylow - axis->ylow) / (dyl + dyr - 1); 292 yr = (dyl*axis->yhigh + dyr*axis->ylow - axis->yhigh) / (dyl + dyr - 1); 293 PetscCall(PetscDrawSetCoordinates(draw,xl,yl,xr,yr)); 294 PetscCall(PetscDrawStringGetSize(draw,&tw,&th)); 295 296 /* PetscDraw the axis lines */ 297 PetscCall(PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xhigh,axis->ylow,ac)); 298 PetscCall(PetscDrawLine(draw,axis->xlow,axis->ylow,axis->xlow,axis->yhigh,ac)); 299 PetscCall(PetscDrawLine(draw,axis->xlow,axis->yhigh,axis->xhigh,axis->yhigh,ac)); 300 PetscCall(PetscDrawLine(draw,axis->xhigh,axis->ylow,axis->xhigh,axis->yhigh,ac)); 301 302 /* PetscDraw the top label */ 303 if (axis->toplabel) { 304 PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->yhigh + 0.5*th; 305 PetscCall(PetscDrawStringCentered(draw,x,y,cc,axis->toplabel)); 306 } 307 308 /* PetscDraw the X ticks and labels */ 309 if (axis->xticks) { 310 numx = (int)(.15*(axis->xhigh-axis->xlow)/tw); numx = PetscClipInterval(numx,2,6); 311 PetscCall((*axis->xticks)(axis->xlow,axis->xhigh,numx,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS)); 312 /* PetscDraw in tick marks */ 313 for (i=0; i<ntick; i++) { 314 PetscCall(PetscDrawLine(draw,tickloc[i],axis->ylow,tickloc[i],axis->ylow+.5*th,tc)); 315 PetscCall(PetscDrawLine(draw,tickloc[i],axis->yhigh,tickloc[i],axis->yhigh-.5*th,tc)); 316 } 317 /* label ticks */ 318 if (axis->xlabelstr) { 319 for (i=0; i<ntick; i++) { 320 if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i]; 321 else if (i > 0) sep = tickloc[i] - tickloc[i-1]; 322 else sep = 0.0; 323 PetscCall((*axis->xlabelstr)(tickloc[i],sep,&p)); 324 PetscCall(PetscDrawStringCentered(draw,tickloc[i],axis->ylow-1.5*th,cc,p)); 325 } 326 } 327 } 328 if (axis->xlabel) { 329 PetscReal x = (axis->xlow + axis->xhigh)/2, y = axis->ylow - 1.5*th; 330 if (axis->xlabelstr) y -= 1.5*th; 331 PetscCall(PetscDrawStringCentered(draw,x,y,cc,axis->xlabel)); 332 } 333 334 /* PetscDraw the Y ticks and labels */ 335 if (axis->yticks) { 336 numy = (int)(.50*(axis->yhigh-axis->ylow)/th); numy = PetscClipInterval(numy,2,6); 337 PetscCall((*axis->yticks)(axis->ylow,axis->yhigh,numy,&ntick,tickloc,PETSC_DRAW_AXIS_MAX_SEGMENTS)); 338 /* PetscDraw in tick marks */ 339 for (i=0; i<ntick; i++) { 340 PetscCall(PetscDrawLine(draw,axis->xlow,tickloc[i],axis->xlow+.5*tw,tickloc[i],tc)); 341 PetscCall(PetscDrawLine(draw,axis->xhigh,tickloc[i],axis->xhigh-.5*tw,tickloc[i],tc)); 342 } 343 /* label ticks */ 344 if (axis->ylabelstr) { 345 for (i=0; i<ntick; i++) { 346 if (i < ntick - 1) sep = tickloc[i+1] - tickloc[i]; 347 else if (i > 0) sep = tickloc[i] - tickloc[i-1]; 348 else sep = 0.0; 349 PetscCall((*axis->ylabelstr)(tickloc[i],sep,&p)); 350 PetscCall(PetscStrlen(p,&len)); ytlen = PetscMax(ytlen,len); 351 PetscCall(PetscDrawString(draw,axis->xlow-(len+.5)*tw,tickloc[i]-.5*th,cc,p)); 352 } 353 } 354 } 355 if (axis->ylabel) { 356 PetscReal x = axis->xlow - 2.0*tw, y = (axis->ylow + axis->yhigh)/2; 357 if (axis->ylabelstr) x -= (ytlen+.5)*tw; 358 PetscCall(PetscStrlen(axis->ylabel,&len)); 359 PetscCall(PetscDrawStringVertical(draw,x,y+len*th/2,cc,axis->ylabel)); 360 } 361 362 PetscCall(PetscDrawGetCoordinates(draw,&coors[0],&coors[1],&coors[2],&coors[3])); 363 finally: 364 ierr = PetscDrawCollectiveEnd(draw);PetscCall(ierr); 365 PetscCallMPI(MPI_Bcast(coors,4,MPIU_REAL,0,PetscObjectComm((PetscObject)draw))); 366 PetscCall(PetscDrawSetCoordinates(draw,coors[0],coors[1],coors[2],coors[3])); 367 PetscFunctionReturn(0); 368 } 369 370 /* 371 Removes all zeros but one from .0000 372 */ 373 PetscErrorCode PetscStripe0(char *buf) 374 { 375 size_t n; 376 PetscBool flg; 377 char *str; 378 379 PetscFunctionBegin; 380 PetscCall(PetscStrlen(buf,&n)); 381 PetscCall(PetscStrendswith(buf,"e00",&flg)); 382 if (flg) buf[n-3] = 0; 383 PetscCall(PetscStrstr(buf,"e0",&str)); 384 if (str) { 385 buf[n-2] = buf[n-1]; 386 buf[n-1] = 0; 387 } 388 PetscCall(PetscStrstr(buf,"e-0",&str)); 389 if (str) { 390 buf[n-2] = buf[n-1]; 391 buf[n-1] = 0; 392 } 393 PetscFunctionReturn(0); 394 } 395 396 /* 397 Removes all zeros but one from .0000 398 */ 399 PetscErrorCode PetscStripAllZeros(char *buf) 400 { 401 size_t i,n; 402 403 PetscFunctionBegin; 404 PetscCall(PetscStrlen(buf,&n)); 405 if (buf[0] != '.') PetscFunctionReturn(0); 406 for (i=1; i<n; i++) { 407 if (buf[i] != '0') PetscFunctionReturn(0); 408 } 409 buf[0] = '0'; 410 buf[1] = 0; 411 PetscFunctionReturn(0); 412 } 413 414 /* 415 Removes trailing zeros 416 */ 417 PetscErrorCode PetscStripTrailingZeros(char *buf) 418 { 419 char *found; 420 size_t i,n,m = PETSC_MAX_INT; 421 422 PetscFunctionBegin; 423 /* if there is an e in string DO NOT strip trailing zeros */ 424 PetscCall(PetscStrchr(buf,'e',&found)); 425 if (found) PetscFunctionReturn(0); 426 427 PetscCall(PetscStrlen(buf,&n)); 428 /* locate decimal point */ 429 for (i=0; i<n; i++) { 430 if (buf[i] == '.') {m = i; break;} 431 } 432 /* if not decimal point then no zeros to remove */ 433 if (m == PETSC_MAX_INT) PetscFunctionReturn(0); 434 /* start at right end of string removing 0s */ 435 for (i=n-1; i>m; i++) { 436 if (buf[i] != '0') PetscFunctionReturn(0); 437 buf[i] = 0; 438 } 439 PetscFunctionReturn(0); 440 } 441 442 /* 443 Removes leading 0 from 0.22 or -0.22 444 */ 445 PetscErrorCode PetscStripInitialZero(char *buf) 446 { 447 size_t i,n; 448 449 PetscFunctionBegin; 450 PetscCall(PetscStrlen(buf,&n)); 451 if (buf[0] == '0') { 452 for (i=0; i<n; i++) buf[i] = buf[i+1]; 453 } else if (buf[0] == '-' && buf[1] == '0') { 454 for (i=1; i<n; i++) buf[i] = buf[i+1]; 455 } 456 PetscFunctionReturn(0); 457 } 458 459 /* 460 Removes the extraneous zeros in numbers like 1.10000e6 461 */ 462 PetscErrorCode PetscStripZeros(char *buf) 463 { 464 size_t i,j,n; 465 466 PetscFunctionBegin; 467 PetscCall(PetscStrlen(buf,&n)); 468 if (n<5) PetscFunctionReturn(0); 469 for (i=1; i<n-1; i++) { 470 if (buf[i] == 'e' && buf[i-1] == '0') { 471 for (j=i; j<n+1; j++) buf[j-1] = buf[j]; 472 PetscCall(PetscStripZeros(buf)); 473 PetscFunctionReturn(0); 474 } 475 } 476 PetscFunctionReturn(0); 477 } 478 479 /* 480 Removes the plus in something like 1.1e+2 or 1.1e+02 481 */ 482 PetscErrorCode PetscStripZerosPlus(char *buf) 483 { 484 size_t i,j,n; 485 486 PetscFunctionBegin; 487 PetscCall(PetscStrlen(buf,&n)); 488 if (n<5) PetscFunctionReturn(0); 489 for (i=1; i<n-2; i++) { 490 if (buf[i] == '+') { 491 if (buf[i+1] == '0') { 492 for (j=i+1; j<n; j++) buf[j-1] = buf[j+1]; 493 PetscFunctionReturn(0); 494 } else { 495 for (j=i+1; j<n+1; j++) buf[j-1] = buf[j]; 496 PetscFunctionReturn(0); 497 } 498 } else if (buf[i] == '-') { 499 if (buf[i+1] == '0') { 500 for (j=i+1; j<n; j++) buf[j] = buf[j+1]; 501 PetscFunctionReturn(0); 502 } 503 } 504 } 505 PetscFunctionReturn(0); 506 } 507