1 /* ************************************************************************* 2 plotting.hpp - GDL routines for plotting 3 ------------------- 4 begin : July 22 2002 5 copyright : (C) 2002 by Marc Schellens 6 email : m_schellens@users.sf.net 7 ***************************************************************************/ 8 9 /* ************************************************************************* 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef PLOTTING_HPP_ 19 #define PLOTTING_HPP_ 20 #define gdlPlot_Min(a, b) ((a) < (b) ? (a) : (b)) 21 #define gdlPlot_Max(a, b) ((a) > (b) ? (a) : (b)) 22 23 24 //To debug Affine 3D homogenous projections matrices. 25 //IDL define a matrix as M[ncol,mrow] and print as such. However col_major and 26 //row_major refer to the math notation M[row,col] where row=dim(0) and col=dim(1). 27 //Matrices are stored COL Major in IDL/Fortran and ROW Major in C,C++ etc. 28 //so element at (i,j) is computed as (j*dim0 + i) for ColMajor/IDL 29 //and (i*dim1 + j) for RowMajor/C 30 31 #define TRACEMATRIX_C(var__) \ 32 {int dim0__=(var__)->Dim(0), dim1__=(var__)->Dim(1); \ 33 fprintf(stderr,"c matrix[%d,%d]\n",dim0__,dim1__); \ 34 for (int row=0; row < dim0__ ; row++) \ 35 { \ 36 for (int col=0; col < dim1__-1; col++) \ 37 { \ 38 fprintf(stderr,"%g, ",(*var__)[row*dim1__ + col]); \ 39 } \ 40 fprintf(stderr,"%g\n",(*var__)[row*dim1__ + dim1__ -1]); \ 41 } \ 42 fprintf(stderr,"\n"); \ 43 } 44 //The following abbrevs should output the C matrix as IDL would do (ie,transposed): 45 #define TRACEMATRIX_IDL(var__) \ 46 {int dim0__=(var__)->Dim(0), dim1__=(var__)->Dim(1); \ 47 fprintf(stderr,"idl matrix[%d,%d]\n[",dim0__,dim1__); \ 48 for (int col=0; col < dim1__; col++) \ 49 { \ 50 fprintf(stderr,"["); \ 51 for (int row=0; row < dim0__; row++) \ 52 { \ 53 fprintf(stderr,"%g",(*var__)[row*dim1__ + col]); \ 54 if (row<dim0__-1) fprintf(stderr," ,"); \ 55 else if (col<dim1__-1) fprintf(stderr," ],$\n"); else fprintf(stderr," ]]\n") ; \ 56 } \ 57 } \ 58 } 59 60 #include "envt.hpp" 61 #include "graphicsdevice.hpp" 62 #include "initsysvar.hpp" 63 64 #ifdef USE_LIBPROJ 65 #include "projections.hpp" 66 #endif 67 68 struct GDL_3DTRANSFORMDATA 69 { 70 DDoubleGDL* Matrix; 71 DDouble zValue; 72 int* code; 73 DDouble x0; 74 DDouble xs; 75 DDouble y0; 76 DDouble ys; 77 DDouble z0; 78 DDouble zs; 79 bool xlog; 80 bool ylog; 81 bool zlog; 82 }; 83 84 static GDL_3DTRANSFORMDATA Data3d; 85 86 static int code012[3] = {0, 1, 2}; 87 static int code102[3] = {1, 0, 2}; 88 static int code120[3] = {1, 2, 0}; 89 static int code210[3] = {2, 1, 0}; 90 static int code201[3] = {2, 0, 1}; 91 static int code021[3] = {0, 2, 1}; 92 93 enum ORIENTATION3D 94 { 95 NORMAL3D=0, 96 XY, 97 XZ, 98 YZ, 99 XZYZ, 100 XZXY 101 }; 102 103 enum PLOT_AXES_IDENTIFIERS 104 { 105 XAXIS=0, 106 YAXIS, 107 ZAXIS, 108 XAXIS2, //special identifiere for gdlAxis 109 YAXIS2, 110 ZAXIS2 111 }; 112 113 static const std::string axisName[6]={"X","Y","Z","X","Y","Z"}; 114 115 #define GDL_NONE -1 116 #define GDL_TICKFORMAT 0 117 #define GDL_TICKUNITS 1 118 #define GDL_TICKFORMAT_AND_UNITS 2 119 struct GDL_TICKDATA 120 { 121 GDLGStream *a; 122 bool isLog; 123 DDouble axisrange; //to circumvent plplot passing a non-zero value instead of strict 0.0 124 double nchars; //length of string *returned* after formatting. Can be non-integer. 125 }; 126 127 struct GDL_TICKNAMEDATA 128 { 129 GDLGStream *a; 130 bool isLog; 131 DDouble axisrange; //to circumvent plplot passing a non-zero value instead of strict 0.0 132 double nchars; //length of string *returned* after formatting. Can be non-integer. 133 SizeT counter; 134 SizeT nTickName; 135 DStringGDL* TickName; 136 }; 137 138 struct GDL_MULTIAXISTICKDATA 139 { 140 GDLGStream *a; 141 bool isLog; 142 DDouble axisrange; //to circumvent plplot passing a non-zero value instead of strict 0.0 143 double nchars; //length of string *returned* after formatting. Can be non-integer. 144 SizeT counter; 145 bool reset; //reset internal counter each time a new 'axis' command is issued 146 int what; 147 SizeT nTickFormat; 148 DDouble axismin; 149 DDouble axismax; 150 DStringGDL* TickFormat; 151 SizeT nTickUnits; 152 DStringGDL* TickUnits; 153 EnvT *e; 154 }; 155 156 typedef struct GDL_SAVEBOX { 157 bool initialized; 158 PLFLT wx1; //world coord of x min 159 PLFLT wx2; 160 PLFLT wy1; 161 PLFLT wy2; 162 PLFLT nx1; 163 PLFLT nx2; 164 PLFLT ny1; 165 PLFLT ny2; 166 } gdlSavebox ; 167 168 namespace lib { 169 170 using namespace std; 171 172 // main plotting routine (all defined using the plotting_routine_call class) 173 void plot( EnvT* e); 174 void plot_io( EnvT* e); 175 void plot_oo( EnvT* e); 176 void plot_oi( EnvT* e); 177 void oplot( EnvT* e); 178 void plots( EnvT* e); 179 void surface( EnvT* e); 180 void shade_surf( EnvT* e); 181 void contour( EnvT* e); 182 void xyouts( EnvT* e); 183 void axis( EnvT* e); 184 void polyfill( EnvT* e); 185 void tv_image( EnvT* e); 186 void usersym( EnvT* e); 187 void set_shading( EnvT* e); 188 189 // other plotting routines 190 void erase( EnvT* e); 191 void tvlct( EnvT* e); 192 void wshow( EnvT* e); 193 void wdelete( EnvT* e); 194 void wset( EnvT* e); 195 void window( EnvT* e); 196 void set_plot( EnvT* e); 197 BaseGDL* get_screen_size( EnvT* e); 198 void device( EnvT* e); 199 void cursor( EnvT* e); 200 void tvcrs( EnvT* e); 201 void empty(EnvT* e); 202 BaseGDL* format_axis_values(EnvT *e); 203 void scale3_pro(EnvT* e); 204 void t3d_pro( EnvT* e); 205 206 BaseGDL* convert_coord( EnvT* e); 207 208 // Map stuff 209 void get_mapset(bool &mapset); 210 void set_mapset(bool mapset); 211 #ifdef USE_LIBPROJ 212 void GDLgrProjectedPolygonPlot(GDLGStream * a, PROJTYPE ref, DStructGDL* map, 213 DDoubleGDL *lons, DDoubleGDL *lats, bool isRadians, 214 bool const doFill, DLongGDL *conn=NULL); 215 #endif 216 //3D conversions 217 void SelfTranspose3d(DDoubleGDL* me); 218 void SelfReset3d(DDoubleGDL* me); 219 void SelfTranslate3d(DDoubleGDL* me, DDouble *trans); 220 void SelfScale3d(DDoubleGDL* me, DDouble *scale); 221 void SelfRotate3d(DDoubleGDL* me, DDouble *rot); 222 void SelfPerspective3d(DDoubleGDL* me, DDouble zdist); 223 void SelfOblique3d(DDoubleGDL* me, DDouble dist, DDouble angle); 224 void SelfExch3d(DDoubleGDL* me, DLong code); 225 void gdl3dTo2dTransformContour(PLFLT x, PLFLT y, PLFLT *xt, PLFLT *yt, PLPointer data); 226 void gdl3dTo2dTransform(PLFLT x, PLFLT y, PLFLT *xt, PLFLT *yt, PLPointer data); 227 void gdlProject3dCoordinatesIn2d( DDoubleGDL* Matrix, DDoubleGDL *xVal, DDouble *sx, 228 DDoubleGDL *yVal, DDouble *sy, DDoubleGDL* zVal, 229 DDouble *sz, DDoubleGDL *xValou, DDoubleGDL *yValou); 230 DDoubleGDL* gdlComputePlplotRotationMatrix(DDouble az, DDouble alt, DDouble zValue, DDouble scale=1.0); 231 DDoubleGDL* gdlConvertT3DMatrixToPlplotRotationMatrix(DDouble zValue, DDouble &az, DDouble &alt, 232 DDouble &ay, DDouble &scale, ORIENTATION3D &code); 233 DDoubleGDL* gdlGetScaledNormalizedT3DMatrix(DDoubleGDL* Matrix=NULL); 234 DDoubleGDL* gdlGetT3DMatrix(); 235 void gdlNormed3dToWorld3d(DDoubleGDL *xVal, DDoubleGDL *yVal, DDoubleGDL* zVal, 236 DDoubleGDL* xValou, DDoubleGDL *yValou, DDoubleGDL *zValou); 237 void gdl3dto2dProjectDDouble(DDoubleGDL* t3dMatrix, DDoubleGDL *xVal, DDoubleGDL *yVal, 238 DDoubleGDL* zVal, DDoubleGDL *xValou, DDoubleGDL *yValou, int* code); 239 bool T3Denabled(); 240 241 class plotting_routine_call 242 { 243 // ensure execution of child-class destructors ~plotting_routine_call()244 public: virtual ~plotting_routine_call() {}; 245 246 // private fields 247 private: SizeT _nParam; 248 private: bool overplot; 249 private: bool isDB; //see below why commented. 250 251 // common helper methods nParam()252 protected: inline SizeT nParam() { return _nParam; } 253 254 // prototypes for methods defining various steps 255 private: virtual bool handle_args(EnvT*) = 0; // return value = overplot 256 private: virtual void old_body(EnvT*, GDLGStream*) = 0; 257 private: virtual void call_plplot(EnvT*, GDLGStream*) = 0; 258 private: virtual void post_call(EnvT*, GDLGStream*) = 0; 259 260 // all steps combined (virtual methods cannot be called from ctor) call(EnvT * e,SizeT n_params_required)261 public: void call(EnvT* e, SizeT n_params_required) 262 { 263 // when !d.name == Null we do nothing ! 264 DString name = (*static_cast<DStringGDL*>(SysVar::D()->GetTag(SysVar::D()->Desc()->TagIndex("NAME"), 0)))[0]; 265 if (name == "NULL") return; 266 267 _nParam = e->NParam(n_params_required); 268 269 overplot = handle_args(e); 270 271 GDLGStream* actStream = GraphicsDevice::GetDevice()->GetStream(); 272 if (actStream == NULL) e->Throw("Unable to create window."); 273 274 //ALL THE DoubleBuffering and Flush() code below introduces terrible slowness in remote X displays, as well as a lot of time lost 275 //for displays on the same server. They are completely removed now. 276 // //double buffering kills the logic and operation of XOR modes. Use HasSafeDoubleBuffering() that tests this feature.) 277 // isDB = actStream->HasSafeDoubleBuffering(); 278 // if (isDB) actStream->SetDoubleBuffering(); 279 280 if (name == "X" || name == "MAC" || name == "WIN" ) actStream->updatePageInfo(); //since window size can change 281 282 old_body(e, actStream); // TODO: to be removed! 283 call_plplot(e, actStream); 284 285 post_call(e, actStream); 286 // IDEM: SLOW 287 // if (isDB) actStream->eop(); else actStream->flush(); 288 // if (isDB) actStream->UnSetDoubleBuffering(); 289 290 //this is absolutely necessary for widgets as for windows. However the virtual Update function 291 //i.e., calling plstream::cmd(PLESC_EXPOSE, NULL) is very slow. 292 // See how to overload it by a faster function such as in GDLXStream::Update() . 293 actStream->Update(); 294 } 295 }; 296 void gdlDoRangeExtrema(DDoubleGDL *xVal, DDoubleGDL *yVal, DDouble &min, DDouble &max, DDouble xmin, DDouble xmax, bool doMinMax=FALSE, DDouble minVal=0, DDouble maxVal=0); 297 void draw_polyline(GDLGStream *a, DDoubleGDL *xVal, DDoubleGDL *yVal, 298 DDouble minVal, DDouble maxVal, bool doMinMax, 299 bool xLog, bool yLog, //end non-default values 300 DLong psym=0, bool useProjectionInfo=false, bool append=FALSE, DLongGDL *color=NULL); 301 //protect from (inverted, strange) axis log values 302 void gdlHandleUnwantedAxisValue(DDouble &min, DDouble &max, bool log); 303 void gdlSetGraphicsPenColorToBackground(GDLGStream *a); 304 void gdlLineStyle(GDLGStream *a, DLong style); 305 void gdlStoreAxisCRANGE(int axisId, DDouble Start, DDouble End, bool log); 306 void gdlStoreAxisSandWINDOW(GDLGStream* actStream, int axisId, DDouble Start, DDouble End, bool log=false); 307 void gdlGetAxisType(int axisId, bool &log); 308 void gdlGetCurrentAxisRange(int axisId, DDouble &Start, DDouble &End, bool checkMapset=FALSE); 309 void gdlGetCurrentAxisWindow(int axisId, DDouble &wStart, DDouble &wEnd); 310 void gdlStoreAxisType(int axisId, bool type); 311 void gdlGetCharSizes(GDLGStream *a, PLFLT &nsx, PLFLT &nsy, DDouble &wsx, DDouble &wsy, 312 DDouble &dsx, DDouble &dsy, DDouble &lsx, DDouble &lsy); 313 void GetSFromPlotStructs(DDouble **sx, DDouble **sy, DDouble **sz=NULL); 314 void GetWFromPlotStructs(DFloat **wx, DFloat **wy); 315 void setPlplotScale(GDLGStream* a); 316 void DataCoordLimits(DDouble *sx, DDouble *sy, DFloat *wx, DFloat *wy, 317 DDouble *xStart, DDouble *xEnd, DDouble *yStart, DDouble *yEnd, bool); 318 void stopClipping(GDLGStream *a); 319 void gdlStoreCLIP(DLongGDL* clipBox); 320 void GetCurrentUserLimits(GDLGStream *a, 321 DDouble &xStart, DDouble &xEnd, DDouble &yStart, DDouble &yEnd); 322 PLFLT gdlAdjustAxisRange(EnvT* e, int axisId, DDouble &val_min, DDouble &val_max, bool log = false, int calendarcode = 0); 323 PLFLT AutoTick(DDouble x); 324 void setIsoPort(GDLGStream* actStream,PLFLT x1,PLFLT x2,PLFLT y1,PLFLT y2,PLFLT aspect); 325 void GetMinMaxVal( DDoubleGDL* val, double* minVal, double* maxVal); 326 void GetMinMaxValuesForSubset( DDoubleGDL* val, DDouble &minVal, DDouble &maxVal, SizeT endElement); 327 void CheckMargin( GDLGStream* actStream, 328 DFloat xMarginL, DFloat xMarginR, DFloat yMarginB, DFloat yMarginT, 329 PLFLT& xMR, PLFLT& xML, PLFLT& yMB, PLFLT& yMT); 330 void UpdateSWPlotStructs(GDLGStream* actStream, DDouble xStart, DDouble xEnd, DDouble yStart, 331 DDouble yEnd, bool xLog, bool yLog); 332 gdlSavebox* getSaveBox(); 333 gdlSavebox* getTempBox(); 334 void gdlSimpleAxisTickFunc( PLINT axis, PLFLT value, char *label, PLINT length, PLPointer data); 335 void gdlSingleAxisTickNamedFunc( PLINT axis, PLFLT value, char *label, PLINT length, PLPointer data); 336 void gdlMultiAxisTickFunc(PLINT axis, PLFLT value, char *label, PLINT length, PLPointer data); 337 void doOurOwnFormat(PLINT axisNotUsed, PLFLT value, char *label, PLINT length, PLPointer data); 338 // 339 //--------------FOLLOWING ARE STATIC FUNCTIONS----------------------------------------------- 340 //This because static pointers to options indexes are needed to speed up process, but these indexes vary between 341 //the definition of the caller functions (e.g. "CHARSIZE" is 1 for CONTOUR but 7 for XYOUTS). So they need to be kept 342 //static (for speed) but private for each graphic command. gdlSetGraphicsBackgroundColorFromKw(EnvT * e,GDLGStream * a,bool kw=true)343 static void gdlSetGraphicsBackgroundColorFromKw(EnvT *e, GDLGStream *a, bool kw=true) 344 { 345 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 346 DLong background= 347 (*static_cast<DLongGDL*> 348 (pStruct->GetTag(pStruct->Desc()->TagIndex("BACKGROUND"), 0)))[0]; 349 if ( kw ) { 350 static int BACKGROUNDIx=e->KeywordIx("BACKGROUND"); 351 e->AssureLongScalarKWIfPresent(BACKGROUNDIx, background); 352 } 353 DLong decomposed=GraphicsDevice::GetDevice()->GetDecomposed(); 354 a->Background(background,decomposed); 355 } gdlSetGraphicsForegroundColorFromKw(EnvT * e,GDLGStream * a,string OtherColorKw="")356 static void gdlSetGraphicsForegroundColorFromKw(EnvT *e, GDLGStream *a, string OtherColorKw="") 357 { 358 // Get COLOR from PLOT system variable 359 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 360 DLong color= 361 (*static_cast<DLongGDL*> 362 (pStruct->GetTag(pStruct->Desc()->TagIndex("COLOR"), 0)))[0]; 363 364 DLongGDL *colorVect; 365 static int colorIx=e->KeywordIx ( "COLOR" ); 366 int realcolorIx=colorIx; 367 //eventually do not get color from standard "COLOR" keyword but from another... 368 if (OtherColorKw != "") realcolorIx=e->KeywordIx (OtherColorKw); 369 if ( e->GetKW ( realcolorIx )!=NULL ) 370 { 371 colorVect=e->GetKWAs<DLongGDL>( realcolorIx ); //color can be vectorial, but... 372 color=(*colorVect)[0]; //this function only sets color to 1st arg in list! 373 } 374 // Get decomposed value for colors 375 DLong decomposed=GraphicsDevice::GetDevice()->GetDecomposed(); 376 a->Color(color, decomposed); 377 } 378 gdlGetPsym(EnvT * e,DLong & psym)379 static void gdlGetPsym(EnvT *e, DLong &psym) 380 { 381 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 382 psym=(*static_cast<DLongGDL*> 383 (pStruct->GetTag(pStruct->Desc()->TagIndex("PSYM"), 0)))[0]; 384 static int PSYMIx=e->KeywordIx("PSYM"); 385 e->AssureLongScalarKWIfPresent(PSYMIx, psym); 386 if ( psym>10||psym < -8||psym==9 ) 387 e->Throw( 388 "PSYM (plotting symbol) out of range."); 389 } gdlSetSymsize(EnvT * e,GDLGStream * a)390 static void gdlSetSymsize(EnvT *e, GDLGStream *a) 391 { 392 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 393 DFloat symsize=(*static_cast<DFloatGDL*> 394 (pStruct->GetTag(pStruct->Desc()->TagIndex("SYMSIZE"), 0)))[0]; 395 //NOTE THAT AS OF IDL 8.2 !P.SYMSIZE, HOWEVER EXISTING, IS NOT TAKEN INTO ACCOUNT. We however do not want 396 //to reproduce this feature. 397 static int SYMSIZEIx=e->KeywordIx("SYMSIZE"); 398 e->AssureFloatScalarKWIfPresent(SYMSIZEIx, symsize); 399 if ( symsize<=0.0 ) symsize=1.0; 400 a->setSymbolSize(symsize); 401 } 402 // static void GetUserSymSize(EnvT *e, GDLGStream *a, DDouble& UsymConvX, DDouble& UsymConvY) 403 // { 404 // //get symsize 405 // DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 406 // DFloat symsize=(*static_cast<DFloatGDL*> 407 // (pStruct->GetTag(pStruct->Desc()->TagIndex("SYMSIZE"), 0)))[0]; 408 // static int SYMSIZEIx = e->KeywordIx("SYMSIZE"); 409 // e->AssureFloatScalarKWIfPresent(SYMSIZEIx, symsize); 410 // if ( symsize<=0.0 ) symsize=1.0; 411 // 412 // UsymConvX=(0.5*symsize*(a->wCharLength()/a->charScale())); //be dependent only on symsize! 413 // UsymConvY=(0.5*symsize*(a->wCharHeight()/a->charScale())); 414 // PLFLT wun, wdeux, wtrois, wquatre; //take care of axes world orientation! 415 // a->pageWorldCoordinates(wun, wdeux, wtrois, wquatre); 416 // if ((wdeux-wun)<0) UsymConvX*=-1.0; 417 // if ((wquatre-wtrois)<0) UsymConvY*=-1.0; 418 // if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"GetUserSymSize(%f,%f), charlen=%f, charheight=%f, charscale=%f\n", 419 // UsymConvX, UsymConvY,a->wCharLength(),a->wCharHeight(),a->charScale()); 420 // } gdlSetPlotCharsize(EnvT * e,GDLGStream * a,bool accept_sizeKw=false)421 static void gdlSetPlotCharsize(EnvT *e, GDLGStream *a, bool accept_sizeKw=false) 422 { 423 PLFLT charsize; 424 DDouble pmultiscale=1.0; 425 // get !P preference or !FANCY ... they should agree as charsize = 0.2*FANCY+0.8 426 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 427 DFloat* charsizePos=&((*static_cast<DFloatGDL*>(pStruct->GetTag(pStruct->Desc()->TagIndex("CHARSIZE"), 0)))[0]); 428 charsize=charsizePos[0]; 429 // //if charsize==0 see if !FANCY is set to something above 1 or below 1 430 // DIntGDL* fancy= SysVar::GetFancy(); 431 // if ((*fancy)[0] > -4) { //negative values are a mess 432 // PLFLT fancySize = 0.2 * (*fancy)[0] + 0.8; 433 // if (fancySize != charsize) { //make them agree 434 // charsize = fancySize; 435 // charsizePos[0] = charsize; 436 // } 437 // } 438 //overload with command preference. Charsize may be a vector now in some gdl commands, take care of it: 439 if (accept_sizeKw) //XYOUTS specials! 440 { 441 static int SIZEIx=e->KeywordIx("SIZE"); //define here only (else trig an assert() ) 442 DFloat fcharsize; 443 fcharsize=charsize; 444 e->AssureFloatScalarKWIfPresent(SIZEIx, fcharsize); 445 charsize=fcharsize; 446 } 447 static int charsizeIx=e->KeywordIx ( "CHARSIZE" ); 448 if ( e->GetKW ( charsizeIx )!=NULL ) 449 { 450 DFloatGDL* charsizeVect=e->GetKWAs<DFloatGDL>( charsizeIx ); 451 charsize=(*charsizeVect)[0]; 452 } 453 if ( charsize<=0.0 ) charsize=1.0; 454 // adjust if MULTI: 455 DLongGDL* pMulti=SysVar::GetPMulti(); 456 if ( (*pMulti)[1]>2||(*pMulti)[2]>2 ) pmultiscale=0.5; 457 a->sizeChar(charsize*pmultiscale); 458 } 459 gdlSetPlotCharthick(EnvT * e,GDLGStream * a)460 static void gdlSetPlotCharthick(EnvT *e, GDLGStream *a) 461 { 462 // get !P preference 463 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 464 DFloat charthick=(*static_cast<DFloatGDL*> 465 (pStruct->GetTag 466 (pStruct->Desc()->TagIndex("CHARTHICK"), 0)))[0]; 467 static int charthickIx=e->KeywordIx ( "CHARTHICK" ); //Charthick values may be vector in GDL, not in IDL! 468 if ( e->GetKW ( charthickIx )!=NULL ) 469 { 470 DFloatGDL* charthickVect=e->GetKWAs<DFloatGDL>( charthickIx ); 471 charthick=(*charthickVect)[0]; 472 } 473 if ( charthick <= 0.0 ) charthick=1.0; 474 a->Thick(charthick); 475 } 476 gdlComputeTickInterval(EnvT * e,int axisId,DDouble & min,DDouble & max,bool log)477 static PLFLT gdlComputeTickInterval(EnvT *e, int axisId, DDouble &min, DDouble &max, bool log) 478 { 479 DLong nticks=0; 480 481 static int XTICKSIx = e->KeywordIx("XTICKS"); 482 static int YTICKSIx = e->KeywordIx("YTICKS"); 483 static int ZTICKSIx = e->KeywordIx("ZTICKS"); 484 int choosenIx=XTICKSIx; 485 DStructGDL* Struct=NULL; 486 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKSIx; } 487 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKSIx; } 488 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKSIx; } 489 490 if ( Struct!=NULL ) 491 { 492 unsigned tickTag=Struct->Desc()->TagIndex("TICKS"); 493 nticks=(*static_cast<DLongGDL*>(Struct->GetTag(tickTag, 0)))[0]; 494 } 495 e->AssureLongScalarKWIfPresent(choosenIx, nticks); 496 497 PLFLT intv; 498 if (nticks == 0) 499 { 500 intv = (log)? AutoTick(log10(max-min)): AutoTick(max-min); 501 } else { 502 intv = (log)? log10(max-min)/nticks: (max-min)/nticks; 503 } 504 return intv; 505 } 506 gdlGetDesiredAxisCharsize(EnvT * e,int axisId,DFloat & charsize)507 static void gdlGetDesiredAxisCharsize(EnvT* e, int axisId, DFloat &charsize) 508 { 509 //default: 510 charsize=1.0; 511 // get !P preference. Even if [xyz]charsize is absent, presence of charsize or !P.charsize must be taken into account. 512 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 513 charsize=(*static_cast<DFloatGDL*> 514 (pStruct->GetTag 515 (pStruct->Desc()->TagIndex("CHARSIZE"), 0)))[0]; 516 static int CharsizeIx= e->KeywordIx( "CHARSIZE"); 517 //cerr<<" CHARSIZE: "<< CharsizeIx<<" ("<< &CharsizeIx<<")"<<endl; 518 e->AssureFloatScalarKWIfPresent(CharsizeIx, charsize); // option charsize overloads P.CHARSIZE 519 if (charsize==0) charsize=1.0; 520 // Axis Preference. Is a Multiplier! 521 static int XCharsizeIx = e->KeywordIx("XCHARSIZE"); 522 static int YCharsizeIx = e->KeywordIx("YCHARSIZE"); 523 static int ZCharsizeIx = e->KeywordIx("ZCHARSIZE"); 524 int choosenIx=XCharsizeIx; 525 DStructGDL* Struct=NULL; 526 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XCharsizeIx; } 527 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YCharsizeIx; } 528 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZCharsizeIx; } 529 530 if ( Struct!=NULL ) 531 { 532 unsigned charsizeTag=Struct->Desc()->TagIndex("CHARSIZE"); //[XYZ].CHARSIZE 533 DFloat axisCharsizeMultiplier=(*static_cast<DFloatGDL*>(Struct->GetTag(charsizeTag, 0)))[0]; 534 e->AssureFloatScalarKWIfPresent(choosenIx, axisCharsizeMultiplier); //option [XYZ]CHARSIZE overloads ![XYZ].CHARSIZE 535 if (axisCharsizeMultiplier>0.0) charsize*=axisCharsizeMultiplier; //IDL Behaviour... 536 } 537 } gdlSetAxisCharsize(EnvT * e,GDLGStream * a,int axisId)538 static void gdlSetAxisCharsize(EnvT *e, GDLGStream *a, int axisId) 539 { 540 541 DFloat charsize=0.0; 542 DDouble pmultiscale=1.0; 543 gdlGetDesiredAxisCharsize(e, axisId, charsize); 544 // adjust if MULTI: 545 DLongGDL* pMulti=SysVar::GetPMulti(); 546 if ( (*pMulti)[1]>2||(*pMulti)[2]>2 ) pmultiscale=0.5; //IDL behaviour 547 // scale default value (which depends on number of subpages) 548 // a->schr(0.0, charsize*pmultiscale); 549 a->sizeChar(charsize*pmultiscale); 550 } 551 gdlGetDesiredAxisGridStyle(EnvT * e,int axisId,DLong & axisGridstyle)552 static void gdlGetDesiredAxisGridStyle(EnvT* e, int axisId, DLong &axisGridstyle) 553 { 554 axisGridstyle=0; 555 DStructGDL* Struct=NULL; 556 static int XGRIDSTYLEIx = e->KeywordIx("XGRIDSTYLE"); 557 static int YGRIDSTYLEIx = e->KeywordIx("YGRIDSTYLE"); 558 static int ZGRIDSTYLEIx = e->KeywordIx("ZGRIDSTYLE"); 559 int choosenIx=XGRIDSTYLEIx; 560 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XGRIDSTYLEIx; } 561 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YGRIDSTYLEIx; } 562 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZGRIDSTYLEIx; } 563 564 if ( Struct!=NULL ) 565 { 566 unsigned gridstyleTag=Struct->Desc()->TagIndex("GRIDSTYLE"); 567 axisGridstyle=(*static_cast<DLongGDL*>(Struct->GetTag(gridstyleTag, 0)))[0]; 568 e->AssureLongScalarKWIfPresent(choosenIx, axisGridstyle); 569 } 570 } gdlGetDesiredAxisMargin(EnvT * e,int axisId,DFloat & start,DFloat & end)571 static void gdlGetDesiredAxisMargin(EnvT *e, int axisId, DFloat &start, DFloat &end) 572 { 573 static int XMARGINIx = e->KeywordIx("XMARGIN"); 574 static int YMARGINIx = e->KeywordIx("YMARGIN"); 575 static int ZMARGINIx = e->KeywordIx("ZMARGIN"); 576 int choosenIx=XMARGINIx; 577 DStructGDL* Struct=NULL; 578 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XMARGINIx; } 579 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YMARGINIx; } 580 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZMARGINIx; } 581 582 if ( Struct!=NULL ) 583 { 584 unsigned marginTag=Struct->Desc()->TagIndex("MARGIN"); 585 start= (*static_cast<DFloatGDL*>(Struct->GetTag(marginTag, 0)))[0]; 586 end = (*static_cast<DFloatGDL*>(Struct->GetTag(marginTag, 0)))[1]; 587 } 588 589 BaseGDL* Margin=e->GetKW(choosenIx); 590 if ( Margin!=NULL ) 591 { 592 if ( Margin->N_Elements()>2 ) 593 e->Throw("Keyword array parameter "+axisName[axisId]+"MARGIN must have from 1 to 2 elements."); 594 Guard<DFloatGDL> guard; 595 DFloatGDL* MarginF=static_cast<DFloatGDL*> 596 (Margin->Convert2(GDL_FLOAT, BaseGDL::COPY)); 597 guard.Reset(MarginF); 598 start=(*MarginF)[0]; 599 if ( MarginF->N_Elements()>1 ) 600 end=(*MarginF)[1]; 601 } 602 } gdlGetDesiredAxisMinor(EnvT * e,int axisId,DLong & axisMinor)603 static void gdlGetDesiredAxisMinor(EnvT* e, int axisId, DLong &axisMinor) 604 { 605 axisMinor=0; 606 static int XMINORIx = e->KeywordIx("XMINOR"); 607 static int YMINORIx = e->KeywordIx("YMINOR"); 608 static int ZMINORIx = e->KeywordIx("ZMINOR"); 609 int choosenIx=XMINORIx; 610 DStructGDL* Struct=NULL; 611 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XMINORIx; } 612 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YMINORIx; } 613 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZMINORIx; } 614 if ( Struct!=NULL ) 615 { 616 unsigned AxisMinorTag=Struct->Desc()->TagIndex("MINOR"); 617 axisMinor=(*static_cast<DLongGDL*>(Struct->GetTag(AxisMinorTag,0)))[0]; 618 } 619 e->AssureLongScalarKWIfPresent(choosenIx, axisMinor); 620 } gdlGetDesiredAxisRange(EnvT * e,int axisId,DDouble & start,DDouble & end)621 static bool gdlGetDesiredAxisRange(EnvT *e, int axisId, DDouble &start, DDouble &end) 622 { 623 bool set=FALSE; 624 static int XRANGEIx = e->KeywordIx("XRANGE"); 625 static int YRANGEIx = e->KeywordIx("YRANGE"); 626 static int ZRANGEIx = e->KeywordIx("ZRANGE"); 627 int choosenIx=XRANGEIx; 628 DStructGDL* Struct=NULL; 629 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XRANGEIx; } 630 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YRANGEIx; } 631 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZRANGEIx; } 632 if ( Struct!=NULL ) 633 { 634 DDouble test1, test2; 635 unsigned rangeTag=Struct->Desc()->TagIndex("RANGE"); 636 test1=(*static_cast<DDoubleGDL*>(Struct->GetTag(rangeTag, 0)))[0]; 637 test2=(*static_cast<DDoubleGDL*>(Struct->GetTag(rangeTag, 0)))[1]; 638 if ( !((test1-test2)==0.0) ) 639 { 640 start=test1; 641 end=test2; 642 set=true; 643 } 644 } 645 BaseGDL* Range=e->GetKW(choosenIx); 646 if ( Range!=NULL ) 647 { 648 if ( Range->N_Elements()!=2 ) 649 e->Throw("Keyword array parameter "+axisName[axisId]+"RANGE must have 2 elements."); 650 Guard<DDoubleGDL> guard; 651 DDoubleGDL* RangeF=static_cast<DDoubleGDL*>(Range->Convert2(GDL_DOUBLE, BaseGDL::COPY)); 652 guard.Reset(RangeF); 653 if (!(((*RangeF)[0]-(*RangeF)[1])==0.0)) 654 { 655 start=(*RangeF)[0]; 656 end=(*RangeF)[1]; 657 set=true; 658 } 659 } 660 return set; 661 } gdlGetDesiredAxisStyle(EnvT * e,int axisId,DLong & style)662 static void gdlGetDesiredAxisStyle(EnvT *e, int axisId, DLong &style) 663 { 664 static int XSTYLEIx = e->KeywordIx("XSTYLE"); 665 static int YSTYLEIx = e->KeywordIx("YSTYLE"); 666 static int ZSTYLEIx = e->KeywordIx("ZSTYLE"); 667 int choosenIx=XSTYLEIx; 668 DStructGDL* Struct=NULL; 669 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XSTYLEIx; } 670 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YSTYLEIx; } 671 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZSTYLEIx; } 672 673 if ( Struct!=NULL ) 674 { 675 int styleTag=Struct->Desc()->TagIndex("STYLE"); 676 style= (*static_cast<DLongGDL*>(Struct->GetTag(styleTag, 0)))[0]; 677 } 678 679 e->AssureLongScalarKWIfPresent( choosenIx, style); 680 } gdlGetDesiredAxisThick(EnvT * e,int axisId,DFloat & thick)681 static void gdlGetDesiredAxisThick(EnvT *e, int axisId, DFloat &thick) 682 { 683 thick=1.0; 684 static int XTHICKIx = e->KeywordIx("XTHICK"); 685 static int YTHICKIx = e->KeywordIx("YTHICK"); 686 static int ZTHICKIx = e->KeywordIx("ZTHICK"); 687 int choosenIx=XTHICKIx; 688 DStructGDL* Struct=NULL; 689 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTHICKIx; } 690 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTHICKIx; } 691 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTHICKIx; } 692 693 if ( Struct!=NULL ) 694 { 695 //not static! 696 int thickTag=Struct->Desc()->TagIndex("THICK"); 697 thick = (*static_cast<DFloatGDL*>(Struct->GetTag(thickTag, 0)))[0]; 698 } 699 e->AssureFloatScalarKWIfPresent(choosenIx, thick); 700 if ( thick <= 0.0 ) thick=1.0; 701 } gdlGetDesiredAxisTickget(EnvT * e,int axisId,DDoubleGDL * Axistickget)702 static void gdlGetDesiredAxisTickget(EnvT *e, int axisId, DDoubleGDL *Axistickget) 703 { 704 //TODO! 705 } 706 gdlGetDesiredAxisTickFormat(EnvT * e,int axisId,DStringGDL * & axisTickformatVect)707 static void gdlGetDesiredAxisTickFormat(EnvT* e, int axisId, DStringGDL* &axisTickformatVect) 708 { 709 static int XTICKFORMATIx = e->KeywordIx("XTICKFORMAT"); 710 static int YTICKFORMATIx = e->KeywordIx("YTICKFORMAT"); 711 static int ZTICKFORMATIx = e->KeywordIx("ZTICKFORMAT"); 712 int choosenIx=XTICKFORMATIx; 713 DStructGDL* Struct=NULL; 714 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKFORMATIx; } 715 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKFORMATIx; } 716 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKFORMATIx; } 717 718 if ( Struct!=NULL ) 719 { 720 unsigned AxisTickformatTag=Struct->Desc()->TagIndex("TICKFORMAT"); 721 axisTickformatVect = static_cast<DStringGDL*>(Struct->GetTag(AxisTickformatTag,0)); 722 } 723 if ( e->GetKW ( choosenIx )!=NULL ) 724 { 725 axisTickformatVect=e->GetKWAs<DStringGDL>( choosenIx ); 726 } 727 } 728 gdlGetDesiredAxisTickInterval(EnvT * e,int axisId,DDouble & axisTickinterval)729 static void gdlGetDesiredAxisTickInterval(EnvT* e, int axisId, DDouble &axisTickinterval) 730 { 731 axisTickinterval=0; 732 static int XTICKINTERVALIx = e->KeywordIx("XTICKINTERVAL"); 733 static int YTICKINTERVALIx = e->KeywordIx("YTICKINTERVAL"); 734 static int ZTICKINTERVALIx = e->KeywordIx("ZTICKINTERVAL"); 735 int choosenIx=XTICKINTERVALIx; 736 DStructGDL* Struct=NULL; 737 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKINTERVALIx; } 738 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKINTERVALIx; } 739 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKINTERVALIx; } 740 741 if ( Struct!=NULL ) 742 { 743 axisTickinterval=(*static_cast<DDoubleGDL*> 744 (Struct->GetTag 745 (Struct->Desc()->TagIndex("TICKINTERVAL"), 0)))[0]; 746 } 747 e->AssureDoubleScalarKWIfPresent(choosenIx, axisTickinterval); 748 } 749 gdlGetDesiredAxisTickLayout(EnvT * e,int axisId,DLong & axisTicklayout)750 static void gdlGetDesiredAxisTickLayout(EnvT* e, int axisId, DLong &axisTicklayout) 751 { 752 axisTicklayout=0; 753 static int XTICKLAYOUTIx = e->KeywordIx("XTICKLAYOUT"); 754 static int YTICKLAYOUTIx = e->KeywordIx("YTICKLAYOUT"); 755 static int ZTICKLAYOUTIx = e->KeywordIx("ZTICKLAYOUT"); 756 int choosenIx=XTICKLAYOUTIx; 757 DStructGDL* Struct=NULL; 758 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKLAYOUTIx; } 759 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKLAYOUTIx; } 760 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKLAYOUTIx; } 761 if ( Struct!=NULL ) 762 { 763 axisTicklayout=(*static_cast<DLongGDL*> 764 (Struct->GetTag 765 (Struct->Desc()->TagIndex("TICKLAYOUT"), 0)))[0]; 766 } 767 e->AssureLongScalarKWIfPresent(choosenIx, axisTicklayout); 768 } 769 gdlGetDesiredAxisTickLen(EnvT * e,int axisId,DFloat & ticklen)770 static void gdlGetDesiredAxisTickLen(EnvT* e, int axisId, DFloat &ticklen) 771 { 772 // order: !P.TICKLEN, TICKLEN, !X.TICKLEN, /XTICKLEN 773 // get !P preference 774 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 775 ticklen=(*static_cast<DFloatGDL*> 776 (pStruct->GetTag 777 (pStruct->Desc()->TagIndex("TICKLEN"), 0)))[0]; //!P.TICKLEN, always exist, may be 0 778 static int TICKLENIx = e->KeywordIx("TICKLEN"); 779 e->AssureFloatScalarKWIfPresent(TICKLENIx, ticklen); //overwritten by TICKLEN option 780 781 static int XTICKLENIx = e->KeywordIx("XTICKLEN"); 782 static int YTICKLENIx = e->KeywordIx("YTICKLEN"); 783 static int ZTICKLENIx = e->KeywordIx("ZTICKLEN"); 784 int choosenIx=XTICKLENIx; 785 DStructGDL* Struct=NULL; 786 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKLENIx; } 787 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKLENIx; } 788 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKLENIx; } 789 if ( Struct!=NULL ) 790 { 791 unsigned ticklenTag=Struct->Desc()->TagIndex("TICKLEN"); 792 DFloat axisTicklen=(*static_cast<DFloatGDL*>(Struct->GetTag(ticklenTag, 0)))[0]; //![XYZ].TICKLEN (exist) 793 e->AssureFloatScalarKWIfPresent(choosenIx, axisTicklen); //overriden by kw 794 if (axisTicklen!=0.0) ticklen=axisTicklen; 795 } 796 } 797 gdlGetDesiredAxisTickName(EnvT * e,GDLGStream * a,int axisId,DStringGDL * & axisTicknameVect)798 static void gdlGetDesiredAxisTickName(EnvT* e, GDLGStream* a, int axisId, DStringGDL* &axisTicknameVect) 799 { 800 801 static int XTICKNAMEIx = e->KeywordIx("XTICKNAME"); 802 static int YTICKNAMEIx = e->KeywordIx("YTICKNAME"); 803 static int ZTICKNAMEIx = e->KeywordIx("ZTICKNAME"); 804 int choosenIx=XTICKNAMEIx; 805 DStructGDL* Struct=NULL; 806 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKNAMEIx; } 807 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKNAMEIx; } 808 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKNAMEIx; } 809 if ( Struct!=NULL ) 810 { 811 unsigned AxisTicknameTag=Struct->Desc()->TagIndex("TICKNAME"); 812 axisTicknameVect=static_cast<DStringGDL*>(Struct->GetTag(AxisTicknameTag,0)); 813 } 814 if ( e->GetKW ( choosenIx )!=NULL ) 815 { 816 axisTicknameVect=e->GetKWAs<DStringGDL>( choosenIx ); 817 //translate format codes here: 818 // for (SizeT iname=0; iname < axisTicknameVect->N_Elements(); ++iname) { 819 // std::string out = std::string(""); 820 // a->TranslateFormatCodes(((*axisTicknameVect)[iname]).c_str(),out); 821 ////TBD: not finished, see cases not treated in TransmateFormatCodes (gdlgstream.cpp) 822 // (*axisTicknameVect)[iname]=out; 823 // } 824 } 825 826 } 827 gdlGetDesiredAxisTicks(EnvT * e,int axisId,DLong & axisTicks)828 static void gdlGetDesiredAxisTicks(EnvT* e, int axisId, DLong &axisTicks) 829 { 830 axisTicks=0; 831 832 static int XTICKSIx = e->KeywordIx("XTICKS"); 833 static int YTICKSIx = e->KeywordIx("YTICKS"); 834 static int ZTICKSIx = e->KeywordIx("ZTICKS"); 835 int choosenIx=XTICKSIx; 836 DStructGDL* Struct=NULL; 837 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKSIx; } 838 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKSIx; } 839 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKSIx; } 840 841 if ( Struct!=NULL ) 842 { 843 axisTicks=(*static_cast<DLongGDL*> 844 (Struct->GetTag 845 (Struct->Desc()->TagIndex("TICKS"), 0)))[0]; 846 } 847 e->AssureLongScalarKWIfPresent(choosenIx, axisTicks); 848 if (axisTicks > 59) e->Throw("Value of number of ticks is out of allowed range."); 849 } 850 851 852 //if axis tick units is specified, first tickunit determines how the automatic limits are computed. 853 // for example, if tickunits=['year','day'] the limits will be on a round nuber of years. 854 // This is conveyed by the code gdlGetCalendarCode(EnvT * e,int axisId)855 static int gdlGetCalendarCode(EnvT* e, int axisId) 856 { 857 static int XTICKUNITSIx = e->KeywordIx("XTICKUNITS"); 858 static int YTICKUNITSIx = e->KeywordIx("YTICKUNITS"); 859 static int ZTICKUNITSIx = e->KeywordIx("ZTICKUNITS"); 860 int choosenIx=XTICKUNITSIx; 861 DStructGDL* Struct=NULL; 862 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKUNITSIx; } 863 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKUNITSIx; } 864 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKUNITSIx; } 865 DStringGDL* axisTickunitsVect=NULL; 866 if ( Struct!=NULL ) 867 { 868 unsigned AxisTickunitsTag=Struct->Desc()->TagIndex("TICKUNITS"); 869 axisTickunitsVect=static_cast<DStringGDL*>(Struct->GetTag(AxisTickunitsTag,0)); 870 } 871 if ( e->GetKW ( choosenIx )!=NULL ) 872 { 873 axisTickunitsVect=e->GetKWAs<DStringGDL>( choosenIx ); 874 } 875 int code=0; 876 DString what=StrUpCase((*axisTickunitsVect)[0]); 877 if (what.substr(0,4)=="YEAR") code=1; 878 else if (what.substr(0,5)=="MONTH") code=2; 879 else if (what.substr(0,3)=="DAY") code=3; 880 else if (what.substr(0,7)=="NUMERIC") code=3; 881 else if (what.substr(0,4)=="HOUR") code=4; 882 else if (what.substr(0,6)=="MINUTE") code=5; 883 else if (what.substr(0,6)=="SECOND") code=6; 884 else if (what.substr(0,4)=="TIME") code=7; 885 return code; 886 } 887 gdlGetDesiredAxisTickUnits(EnvT * e,int axisId,DStringGDL * & axisTickunitsVect)888 static void gdlGetDesiredAxisTickUnits(EnvT* e, int axisId, DStringGDL* &axisTickunitsVect) 889 { 890 static int XTICKUNITSIx = e->KeywordIx("XTICKUNITS"); 891 static int YTICKUNITSIx = e->KeywordIx("YTICKUNITS"); 892 static int ZTICKUNITSIx = e->KeywordIx("ZTICKUNITS"); 893 int choosenIx=XTICKUNITSIx; 894 DStructGDL* Struct=NULL; 895 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKUNITSIx; } 896 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKUNITSIx; } 897 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKUNITSIx; } 898 if ( Struct!=NULL ) 899 { 900 unsigned AxisTickunitsTag=Struct->Desc()->TagIndex("TICKUNITS"); 901 axisTickunitsVect=static_cast<DStringGDL*>(Struct->GetTag(AxisTickunitsTag,0)); 902 } 903 if ( e->GetKW ( choosenIx )!=NULL ) 904 { 905 axisTickunitsVect=e->GetKWAs<DStringGDL>( choosenIx ); 906 } 907 } 908 gdlGetDesiredAxisTickv(EnvT * e,int axisId,DDoubleGDL * axisTickvVect)909 static void gdlGetDesiredAxisTickv(EnvT* e, int axisId, DDoubleGDL* axisTickvVect) 910 { 911 static int XTICKVIx = e->KeywordIx("XTICKV"); 912 static int YTICKVIx = e->KeywordIx("YTICKV"); 913 static int ZTICKVIx = e->KeywordIx("ZTICKV"); 914 int choosenIx=XTICKVIx; 915 DStructGDL* Struct=NULL; 916 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTICKVIx; } 917 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTICKVIx; } 918 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTICKVIx; } 919 if ( Struct!=NULL ) 920 { 921 unsigned AxisTickvTag=Struct->Desc()->TagIndex("TICKV"); 922 axisTickvVect=static_cast<DDoubleGDL*>(Struct->GetTag(AxisTickvTag,0)); 923 924 } 925 if ( e->GetKW ( choosenIx )!=NULL ) 926 { 927 axisTickvVect=e->GetKWAs<DDoubleGDL>( choosenIx ); 928 } 929 } 930 gdlGetDesiredAxisTitle(EnvT * e,int axisId,DString & title)931 static void gdlGetDesiredAxisTitle(EnvT *e, int axisId, DString &title) 932 { 933 static int XTITLEIx = e->KeywordIx("XTITLE"); 934 static int YTITLEIx = e->KeywordIx("YTITLE"); 935 static int ZTITLEIx = e->KeywordIx("ZTITLE"); 936 int choosenIx=XTITLEIx; 937 DStructGDL* Struct=NULL; 938 if ( axisId==XAXIS ) { Struct=SysVar::X(); choosenIx=XTITLEIx; } 939 if ( axisId==YAXIS ) { Struct=SysVar::Y(); choosenIx=YTITLEIx; } 940 if ( axisId==ZAXIS ) { Struct=SysVar::Z(); choosenIx=ZTITLEIx; } 941 942 if ( Struct!=NULL ) 943 { 944 unsigned titleTag=Struct->Desc()->TagIndex("TITLE"); 945 title= 946 (*static_cast<DStringGDL*>(Struct->GetTag(titleTag, 0)))[0]; 947 } 948 949 e->AssureStringScalarKWIfPresent(choosenIx, title); 950 } 951 gdlSetLineStyle(EnvT * e,GDLGStream * a)952 static void gdlSetLineStyle(EnvT *e, GDLGStream *a) 953 { 954 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 955 DLong linestyle= 956 (*static_cast<DLongGDL*> 957 (pStruct->GetTag(pStruct->Desc()->TagIndex("LINESTYLE"), 0)))[0]; 958 959 // if the LINESTYLE keyword is present, the value will be change 960 DLong linestyleNew=-1111; 961 static int linestyleIx = e->KeywordIx("LINESTYLE"); 962 963 if (e->KeywordSet(linestyleIx)) e->AssureLongScalarKWIfPresent(linestyleIx, linestyleNew); 964 965 bool debug=false; 966 if ( debug ) 967 { 968 cout<<"temp_linestyle "<<linestyleNew<<endl; 969 cout<<" linestyle "<<linestyle<<endl; 970 } 971 if ( linestyleNew!= -1111 ) 972 { 973 linestyle=linestyleNew; 974 }//+1; 975 if ( linestyle<0 ) 976 { 977 linestyle=0; 978 } 979 if ( linestyle>5 ) 980 { 981 linestyle=5; 982 } 983 gdlLineStyle(a, linestyle); 984 } 985 986 987 gdlGetPenThickness(EnvT * e,GDLGStream * a)988 static DFloat gdlGetPenThickness(EnvT *e, GDLGStream *a) 989 { 990 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 991 DFloat thick=(*static_cast<DFloatGDL*> 992 (pStruct->GetTag(pStruct->Desc()->TagIndex("THICK"), 0)))[0]; 993 994 static int THICKIx = e->KeywordIx("THICK"); 995 e->AssureFloatScalarKWIfPresent(THICKIx, thick); 996 if ( thick <= 0.0 ) thick=1.0; 997 return thick; 998 } 999 gdlSetPenThickness(EnvT * e,GDLGStream * a)1000 static void gdlSetPenThickness(EnvT *e, GDLGStream *a) 1001 { 1002 a->Thick(gdlGetPenThickness(e, a)); 1003 } 1004 gdlWriteTitleAndSubtitle(EnvT * e,GDLGStream * a)1005 static void gdlWriteTitleAndSubtitle(EnvT* e, GDLGStream *a) 1006 { 1007 unsigned titleTag=SysVar::P()->Desc()->TagIndex("TITLE"); 1008 unsigned subTitleTag=SysVar::P()->Desc()->TagIndex("SUBTITLE"); 1009 DString title=(*static_cast<DStringGDL*>(SysVar::P()->GetTag(titleTag, 0)))[0]; 1010 DString subTitle=(*static_cast<DStringGDL*>(SysVar::P()->GetTag(subTitleTag, 0)))[0]; 1011 1012 static int TITLEIx = e->KeywordIx("TITLE"); 1013 static int SUBTITLEIx = e->KeywordIx("SUBTITLE"); 1014 e->AssureStringScalarKWIfPresent(TITLEIx, title); 1015 e->AssureStringScalarKWIfPresent(SUBTITLEIx, subTitle); 1016 if (title.empty() && subTitle.empty()) return; 1017 1018 gdlSetPlotCharsize(e, a); 1019 if (!title.empty()) 1020 { 1021 e->AssureStringScalarKWIfPresent(TITLEIx, title); 1022 gdlSetPlotCharthick(e, a); 1023 a->sizeChar(1.25*a->charScale()); 1024 a->mtex("t", 1.5, 0.5, 0.5, title.c_str()); //position is in units of current char height. baseline at half-height 1025 a->sizeChar(a->charScale()/1.25); 1026 } 1027 if (!subTitle.empty()) 1028 { 1029 e->AssureStringScalarKWIfPresent(SUBTITLEIx, subTitle); 1030 DFloat step=a->mmLineSpacing()/a->mmCharHeight(); 1031 a->mtex("b", 5*step, 0.5, 0.5, subTitle.c_str()); 1032 } 1033 } 1034 //call this function if Y data is strictly >0. 1035 //set yStart to 0 only if gdlYaxisNoZero is false. gdlYaxisNoZero(EnvT * e)1036 static bool gdlYaxisNoZero(EnvT* e) 1037 { 1038 //no explict range given? 1039 DDouble test1, test2; 1040 unsigned rangeTag=SysVar::Y()->Desc()->TagIndex("RANGE"); 1041 test1=(*static_cast<DDoubleGDL*>(SysVar::Y()->GetTag(rangeTag, 0)))[0]; 1042 test2=(*static_cast<DDoubleGDL*>(SysVar::Y()->GetTag(rangeTag, 0)))[1]; 1043 if(!(test1==0.0 && test2==0.0)) return TRUE; 1044 static int YRANGEIx=e->KeywordIx( "YRANGE"); 1045 1046 if ( e->KeywordPresent( YRANGEIx)) return TRUE; 1047 //Style contains 1? 1048 DLong ystyle; 1049 gdlGetDesiredAxisStyle(e, YAXIS, ystyle); 1050 if (ystyle&1) return TRUE; 1051 1052 DLong nozero=0; 1053 if (ystyle&16) nozero=1; 1054 static int YNOZEROIx=e->KeywordIx( "YNOZERO"); 1055 if ( e->KeywordSet(YNOZEROIx)) nozero = 1; 1056 return (nozero==1); 1057 } 1058 1059 1060 //advance to next plot unless the noerase flag is set 1061 // function declared static (local to each function using it) to avoid messing the NOERASEIx index which is not the same. gdlNextPlotHandlingNoEraseOption(EnvT * e,GDLGStream * a,bool noe=0)1062 static void gdlNextPlotHandlingNoEraseOption(EnvT *e, GDLGStream *a, bool noe=0) 1063 { 1064 bool noErase=FALSE; 1065 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 1066 1067 if ( !noe ) 1068 { 1069 DLong LnoErase=(*static_cast<DLongGDL*> 1070 (pStruct-> 1071 GetTag(pStruct->Desc()->TagIndex("NOERASE"), 0)))[0]; 1072 noErase=(LnoErase==1); 1073 static int NOERASEIx = e->KeywordIx("NOERASE"); 1074 1075 if ( e->KeywordSet(NOERASEIx) ) 1076 { 1077 noErase=TRUE; 1078 } 1079 } 1080 else 1081 { 1082 noErase=TRUE; 1083 } 1084 1085 a->NextPlot(!noErase); 1086 // all but the first element of !P.MULTI are ignored if POSITION kw or !P.POSITION or !P.REGION is specified 1087 // TODO: !P.REGION! 1088 1089 DFloatGDL* pos=NULL; 1090 1091 // system variable !P.REGION first ?? TODO 1092 pos=static_cast<DFloatGDL*>(pStruct-> GetTag(pStruct->Desc()->TagIndex("POSITION"), 0)); 1093 if ( (*pos)[0]==(*pos)[2] ) pos=NULL; //ignored 1094 1095 // keyword 1096 if ( pos==NULL ) 1097 { 1098 static int positionIx=e->KeywordIx("POSITION"); 1099 if ( e->GetKW ( positionIx )!=NULL ) 1100 { 1101 pos=e->GetKWAs<DFloatGDL>(positionIx); 1102 } 1103 } 1104 if ( pos!=NULL ) a->NoSub(); 1105 } gdlSet3DViewPortAndWorldCoordinates(EnvT * e,GDLGStream * actStream,DDoubleGDL * Matrix,bool xLog,bool yLog,DDouble xStart,DDouble xEnd,DDouble yStart,DDouble yEnd,DDouble zStart=0.0,DDouble zEnd=1.0,bool zLog=false)1106 static bool gdlSet3DViewPortAndWorldCoordinates(EnvT* e, 1107 GDLGStream* actStream, 1108 DDoubleGDL* Matrix, 1109 bool xLog, bool yLog, 1110 DDouble xStart, 1111 DDouble xEnd, 1112 DDouble yStart, 1113 DDouble yEnd, DDouble zStart=0.0, DDouble zEnd=1.0, bool zLog=false) 1114 { 1115 1116 // set ![XY].CRANGE Before doing anything relative to 3D. 1117 gdlStoreAxisCRANGE(XAXIS, xStart, xEnd, xLog); 1118 gdlStoreAxisCRANGE(YAXIS, yStart, yEnd, yLog); 1119 gdlStoreAxisCRANGE(ZAXIS, zStart, zEnd, zLog); 1120 //set ![XY].type 1121 gdlStoreAxisType(XAXIS,xLog); 1122 gdlStoreAxisType(YAXIS,yLog); 1123 gdlStoreAxisType(ZAXIS,zLog); 1124 //set ![XY].WINDOW and ![XY].S 1125 gdlStoreAxisSandWINDOW(actStream, XAXIS, xStart, xEnd, xLog); 1126 gdlStoreAxisSandWINDOW(actStream, YAXIS, yStart, yEnd, yLog); 1127 gdlStoreAxisSandWINDOW(actStream, ZAXIS, zStart, zEnd, zLog); 1128 1129 //3D work 1130 enum{ DATA=0, 1131 NORMAL, 1132 DEVICE 1133 } coordinateSystem=DATA; 1134 //To center plot, compute projected corners of 1 unit box 1135 static DDouble zz[8]={0,0,0,0,1,1,1,1}; 1136 static DDouble yy[8]={0,0,1,1,0,0,1,1}; 1137 static DDouble xx[8]={0,1,0,1,0,1,0,1}; 1138 static DDouble ww[8]={1,1,1,1,1,1,1,1}; 1139 1140 DDoubleGDL* V=(new DDoubleGDL(dimension(8,4))); 1141 memcpy(&((*V)[0]),xx,8*sizeof(double)); 1142 memcpy(&((*V)[8]),yy,8*sizeof(double)); 1143 memcpy(&((*V)[16]),zz,8*sizeof(double)); 1144 memcpy(&((*V)[24]),ww,8*sizeof(double)); 1145 1146 DDoubleGDL* pV=(Matrix->MatrixOp(V,false,true)); 1147 1148 DDouble xmin,xmax,ymin,ymax; 1149 DLong iMin,iMax; 1150 pV->MinMax(&iMin,&iMax,NULL,NULL,false,0,0,4); 1151 xmin=(*pV)[iMin]; 1152 xmax=(*pV)[iMax]; 1153 pV->MinMax(&iMin,&iMax,NULL,NULL,false,1,0,4); 1154 ymin=(*pV)[iMin]; 1155 ymax=(*pV)[iMax]; 1156 1157 PLFLT xMR, xML, yMB, yMT; 1158 DFloat xMarginL, xMarginR, yMarginB, yMarginT; 1159 gdlGetDesiredAxisMargin(e, XAXIS, xMarginL, xMarginR); 1160 gdlGetDesiredAxisMargin(e, YAXIS, yMarginB, yMarginT); 1161 PLFLT scl=actStream->nCharLength(); //current char width 1162 xML=xMarginL*scl; //margin as percentage of subpage 1163 xMR=xMarginR*scl; 1164 scl=actStream->nCharHeight(); //current char height 1165 yMB=(yMarginB)*scl; 1166 yMT=(yMarginT)*scl; 1167 1168 if ( xML+xMR>=1.0 ) 1169 { 1170 PLFLT xMMult=xML+xMR; 1171 xML/=xMMult*1.5; 1172 xMR/=xMMult*1.5; 1173 } 1174 if ( yMB+yMT>=1.0 ) 1175 { 1176 PLFLT yMMult=yMB+yMT; 1177 yMB/=yMMult*1.5; 1178 yMT/=yMMult*1.5; 1179 } 1180 1181 static PLFLT positionP[4]={0, 0, 0, 0}; 1182 static PLFLT regionP[4]={0, 0, 0, 0}; 1183 static PLFLT position[4]={0,0,1,1}; 1184 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 1185 // Get !P.position values. !P.REGION is superseded by !P.POSITION 1186 if ( pStruct!=NULL ) 1187 { 1188 1189 unsigned regionTag=pStruct->Desc()->TagIndex("REGION"); 1190 for ( SizeT i=0; i<4; ++i ) regionP[i]=(PLFLT)(*static_cast<DFloatGDL*>(pStruct->GetTag(regionTag, 0)))[i]; 1191 unsigned positionTag=pStruct->Desc()->TagIndex("POSITION"); 1192 for ( SizeT i=0; i<4; ++i ) positionP[i]=(PLFLT)(*static_cast<DFloatGDL*>(pStruct->GetTag(positionTag, 0)))[i]; 1193 } 1194 if (regionP[0]!=regionP[2] && positionP[0]==positionP[2]) //if not ignored, and will be used, as 1195 //a surrogate of !P.Position: 1196 { 1197 //compute position removing margins 1198 positionP[0]=regionP[0]+xMarginL*actStream->nCharLength(); 1199 positionP[1]=regionP[1]+yMarginB*actStream->nCharHeight(); 1200 positionP[2]=regionP[2]-xMarginR*actStream->nCharLength(); 1201 positionP[3]=regionP[3]-yMarginT*actStream->nCharHeight(); 1202 } 1203 //compatibility: Position NEVER outside [0,1]: 1204 positionP[0]=max(0.0,positionP[0]); 1205 positionP[1]=max(0.0,positionP[1]); 1206 positionP[2]=min(1.0,positionP[2]); 1207 positionP[3]=min(1.0,positionP[3]); 1208 1209 //check presence of DATA,DEVICE and NORMAL options 1210 static int DATAIx=e->KeywordIx("DATA"); 1211 static int DEVICEIx=e->KeywordIx("DEVICE"); 1212 static int NORMALIx=e->KeywordIx("NORMAL"); 1213 1214 if (e->KeywordSet(DATAIx)) coordinateSystem = DATA; 1215 if (e->KeywordSet(DEVICEIx)) coordinateSystem = DEVICE; 1216 if (e->KeywordSet(NORMALIx)) coordinateSystem = NORMAL; 1217 // if (coordinateSystem==DATA && !actStream->validWorldBox()) e->Throw("PLOT: Data coordinate system not established."); 1218 // read boxPosition if needed 1219 static int positionIx = e->KeywordIx( "POSITION"); 1220 DFloatGDL* boxPosition = e->IfDefGetKWAs<DFloatGDL>( positionIx); 1221 if (boxPosition == NULL) boxPosition = (DFloatGDL*) 0xF; 1222 if ( boxPosition!=(DFloatGDL*)0xF) 1223 { 1224 for ( SizeT i=0; i<4&&i<boxPosition->N_Elements(); ++i ) position[i]=(*boxPosition)[i]; 1225 } 1226 // modify positionP and/or boxPosition to NORMAL if DEVICE is present 1227 if (coordinateSystem==DEVICE) 1228 { 1229 PLFLT normx; 1230 PLFLT normy; 1231 actStream->DeviceToNormedDevice(positionP[0], positionP[1], normx, normy); 1232 positionP[0]=normx; 1233 positionP[1]=normy; 1234 actStream->DeviceToNormedDevice(positionP[2], positionP[3], normx, normy); 1235 positionP[2]=normx; 1236 positionP[3]=normy; 1237 if ( boxPosition!=(DFloatGDL*)0xF) 1238 { 1239 actStream->DeviceToNormedDevice(position[0], position[1], normx, normy); 1240 position[0]=normx; 1241 position[1]=normy; 1242 actStream->DeviceToNormedDevice(position[2], position[3], normx, normy); 1243 position[2]=normx; 1244 position[3]=normy; 1245 } 1246 } 1247 if ( boxPosition!=(DFloatGDL*)0xF) 1248 { //compatibility again: Position NEVER outside [0,1]: 1249 position[0]=max(0.0,position[0]); 1250 position[1]=max(0.0,position[1]); 1251 position[2]=min(1.0,position[2]); 1252 position[3]=min(1.0,position[3]); 1253 } 1254 1255 // New plot without POSITION=[] as argument 1256 if ( boxPosition==(DFloatGDL*)0xF ) 1257 { 1258 // If !P.position not set use default values. coordinatesSystem not used even if present! 1259 if ( positionP[0]==0&&positionP[1]==0&& 1260 positionP[2]==0&&positionP[3]==0 ) 1261 { 1262 // Set to (smart?) default values 1263 position[0]=0; 1264 position[1]=0+2*(yMB/yMarginB); //subtitle 1265 position[2]=1.0; 1266 position[3]=1.0-2*(yMT/yMarginT); //title 1267 actStream->vpor(position[0], position[2], position[1], position[3]); 1268 } 1269 else 1270 { 1271 // Use !P.position values. 1272 actStream->vpor(positionP[0], positionP[2], positionP[1], positionP[3]); 1273 } 1274 } 1275 else // Position keyword set 1276 { 1277 actStream->vpor(position[0], position[2], position[1], position[3]); 1278 } 1279 //adjust 'world' values to give room to axis labels. Could be better if we take 1280 //into account projection angles 1281 // fix word values without labels: 1282 actStream->wind(xmin, xmax, ymin, ymax); 1283 //compute world Charsize 1284 PLFLT xb, xe, yb, ye; 1285 xb=xmin-xMarginL*actStream->wCharLength(); 1286 xe=xmax+xMarginR*actStream->wCharLength(); 1287 yb=ymin-yMarginB*actStream->wCharHeight(); 1288 ye=ymax-yMarginT*actStream->wCharHeight(); 1289 actStream->wind(xb, xe, yb, ye); 1290 1291 1292 //Clipping is false in 3D... 1293 1294 //set P.CLIP (done by PLOT, CONTOUR, SHADE_SURF, and SURFACE) 1295 Guard<BaseGDL> clipbox_guard; 1296 DLongGDL* clipBox= new DLongGDL(4, BaseGDL::ZERO); clipbox_guard.Reset(clipBox); 1297 PLFLT x,y; 1298 actStream->gvpd(xmin, xmax, ymin, ymax); 1299 1300 actStream->NormedDeviceToDevice(xmin, ymin, x,y); 1301 (*clipBox)[0]=x; 1302 (*clipBox)[1]=y; 1303 actStream->NormedDeviceToDevice(xmax, ymax,x,y); 1304 (*clipBox)[2]=x; 1305 (*clipBox)[3]=y; 1306 gdlStoreCLIP(clipBox); 1307 return true; 1308 } 1309 //TODO: put margin discovery in gdlSetViewPortAndWorldCoordinates (simplify call list) 1310 //also, solve the proble of passing back xStart etc if they are changed by unwantedaxisvalue()) 1311 gdlSetViewPortAndWorldCoordinates(EnvT * e,GDLGStream * actStream,bool xLog,bool yLog,DFloat xMarginL,DFloat xMarginR,DFloat yMarginB,DFloat yMarginT,DDouble xStart,DDouble xEnd,DDouble yStart,DDouble yEnd,DLong iso)1312 static bool gdlSetViewPortAndWorldCoordinates(EnvT* e, 1313 GDLGStream* actStream, 1314 bool xLog, bool yLog, 1315 DFloat xMarginL, 1316 DFloat xMarginR, 1317 DFloat yMarginB, 1318 DFloat yMarginT, 1319 DDouble xStart, 1320 DDouble xEnd, 1321 DDouble yStart, 1322 DDouble yEnd, 1323 DLong iso) 1324 { 1325 1326 PLFLT xMR; 1327 PLFLT xML; 1328 PLFLT yMB; 1329 PLFLT yMT; 1330 enum{ DATA=0, 1331 NORMAL, 1332 DEVICE 1333 } coordinateSystem=DATA; 1334 1335 CheckMargin(actStream, 1336 xMarginL, 1337 xMarginR, 1338 yMarginB, 1339 yMarginT, 1340 xMR, xML, yMB, yMT); 1341 1342 // viewport - POSITION overrides 1343 static bool kwP=FALSE; 1344 static bool do_iso=FALSE; 1345 static PLFLT aspect=0.0; 1346 1347 static PLFLT positionP[4]={0, 0, 0, 0}; 1348 static PLFLT regionP[4]={0, 0, 0, 0}; 1349 static PLFLT position[4]={0,0,1,1}; 1350 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 1351 // Get !P.position values. !P.REGION is superseded by !P.POSITION 1352 if ( pStruct!=NULL ) 1353 { 1354 1355 unsigned regionTag=pStruct->Desc()->TagIndex("REGION"); 1356 for ( SizeT i=0; i<4; ++i ) regionP[i]=(PLFLT)(*static_cast<DFloatGDL*>(pStruct->GetTag(regionTag, 0)))[i]; 1357 unsigned positionTag=pStruct->Desc()->TagIndex("POSITION"); 1358 for ( SizeT i=0; i<4; ++i ) positionP[i]=(PLFLT)(*static_cast<DFloatGDL*>(pStruct->GetTag(positionTag, 0)))[i]; 1359 } 1360 if (regionP[0]!=regionP[2] && positionP[0]==positionP[2]) //if not ignored, and will be used, as 1361 //a surrogate of !P.Position: 1362 { 1363 //compute position removing margins 1364 positionP[0]=regionP[0]+xMarginL*actStream->nCharLength(); 1365 positionP[1]=regionP[1]+yMarginB*actStream->nLineSpacing(); 1366 positionP[2]=regionP[2]-xMarginR*actStream->nCharLength(); 1367 positionP[3]=regionP[3]-yMarginT*actStream->nLineSpacing(); 1368 } 1369 //compatibility: Position NEVER outside [0,1]: 1370 positionP[0]=max(0.0,positionP[0]); 1371 positionP[1]=max(0.0,positionP[1]); 1372 positionP[2]=min(1.0,positionP[2]); 1373 positionP[3]=min(1.0,positionP[3]); 1374 1375 //check presence of DATA,DEVICE and NORMAL options 1376 static int DATAIx=e->KeywordIx("DATA"); 1377 static int DEVICEIx=e->KeywordIx("DEVICE"); 1378 static int NORMALIx=e->KeywordIx("NORMAL"); 1379 1380 if (e->KeywordSet(DATAIx)) coordinateSystem = DATA; 1381 if (e->KeywordSet(DEVICEIx)) coordinateSystem = DEVICE; 1382 if (e->KeywordSet(NORMALIx)) coordinateSystem = NORMAL; 1383 // if (coordinateSystem==DATA && !actStream->validWorldBox()) e->Throw("PLOT: Data coordinate system not established."); 1384 // read boxPosition if needed 1385 static int positionIx = e->KeywordIx( "POSITION"); 1386 DFloatGDL* boxPosition = e->IfDefGetKWAs<DFloatGDL>( positionIx); 1387 if (boxPosition == NULL) boxPosition = (DFloatGDL*) 0xF; 1388 if ( boxPosition!=NULL && boxPosition!=(DFloatGDL*)0xF ) 1389 { 1390 for ( SizeT i=0; i<4&&i<boxPosition->N_Elements(); ++i ) position[i]=(*boxPosition)[i]; 1391 } 1392 // modify positionP and/or boxPosition to NORMAL if DEVICE is present 1393 if (coordinateSystem==DEVICE) 1394 { 1395 PLFLT normx; 1396 PLFLT normy; 1397 actStream->DeviceToNormedDevice(positionP[0], positionP[1], normx, normy); 1398 positionP[0]=normx; 1399 positionP[1]=normy; 1400 actStream->DeviceToNormedDevice(positionP[2], positionP[3], normx, normy); 1401 positionP[2]=normx; 1402 positionP[3]=normy; 1403 if ( boxPosition!=NULL && boxPosition!=(DFloatGDL*)0xF ) 1404 { 1405 actStream->DeviceToNormedDevice(position[0], position[1], normx, normy); 1406 position[0]=normx; 1407 position[1]=normy; 1408 actStream->DeviceToNormedDevice(position[2], position[3], normx, normy); 1409 position[2]=normx; 1410 position[3]=normy; 1411 } 1412 } 1413 if ( boxPosition!=NULL && boxPosition!=(DFloatGDL*)0xF ) 1414 { 1415 //compatibility again: Position NEVER outside [0,1]: 1416 position[0]=max(0.0,position[0]); 1417 position[1]=max(0.0,position[1]); 1418 position[2]=min(1.0,position[2]); 1419 position[3]=min(1.0,position[3]); 1420 } 1421 // Adjust Start and End for Log (convert to log) 1422 if ( boxPosition!=NULL ) //new box 1423 { 1424 if ( xLog ) 1425 { 1426 gdlHandleUnwantedAxisValue(xStart, xEnd, xLog); 1427 xStart=log10(xStart); 1428 xEnd=log10(xEnd); 1429 } 1430 if ( yLog ) 1431 { 1432 gdlHandleUnwantedAxisValue(yStart, yEnd, yLog); 1433 yStart=log10(yStart); 1434 yEnd=log10(yEnd); 1435 } 1436 } 1437 // If pos == NULL (oplot, /OVERPLOT etc: Reuse previous values) 1438 if ( boxPosition==NULL ) 1439 { 1440 // If position keyword previously set 1441 if ( kwP ) 1442 { 1443 // Creates a viewport with the specified normalized subpage coordinates. 1444 if ( do_iso ) setIsoPort(actStream, position[0], position[2], position[1], position[3], aspect); 1445 else actStream->vpor(position[0], position[2], position[1], position[3]); 1446 } 1447 else 1448 { 1449 // If !P.position not set 1450 if ( positionP[0]==0&&positionP[1]==0&& 1451 positionP[2]==0&&positionP[3]==0 ) 1452 { 1453 if ( do_iso ) setIsoPort(actStream, position[0], position[2], position[1], position[3], aspect); 1454 else actStream->vpor(position[0], position[2], position[1], position[3]); 1455 } 1456 else 1457 { 1458 // !P.position set 1459 if ( do_iso ) setIsoPort(actStream, positionP[0], positionP[2], positionP[1], positionP[3], aspect); 1460 else actStream->vpor(positionP[0], positionP[2], positionP[1], positionP[3]); 1461 } 1462 } 1463 } 1464 else //New Plot 1465 { 1466 if ( iso==1 ) // Check ISOTROPIC first 1467 { 1468 do_iso=TRUE; 1469 aspect=abs((yEnd-yStart)/(xEnd-xStart)); //log-log or lin-log 1470 } 1471 else 1472 { 1473 do_iso=FALSE; 1474 aspect=0.0; // vpas with aspect=0.0 equals vpor. 1475 } 1476 1477 // New plot without POSITION=[] as argument 1478 if ( boxPosition==(DFloatGDL*)0xF ) 1479 { 1480 kwP=false; 1481 // If !P.position not set use default values. coordinatesSystem not used even if present! 1482 if ( positionP[0]==0&&positionP[1]==0&& 1483 positionP[2]==0&&positionP[3]==0 ) 1484 { 1485 1486 // Set to default values 1487 position[0]=xML; 1488 position[1]=yMB; 1489 position[2]=1.0-xMR; 1490 position[3]=1.0-yMT; 1491 if ( do_iso ) setIsoPort(actStream, position[0], position[2], position[1], position[3], aspect); 1492 else actStream->vpor(position[0], position[2], position[1], position[3]); 1493 } 1494 else 1495 { 1496 // Use !P.position values. 1497 if ( do_iso ) setIsoPort(actStream, positionP[0], positionP[2], positionP[1], positionP[3], aspect); 1498 else actStream->vpor(positionP[0], positionP[2], positionP[1], positionP[3]); 1499 } 1500 } 1501 else // Position keyword set 1502 { 1503 kwP=true; 1504 if ( do_iso ) setIsoPort(actStream, position[0], position[2], position[1], position[3], aspect); 1505 else actStream->vpor(position[0], position[2], position[1], position[3]); 1506 } 1507 } 1508 1509 // for OPLOT start and end values are already log 1510 // SA: changing only local variables! 1511 1512 //cout << "VP wind: "<<xStart<<" "<<xEnd<<" "<<yStart<<" "<<yEnd<<endl; 1513 //printf("data lim (setv): %f %f %f %f\n", xStart, xEnd, yStart, yEnd); 1514 // set world coordinates 1515 //protection against silly coordinates 1516 if (xStart==xEnd) 1517 { 1518 Message(e->GetProName()+"Coordinate system in error, please report to authors."); 1519 xStart=0.0; 1520 xEnd=1.0; 1521 } 1522 if (yStart==yEnd) 1523 { 1524 Message(e->GetProName()+"Coordinate system in error, please report to authors."); 1525 yStart=0.0; 1526 yEnd=1.0; 1527 } 1528 actStream->wind(xStart, xEnd, yStart, yEnd); 1529 // cout << "xStart " << xStart << " xEnd "<<xEnd<<endl; 1530 // cout << "yStart " << yStart << " yEnd "<<yEnd<<endl; 1531 1532 // set ![XYZ].CRANGE (Z is not defined but must be [0,1]) 1533 gdlStoreAxisCRANGE(XAXIS, xStart, xEnd, FALSE); //already in log here if relevant! 1534 gdlStoreAxisCRANGE(YAXIS, yStart, yEnd, FALSE); 1535 1536 //set ![XY].type 1537 gdlStoreAxisType(XAXIS,xLog); 1538 gdlStoreAxisType(YAXIS,yLog); 1539 1540 //set ![XY].WINDOW and ![XY].S 1541 gdlStoreAxisSandWINDOW(actStream, XAXIS, xStart, xEnd, FALSE);//already in log here if relevant! 1542 gdlStoreAxisSandWINDOW(actStream, YAXIS, yStart, yEnd, FALSE); 1543 //set P.CLIP (done by PLOT, CONTOUR, SHADE_SURF, and SURFACE) 1544 Guard<BaseGDL> clipbox_guard; 1545 DLongGDL* clipBox= new DLongGDL(4, BaseGDL::ZERO); clipbox_guard.Reset(clipBox); 1546 PLFLT xmin, xmax, ymin, ymax, x,y; 1547 actStream->gvpd(xmin, xmax, ymin, ymax); 1548 1549 actStream->NormedDeviceToDevice(xmin, ymin, x,y); 1550 (*clipBox)[0]=x; 1551 (*clipBox)[1]=y; 1552 actStream->NormedDeviceToDevice(xmax, ymax,x,y); 1553 (*clipBox)[2]=x; 1554 (*clipBox)[3]=y; 1555 gdlStoreCLIP(clipBox); 1556 return true; 1557 } 1558 startClipping(EnvT * e,GDLGStream * a,bool canUsePClip=false)1559 static bool startClipping(EnvT *e, GDLGStream *a, bool canUsePClip=false) 1560 { 1561 if (GDL_DEBUG_PLSTREAM) fprintf(stderr,"startClipping\n"); 1562 //function to be called when clipping must be actived, i.e., if the combination of CLIP= and NOCLIP= necessitate it 1563 //the function retrieves the pertinent information in keywords 1564 enum 1565 { 1566 DATA=0, 1567 NORMAL, 1568 DEVICE 1569 } coordinateSystem=DATA; 1570 bool xinverted=FALSE; 1571 bool yinverted=FALSE; //for inverted DATA coordinates 1572 1573 1574 1575 static int clippingix=e->KeywordIx("CLIP"); 1576 DFloatGDL* clipBox=NULL; 1577 clipBox=e->IfDefGetKWAs<DFloatGDL>(clippingix); 1578 1579 //Get saveBox 1580 gdlSavebox* saveBox=getSaveBox(); 1581 //Save current box 1582 a->gvpd(saveBox->nx1, saveBox->nx2, saveBox->ny1, saveBox->ny2); //save norm of current box 1583 a->gvpw(saveBox->wx1, saveBox->wx2, saveBox->wy1, saveBox->wy2); //save world of current box 1584 saveBox->initialized=true; //mark as initialized (debug complicated clipping algo) 1585 //test axis inversion 1586 xinverted=(saveBox->wx1>saveBox->wx2); 1587 yinverted=(saveBox->wy1>saveBox->wy2); 1588 //GET CLIPPING 1589 PLFLT dClipBox[4]={0, 0, 0, 0}; 1590 PLFLT tempbox[4]={0, 0, 0, 0}; 1591 DDouble un, deux, trois, quatre; 1592 static int NOCLIPIx=e->KeywordIx("NOCLIP"); 1593 static string proname=e->GetProName(); 1594 static bool invertedMeaning=(proname=="PLOTS"||proname=="POLYFILL"||proname=="XYOUTS"); 1595 int noclipvalue=1; 1596 e->AssureLongScalarKWIfPresent( NOCLIPIx, noclipvalue); 1597 bool willNotClip; 1598 //eliminate simple cases 1599 if (invertedMeaning) willNotClip=(noclipvalue==1); else willNotClip=(e->KeywordSet(NOCLIPIx)); 1600 if (willNotClip) return false; 1601 if ( !canUsePClip && clipBox==NULL ) return false; 1602 if ( !canUsePClip && clipBox->N_Elements()<4) return false; 1603 //now we can start checking more deeply 1604 if (proname != "OPLOT") { //OPLOT has no /DEVICE /NORM and is already /DATA 1605 static int DATAIx=e->KeywordIx("DATA"); 1606 static int DEVICEIx=e->KeywordIx("DEVICE"); 1607 static int NORMALIx=e->KeywordIx("NORMAL"); 1608 1609 if (e->KeywordSet(DATAIx)) coordinateSystem = DATA; 1610 if (e->KeywordSet(DEVICEIx)) coordinateSystem = DEVICE; 1611 if (e->KeywordSet(NORMALIx)) coordinateSystem = NORMAL; 1612 } 1613 1614 if ( clipBox==NULL && canUsePClip ) //get !P.CLIP. Coordinates are always DEVICE 1615 { 1616 DStructGDL* pStruct=SysVar::P(); //MUST NOT BE STATIC, due to .reset 1617 unsigned clipTag=pStruct->Desc()->TagIndex("CLIP"); //is in device coordinates 1618 for ( int i=0; i<4; ++i ) tempbox[i]=dClipBox[i]=(*static_cast<DLongGDL*>(pStruct->GetTag(clipTag, 0)))[i]; 1619 coordinateSystem = DEVICE; //is in device coordinates 1620 if (GDL_DEBUG_PLSTREAM) fprintf(stderr, "using !P.CLIP=[%f,%f,%f,%f]\n", dClipBox[0], dClipBox[1], dClipBox[2], dClipBox[3]); 1621 } 1622 else //get units, convert to world coords for plplot, take care of axis direction 1623 { 1624 if ( (*clipBox)[0]>=(*clipBox)[2] ||(*clipBox)[1]>=(*clipBox)[3] ) { 1625 coordinateSystem=NORMAL; 1626 tempbox[0]=0.0; 1627 tempbox[1]=0.0; 1628 tempbox[2]=0.00001; //ridiculous but works. 1629 tempbox[3]=0.00001; 1630 } else for ( int i=0; i<4&&i<clipBox->N_Elements(); ++i ) tempbox[i]=dClipBox[i]=(*clipBox)[i]; 1631 1632 if (GDL_DEBUG_PLSTREAM) fprintf(stderr, "using given CLIP=[%f,%f,%f,%f]\n", dClipBox[0], dClipBox[1], dClipBox[2], dClipBox[3]); 1633 if ( coordinateSystem==DATA ) 1634 { 1635 int *tx,*ty; 1636 int txn[2]={0,2}; 1637 int txr[2]={2,0}; 1638 int tyn[2]={1,3}; 1639 int tyr[2]={3,1}; 1640 if(tempbox[0]<tempbox[2]) { if (xinverted) tx=txr; else tx=txn;} else { if (xinverted) tx=txn; else tx=txr;} 1641 if(tempbox[1]<tempbox[3]) { if (yinverted) ty=tyr; else ty=tyn;} else { if (yinverted) ty=tyn; else ty=tyr;} 1642 un=tempbox[tx[0]]; 1643 deux=tempbox[ty[0]]; 1644 a->WorldToDevice(un, deux, trois, quatre); 1645 dClipBox[0]=trois; 1646 dClipBox[1]=quatre; 1647 un=tempbox[tx[1]]; 1648 deux=tempbox[ty[1]]; 1649 a->WorldToDevice(un, deux, trois, quatre); 1650 dClipBox[2]=trois; 1651 dClipBox[3]=quatre; 1652 } 1653 else if ( coordinateSystem==NORMAL ) 1654 { 1655 a->NormToDevice(tempbox[0], tempbox[1], dClipBox[0], dClipBox[1]); 1656 a->NormToDevice(tempbox[2], tempbox[3], dClipBox[2], dClipBox[3]); 1657 } 1658 } 1659 // we are now in DEVICE Coords 1660 // } 1661 //if new box is in error, return it: 1662 if (dClipBox[0]>=dClipBox[2]||dClipBox[1]>=dClipBox[3]) return false; 1663 //compute and set corresponding world coords before using whole page: 1664 a->DeviceToWorld(dClipBox[0], dClipBox[1],tempbox[0], tempbox[1]); 1665 a->DeviceToWorld(dClipBox[2], dClipBox[3],tempbox[2], tempbox[3]); 1666 1667 a->NoSub(); 1668 // set full page viewport for the clip box boundaries: 1669 PLFLT xmin,xmax,ymin,ymax; 1670 a->DeviceToNormedDevice(dClipBox[0], dClipBox[1],xmin, ymin); 1671 a->DeviceToNormedDevice(dClipBox[2], dClipBox[3],xmax, ymax); 1672 a->vpor(xmin, xmax,ymin, ymax); 1673 a->wind(tempbox[0], tempbox[2], tempbox[1], tempbox[3]); 1674 // a->box( "bc", 0, 0, "bc", 0.0, 0); 1675 return TRUE; 1676 } gdlAxis(EnvT * e,GDLGStream * a,int axisId,DDouble Start,DDouble End,bool Log,DLong modifierCode=0,DDouble NormedLength=0)1677 static bool gdlAxis(EnvT *e, GDLGStream *a, int axisId, DDouble Start, DDouble End, bool Log, 1678 DLong modifierCode=0, DDouble NormedLength=0) 1679 { 1680 static GDL_TICKDATA tdata; 1681 tdata.a=a; 1682 tdata.isLog=Log; 1683 tdata.axisrange=abs(End-Start); 1684 1685 static GDL_TICKNAMEDATA data; 1686 data.a=a; 1687 data.isLog=Log; 1688 data.axisrange=abs(End-Start); 1689 data.nTickName=0; 1690 1691 static GDL_MULTIAXISTICKDATA muaxdata; 1692 muaxdata.e=e; 1693 muaxdata.a=a; 1694 muaxdata.isLog=Log; 1695 muaxdata.what=GDL_NONE; 1696 muaxdata.nTickFormat=0; 1697 muaxdata.nTickUnits=0; 1698 muaxdata.axismin=Start; 1699 muaxdata.axismax=End; 1700 muaxdata.axisrange=abs(End-Start); 1701 muaxdata.reset=true; 1702 1703 //special values 1704 PLFLT OtherAxisSizeInMm; 1705 if (axisId==XAXIS) OtherAxisSizeInMm=a->mmyPageSize()*(a->boxnYSize()); 1706 if (axisId==YAXIS) OtherAxisSizeInMm=a->mmxPageSize()*(a->boxnXSize()); 1707 //special for AXIS who change the requested box size! 1708 if (axisId==XAXIS2) {axisId=XAXIS; OtherAxisSizeInMm=a->mmyPageSize()*(NormedLength);} 1709 if (axisId==YAXIS2) {axisId=YAXIS; OtherAxisSizeInMm=a->mmxPageSize()*(NormedLength);} 1710 1711 DLong GridStyle; 1712 gdlGetDesiredAxisGridStyle(e, axisId, GridStyle); 1713 DLong Minor; 1714 gdlGetDesiredAxisMinor(e, axisId, Minor); 1715 DLong Style; 1716 gdlGetDesiredAxisStyle(e, axisId, Style); 1717 DFloat Thick; 1718 gdlGetDesiredAxisThick(e, axisId, Thick); 1719 DStringGDL* TickFormat; 1720 gdlGetDesiredAxisTickFormat(e, axisId, TickFormat); 1721 DDouble TickInterval; 1722 gdlGetDesiredAxisTickInterval(e, axisId, TickInterval); 1723 DLong TickLayout; 1724 gdlGetDesiredAxisTickLayout(e, axisId, TickLayout); 1725 DFloat TickLen; 1726 gdlGetDesiredAxisTickLen(e, axisId, TickLen); 1727 DStringGDL* TickName; 1728 gdlGetDesiredAxisTickName(e, a, axisId, TickName); 1729 DLong Ticks; 1730 gdlGetDesiredAxisTicks(e, axisId, Ticks); 1731 DStringGDL* TickUnits; 1732 gdlGetDesiredAxisTickUnits(e, axisId, TickUnits); 1733 // DDoubleGDL *Tickv; 1734 // gdlGetDesiredAxisTickv(e, axisId, Tickv); 1735 DString Title; 1736 gdlGetDesiredAxisTitle(e, axisId, Title); 1737 1738 bool hasTickUnitDefined = (TickUnits->NBytes()>0); 1739 int tickUnitArraySize=(hasTickUnitDefined)?TickUnits->N_Elements():0; 1740 1741 //For labels we need ticklen in current character size, for ticks we need it in mm 1742 DFloat ticklen_in_mm= TickLen; 1743 if (TickLen<0) ticklen_in_mm*=-1; 1744 //ticklen in a percentage of box x or y size, to be expressed in mm 1745 if (axisId==XAXIS) ticklen_in_mm=a->mmyPageSize()*(a->boxnYSize())*ticklen_in_mm; 1746 if (axisId==YAXIS) ticklen_in_mm=a->mmxPageSize()*(a->boxnXSize())*ticklen_in_mm; 1747 DFloat ticklen_as_norm=(axisId==XAXIS)?a->mm2ndy(ticklen_in_mm):a->mm2ndx(ticklen_in_mm); //in normed coord 1748 //eventually, each succesive X or Y axis is separated from previous by interligne + ticklen in adequate units. 1749 DFloat interligne_as_char; 1750 DFloat interligne_as_norm; 1751 DFloat typical_char_size_mm= (axisId==XAXIS)?a->mmCharHeight():a->mmCharLength(); 1752 interligne_as_char=(axisId==XAXIS)?a->mmLineSpacing()/typical_char_size_mm:a->mmCharLength()/typical_char_size_mm; //in normed coord 1753 interligne_as_norm=(axisId==XAXIS)?a->nLineSpacing():a->nCharLength(); //in normed coord 1754 DFloat displacement_of_new_axis_as_norm=2*interligne_as_norm+ticklen_as_norm; 1755 DFloat current_displacement=0; 1756 DFloat title_position=0; 1757 if ( (Style&4)!=4 ) //if we write the axis... 1758 { 1759 double nchars; //max number of chars written in label of axis. 1760 string Opt; 1761 string otherOpt; 1762 if (TickInterval==0) 1763 { 1764 if (Ticks<=0) TickInterval=gdlComputeTickInterval(e, axisId, Start, End, Log); 1765 else if (Ticks>1) TickInterval=(End-Start)/Ticks; 1766 else TickInterval=(End-Start); 1767 } else { //check that tickinterval does not make more than 59 ticks: 1768 if (abs((End-Start)/TickInterval) > 59) TickInterval=(End-Start)/59; 1769 } 1770 //first write labels only: 1771 gdlSetAxisCharsize(e, a, axisId); 1772 gdlSetPlotCharthick(e, a); 1773 1774 //axis, 1st time: labels 1775 Opt="tvx";otherOpt="tv"; //draw major ticks "t" + v:values perp to Y axis + x: 1776 // the x option is in plplot 5.9.8 but not before. It permits 1777 // to avoid writing tick marks here (they will be written after) 1778 // I hope old plplots were clever enough to ignore 'x' 1779 // if they did not understand 'x' 1780 if ( Log ) Opt+="l"; //"l" for log; otherOpt is never in log I believe 1781 if (TickName->NBytes()>0) // /TICKNAME=[array] 1782 { 1783 data.counter=0; 1784 data.nchars=0; 1785 data.TickName=TickName; 1786 data.nTickName=TickName->N_Elements(); 1787 a->slabelfunc( gdlSingleAxisTickNamedFunc, &data ); 1788 Opt+="o"; 1789 if (modifierCode==2) Opt+="m"; else Opt+="n"; 1790 if (axisId==XAXIS) a->box(Opt.c_str(), TickInterval, Minor, "", 0.0, 0); 1791 else if (axisId==YAXIS) a->box("", 0.0 ,0.0, Opt.c_str(), TickInterval, Minor); 1792 nchars=data.nchars; 1793 if (axisId==YAXIS) title_position=nchars+2.5; else title_position=3.5; 1794 a->slabelfunc( NULL, NULL ); 1795 } 1796 //care Tickunits size is 10 if not defined because it is the size of !X.TICKUNITS. 1797 else if (hasTickUnitDefined) // /TICKUNITS=[several types of axes written below each other] 1798 { 1799 muaxdata.counter=0; 1800 muaxdata.what=GDL_TICKUNITS; 1801 if (TickFormat->NBytes()>0) // with also TICKFORMAT option.. 1802 { 1803 muaxdata.what=GDL_TICKFORMAT_AND_UNITS; 1804 muaxdata.TickFormat=TickFormat; 1805 muaxdata.nTickFormat=TickFormat->N_Elements(); 1806 } 1807 muaxdata.TickUnits=TickUnits; 1808 muaxdata.nTickUnits=tickUnitArraySize; 1809 a->slabelfunc( gdlMultiAxisTickFunc, &muaxdata ); 1810 Opt+="o";otherOpt+="o"; //use external func custom labeling 1811 if (modifierCode==2) {Opt+="m"; otherOpt+="m";} else {Opt+="n"; otherOpt+="n";} //m: write numerical/right above, n: below/left (normal) 1812 PLFLT un,deux,trois,quatre,xun,xdeux,xtrois,xquatre; 1813 a->getCurrentNormBox(un,deux,trois,quatre); 1814 a->getCurrentWorldBox(xun,xdeux,xtrois,xquatre); 1815 a->smaj(ticklen_in_mm, 1.0 ); 1816 for (SizeT i=0; i< muaxdata.nTickUnits; ++i) //loop on TICKUNITS axis 1817 { 1818 muaxdata.nchars=0; //set nchars to 0, at the end nchars will be the maximum size. 1819 if (i>0) Opt=otherOpt+"b"; //supplementary axes are to be wwritten with ticks, no smallticks; 1820 if (axisId==XAXIS) 1821 { 1822 a->vpor(un,deux,trois-current_displacement,quatre); 1823 a->wind(xun,xdeux,xtrois,xquatre); 1824 a->box(Opt.c_str(), TickInterval, Minor, "", 0.0, 0); //to avoid plplot crashes: do not use tickinterval. or recompute it correctly (no too small!) 1825 title_position=current_displacement/a->nCharHeight()+3.5; 1826 current_displacement+=displacement_of_new_axis_as_norm; //and the spacing plus the ticklengths 1827 } 1828 else if (axisId==YAXIS) 1829 { 1830 a->vpor(un-current_displacement,deux,trois,quatre); 1831 a->wind(xun,xdeux,xtrois,xquatre); 1832 a->box("", 0.0 ,0.0, Opt.c_str(), TickInterval, Minor); //to avoid plplot crashes: do not use tickinterval. or recompute it correctly (no too small!) 1833 nchars=muaxdata.nchars; 1834 title_position=current_displacement/a->nCharLength()+nchars+2.5; 1835 current_displacement+=(nchars-1)*a->nCharLength(); //we'll skip what was written 1836 current_displacement+=displacement_of_new_axis_as_norm; //and the spacing plus the ticklengths 1837 } 1838 muaxdata.counter++; 1839 } 1840 a->vpor(un,deux,trois,quatre); 1841 a->wind(xun,xdeux,xtrois,xquatre); 1842 a->slabelfunc( NULL, NULL ); 1843 } 1844 else if (TickFormat->NBytes()>0) //no /TICKUNITS=> only 1 value taken into account 1845 { 1846 muaxdata.counter=0; 1847 muaxdata.nchars=0; 1848 muaxdata.what=GDL_TICKFORMAT; 1849 muaxdata.TickFormat=TickFormat; 1850 muaxdata.nTickFormat=1; 1851 a->slabelfunc( gdlMultiAxisTickFunc, &muaxdata ); 1852 Opt+="o"; 1853 if (modifierCode==2) Opt+="m"; else Opt+="n"; 1854 if (axisId==XAXIS) a->box(Opt.c_str(), TickInterval, Minor, "", 0.0, 0); 1855 else if (axisId==YAXIS) a->box("", 0.0 ,0.0, Opt.c_str(), TickInterval, Minor); 1856 nchars=muaxdata.nchars; 1857 if (axisId==YAXIS) title_position=nchars+2; else title_position=3.5; 1858 a->slabelfunc( NULL, NULL ); 1859 } 1860 else 1861 { 1862 tdata.nchars=0; 1863 a->slabelfunc( gdlSimpleAxisTickFunc, &tdata ); 1864 Opt+="o"; 1865 if (modifierCode==2) Opt+="m"; else Opt+="n"; 1866 if (axisId==XAXIS) a->box(Opt.c_str(), TickInterval, Minor, "", 0.0, 0); 1867 else if (axisId==YAXIS) a->box("", 0.0 ,0.0, Opt.c_str(), TickInterval, Minor); 1868 nchars=tdata.nchars; 1869 if (axisId==YAXIS) title_position=nchars+2; else title_position=3.5; 1870 a->slabelfunc( NULL, NULL ); 1871 } 1872 1873 if (modifierCode==0 ||modifierCode==1) 1874 { 1875 if (axisId==XAXIS) a->mtex("b",title_position, 0.5, 0.5, Title.c_str()); 1876 else if (axisId==YAXIS) a->mtex("l",title_position,0.5,0.5,Title.c_str()); 1877 } 1878 else if (modifierCode==2) 1879 { 1880 if (axisId==XAXIS) a->mtex("t", title_position, 0.5, 0.5, Title.c_str()); 1881 else if (axisId==YAXIS) a->mtex("r",title_position,0.5,0.5,Title.c_str()); 1882 } 1883 1884 if (TickLayout==0) 1885 { 1886 a->smaj(ticklen_in_mm, 1.0); //set base ticks to default 0.02 viewport converted to mm. 1887 a->smin(ticklen_in_mm/2.0,1.0); //idem min (plplt defaults) 1888 //thick for box and ticks. 1889 a->Thick(Thick); 1890 1891 //ticks or grid eventually with style and length: 1892 if (abs(TickLen)<1e-6) Opt=""; else Opt="st"; //remove ticks if ticklen=0 1893 if (TickLen<0) {Opt+="i"; TickLen=-TickLen;} 1894 switch(modifierCode) 1895 { 1896 case 2: 1897 Opt+="c"; 1898 break; 1899 case 1: 1900 Opt+="b"; 1901 break; 1902 case 0: 1903 if ( (Style&8)==8 ) Opt+="b"; else Opt+="bc"; 1904 } 1905 //gridstyle applies here: 1906 gdlLineStyle(a,GridStyle); 1907 if ( Log ) Opt+="l"; 1908 if (axisId==XAXIS) a->box(Opt.c_str(), TickInterval, Minor, "", 0.0, 0); 1909 else if (axisId==YAXIS) a->box("", 0.0, 0, Opt.c_str(), TickInterval, Minor); 1910 //reset gridstyle 1911 gdlLineStyle(a,0); 1912 // pass over with outer box, with thick. No style applied, only ticks 1913 Opt=" "; 1914 switch(modifierCode) 1915 { 1916 case 2: 1917 Opt+="c"; 1918 break; 1919 case 1: 1920 Opt+="b"; 1921 break; 1922 case 0: 1923 if ( (Style&8)==8 ) Opt+="b"; else Opt+="bc"; 1924 } 1925 if (axisId==XAXIS) a->box(Opt.c_str(), 0.0, 0, "", 0.0, 0); 1926 else if (axisId==YAXIS) a->box("", 0.0, 0 , Opt.c_str(), 0.0, 0); 1927 } 1928 //reset charsize & thick 1929 a->Thick(1.0); 1930 a->sizeChar(1.0); 1931 } 1932 return 0; 1933 } 1934 1935 gdlBox(EnvT * e,GDLGStream * a,DDouble xStart,DDouble xEnd,DDouble yStart,DDouble yEnd,bool xLog,bool yLog)1936 static bool gdlBox(EnvT *e, GDLGStream *a, DDouble xStart, DDouble xEnd, DDouble yStart, DDouble yEnd, bool xLog, bool yLog) 1937 { 1938 gdlWriteTitleAndSubtitle(e, a); 1939 gdlAxis(e, a, XAXIS, xStart, xEnd, xLog); 1940 gdlAxis(e, a, YAXIS, yStart, yEnd, yLog); 1941 // title and sub title 1942 return true; 1943 } gdlAxis3(EnvT * e,GDLGStream * a,int axisId,DDouble Start,DDouble End,bool Log,DLong zAxisCode=0,DDouble NormedLength=0)1944 static bool gdlAxis3(EnvT *e, GDLGStream *a, int axisId, DDouble Start, DDouble End, bool Log, DLong zAxisCode=0, DDouble NormedLength=0) 1945 { 1946 string addCode="b"; //for X and Y, and some Z 1947 if(zAxisCode==1 || zAxisCode==4) addCode="cm"; 1948 bool doZ=(zAxisCode>=0); 1949 1950 static GDL_TICKDATA tdata; 1951 tdata.a=a; 1952 tdata.isLog=Log; 1953 tdata.axisrange=abs(End-Start); 1954 1955 static GDL_TICKNAMEDATA data; 1956 data.a=a; 1957 data.isLog=Log; 1958 data.axisrange=abs(End-Start); 1959 1960 data.nTickName=0; 1961 1962 static GDL_MULTIAXISTICKDATA muaxdata; 1963 muaxdata.a=a; 1964 muaxdata.isLog=Log; 1965 muaxdata.axisrange=abs(End-Start); 1966 1967 muaxdata.what=GDL_NONE; 1968 muaxdata.nTickFormat=0; 1969 muaxdata.nTickUnits=0; 1970 muaxdata.axismin=Start; 1971 muaxdata.axismax=End; 1972 muaxdata.e=e; 1973 muaxdata.reset=true; 1974 1975 //special values 1976 PLFLT OtherAxisSizeInMm; 1977 if (axisId==XAXIS) OtherAxisSizeInMm=a->mmyPageSize()*(a->boxnYSize()); 1978 if (axisId==YAXIS) OtherAxisSizeInMm=a->mmxPageSize()*(a->boxnXSize()); 1979 if (axisId==ZAXIS) OtherAxisSizeInMm=a->mmxPageSize()*(a->boxnXSize()); //not always correct 1980 //special for AXIS who change the requested box size! 1981 if (axisId==XAXIS2) {axisId=XAXIS; OtherAxisSizeInMm=a->mmyPageSize()*(NormedLength);} 1982 if (axisId==YAXIS2) {axisId=YAXIS; OtherAxisSizeInMm=a->mmxPageSize()*(NormedLength);} 1983 if (axisId==ZAXIS2) {axisId=ZAXIS; OtherAxisSizeInMm=a->mmxPageSize()*(NormedLength);} //not always correct 1984 1985 // DFloat Charsize;//done in gdlSetAxisCharsize() below 1986 // gdlGetDesiredAxisCharsize(e, axisId, Charsize); 1987 DLong GridStyle; 1988 gdlGetDesiredAxisGridStyle(e, axisId, GridStyle); 1989 // DFloat MarginL, MarginR; //unused yet (fixme) 1990 // gdlGetDesiredAxisMargin(e, axisId, MarginL, MarginR); 1991 DLong Minor; 1992 gdlGetDesiredAxisMinor(e, axisId, Minor); 1993 DLong Style; 1994 gdlGetDesiredAxisStyle(e, axisId, Style); 1995 DFloat Thick; 1996 gdlGetDesiredAxisThick(e, axisId, Thick); 1997 DStringGDL* TickFormat; 1998 gdlGetDesiredAxisTickFormat(e, axisId, TickFormat); 1999 DDouble TickInterval; 2000 gdlGetDesiredAxisTickInterval(e, axisId, TickInterval); 2001 DLong TickLayout; 2002 gdlGetDesiredAxisTickLayout(e, axisId, TickLayout); 2003 DFloat TickLen; 2004 gdlGetDesiredAxisTickLen(e, axisId, TickLen); 2005 DStringGDL* TickName; 2006 gdlGetDesiredAxisTickName(e, a, axisId, TickName); 2007 DLong Ticks; 2008 gdlGetDesiredAxisTicks(e, axisId, Ticks); 2009 DStringGDL* TickUnits; 2010 gdlGetDesiredAxisTickUnits(e, axisId, TickUnits); 2011 // DDoubleGDL* Tickv; 2012 // gdlGetDesiredAxisTickv(e, axisId, Tickv); 2013 DString Title; 2014 gdlGetDesiredAxisTitle(e, axisId, Title); 2015 2016 bool hasTickUnitDefined = (TickUnits->NBytes()>0); 2017 int tickUnitArraySize=(hasTickUnitDefined)?TickUnits->N_Elements():0; 2018 //For labels we need ticklen in current character size, for ticks we need it in mm 2019 DFloat ticklen_in_mm= TickLen; 2020 if (TickLen<0) ticklen_in_mm*=-1; 2021 //ticklen in a percentage of box x or y size, to be expressed in mm 2022 if (axisId==XAXIS) ticklen_in_mm=a->mmyPageSize()*(a->boxnYSize())*ticklen_in_mm; 2023 if (axisId==YAXIS) ticklen_in_mm=a->mmyPageSize()*(a->boxnXSize())*ticklen_in_mm; 2024 //eventually, each succesive X or Y axisId is separated from previous by interligne + ticklen in adequate units. 2025 DFloat interligne; 2026 if (axisId==XAXIS) interligne=a->mmLineSpacing()/a->mmCharHeight(); //in units of character size 2027 if (axisId==YAXIS) interligne=a->mmLineSpacing()/a->mmCharLength(); //in units of character size 2028 2029 if ( (Style&4)!=4 ) //if we write the axis... 2030 { 2031 if (TickInterval==0) 2032 { 2033 if (Ticks<=0) TickInterval=gdlComputeTickInterval(e, axisId, Start, End, Log); 2034 else if (Ticks>1) TickInterval=(End-Start)/Ticks; 2035 else TickInterval=(End-Start); 2036 } 2037 //Following hopefully corrects a bug in plplot when TickInterval is very very tiny. The only solution 2038 // is to avoid plotting the axis! 2039 if (TickInterval < 10*std::numeric_limits<double>::epsilon()) { 2040 return 0; 2041 } 2042 string Opt; 2043 //first write labels only: 2044 gdlSetAxisCharsize(e, a, axisId); 2045 gdlSetPlotCharthick(e, a); 2046 // axis legend if box style, else do not draw. Take care writing BELOW/ABOVE all axis if tickunits present:actStream->wCharHeight() 2047 DDouble displacement=(tickUnitArraySize>1)?2.5*tickUnitArraySize:0; 2048 2049 //no option to care of placement of Z axis??? 2050 if (axisId==XAXIS) a->mtex3("xp",3.5+displacement, 0.5, 0.5, Title.c_str()); 2051 else if (axisId==YAXIS) a->mtex3("yp",5.0+displacement,0.5,0.5,Title.c_str()); 2052 else if (doZ) a->mtex3("zp",5.0+displacement,0.5,0.5,Title.c_str()); 2053 2054 //axis, 1st time: labels 2055 Opt=addCode+"nst"; //will write labels beside the left hand axis (u) at major ticks (n) 2056 if ( Log ) Opt+="l"; 2057 if (TickName->NBytes()>0) // /TICKNAME=[array] 2058 { 2059 data.counter=0; 2060 data.TickName=TickName; 2061 data.nTickName=TickName->N_Elements(); 2062 a->slabelfunc( gdlSingleAxisTickNamedFunc, &data ); 2063 Opt+="o"; 2064 if (axisId==XAXIS) a->box3(Opt.c_str(), "" , TickInterval, Minor, "", "", 0.0, 0, "", "", 0.0, 0); 2065 else if (axisId==YAXIS) a->box3("", "", 0.0 ,0.0, Opt.c_str(),"", TickInterval, Minor, "", "", 0.0, 0); 2066 else if (doZ) if (axisId==ZAXIS) a->box3("", "", 0.0, 0, "", "", 0.0, 0, Opt.c_str(), "", TickInterval, Minor); 2067 a->slabelfunc( NULL, NULL ); 2068 } 2069 //care Tickunits size is 10 if not defined because it is the size of !X.TICKUNITS. 2070 else if (hasTickUnitDefined) // /TICKUNITS=[several types of axes written below each other] 2071 { 2072 muaxdata.counter=0; 2073 muaxdata.what=GDL_TICKUNITS; 2074 if (TickFormat->NBytes()>0) // with also TICKFORMAT option.. 2075 { 2076 muaxdata.what=GDL_TICKFORMAT_AND_UNITS; 2077 muaxdata.TickFormat=TickFormat; 2078 muaxdata.nTickFormat=TickFormat->N_Elements(); 2079 } 2080 muaxdata.TickUnits=TickUnits; 2081 muaxdata.nTickUnits=tickUnitArraySize; 2082 a->slabelfunc( gdlMultiAxisTickFunc, &muaxdata ); 2083 Opt+="o"; 2084 for (SizeT i=0; i< muaxdata.nTickUnits; ++i) //loop on TICKUNITS axis 2085 { 2086 // no equivalent in 3d yet... 2087 // PLFLT un,deux,trois,quatre,xun,xdeux,xtrois,xquatre; 2088 // a->plstream::gvpd(un,deux,trois,quatre); 2089 // a->plstream::gvpw(xun,xdeux,xtrois,xquatre); 2090 if (axisId==XAXIS) a->box3(Opt.c_str(), "", TickInterval, Minor, "", "", 0.0, 0, "", "", 0.0, 0); 2091 else if (axisId==YAXIS) a->box3("", "", 0.0 ,0.0, Opt.c_str(),"", TickInterval, Minor, "", "", 0.0, 0); 2092 else if (doZ) if (axisId==ZAXIS) a->box3("", "", 0.0, 0, "", "", 0.0, 0, Opt.c_str(), "", TickInterval, Minor); 2093 // a->plstream::vpor(un,deux,trois,quatre); 2094 // a->plstream::wind(xun,xdeux,xtrois,xquatre); 2095 muaxdata.counter++; 2096 } 2097 a->slabelfunc( NULL, NULL ); 2098 } 2099 else if (TickFormat->NBytes()>0) //no /TICKUNITS=> only 1 value taken into account 2100 { 2101 muaxdata.counter=0; 2102 muaxdata.what=GDL_TICKFORMAT; 2103 muaxdata.TickFormat=TickFormat; 2104 muaxdata.nTickFormat=1; 2105 a->slabelfunc( gdlMultiAxisTickFunc, &muaxdata ); 2106 Opt+="o"; 2107 if (axisId==XAXIS) a->box3(Opt.c_str(), "", TickInterval, Minor, "", "", 0.0, 0, "", "", 0.0, 0); 2108 else if (axisId==YAXIS) a->box3("", "", 0.0 ,0.0, Opt.c_str(),"", TickInterval, Minor, "", "", 0.0, 0); 2109 else if (doZ) if (axisId==ZAXIS) a->box3("", "", 0.0, 0, "", "", 0.0, 0, Opt.c_str(), "", TickInterval, Minor); 2110 2111 a->slabelfunc( NULL, NULL ); 2112 } 2113 else 2114 { 2115 a->slabelfunc( gdlSimpleAxisTickFunc, &tdata ); 2116 Opt+="o"; 2117 if (axisId==XAXIS) a->box3(Opt.c_str(), "", TickInterval, Minor, "", "", 0.0, 0, "", "", 0.0, 0); 2118 else if (axisId==YAXIS) a->box3("", "", 0.0 ,0.0, Opt.c_str(),"", TickInterval, Minor, "", "", 0.0, 0); 2119 else if (doZ) if (axisId==ZAXIS) a->box3("", "", 0.0, 0, "", "", 0.0, 0, Opt.c_str(), "", TickInterval, Minor); 2120 a->slabelfunc( NULL, NULL ); 2121 } 2122 2123 if (TickLayout==0) 2124 { 2125 a->smaj(ticklen_in_mm, 1.0); //set base ticks to default 0.02 viewport converted to mm. 2126 a->smin(ticklen_in_mm/2.0,1.0); //idem min (plplt defaults) 2127 //thick for box and ticks. 2128 a->Thick(Thick); 2129 2130 //ticks or grid eventually with style and length: 2131 if (abs(TickLen)<1e-6) Opt=""; else Opt="st"; //remove ticks if ticklen=0 2132 if (TickLen<0) {Opt+="i"; TickLen=-TickLen;} 2133 2134 //gridstyle applies here: 2135 gdlLineStyle(a,GridStyle); 2136 if ( Log ) Opt+="l"; 2137 if (axisId==XAXIS) a->box3(Opt.c_str(), "", TickInterval, Minor, "", "", 0.0, 0, "", "", 0.0, 0); 2138 else if (axisId==YAXIS) a->box3("", "", 0.0 ,0.0, Opt.c_str(),"", TickInterval, Minor, "", "", 0.0, 0); 2139 else if (doZ) if (axisId==ZAXIS) a->box3("", "", 0.0, 0, "", "", 0.0, 0, Opt.c_str(), "", TickInterval, Minor); 2140 //reset ticks to default plplot value... 2141 //reset gridstyle 2142 gdlLineStyle(a,0); 2143 // pass over with outer box, with thick. No style applied, only ticks 2144 Opt="b"; 2145 if (axisId==XAXIS) a->box3(Opt.c_str(), "", TickInterval, Minor, "","",0,0,"","",0,0); 2146 else if (axisId==YAXIS) a->box3("","",0,0, Opt.c_str(), "", TickInterval, Minor, "","",0,0); 2147 else if (doZ) if (axisId==ZAXIS) a->box3("","",0,0,"","",0,0, Opt.c_str(), "", TickInterval, Minor); 2148 } 2149 //reset charsize & thick 2150 a->Thick(1.0); 2151 a->sizeChar(1.0); 2152 } 2153 return 0; 2154 } 2155 gdlBox3(EnvT * e,GDLGStream * a,DDouble xStart,DDouble xEnd,DDouble yStart,DDouble yEnd,DDouble zStart,DDouble zEnd,bool xLog,bool yLog,bool zLog,bool doSpecialZAxisPlacement=0)2156 static bool gdlBox3(EnvT *e, GDLGStream *a, DDouble xStart, DDouble xEnd, DDouble yStart, 2157 DDouble yEnd, DDouble zStart, DDouble zEnd, bool xLog, bool yLog, bool zLog, bool doSpecialZAxisPlacement=0) 2158 { 2159 DLong zAxisCode=0; 2160 static int ZAXISIx=e->KeywordIx("ZAXIS"); 2161 if (doSpecialZAxisPlacement) e->AssureLongScalarKWIfPresent(ZAXISIx, zAxisCode); 2162 gdlAxis3(e, a, XAXIS, xStart, xEnd, xLog, 0); 2163 gdlAxis3(e, a, YAXIS, yStart, yEnd, yLog, 0); 2164 gdlAxis3(e, a, ZAXIS, zStart, zEnd, zLog, zAxisCode); 2165 // title and sub title 2166 gdlWriteTitleAndSubtitle(e, a); 2167 return true; 2168 } 2169 2170 } // namespace 2171 2172 #endif 2173