Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_hplot 5 #define tools_hplot 6 7 // Used in tools::sg::axis. 8 // 9 // Code extracted from ROOT-4.03.02/root/graf/stc/TGaxis.cxx. 10 // Itself built from code extracted from HPLOT. 11 // 12 // Take care, all the below is highly disgusting... 13 // (You can even find.. gotos !) 14 // 15 // Except for the public methods we let the style "as it". 16 17 #include "mnmx" 18 #include "lina/vec3f" 19 #include "mathd" //pi 20 #include "snpf" 21 #include "out_error" 22 23 #include <string> 24 #include <vector> 25 26 #include <cstring> 27 #include <ctime> 28 #include <cmath> 29 #include <cfloat> 30 31 namespace tools { 32 namespace hplot { 33 34 class _text { 35 public: 36 _text(double aX,double aY, 37 double aAngle,double aSize, 38 const std::string& aString, 39 short aAlign) 40 :fX(aX),fY(aY) 41 ,fAngle(aAngle),fSize(aSize) 42 ,fString(aString),fAlign(aAlign) 43 {} 44 virtual ~_text(){} 45 public: 46 _text(const _text& aFrom) 47 :fX(aFrom.fX),fY(aFrom.fY) 48 ,fAngle(aFrom.fAngle),fSize(aFrom.fSize) 49 ,fString(aFrom.fString) 50 ,fAlign(aFrom.fAlign) 51 {} 52 _text& operator=(const _text& aFrom){ 53 fX = aFrom.fX; 54 fY = aFrom.fY; 55 fAngle = aFrom.fAngle; 56 fSize = aFrom.fSize; 57 fString = aFrom.fString; 58 fAlign = aFrom.fAlign; 59 return *this; 60 } 61 public: 62 double fX; 63 double fY; 64 double fAngle; //Degree 65 double fSize; 66 std::string fString; 67 short fAlign; 68 }; 69 70 71 class axis { 72 73 // Ok, you really want to read all that. You had been warned... 74 75 enum { 76 TAxis_kTickPlus = (1<<(9)), 77 TAxis_kTickMinus = (1<<(10)), 78 TAxis_kAxisRange = (1<<(11)), 79 TAxis_kCenterTitle = (1<<(12)), 80 TAxis_kCenterLabels = (1<<(14)), //bit 13 is used by TObject 81 TAxis_kRotateTitle = (1<<(15)), 82 TAxis_kPalette = (1<<(16)), 83 TAxis_kNoExponent = (1<<(17)), 84 TAxis_kLabelsHori = (1<<(18)), 85 TAxis_kLabelsVert = (1<<(19)), 86 TAxis_kLabelsDown = (1<<(20)), 87 TAxis_kLabelsUp = (1<<(21)), 88 TAxis_kIsInteger = (1<<(22)), 89 TAxis_kMoreLogLabels = (1<<(23)), 90 TAxis_kDecimals = (1<<(11)) 91 }; //in fBits2 92 93 enum { 94 kIsOnHeap = 0x01000000, // object is on heap 95 kNotDeleted = 0x02000000, // object has not been deleted 96 kZombie = 0x04000000, // object ctor failed 97 kBitMask = 0x00ffffff 98 }; 99 100 static int GetTextFont() { return 132;} 101 102 static double TMath_ATan2(double y, double x) { 103 if (x != 0) return ::atan2(y, x); 104 if (y == 0) return 0; 105 if (y > 0) return half_pi(); 106 else return -half_pi(); 107 } 108 109 //static short TMath_Abs(short d) { return (d >= 0) ? d : -d; } 110 static int TMath_Abs(int d) { return (d >= 0) ? d : -d; } 111 //static long TMath_Abs(long d) { return (d >= 0) ? d : -d; } 112 //static float TMath_Abs(float d) { return (d >= 0) ? d : -d; } 113 static double TMath_Abs(double d) { return (d >= 0) ? d : -d; } 114 115 static void TGaxis_Rotate( 116 double X, double Y, double CFI, double SFI 117 ,double XT, double YT, double &U, double &V) 118 { 119 U = CFI*X-SFI*Y+XT; 120 V = SFI*X+CFI*Y+YT; 121 } 122 123 public: 124 axis(std::ostream& a_out) 125 :m_out(a_out) 126 //,fMaxDigits(5) 127 ,fBits(kNotDeleted) 128 ,fTickSize(0.03F) 129 ,fLabelOffset(0.005F) 130 ,fLabelSize(0.04F) 131 ,fTitleOffset(1) 132 ,fTitleSize(0.04F) 133 ,fLabelFont(62) 134 {} 135 136 virtual ~axis(){} 137 private: //to discourage inheriting that. 138 axis(const axis& a_from):m_out(a_from.m_out){} 139 axis& operator=(const axis&){return *this;} 140 public: 141 void set_title(const std::string& aTitle) { 142 fTitle = aTitle; 143 } 144 private: 145 bool testBit(unsigned int f) { 146 return (bool) ((fBits & f) != 0); 147 } 148 149 static void TGaxis_LabelsLimits(std::ostream& a_out,const char *label, 150 int &first,int &last) { 151 last = int(::strlen(label))-1; 152 for (int i=0; i<=last; i++) { 153 if (::strchr("1234567890-+.", label[i]) ) { first = i; return; } 154 } 155 out_error(a_out,"LabelsLimits", "attempt to draw a blank label"); 156 } 157 static void SETOPT(const std::string& aCHOPT,char aChar,int& aOpt) { 158 aOpt = aCHOPT.find(aChar)!=std::string::npos?1:0; 159 } 160 161 public: 162 void paint(double xmin, double ymin, 163 double xmax, double ymax, 164 double& wmin,double& wmax, 165 int& ndiv,const std::string& aCHOPT, 166 double gridlength,bool drawGridOnly, 167 std::vector<float>& aLinesAxis, //n*(2+2) 168 std::vector<float>& aLinesGrid, //n*(2+2) 169 std::vector<_text>& aTexts){ 170 // Control function to draw an axis 171 // ================================ 172 // 173 //============> Original authors (O.Couet C.E.Vandoni N.Cremel-Somon) 174 // largely modified and converted to C++ class by Rene Brun 175 // 176 // _Input parameters: 177 // 178 // xmin : X origin coordinate in WC space. 179 // xmax : X end axis coordinate in WC space. 180 // ymin : Y origin coordinate in WC space. 181 // ymax : Y end axis coordinate in WC space. 182 // wmin : Lowest value for the tick mark 183 // labels written on the axis. 184 // wmax : Highest value for the tick mark labels 185 // written on the axis. 186 // ndiv : Number of divisions. 187 // 188 // ndiv=N1 + 100*N2 + 10000*N3 189 // N1=number of 1st divisions. 190 // N2=number of 2nd divisions. 191 // N3=number of 3rd divisions. 192 // e.g.: 193 // nndi=0 --> no tick marks. 194 // nndi=2 --> 2 divisions, one tick mark in the middle 195 // of the axis. 196 // 197 // chopt : Options (see below). 198 // 199 // chopt='G': loGarithmic scale, default is linear. 200 // chopt='B': Blank axis. Useful to superpose axis. 201 // 202 // Orientation of tick marks on axis. 203 // ---------------------------------- 204 // 205 // Tick marks are normally drawn on the positive side of the axis, 206 // however, if X0=X1, then negative. 207 // 208 // chopt='+': tick marks are drawn on Positive side. (default) 209 // chopt='-': tick mark are drawn on the negative side. 210 // i.e: '+-' --> tick marks are drawn on both sides of the axis. 211 // chopt='U': Unlabeled axis, default is labeled. 212 // 213 // Size of tick marks 214 // ------------------ 215 // By default, tick marks have a length equal to 3 per cent of the 216 // axis length. 217 // When the option "S" is specified, the length of the tick marks 218 // is equal to fTickSize*axis_length, where fTickSize may be set 219 // via TGaxis::SetTickSize. 220 // 221 // Position of labels on axis. 222 // --------------------------- 223 // 224 // Labels are normally drawn on side opposite to tick marks. 225 // However: 226 // 227 // chopt='=': on Equal side 228 // 229 // Orientation of labels on axis. 230 // ------------------------------ 231 // 232 // Labels are normally drawn parallel to the axis. 233 // However if X0=X1, then Orthogonal 234 // if Y0=Y1, then Parallel 235 // 236 // Position of labels on tick marks. 237 // --------------------------------- 238 // 239 // Labels are centered on tick marks. 240 // However , if X0=X1, then they are right adjusted. 241 // 242 // chopt='R': labels are Right adjusted on tick mark. 243 // (default is centered) 244 // chopt='L': labels are Left adjusted on tick mark. 245 // chopt='C': labels are Centered on tick mark. 246 // chopt='M': In the Middle of the divisions. 247 // 248 // Format of labels. 249 // ----------------- 250 // 251 // Blank characters are stripped, and then the 252 // label is correctly aligned. the dot, if last 253 // character of the string, is also stripped, 254 // unless the option "." (a dot, or period) is specified. 255 // if SetDecimals(true) has been called (bit TAxis_kDecimals set). 256 // all labels have the same number of decimals after the "." 257 // The same is true if gStyle->SetStripDecimals(false) has been called. 258 // 259 // In the following, we have some parameters, like 260 // tick marks length and characters height (in percentage 261 // of the length of the axis (WC)) 262 // The default values are as follows: 263 // 264 // Primary tick marks: 3.0 % 265 // Secondary tick marks: 1.5 % 266 // Third order tick marks: .75 % 267 // Characters height for labels: 4% 268 // 269 // Labels offset: 1.0 % 270 // 271 // Optional grid. 272 // -------------- 273 // 274 // chopt='W': cross-Wire 275 // In case of a log axis, the grid is only drawn for the primary 276 // tick marks if the number of secondary and tertiary divisions is 0. 277 // 278 // Axis bining optimization. 279 // ------------------------- 280 // 281 // By default the axis bining is optimized . 282 // 283 // chopt='N': No bining optimization 284 // chopt='I': Integer labelling 285 // 286 // Maximum Number of Digits for the axis labels 287 // -------------------------------------------- 288 // See the static function TGaxis::SetMaxDigits 289 // 290 // Time representation. 291 // -------------------- 292 // 293 // Axis labels may be considered as times, plotted in a defined 294 // time format. 295 // The format is set with SetTimeFormat(). 296 // wmin and wmax are considered as two time values in seconds. 297 // The time axis will be spread around the time offset value (set with 298 // SetTimeOffset() ). Actually it will go from TimeOffset+wmin to 299 // TimeOffset+wmax. 300 // see examples in tutorials timeonaxis.C and timeonaxis2.C 301 // 302 // chopt='t': Plot times with a defined format instead of values 303 // 304 305 aLinesAxis.clear(); 306 aLinesGrid.clear(); 307 aTexts.clear(); 308 309 double alfa, beta, ratio1, ratio2, grid_side; 310 double axis_lengthN = 0; 311 double axis_length0 = 0; 312 double axis_length1 = 0; 313 double charheight; 314 double phil, phi, sinphi, cosphi, asinphi, acosphi; 315 double BinLow, BinLow2, BinLow3; 316 double BinHigh, BinHigh2, BinHigh3; 317 double BinWidth, BinWidth2, BinWidth3; 318 double xpl1, xpl2, ypl1, ypl2; 319 double Xtick = 0; 320 double Xtick0, Xtick1, DXtick=0; 321 double Ytick, Ytick0, Ytick1; 322 double Wlabel, DWlabel; 323 double Xlabel, Ylabel; 324 double DXlabel; 325 double X0, X1, Y0, Y1, XX0, XX1, YY0, YY1; 326 XX0 = XX1 = YY0 = YY1 = 0; 327 double Xxmin, Xxmax, Yymin, Yymax; 328 Xxmin = Xxmax = Yymin = Yymax = 0; 329 double XLside,XMside; 330 double WW, AF, RNE; 331 double XX, YY; 332 double Y; 333 double Xtwo; 334 int i, j, k, l, decade, ltick; 335 int Mside, Lside; 336 int IF1, IF2, NA, NF, NCH; 337 int OptionLog,OptionBlank,OptionVert,OptionPlus,OptionMinus; 338 int OptionUnlab,OptionPara; 339 int OptionDown,OptionRight,OptionLeft,OptionCent,OptionEqual; 340 int OptionDecimals=0,OptionDot; 341 int OptionY,OptionText,OptionGrid,OptionSize,OptionNoopt; 342 int OptionInt,OptionM,OptionUp,OptionX; 343 int OptionTime; 344 int first,last; 345 int nbins; 346 int N1Aold = 0; 347 int NN1old = 0; 348 int Xalign,Yalign; 349 int ndyn; 350 char LABEL[256]; 351 char CHTEMP[256]; 352 double rangeOffset = 0; 353 354 double epsilon = 1e-5; 355 const double kPI = pi(); //GB 356 double textSize = 0.05; //GB 357 short textAlign = 11; //GB 358 BinWidth = 0; //GB 359 BinWidth2 = 0; //GB 360 BinWidth3 = 0; //GB 361 nbins = 0; //GB 362 BinHigh = 0; //GB 363 BinHigh2 = 0; //GB 364 BinHigh3 = 0; //GB 365 BinLow = 0; //GB 366 BinLow2 = 0; //GB 367 BinLow3 = 0; //GB 368 first = 0; //GB 369 last = 0; //GB 370 371 double rwmi = wmin; 372 double rwma = wmax; 373 374 //out_error(m_out,"android_debug","start"); 375 376 bool noExponent = testBit(TAxis_kNoExponent); 377 378 // If MoreLogLabels = true more Log Intermediate Labels are drawn. 379 bool MoreLogLabels = testBit(TAxis_kMoreLogLabels); 380 381 // the following parameters correspond to the pad range in NDC 382 // and the WC coordinates in the pad 383 384 double padh = 1;//FIXME gPad->GetWh()*gPad->GetAbsHNDC(); 385 double RWxmin = 0; 386 double RWxmax = 1; 387 double RWymin = 0; 388 double RWymax = 1; 389 390 SETOPT(aCHOPT,'G',OptionLog); 391 SETOPT(aCHOPT,'B',OptionBlank); 392 SETOPT(aCHOPT,'V',OptionVert); 393 SETOPT(aCHOPT,'+',OptionPlus); 394 SETOPT(aCHOPT,'-',OptionMinus); 395 SETOPT(aCHOPT,'U',OptionUnlab); 396 SETOPT(aCHOPT,'P',OptionPara); 397 SETOPT(aCHOPT,'O',OptionDown); 398 SETOPT(aCHOPT,'R',OptionRight); 399 SETOPT(aCHOPT,'L',OptionLeft); 400 SETOPT(aCHOPT,'C',OptionCent); 401 SETOPT(aCHOPT,'=',OptionEqual); 402 SETOPT(aCHOPT,'Y',OptionY); 403 SETOPT(aCHOPT,'T',OptionText); 404 SETOPT(aCHOPT,'W',OptionGrid); 405 SETOPT(aCHOPT,'S',OptionSize); 406 SETOPT(aCHOPT,'N',OptionNoopt); 407 SETOPT(aCHOPT,'I',OptionInt); 408 SETOPT(aCHOPT,'M',OptionM); 409 SETOPT(aCHOPT,'0',OptionUp); 410 SETOPT(aCHOPT,'X',OptionX); 411 SETOPT(aCHOPT,'t',OptionTime); 412 SETOPT(aCHOPT,'.',OptionDot); 413 414 if (testBit(TAxis_kTickPlus)) OptionPlus = 2; 415 if (testBit(TAxis_kTickMinus)) OptionMinus = 2; 416 if (testBit(TAxis_kCenterLabels)) OptionM = 1; 417 if (testBit(TAxis_kDecimals)) OptionDecimals = 1; 418 /*FIXME if (fAxis) { 419 if (fAxis->GetLabels()) { 420 OptionM = 1; 421 OptionText = 1; 422 ndiv = fAxis->GetLast()-fAxis->GetFirst()+1; 423 } 424 }*/ 425 426 // Set the grid length 427 428 if (OptionGrid) { 429 if (gridlength == 0) gridlength = 0.8; 430 /*FIXME 431 linegrid = new TLine(); 432 linegrid->SetLineColor(gStyle->GetGridColor()); 433 if (linegrid->GetLineColor() == 0) 434 linegrid->SetLineColor(GetLineColor()); 435 linegrid->SetLineStyle(gStyle->GetGridStyle()); 436 linegrid->SetLineWidth(gStyle->GetGridWidth());*/ 437 } 438 439 440 if (OptionTime) { 441 //printf("debug : SbAxisHPLOT::paint : fTimeFormat : \"%s\"\n", 442 // fTimeFormat.c_str()); 443 } 444 445 //out_error(m_out,"android_debug","0000"); 446 // Determine time format 447 std::string timeformat; 448 std::string::size_type IdF = fTimeFormat.find("%F"); 449 if (IdF!=std::string::npos) { 450 timeformat = fTimeFormat.substr(0,IdF); 451 } else { 452 timeformat = fTimeFormat; 453 } 454 455 //out_error(m_out,"android_debug","0001"); 456 // determine the time offset and correct for time offset not being integer 457 double timeoffset = 0; 458 if (OptionTime) { 459 if (IdF!=std::string::npos) { 460 int LnF = int(fTimeFormat.size()); 461 std::string stringtimeoffset = fTimeFormat.substr(IdF+2,LnF-(IdF+2)); 462 int yy, mm, dd, hh, mi, ss; 463 if (::sscanf(stringtimeoffset.c_str(), 464 "%d-%d-%d %d:%d:%d", &yy, &mm, &dd, &hh, &mi, &ss) == 6) { 465 struct tm tp; 466 struct tm* tptest; 467 time_t timeoffsettest; 468 tp.tm_year = yy-1900; 469 tp.tm_mon = mm-1; 470 tp.tm_mday = dd; 471 tp.tm_hour = hh; 472 tp.tm_min = mi; 473 tp.tm_sec = ss; 474 tp.tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages) 475 timeoffset = double(mktime(&tp)); 476 // have to correct this time to go back to UTC 477 timeoffsettest = (time_t)((long)timeoffset); 478 tptest = gmtime(&timeoffsettest); 479 timeoffset += timeoffsettest - mktime(tptest); 480 // Add the time offset's decimal part if it is there 481 std::string::size_type Ids = stringtimeoffset.find("s"); 482 if (Ids != std::string::npos) { 483 float dp; 484 size_t Lns = stringtimeoffset.size(); 485 std::string sdp = stringtimeoffset.substr(Ids+1,Lns-(Ids+1)); 486 ::sscanf(sdp.c_str(),"%g",&dp); 487 timeoffset += dp; 488 } 489 // if OptionTime = 2 gmtime will be used instead of localtime 490 if (stringtimeoffset.find("GMT")!=std::string::npos) 491 OptionTime =2; 492 } else { 493 out_error(m_out,"PaintAxis", "Time offset has not the right format"); 494 } 495 } else { 496 out_error(m_out,"PaintAxis", "%%F not found in fTimeFormat."); 497 //FIXME timeoffset = gStyle->GetTimeOffset(); 498 } 499 wmin += timeoffset - (int)(timeoffset); 500 wmax += timeoffset - (int)(timeoffset); 501 // correct for time offset at a good limit (min, hour, 502 // day, month, year) 503 struct tm* tp0; 504 time_t timetp = (time_t)((long)(timeoffset)); 505 double range = wmax - wmin; 506 long rangeBase = 60; 507 if (range>60) rangeBase = 60*20; // minutes 508 if (range>3600) rangeBase = 3600*20; // hours 509 if (range>86400) rangeBase = 86400*20; // days 510 if (range>2419200) rangeBase = 31556736; // months (average # days) 511 rangeOffset = (double) ((long)(timeoffset)%rangeBase); 512 if (range>31536000) { 513 tp0 = gmtime(&timetp); 514 tp0->tm_mon = 0; 515 tp0->tm_mday = 1; 516 tp0->tm_hour = 0; 517 tp0->tm_min = 0; 518 tp0->tm_sec = 0; 519 tp0->tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages) 520 rangeBase = long(timetp-mktime(tp0)); // years 521 rangeOffset = (double) (rangeBase); 522 } 523 wmax += rangeOffset; 524 wmin += rangeOffset; 525 } 526 527 // Determine number of divisions 1, 2 and 3 528 int N1A = ndiv%100; 529 int N2A = (ndiv%10000 - N1A)/100; 530 int N3A = ndiv/10000; 531 int NN3 = mx<int>(N3A,1); 532 int NN2 = mx<int>(N2A,1)*NN3; 533 int NN1 = mx<int>(N1A,1)*NN2+1; 534 int Nticks= NN1; 535 536 // Axis bining optimization is ignored if: 537 // - the first and the last label are equal 538 // - the number of divisions is 0 539 // - less than 1 primary division is requested 540 // - logarithmic scale is requested 541 542 if (wmin == wmax || ndiv == 0 || N1A <= 1 || OptionLog) { 543 OptionNoopt = 1; 544 OptionInt = 0; 545 } 546 547 // Axis bining optimization 548 if ( (wmax-wmin) < 1 && OptionInt) { 549 out_error(m_out,"PaintAxis", "option I not available"); 550 OptionInt = 0; 551 } 552 //out_error(m_out,"android_debug","0002"); 553 if (!OptionNoopt || OptionInt ) { 554 555 // Primary divisions optimization 556 // When integer labelling is required, Optimize is invoked first 557 // and only if the result is not an integer labelling, AdjustBinSize 558 // is invoked. 559 560 optimizeLimits(wmin,wmax,N1A, 561 BinLow,BinHigh,nbins,BinWidth, 562 aCHOPT); 563 if (OptionInt) { 564 if (BinLow != double(int(BinLow)) || 565 BinWidth != double(int(BinWidth))) { 566 adjustBinSize(wmin,wmax,N1A,BinLow,BinHigh,nbins,BinWidth); 567 } 568 } 569 if ((wmin-BinLow) > epsilon) { BinLow += BinWidth; nbins--; } 570 if ((BinHigh-wmax) > epsilon) { BinHigh -= BinWidth; nbins--; } 571 if (xmax == xmin) { 572 double rtyw = (ymax-ymin)/(wmax-wmin); 573 Xxmin = xmin; 574 Xxmax = xmax; 575 Yymin = rtyw*(BinLow-wmin) + ymin; 576 Yymax = rtyw*(BinHigh-wmin) + ymin; 577 } else { 578 double rtxw = (xmax-xmin)/(wmax-wmin); 579 Xxmin = rtxw*(BinLow-wmin) + xmin; 580 Xxmax = rtxw*(BinHigh-wmin) + xmin; 581 if (ymax == ymin) { 582 Yymin = ymin; 583 Yymax = ymax; 584 } else { 585 alfa = (ymax-ymin)/(xmax-xmin); 586 beta = (ymin*xmax-ymax*xmin)/(xmax-xmin); 587 Yymin = alfa*Xxmin + beta; 588 Yymax = alfa*Xxmax + beta; 589 } 590 } 591 /*GB if (fFunction) { 592 Yymin = ymin; 593 Yymax = ymax; 594 Xxmin = xmin; 595 Xxmax = xmax; 596 } else*/ { 597 wmin = BinLow; 598 wmax = BinHigh; 599 } 600 601 // Secondary divisions optimization 602 int NB2 = N2A; 603 if (!OptionNoopt && N2A > 1 && BinWidth > 0) { 604 optimizeLimits(wmin,wmin+BinWidth,N2A, 605 BinLow2,BinHigh2,NB2,BinWidth2, 606 aCHOPT); 607 } 608 609 // Tertiary divisions optimization 610 int NB3 = N3A; 611 if (!OptionNoopt && N3A > 1 && BinWidth2 > 0) { 612 optimizeLimits(BinLow2,BinLow2+BinWidth2,N3A, 613 BinLow3,BinHigh3,NB3,BinWidth3, 614 aCHOPT); 615 } 616 N1Aold = N1A; 617 NN1old = NN1; 618 N1A = nbins; 619 NN3 = mx<int>(NB3,1); 620 NN2 = mx<int>(NB2,1)*NN3; 621 NN1 = mx<int>(N1A,1)*NN2+1; 622 Nticks = NN1; 623 } 624 625 //out_error(m_out,"android_debug","0003"); 626 // Coordinates are normalized 627 628 ratio1 = 1/(RWxmax-RWxmin); 629 ratio2 = 1/(RWymax-RWymin); 630 X0 = ratio1*(xmin-RWxmin); 631 X1 = ratio1*(xmax-RWxmin); 632 Y0 = ratio2*(ymin-RWymin); 633 Y1 = ratio2*(ymax-RWymin); 634 if (!OptionNoopt || OptionInt ) { 635 XX0 = ratio1*(Xxmin-RWxmin); 636 XX1 = ratio1*(Xxmax-RWxmin); 637 YY0 = ratio2*(Yymin-RWymin); 638 YY1 = ratio2*(Yymax-RWymin); 639 } 640 641 //out_error(m_out,"android_debug","0004"); 642 if ((X0 == X1) && (Y0 == Y1)) { 643 out_error(m_out,"PaintAxis", "length of axis is 0"); 644 return; 645 } 646 647 // Return wmin, wmax and the number of primary divisions 648 if (OptionX) { 649 ndiv = N1A; 650 return; 651 } 652 653 int maxDigits = 5; 654 //FIXME if (fAxis) maxDigits = fMaxDigits; 655 656 /*FIXME 657 TLatex *textaxis = new TLatex(); 658 lineaxis->SetLineColor(GetLineColor()); 659 lineaxis->SetLineStyle(1); 660 lineaxis->SetLineWidth(GetLineWidth()); 661 textaxis->SetTextColor(GetTextColor()); 662 textaxis->SetTextFont(GetTextFont()); 663 664 if (!gPad->IsBatch()) { 665 float chupxvsav, chupyvsav; 666 gVirtualX->GetCharacterUp(chupxvsav, chupyvsav); 667 gVirtualX->SetClipOFF(gPad->GetCanvasID()); 668 } 669 */ 670 671 // Compute length of axis 672 double axis_length = ::sqrt((X1-X0)*(X1-X0)+(Y1-Y0)*(Y1-Y0)); 673 if (axis_length == 0) { 674 out_error(m_out,"PaintAxis", "length of axis is 0"); 675 return; //goto L210; 676 } 677 678 //out_error(m_out,"android_debug","0005"); 679 if (!OptionNoopt || OptionInt) { 680 axis_lengthN = ::sqrt((XX1-XX0)*(XX1-XX0)+(YY1-YY0)*(YY1-YY0)); 681 axis_length0 = ::sqrt((XX0-X0)*(XX0-X0)+(YY0-Y0)*(YY0-Y0)); 682 axis_length1 = ::sqrt((X1-XX1)*(X1-XX1)+(Y1-YY1)*(Y1-YY1)); 683 if (axis_lengthN < epsilon) { 684 OptionNoopt = 1; 685 OptionInt = 0; 686 wmin = rwmi; 687 wmax = rwma; 688 N1A = N1Aold; 689 NN1 = NN1old; 690 Nticks = NN1; 691 if (OptionTime) { 692 wmin += timeoffset - (int)(timeoffset) + rangeOffset; 693 wmax += timeoffset - (int)(timeoffset) + rangeOffset; 694 } 695 } 696 } 697 698 //out_error(m_out,"android_debug","0006"); 699 if (X0 == X1) { 700 phi = 0.5*kPI; 701 phil = phi; 702 } else { 703 phi = TMath_ATan2((Y1-Y0),(X1-X0)); 704 int px0 = 0;//FIXME gPad->UtoPixel(X0); 705 int py0 = 0;//FIXME gPad->VtoPixel(Y0); 706 int px1 = 0;//FIXME gPad->UtoPixel(X1); 707 int py1 = 0;//FIXME gPad->VtoPixel(Y1); 708 if (X0 < X1) phil = TMath_ATan2(double(py0-py1), double(px1-px0)); 709 else phil = TMath_ATan2(double(py1-py0), double(px0-px1)); 710 } 711 cosphi = ::cos(phi); 712 sinphi = ::sin(phi); 713 acosphi = TMath_Abs(cosphi); 714 asinphi = TMath_Abs(sinphi); 715 if (acosphi <= epsilon) { acosphi = 0; cosphi = 0; } 716 if (asinphi <= epsilon) { asinphi = 0; sinphi = 0; } 717 718 //out_error(m_out,"android_debug","0007"); 719 // Mside positive, tick marks on positive side 720 // Mside negative, tick marks on negative side 721 // Mside zero, tick marks on both sides 722 // Default is positive except for vertical axis 723 724 Mside=1; 725 if (X0 == X1 && Y1 > Y0) Mside = -1; 726 if (OptionPlus) Mside = 1; 727 if (OptionMinus) Mside = -1; 728 if (OptionPlus && OptionMinus) Mside = 0; 729 XMside = Mside; 730 Lside = -Mside; 731 if (OptionEqual) Lside = Mside; 732 if (OptionPlus && OptionMinus) { 733 Lside = -1; 734 if (OptionEqual) Lside=1; 735 } 736 XLside = Lside; 737 738 // Tick marks size 739 double tick_side; 740 if(XMside >= 0) tick_side = 1; 741 else tick_side = -1; 742 743 double atick[3]; 744 if (OptionSize) atick[0] = tick_side*axis_length*fTickSize; 745 else atick[0] = tick_side*axis_length*0.03; 746 747 atick[1] = 0.5*atick[0]; 748 atick[2] = 0.5*atick[1]; 749 750 // Set the side of the grid 751 if ((X0 == X1) && (Y1 > Y0)) grid_side =-1; 752 else grid_side = 1; 753 754 755 //out_error(m_out,"android_debug","0008"); 756 // Compute Values if Function is given 757 /*GB if(fFunction) { 758 rwmi = fFunction->Eval(wmin); 759 rwma = fFunction->Eval(wmax); 760 if(rwmi > rwma) { 761 double t = rwma; 762 rwma = rwmi; 763 rwmi = t; 764 } 765 }*/ 766 767 // Draw the axis if needed... 768 if (!OptionBlank) { 769 xpl1 = X0; 770 xpl2 = X1; 771 ypl1 = Y0; 772 ypl2 = Y1; 773 aLinesAxis.push_back((float)xpl1); 774 aLinesAxis.push_back((float)ypl1); 775 aLinesAxis.push_back((float)xpl2); 776 aLinesAxis.push_back((float)ypl2); 777 } 778 779 //out_error(m_out,"android_debug","0009"); 780 // No bining 781 782 if (ndiv == 0) return; //goto L210; 783 if (wmin == wmax) { 784 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f)", wmin, wmax); 785 return; //goto L210; 786 } 787 788 // Draw axis title if it exists 789 if (!drawGridOnly && fTitle.size()) { 790 textSize = fTitleSize; 791 charheight = fTitleSize; 792 if ((GetTextFont() % 10) > 2) { 793 //FIXME charheight = charheight/gPad->GetWh(); 794 } 795 double toffset = fTitleOffset; 796 if (toffset < 0.1) toffset = 1; 797 if (X1 == X0) Ylabel = XLside*1.6*charheight*toffset; 798 else Ylabel = XLside*1.3*charheight*toffset; 799 if (Y1 == Y0) Ylabel = XLside*1.6*charheight*toffset; 800 double axispos; 801 if (testBit(TAxis_kCenterTitle)) axispos = 0.5*axis_length; 802 else axispos = axis_length; 803 if (testBit(TAxis_kRotateTitle)) { 804 if (X1 >= X0) { 805 if (testBit(TAxis_kCenterTitle)) textAlign = 22; 806 else textAlign = 12; 807 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1); 808 } else { 809 if (testBit(TAxis_kCenterTitle)) textAlign = 22; 810 else textAlign = 32; 811 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1); 812 } 813 out_error(m_out,"PaintAxis","debug : texts : dummy : 000\n"); 814 aTexts.push_back(_text(xpl1,ypl1, 815 phil=(kPI+phil)*180/kPI, 816 fTitleSize, 817 fTitle,textAlign)); 818 } else { 819 if (X1 >= X0) { 820 if (testBit(TAxis_kCenterTitle)) textAlign = 22; 821 else textAlign = 32; 822 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1); 823 } else { 824 if (testBit(TAxis_kCenterTitle)) textAlign = 22; 825 else textAlign = 12; 826 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1); 827 } 828 aTexts.push_back(_text(xpl1,ypl1, 829 phil*180/kPI,fTitleSize, 830 fTitle,textAlign)); 831 } 832 } 833 834 //out_error(m_out,"android_debug","0010"); 835 // Labels preparation: 836 // Get character height 837 // Compute the labels orientation in case of overlaps 838 // with alphanumeric labels for horizontal axis). 839 840 charheight = fLabelSize; 841 if (OptionText) charheight *= 0.66666; 842 //FIXME textaxis->SetTextFont(fLabelFont); 843 //FIXME textaxis->SetTextColor(GetLabelColor()); 844 textSize = charheight; 845 //FIXME textaxis->SetTextAngle(GetTextAngle()); 846 if (fLabelFont%10 > 2) { 847 charheight /= padh; 848 } 849 if (!OptionUp && !OptionDown && !OptionY) { 850 if (!drawGridOnly && OptionText && ((ymin == ymax) || (xmin == xmax))) { 851 textAlign = 32; 852 OptionText = 2; 853 //int nl = 0;//FIXME fAxis->GetLast()-fAxis->GetFirst()+1; 854 //double angle = 0; 855 out_error(m_out,"PaintAxis","debug : FIXME : 000\n"); 856 /*FIXME 857 for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) { 858 textaxis->SetText(0,0,fAxis->GetBinLabel(i)); 859 if (textaxis->GetXsize() < (xmax-xmin)/nl) continue; 860 angle = -20; 861 break; 862 } 863 for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) { 864 if ((!::strcmp(fAxis->GetName(),"xaxis") && !gPad->testBit(kHori)) 865 ||(!::strcmp(fAxis->GetName(),"yaxis") && gPad->testBit(kHori))) { 866 if (nl > 50) angle = 90; 867 if (fAxis->testBit(TAxis_kLabelsHori)) angle = 0; 868 if (fAxis->testBit(TAxis_kLabelsVert)) angle = 90; 869 if (fAxis->testBit(TAxis_kLabelsUp)) angle = 20; 870 if (fAxis->testBit(TAxis_kLabelsDown)) angle =-20; 871 if (angle== 0) textAlign = 23; 872 if (angle== -20) textAlign = 12; 873 out_error(m_out,"PaintAxis","debug : texts : dummy : 002\n"); 874 textaxis->PaintLatex( 875 fAxis->GetBinCenter(i), 876 gPad->GetUymin() - 3*fAxis->GetLabelOffset()* 877 (gPad->GetUymax()-gPad->GetUymin()), 878 angle, 879 charheight, 880 fAxis->GetBinLabel(i)); 881 } else if ((!::strcmp(fAxis->GetName(),"yaxis") && !gPad->testBit(kHori)) 882 || (!::strcmp(fAxis->GetName(),"xaxis") && gPad->testBit(kHori))) { 883 out_error(m_out,"PaintAxis","debug : texts : dummy : 003\n"); 884 textaxis->PaintLatex( 885 gPad->GetUxmin() - 3*fAxis->GetLabelOffset()* 886 (gPad->GetUxmax()-gPad->GetUxmin()), 887 fAxis->GetBinCenter(i), 888 0, 889 charheight, 890 fAxis->GetBinLabel(i)); 891 } else { 892 out_error(m_out,"PaintAxis","debug : texts : dummy : 004\n"); 893 textaxis->PaintLatex( 894 xmin - 3*fAxis->GetLabelOffset()* 895 (gPad->GetUxmax()-gPad->GetUxmin()), 896 ymin +(i-0.5)*(ymax-ymin)/nl, 897 0, 898 charheight, 899 fAxis->GetBinLabel(i)); 900 } 901 }*/ 902 } 903 } 904 905 //out_error(m_out,"android_debug","0011"); 906 // Now determine orientation of labels on axis 907 /*FIXME 908 if (!gPad->IsBatch()) { 909 if (cosphi > 0) gVirtualX->SetCharacterUp(-sinphi,cosphi); 910 else gVirtualX->SetCharacterUp(sinphi,-cosphi); 911 if (X0 == X1) gVirtualX->SetCharacterUp(0,1); 912 if (OptionVert) gVirtualX->SetCharacterUp(0,1); 913 if (OptionPara) gVirtualX->SetCharacterUp(-sinphi,cosphi); 914 if (OptionDown) gVirtualX->SetCharacterUp(cosphi,sinphi); 915 }*/ 916 917 // Now determine text alignment 918 Xalign = 2; 919 Yalign = 1; 920 if (X0 == X1) Xalign = 3; 921 if (Y0 != Y1) Yalign = 2; 922 if (OptionCent) Xalign = 2; 923 if (OptionRight) Xalign = 3; 924 if (OptionLeft) Xalign = 1; 925 if (TMath_Abs(cosphi) > 0.9) { 926 Xalign = 2; 927 } else { 928 if (cosphi*sinphi > 0) Xalign = 1; 929 if (cosphi*sinphi < 0) Xalign = 3; 930 } 931 textAlign = 10*Xalign+Yalign; 932 933 //out_error(m_out,"android_debug","0012"); 934 // Position of labels in Y 935 if (X0 == X1) { 936 if (OptionPlus && !OptionMinus) { 937 if (OptionEqual) Ylabel = fLabelOffset/2 + atick[0]; 938 else Ylabel = -fLabelOffset; 939 } else { 940 Ylabel = fLabelOffset; 941 if (Lside < 0) Ylabel += atick[0]; 942 } 943 } else if (Y0 == Y1) { 944 if (OptionMinus && !OptionPlus) { 945 Ylabel = fLabelOffset+0.5*fLabelSize; 946 Ylabel += TMath_Abs(atick[0]); 947 } else { 948 Ylabel = -fLabelOffset; 949 if (Mside <= 0) Ylabel -= TMath_Abs(atick[0]); 950 } 951 if (OptionLog) Ylabel -= 0.5*charheight; 952 } else { 953 if (Mside+Lside >= 0) Ylabel = fLabelOffset; 954 else Ylabel = -fLabelOffset; 955 } 956 if (OptionText) Ylabel /= 2; 957 958 //out_error(m_out,"android_debug","0013"); 959 // Draw the linear tick marks if needed... 960 if (!OptionLog) { 961 if (ndiv) { 962 /*GB if (fFunction) { 963 if (OptionNoopt && !OptionInt) { 964 DXtick=(BinHigh-BinLow)/double(Nticks-1); 965 } else { 966 DXtick=(BinHigh-BinLow)/double(Nticks-1); 967 } 968 } else */ { 969 if (OptionNoopt && !OptionInt) DXtick=axis_length/double(Nticks-1); 970 else DXtick=axis_lengthN/double(Nticks-1); 971 } 972 for (k=0;k<Nticks; k++) { 973 ltick = 2; 974 if (k%NN3 == 0) ltick = 1; 975 if (k%NN2 == 0) ltick = 0; 976 /*GB if (fFunction) { 977 double xx = BinLow+double(k)*DXtick; 978 double zz = fFunction->Eval(xx)-rwmi; 979 Xtick = zz* axis_length / TMath_Abs(rwma-rwmi); 980 } else */ { 981 Xtick = double(k)*DXtick; 982 } 983 Ytick = 0; 984 if (!Mside) Ytick -= atick[ltick]; 985 if ( OptionNoopt && !OptionInt) { 986 TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,X0,Y0,xpl2,ypl2); 987 TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,X0,Y0,xpl1,ypl1); 988 } 989 else { 990 TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,XX0,YY0,xpl2,ypl2); 991 TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,XX0,YY0,xpl1,ypl1); 992 } 993 if (OptionVert) { 994 if ((X0 != X1) && (Y0 != Y1)) { 995 if (Mside) { 996 xpl1 = xpl2; 997 if (cosphi > 0) ypl1 = ypl2 + atick[ltick]; 998 else ypl1 = ypl2 - atick[ltick]; 999 } 1000 else { 1001 xpl1 = 0.5*(xpl1 + xpl2); 1002 xpl2 = xpl1; 1003 ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick]; 1004 ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick]; 1005 } 1006 } 1007 } 1008 if (!drawGridOnly) { 1009 aLinesAxis.push_back((float)xpl1); 1010 aLinesAxis.push_back((float)ypl1); 1011 aLinesAxis.push_back((float)xpl2); 1012 aLinesAxis.push_back((float)ypl2); 1013 } 1014 1015 if (OptionGrid) { 1016 if (ltick == 0) { 1017 if (OptionNoopt && !OptionInt) { 1018 TGaxis_Rotate(Xtick,0,cosphi,sinphi,X0,Y0 ,xpl2,ypl2); 1019 TGaxis_Rotate 1020 (Xtick,grid_side*gridlength,cosphi,sinphi,X0,Y0, 1021 xpl1,ypl1); 1022 } else { 1023 TGaxis_Rotate(Xtick,0,cosphi ,sinphi,XX0,YY0,xpl2,ypl2); 1024 TGaxis_Rotate 1025 (Xtick,grid_side*gridlength ,cosphi,sinphi,XX0,YY0, 1026 xpl1,ypl1); 1027 } 1028 aLinesGrid.push_back((float)xpl1); 1029 aLinesGrid.push_back((float)ypl1); 1030 aLinesGrid.push_back((float)xpl2); 1031 aLinesGrid.push_back((float)ypl2); 1032 } 1033 } 1034 } 1035 Xtick0 = 0; 1036 Xtick1 = Xtick; 1037 1038 if ((!OptionNoopt || OptionInt) && axis_length0) { 1039 int Nticks0; 1040 /*GB if (fFunction) Nticks0 = int((BinLow-wmin)/DXtick); 1041 else */ Nticks0 = int(axis_length0/DXtick); 1042 if (Nticks0 > 1000) Nticks0 = 1000; 1043 for (k=0; k<=Nticks0; k++) { 1044 ltick = 2; 1045 if (k%NN3 == 0) ltick = 1; 1046 if (k%NN2 == 0) ltick = 0; 1047 Ytick0 = 0; 1048 if (!Mside) Ytick0 -= atick[ltick]; 1049 /*GB if (fFunction) { 1050 Xtick0 = (fFunction->Eval(BinLow - double(k)*DXtick)-rwmi) 1051 * axis_length / TMath_Abs(rwma-rwmi); 1052 }*/ 1053 TGaxis_Rotate(Xtick0,Ytick0,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2); 1054 TGaxis_Rotate(Xtick0,atick[ltick],cosphi,sinphi,XX0,YY0 ,xpl1,ypl1); 1055 if (OptionVert) { 1056 if ((X0 != X1) && (Y0 != Y1)) { 1057 if (Mside) { 1058 xpl1 = xpl2; 1059 if (cosphi > 0) ypl1 = ypl2 + atick[ltick]; 1060 else ypl1 = ypl2 - atick[ltick]; 1061 } 1062 else { 1063 xpl1 = 0.5*(xpl1 + xpl2); 1064 xpl2 = xpl1; 1065 ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick]; 1066 ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick]; 1067 } 1068 } 1069 } 1070 if(!drawGridOnly) { 1071 aLinesAxis.push_back((float)xpl1); 1072 aLinesAxis.push_back((float)ypl1); 1073 aLinesAxis.push_back((float)xpl2); 1074 aLinesAxis.push_back((float)ypl2); 1075 } 1076 1077 if (OptionGrid) { 1078 if (ltick == 0) { 1079 TGaxis_Rotate(Xtick0,0,cosphi,sinphi,XX0,YY0,xpl2,ypl2); 1080 TGaxis_Rotate 1081 (Xtick0,grid_side*gridlength,cosphi,sinphi,XX0,YY0, 1082 xpl1,ypl1); 1083 aLinesGrid.push_back((float)xpl1); 1084 aLinesGrid.push_back((float)ypl1); 1085 aLinesGrid.push_back((float)xpl2); 1086 aLinesGrid.push_back((float)ypl2); 1087 } 1088 } 1089 Xtick0 -= DXtick; 1090 } 1091 } 1092 1093 if ((!OptionNoopt || OptionInt) && axis_length1) { 1094 int Nticks1; 1095 /*GB if (fFunction) Nticks1 = int((wmax-BinHigh)/DXtick); 1096 else */ Nticks1 = int(axis_length1/DXtick); 1097 if (Nticks1 > 1000) Nticks1 = 1000; 1098 for (k=0; k<=Nticks1; k++) { 1099 ltick = 2; 1100 if (k%NN3 == 0) ltick = 1; 1101 if (k%NN2 == 0) ltick = 0; 1102 Ytick1 = 0; 1103 if (!Mside) Ytick1 -= atick[ltick]; 1104 /*GB if (fFunction) { 1105 Xtick1 = (fFunction->Eval(BinHigh + double(k)*DXtick)-rwmi) 1106 * axis_length / TMath_Abs(rwma-rwmi); 1107 }*/ 1108 TGaxis_Rotate(Xtick1,Ytick1,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2); 1109 TGaxis_Rotate(Xtick1,atick[ltick],cosphi,sinphi,XX0,YY0 ,xpl1,ypl1); 1110 if (OptionVert) { 1111 if ((X0 != X1) && (Y0 != Y1)) { 1112 if (Mside) { 1113 xpl1 = xpl2; 1114 if (cosphi > 0) ypl1 = ypl2 + atick[ltick]; 1115 else ypl1 = ypl2 - atick[ltick]; 1116 } 1117 else { 1118 xpl1 = 0.5*(xpl1 + xpl2); 1119 xpl2 = xpl1; 1120 ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick]; 1121 ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick]; 1122 } 1123 } 1124 } 1125 if(!drawGridOnly) { 1126 aLinesAxis.push_back((float)xpl1); 1127 aLinesAxis.push_back((float)ypl1); 1128 aLinesAxis.push_back((float)xpl2); 1129 aLinesAxis.push_back((float)ypl2); 1130 } 1131 1132 if (OptionGrid) { 1133 if (ltick == 0) { 1134 TGaxis_Rotate(Xtick1,0,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2); 1135 TGaxis_Rotate 1136 (Xtick1,grid_side*gridlength,cosphi,sinphi,XX0,YY0, 1137 xpl1,ypl1); 1138 aLinesGrid.push_back((float)xpl1); 1139 aLinesGrid.push_back((float)ypl1); 1140 aLinesGrid.push_back((float)xpl2); 1141 aLinesGrid.push_back((float)ypl2); 1142 } 1143 } 1144 Xtick1 += DXtick; 1145 } 1146 } 1147 } 1148 } 1149 1150 //out_error(m_out,"android_debug","0014"); 1151 // Draw the numeric labels if needed... 1152 if (!drawGridOnly && !OptionUnlab) { 1153 if (!OptionLog) { 1154 if (N1A) { 1155 // Spacing of labels 1156 if ((wmin == wmax) || (ndiv == 0)) { 1157 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax); 1158 return; //goto L210; 1159 } 1160 Wlabel = wmin; 1161 DWlabel = (wmax-wmin)/double(N1A); 1162 if (OptionNoopt && !OptionInt) DXlabel = axis_length/double(N1A); 1163 else DXlabel = axis_lengthN/double(N1A); 1164 1165 char CHCODED[8]; 1166 int NEXE = 0; 1167 bool FLEXE = false; 1168 if (!OptionText && !OptionTime) { 1169 1170 // We have to decide what format to generate 1171 // for numeric labels only) 1172 // Test the magnitude, decide format 1173 FLEXE = false; 1174 NEXE = 0; 1175 bool FLEXPO = false; 1176 bool FLEXNE = false; 1177 WW = mx<double>(TMath_Abs(wmin),TMath_Abs(wmax)); 1178 1179 // First case : (wmax-wmin)/N1A less than 0.001 1180 // 0.001 fMaxDigits of 5 (fMaxDigits) characters). 1181 // Then we use x 10 n 1182 // format. If AF >=0 x10 n cannot be used 1183 double xmicros = 0.00099; 1184 if (maxDigits) xmicros = ::pow(10.,-maxDigits); 1185 if (!noExponent && (TMath_Abs(wmax-wmin)/double(N1A)) < xmicros) { 1186 AF = ::log10(WW) + epsilon; 1187 if (AF < 0) { 1188 FLEXE = true; 1189 NEXE = int(AF); 1190 int IEXE = TMath_Abs(NEXE); 1191 if (IEXE%3 == 1) IEXE += 2; 1192 else if(IEXE%3 == 2) IEXE += 1; 1193 if (NEXE < 0) NEXE = -IEXE; 1194 else NEXE = IEXE; 1195 Wlabel = Wlabel*::pow(10.,IEXE); 1196 DWlabel = DWlabel*::pow(10.,IEXE); 1197 IF1 = maxDigits; 1198 IF2 = maxDigits-2; 1199 goto L110; 1200 } 1201 } 1202 if (WW >= 1) AF = ::log10(WW); 1203 else AF = ::log10(WW*0.0001); 1204 AF += epsilon; 1205 NF = int(AF)+1; 1206 if (!noExponent && NF > maxDigits) FLEXPO = true; 1207 if (!noExponent && NF < -maxDigits) FLEXNE = true; 1208 1209 // Use x 10 n format. (only powers of 3 allowed) 1210 1211 if (FLEXPO) { 1212 FLEXE = true; 1213 while (1) { 1214 NEXE++; 1215 WW /= 10; 1216 Wlabel /= 10; 1217 DWlabel /= 10; 1218 if (NEXE%3 == 0 && WW <= ::pow(10.,maxDigits-1)) break; 1219 } 1220 } 1221 1222 if (FLEXNE) { 1223 FLEXE = true; 1224 RNE = 1/::pow(10.,maxDigits-2); 1225 while (1) { 1226 NEXE--; 1227 WW *= 10; 1228 Wlabel *= 10; 1229 DWlabel *= 10; 1230 if (NEXE%3 == 0 && WW >= RNE) break; 1231 } 1232 } 1233 1234 NA = 0; 1235 for (i=maxDigits-1; i>0; i--) { 1236 if (TMath_Abs(WW) < ::pow(10.,i)) NA = maxDigits-i; 1237 } 1238 ndyn = N1A; 1239 while (ndyn) { 1240 double wdyn = TMath_Abs((wmax-wmin)/ndyn); 1241 if (wdyn <= 0.999 && NA < maxDigits-2) { 1242 NA++; 1243 ndyn /= 10; 1244 } 1245 else break; 1246 } 1247 1248 IF2 = NA; 1249 IF1 = mx<int>(NF+NA,maxDigits)+1; 1250 L110: 1251 if (mn<double>(wmin,wmax) < 0)IF1 = IF1+1; 1252 IF1 = mn<int>(IF1,32); 1253 1254 // In some cases, IF1 and IF2 are too small.... 1255 while (DWlabel < ::pow(10.,-IF2)) { 1256 IF1++; 1257 IF2++; 1258 } 1259 //char* CODED = &CHCODED[0]; //GB : comment out. 1260 if (IF1 > 14) IF1=14; 1261 if (IF2 > 14) IF2=14; 1262 if(IF2)snpf(CHCODED,sizeof(CHCODED),"%%%d.%df",IF1,IF2); 1263 else snpf(CHCODED,sizeof(CHCODED),"%%%d.%df",IF1+1,1); 1264 } 1265 1266 // We draw labels 1267 1268 snpf(CHTEMP,sizeof(CHTEMP),"%g",DWlabel); 1269 1270 size_t ndecimals = 0; 1271 if (OptionDecimals) { 1272 char *dot = ::strchr(CHTEMP,'.'); 1273 if (dot) ndecimals = CHTEMP + ::strlen(CHTEMP) -dot; 1274 } 1275 int Nlabels; 1276 if (OptionM) Nlabels = N1A-1; 1277 else Nlabels = N1A; 1278 double wTimeIni = Wlabel; 1279 for ( k=0; k<=Nlabels; k++) { 1280 /*FIXME if (fFunction) { 1281 double xx = BinLow+double(k*NN2)*DXtick; 1282 double zz = fFunction->Eval(xx)-rwmi; 1283 Wlabel = xx; 1284 Xlabel = zz* axis_length / TMath_Abs(rwma-rwmi); 1285 } else */{ 1286 Xlabel = DXlabel*k; 1287 } 1288 if (OptionM) Xlabel += 0.5*DXlabel; 1289 1290 if (!OptionText && !OptionTime) { 1291 snpf(LABEL,sizeof(LABEL),&CHCODED[0],Wlabel); 1292 LABEL[28] = 0; 1293 Wlabel += DWlabel; 1294 1295 TGaxis_LabelsLimits(m_out,LABEL,first,last); //Eliminate blanks 1296 1297 if (LABEL[first] == '.') { //check if '.' is preceeded by a digit 1298 ::strcpy(CHTEMP, "0"); 1299 ::strcat(CHTEMP, &LABEL[first]); 1300 ::strcpy(LABEL, CHTEMP); 1301 first = 1; last = int(::strlen(LABEL)); 1302 } 1303 if (LABEL[first] == '-' && LABEL[first+1] == '.') { 1304 ::strcpy(CHTEMP, "-0"); 1305 ::strcat(CHTEMP, &LABEL[first+1]); 1306 ::strcpy(LABEL, CHTEMP); 1307 first = 1; last = int(::strlen(LABEL)); 1308 } 1309 1310 // We eliminate the non significant 0 after '.' 1311 if (ndecimals) { 1312 char *adot = ::strchr(LABEL,'.'); 1313 if (adot) adot[ndecimals] = 0; 1314 } else { 1315 while (LABEL[last] == '0') { LABEL[last] = 0; last--;} 1316 } 1317 // We eliminate the dot, unless dot is forced. 1318 if (LABEL[last] == '.') { 1319 if (!OptionDot) { LABEL[last] = 0; last--;} 1320 } 1321 } 1322 1323 // Generate the time labels 1324 1325 if (OptionTime) { 1326 double timed = Wlabel + (int)(timeoffset) - rangeOffset; 1327 time_t timelabel = (time_t)((long)(timed)); 1328 struct tm* utctis; 1329 if (OptionTime == 1) { 1330 utctis = localtime(&timelabel); 1331 } else { 1332 utctis = gmtime(&timelabel); 1333 } 1334 std::string timeformattmp; 1335 if (timeformat.size() < 220) timeformattmp = timeformat; 1336 else timeformattmp = "#splitline{Format}{too long}"; 1337 1338 // Appends fractionnal part if seconds displayed 1339 if (DWlabel<0.9) { 1340 double tmpdb; 1341 size_t tmplast; 1342 snpf(LABEL,sizeof(LABEL),"%%S%7.5f",modf(timed,&tmpdb)); 1343 tmplast = ::strlen(LABEL)-1; 1344 1345 // We eliminate the non significiant 0 after '.' 1346 while (LABEL[tmplast] == '0') { 1347 LABEL[tmplast] = 0; tmplast--; 1348 } 1349 1350 //FIXME timeformattmp.ReplaceAll("%S",LABEL); 1351 // Replace the "0." at the begining by "s" 1352 //FIXME timeformattmp.ReplaceAll("%S0.","%Ss"); 1353 1354 } 1355 1356 ::strftime(LABEL,256,timeformattmp.c_str(),utctis); 1357 ::strcpy(CHTEMP,&LABEL[0]); 1358 first = 0; last=int(::strlen(LABEL))-1; 1359 Wlabel = wTimeIni + (k+1)*DWlabel; 1360 } 1361 1362 // We generate labels (numeric or alphanumeric). 1363 1364 if (OptionNoopt && !OptionInt) 1365 TGaxis_Rotate (Xlabel,Ylabel,cosphi,sinphi,X0,Y0,XX,YY); 1366 else TGaxis_Rotate (Xlabel,Ylabel,cosphi,sinphi,XX0,YY0,XX,YY); 1367 if (Y0 == Y1 && !OptionDown && !OptionUp) { 1368 YY -= 0.80*charheight; 1369 } 1370 if (OptionVert) { 1371 if (X0 != X1 && Y0 != Y1) { 1372 if (OptionNoopt && !OptionInt) 1373 TGaxis_Rotate (Xlabel,0,cosphi,sinphi,X0,Y0,XX,YY); 1374 else TGaxis_Rotate (Xlabel,0,cosphi,sinphi,XX0,YY0,XX,YY); 1375 if (cosphi > 0 ) YY += Ylabel; 1376 if (cosphi < 0 ) YY -= Ylabel; 1377 } 1378 } 1379 if (!OptionY || (X0 == X1)) { 1380 if (!OptionText) { 1381 if (first > last) ::strcpy(CHTEMP, " "); 1382 else ::strcpy(CHTEMP, &LABEL[first]); 1383 aTexts.push_back(_text(XX,YY, 1384 0,textSize,CHTEMP, 1385 textAlign)); 1386 } 1387 else { 1388 if (OptionText == 1) { 1389 out_error(m_out,"PaintAxis","debug : texts : dummy : 006\n"); 1390 /*textaxis->PaintLatex 1391 (gPad->GetX1() + XX*(gPad->GetX2() - gPad->GetX1()), 1392 gPad->GetY1() + YY*(gPad->GetY2() - gPad->GetY1()), 1393 0, 1394 textaxis->GetTextSize(), 1395 fAxis->GetBinLabel(k+fAxis->GetFirst()));*/ 1396 } 1397 } 1398 } 1399 else { 1400 1401 // Text alignment is down 1402 int LNLEN = 0; 1403 if (!OptionText) LNLEN = last-first+1; 1404 else { 1405 int NHILAB = 0; 1406 if (k+1 > NHILAB) LNLEN = 0; 1407 } 1408 for ( l=1; l<=LNLEN; l++) { 1409 if (!OptionText) *CHTEMP = LABEL[first+l-2]; 1410 else { 1411 if (LNLEN == 0) ::strcpy(CHTEMP, " "); 1412 else ::strcpy(CHTEMP, "1"); 1413 } 1414 aTexts.push_back(_text(XX,YY, 1415 0,textSize,CHTEMP, 1416 textAlign)); 1417 YY -= charheight*1.3; 1418 } 1419 } 1420 } 1421 1422 // We use the format x 10 ** n 1423 1424 if (FLEXE && !OptionText && NEXE) { 1425 //G.Barrand ::sprintf(LABEL,"#times10^{%d}", NEXE); 1426 snpf(LABEL,sizeof(LABEL), 1427 "x10^%d!", NEXE); //G.Barrand : PAW encoding. 1428 double Xfactor, Yfactor; 1429 if (X0 != X1) { Xfactor = X1-X0+0.1*charheight; Yfactor = 0; } 1430 else { Xfactor = Y1-Y0+0.1*charheight; Yfactor = 0; } 1431 TGaxis_Rotate (Xfactor,Yfactor,cosphi,sinphi,X0,Y0,XX,YY); 1432 textAlign = 11; 1433 aTexts.push_back(_text(XX,YY, 1434 0,textSize,LABEL, 1435 textAlign)); 1436 } 1437 } 1438 } 1439 } 1440 1441 // Log axis 1442 1443 //out_error(m_out,"android_debug","0015"); 1444 if (OptionLog && ndiv) { 1445 unsigned int xi1=0,xi2 = 0,wi = 0,yi1=0,yi2,hi = 0; 1446 bool firstintlab = true, overlap = false; 1447 if ((wmin == wmax) || (ndiv == 0)) { 1448 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax); 1449 return; //goto L210; 1450 } 1451 if (wmin <= 0) { 1452 out_error(m_out,"PaintAxis", "negative logarithmic axis"); 1453 return; //goto L210; 1454 } 1455 if (wmax <= 0) { 1456 out_error(m_out,"PaintAxis", "negative logarithmic axis"); 1457 return; //goto L210; 1458 } 1459 double XMNLOG = ::log10(wmin); 1460 if (XMNLOG > 0) XMNLOG += 1.E-6; 1461 else XMNLOG -= 1.E-6; 1462 double X00 = 0; 1463 double X11 = axis_length; 1464 double H2 = ::log10(wmax); 1465 double H2SAV = H2; 1466 if (H2 > 0) H2 += 1.E-6; 1467 else H2 -= 1.E-6; 1468 int IH1 = int(XMNLOG); 1469 int IH2 = 1+int(H2); 1470 int NBININ = IH2-IH1+1; 1471 double AXMUL = (X11-X00)/(H2SAV-XMNLOG); 1472 1473 // Plot decade and intermediate tick marks 1474 decade = IH1-2; 1475 int labelnumber = IH1; 1476 if ( XMNLOG > 0 && (XMNLOG-double(IH1) > 0) ) labelnumber++; 1477 for (j=1; j<=NBININ; j++) { 1478 1479 // Plot decade 1480 firstintlab = true, overlap = false; 1481 decade++; 1482 if (X0 == X1 && j == 1) Ylabel += charheight*0.33; 1483 if (Y0 == Y1 && j == 1) Ylabel -= charheight*0.65; 1484 double Xone = X00+AXMUL*(double(decade)-XMNLOG); 1485 //the following statement is a trick to circumvent a gcc bug 1486 //GB if (j < 0) ::printf("j=%d\n",j); //G.Barrand : ??? 1487 if (X00 > Xone) goto L160; 1488 if (Xone > X11) break; 1489 Xtwo = Xone; 1490 Y = 0; 1491 if (!Mside) Y -= atick[0]; 1492 TGaxis_Rotate(Xone,Y,cosphi,sinphi,X0,Y0,xpl2,ypl2); 1493 TGaxis_Rotate(Xtwo,atick[0],cosphi,sinphi,X0,Y0,xpl1,ypl1); 1494 if (OptionVert) { 1495 if ((X0 != X1) && (Y0 != Y1)) { 1496 if (Mside) { 1497 xpl1=xpl2; 1498 if (cosphi > 0) ypl1 = ypl2 + atick[0]; 1499 else ypl1 = ypl2 - atick[0]; 1500 } 1501 else { 1502 xpl1 = 0.5*(xpl1 + xpl2); 1503 xpl2 = xpl1; 1504 ypl1 = 0.5*(ypl1 + ypl2) + atick[0]; 1505 ypl2 = 0.5*(ypl1 + ypl2) - atick[0]; 1506 } 1507 } 1508 } 1509 if (!drawGridOnly) { 1510 aLinesAxis.push_back((float)xpl1); 1511 aLinesAxis.push_back((float)ypl1); 1512 aLinesAxis.push_back((float)xpl2); 1513 aLinesAxis.push_back((float)ypl2); 1514 } 1515 1516 if (OptionGrid) { 1517 TGaxis_Rotate(Xone,0,cosphi,sinphi,X0,Y0,xpl2,ypl2); 1518 TGaxis_Rotate(Xone,grid_side*gridlength,cosphi,sinphi,X0,Y0, 1519 xpl1,ypl1); 1520 aLinesGrid.push_back((float)xpl1); 1521 aLinesGrid.push_back((float)ypl1); 1522 aLinesGrid.push_back((float)xpl2); 1523 aLinesGrid.push_back((float)ypl2); 1524 } 1525 1526 if (!drawGridOnly && !OptionUnlab) { 1527 1528 // We generate labels (numeric only). 1529 if (noExponent) { 1530 double rlab = ::pow(10.,labelnumber); 1531 snpf(LABEL,sizeof(LABEL), "%f", rlab); 1532 TGaxis_LabelsLimits(m_out,LABEL,first,last); 1533 while (last > first) { 1534 if (LABEL[last] != '0') break; 1535 LABEL[last] = 0; 1536 last--; 1537 } 1538 if (LABEL[last] == '.') {LABEL[last] = 0; last--;} 1539 } else { 1540 snpf(LABEL,sizeof(LABEL), "%d", labelnumber); 1541 TGaxis_LabelsLimits(m_out,LABEL,first,last); 1542 } 1543 TGaxis_Rotate (Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY); 1544 if ((X0 == X1) && !OptionPara) { 1545 if (Lside < 0) { 1546 if (Mside < 0) { 1547 if (labelnumber == 0) NCH=1; 1548 else NCH=2; 1549 XX += NCH*charheight; 1550 } else { 1551 if (labelnumber >= 0) XX += 0.25*charheight; 1552 else XX += 0.50*charheight; 1553 } 1554 } 1555 XX += 0.25*charheight; 1556 } 1557 if ((Y0 == Y1) && !OptionDown && !OptionUp) { 1558 if (noExponent) YY += 0.33*charheight; 1559 } 1560 if (N1A == 0) return; //goto L210; 1561 int KMOD = NBININ/N1A; 1562 if (KMOD == 0) KMOD=1000000; 1563 if ((NBININ <= N1A) || (j == 1) || (j == NBININ) || ((NBININ > N1A) 1564 && (j%KMOD == 0))) { 1565 if (labelnumber == 0) { 1566 aTexts.push_back(_text(XX,YY, 1567 0,textSize,"1", 1568 textAlign)); 1569 } else if (labelnumber == 1) { 1570 aTexts.push_back(_text(XX,YY, 1571 0,textSize,"10", 1572 textAlign)); 1573 } else { 1574 if (noExponent) { 1575 out_error(m_out,"PaintAxis","debug : texts : FIXME : 003\n"); 1576 //FIXME textaxis->PaintTextNDC(XX,YY,&LABEL[first]); 1577 } else { 1578 //FIXME : support CERN-ROOT Latex encoding ? 1579 // ::sprintf(CHTEMP, "10^{%d}", labelnumber); 1580 snpf(CHTEMP,sizeof(CHTEMP), 1581 "10^%d?", labelnumber); //PAW encoding. 1582 aTexts.push_back(_text(XX,YY, 1583 0,textSize,CHTEMP, 1584 textAlign)); 1585 } 1586 } 1587 } 1588 labelnumber++; 1589 } 1590 L160: 1591 for (k=2;k<10;k++) { 1592 1593 // Plot intermediate tick marks 1594 //double Xone; //rm shadow warning. 1595 Xone = X00+AXMUL*(::log10(double(k))+double(decade)-XMNLOG); 1596 if (X00 > Xone) continue; 1597 if (Xone > X11) goto L200; 1598 Y = 0; 1599 if (!Mside) Y -= atick[1]; 1600 Xtwo = Xone; 1601 TGaxis_Rotate(Xone,Y,cosphi,sinphi,X0,Y0,xpl2,ypl2); 1602 TGaxis_Rotate(Xtwo,atick[1],cosphi,sinphi,X0,Y0,xpl1,ypl1); 1603 if (OptionVert) { 1604 if ((X0 != X1) && (Y0 != Y1)) { 1605 if (Mside) { 1606 xpl1 = xpl2; 1607 if (cosphi > 0) ypl1 = ypl2 + atick[1]; 1608 else ypl1 = ypl2 - atick[1]; 1609 } 1610 else { 1611 xpl1 = 0.5*(xpl1+xpl2); 1612 xpl2 = xpl1; 1613 ypl1 = 0.5*(ypl1+ypl2) + atick[1]; 1614 ypl2 = 0.5*(ypl1+ypl2) - atick[1]; 1615 } 1616 } 1617 } 1618 int IDN = N1A*2; 1619 if ((NBININ <= IDN) || ((NBININ > IDN) && (k == 5))) { 1620 if(!drawGridOnly) { 1621 aLinesAxis.push_back((float)xpl1); 1622 aLinesAxis.push_back((float)ypl1); 1623 aLinesAxis.push_back((float)xpl2); 1624 aLinesAxis.push_back((float)ypl2); 1625 } 1626 1627 // Draw the intermediate LOG labels if requested 1628 1629 if (MoreLogLabels && !OptionUnlab && 1630 !drawGridOnly && !overlap) { 1631 if (noExponent) { 1632 double rlab = double(k)*::pow(10.,labelnumber-1); 1633 snpf(CHTEMP,sizeof(CHTEMP), "%g", rlab); 1634 } else { 1635 if (labelnumber-1 == 0) { 1636 snpf(CHTEMP,sizeof(CHTEMP), "%d", k); 1637 } else if (labelnumber-1 == 1) { 1638 snpf(CHTEMP,sizeof(CHTEMP), "%d", 10*k); 1639 } else { 1640 //G.Barrand : 1641 //::sprintf(CHTEMP, "%d#times10^{%d}", k, labelnumber-1); 1642 snpf(CHTEMP,sizeof(CHTEMP), 1643 "%dx10^%d!",k,labelnumber-1);//G.Barrand 1644 } 1645 } 1646 TGaxis_Rotate (Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY); 1647 if ((Y0 == Y1) && !OptionDown && !OptionUp) { 1648 if (noExponent) YY += 0.33*charheight; 1649 } 1650 if (X0 == X1) XX += 0.25*charheight; 1651 if (OptionVert) { 1652 if ((X0 != X1) && (Y0 != Y1)) { 1653 TGaxis_Rotate(Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY); 1654 if (cosphi > 0) YY += Ylabel; 1655 else YY -= Ylabel; 1656 } 1657 } 1658 //FIXME textaxis->SetTitle(CHTEMP); 1659 double u = XX; 1660 double v = YY; 1661 if (firstintlab) { 1662 //FIXME textaxis->GetBoundingBox(wi, hi); wi=(Uint)(wi*1.3); hi*=(Uint)(hi*1.3); 1663 xi1 = 0;//FIXME gPad->XtoAbsPixel(u); 1664 yi1 = 0;//FIXME gPad->YtoAbsPixel(v); 1665 firstintlab = false; 1666 out_error(m_out,"PaintAxis","debug : texts : dummy : 010\n"); 1667 aTexts.push_back(_text(u,v, 1668 0,textSize,CHTEMP, 1669 textAlign)); 1670 } else { 1671 xi2 = 0;//FIXME gPad->XtoAbsPixel(u); 1672 yi2 = 0;//FIXME gPad->YtoAbsPixel(v); 1673 if ((X0 == X1 && yi1-hi <= yi2) || (Y0 == Y1 && xi1+wi >= xi2)){ 1674 overlap = true; 1675 } else { 1676 xi1 = xi2; 1677 yi1 = yi2; 1678 //FIXME textaxis->GetBoundingBox(wi, hi); wi=(Uint)(wi*1.3); hi*=(Uint)(hi*1.3); 1679 out_error(m_out,"PaintAxis","debug : texts : dummy : 011\n"); 1680 aTexts.push_back(_text(u,v, 1681 0,textSize,CHTEMP, 1682 textAlign)); 1683 } 1684 } 1685 } 1686 1687 // Draw the intermediate LOG grid if only three 1688 // decades are requested 1689 if (OptionGrid && NBININ <= 5 && ndiv > 100) { 1690 TGaxis_Rotate(Xone,0,cosphi,sinphi,X0,Y0,xpl2, ypl2); 1691 TGaxis_Rotate 1692 (Xone,grid_side*gridlength,cosphi,sinphi,X0,Y0,xpl1,ypl1); 1693 aLinesGrid.push_back((float)xpl1); 1694 aLinesGrid.push_back((float)ypl1); 1695 aLinesGrid.push_back((float)xpl2); 1696 aLinesGrid.push_back((float)ypl2); 1697 } 1698 } //endif ((NBININ <= IDN) || 1699 } //endfor (k=2;k<10;k++) 1700 } //endfor (j=1; j<=NBININ; j++) 1701 L200: 1702 int kuku=0; if (kuku) { } 1703 } //endif (OptionLog && ndiv) 1704 1705 1706 //out_error(m_out,"android_debug","end"); 1707 //L210: 1708 } 1709 1710 /* 1711 void TGaxis_SetDecimals(bool dot) 1712 { 1713 // Set the Decimals flag 1714 // By default, blank characters are stripped, and then the 1715 // label is correctly aligned. The dot, if last character of the string, 1716 // is also stripped, unless this option is specified. 1717 // One can disable the option by calling axis.SetDecimals(true). 1718 // Note the bit is set in fBits (as opposed to fBits2 in TAxis!) 1719 1720 if (dot) SetBit(TAxis_kDecimals); 1721 else ResetBit(TAxis_kDecimals); 1722 } 1723 1724 void TGaxis_SetMaxDigits(int maxd) 1725 { 1726 // static function to set fMaxDigits for axis with the bin content 1727 // (y axis for 1-d histogram, z axis for 2-d histogram) 1728 //fMaxDigits is the maximum number of digits permitted for the axis 1729 //labels above which the notation with 10^N is used. 1730 //For example, to accept 6 digits number like 900000 on an axis 1731 //call TGaxis::SetMaxDigits(6). The default value is 5. 1732 //fMaxDigits must be greater than 0. 1733 1734 fMaxDigits = maxd; 1735 if (maxd < 1) fMaxDigits = 1; 1736 } 1737 1738 void TGaxis_SetMoreLogLabels(bool more) 1739 { 1740 // Set the kMoreLogLabels bit flag 1741 // When this option is selected more labels are drawn when in log scale 1742 // and there is a small number of decades (<3). 1743 // Note that this option is automatically inherited from TAxis 1744 1745 if (more) SetBit(TAxis_kMoreLogLabels); 1746 else ResetBit(TAxis_kMoreLogLabels); 1747 } 1748 void TGaxis_SetNoExponent(bool noExponent) 1749 { 1750 // Set the NoExponent flag 1751 // By default, an exponent of the form 10^N is used when the label values 1752 // are either all very small or very large. 1753 // One can disable the exponent by calling axis.SetNoExponent(true). 1754 1755 if (noExponent) SetBit(TAxis_kNoExponent); 1756 else ResetBit(TAxis_kNoExponent); 1757 } 1758 void TGaxis_SetOption(const std::string& option) 1759 { 1760 fCHOPT = option; 1761 } 1762 */ 1763 1764 void set_time_format(const std::string& a_format) 1765 // Change the format used for time plotting 1766 // ======================================== 1767 // The format string for date and time use the same options as the one used 1768 // in the standard strftime C function, i.e. : 1769 // for date : 1770 // %a abbreviated weekday name 1771 // %b abbreviated month name 1772 // %d day of the month (01-31) 1773 // %m month (01-12) 1774 // %y year without century 1775 // 1776 // for time : 1777 // %H hour (24-hour clock) 1778 // %I hour (12-hour clock) 1779 // %p local equivalent of AM or PM 1780 // %M minute (00-59) 1781 // %S seconds (00-61) 1782 // %% % 1783 // 1784 { 1785 if (a_format.find("%F")!=std::string::npos || !a_format.size()) { 1786 fTimeFormat = a_format; 1787 //::printf("debug : SbAxisHPLOT::setTimeFormat : 000 : \"%s\"\n", 1788 // fTimeFormat.c_str()); 1789 return; 1790 } 1791 1792 std::string::size_type IdF = fTimeFormat.find("%F"); 1793 if (IdF!=std::string::npos) { 1794 size_t LnF = fTimeFormat.size(); 1795 std::string stringtimeoffset = fTimeFormat.substr(IdF,LnF-IdF); 1796 fTimeFormat = a_format; 1797 fTimeFormat += stringtimeoffset; 1798 //::printf("debug : SbAxisHPLOT::setTimeFormat : 001 : \"%s\"\n", 1799 // fTimeFormat.c_str()); 1800 } else { 1801 fTimeFormat = a_format; 1802 1803 // In CERN-ROOT : 1804 //SetTimeOffset(gStyle->GetTimeOffset()); 1805 //TAxis::fTimeOffset = 788918400; // UTC time at 01/01/95 1806 //double UTC_time_1995_01_01__00_00_00 = 788918400; //CERN-ROOT 1807 //setTimeOffset(UTC_time_1995_01_01__00_00_00); 1808 1809 //Be consistent with SoAxis::timeOffset being 0. 1810 double UTC_time_1970_01_01__00_00_00 = 0; //UNIX 1811 set_time_offset(UTC_time_1970_01_01__00_00_00); 1812 1813 //::printf("debug : SbAxisHPLOT::setTimeFormat : 002 : \"%s\"\n", 1814 // fTimeFormat.c_str()); 1815 } 1816 } 1817 1818 void set_time_offset(double toffset,bool a_is_gmt = false) { 1819 // Change the time offse t 1820 1821 std::string::size_type IdF = fTimeFormat.find("%F"); 1822 if (IdF!=std::string::npos) { 1823 fTimeFormat = fTimeFormat.substr(0,IdF); 1824 } 1825 fTimeFormat += "%F"; 1826 1827 time_t timeoff = (time_t)((long)(toffset)); 1828 struct tm* utctis = ::gmtime(&timeoff); 1829 1830 char tmp[256]; 1831 ::strftime(tmp,256,"%Y-%m-%d %H:%M:%S",utctis); 1832 fTimeFormat += tmp; 1833 1834 // append the decimal part of the time offset 1835 double ds = toffset-(int)toffset; 1836 if(ds!= 0) { 1837 snpf(tmp,sizeof(tmp),"s%g",ds); 1838 fTimeFormat += tmp; 1839 } 1840 1841 // If the time is GMT, stamp fTimeFormat 1842 if (a_is_gmt) fTimeFormat += " GMT"; 1843 1844 //::printf("debug : SbAxisHPLOT::setTimeOffset : \"%s\"\n", 1845 // fTimeFormat.c_str()); 1846 } 1847 1848 1849 1850 //////////////////////////////////////////////////////////////////////////// 1851 //////////////////////////////////////////////////////////////////////////// 1852 //////////////////////////////////////////////////////////////////////////// 1853 private: 1854 static void optimizeLimits( 1855 double A1,double A2,int nold 1856 ,double &BinLow, double &BinHigh 1857 ,int &nbins, double &BinWidth 1858 ,const std::string& aCHOPT 1859 ){ 1860 // static function to compute reasonable axis limits 1861 // 1862 // Input parameters: 1863 // 1864 // A1,A2 : Old WMIN,WMAX . 1865 // BinLow,BinHigh : New WMIN,WMAX . 1866 // nold : Old NDIV . 1867 // nbins : New NDIV . 1868 1869 int lwid, kwid; 1870 int ntemp = 0; 1871 int jlog = 0; 1872 double siground = 0; 1873 double alb, awidth, sigfig; 1874 double timemulti = 1; 1875 int roundmode =0; 1876 1877 int OptionTime; 1878 SETOPT(aCHOPT,'t',OptionTime); 1879 1880 double AL = mn<double>(A1,A2); 1881 double AH = mx<double>(A1,A2); 1882 if (AL == AH) AH = AL+1; 1883 // if nold == -1 , program uses binwidth input from calling routine 1884 if (nold == -1 && BinWidth > 0 ) goto L90; 1885 ntemp = (int)mx<double>(nold,2); 1886 if (ntemp < 1) ntemp = 1; 1887 1888 L20: 1889 awidth = (AH-AL)/double(ntemp); 1890 timemulti = 1; 1891 if (awidth >= FLT_MAX) goto LOK; //in float.h 1892 if (awidth <= 0) goto LOK; 1893 1894 // If time representation, bin width should be rounded to seconds 1895 // minutes, hours or days 1896 1897 if (OptionTime && awidth>=60) { // if width in seconds, treat it as normal 1898 // width in minutes 1899 awidth /= 60; timemulti *=60; 1900 roundmode = 1; // round minutes (60) 1901 // width in hours ? 1902 if (awidth>=60) { 1903 awidth /= 60; timemulti *= 60; 1904 roundmode = 2; // round hours (24) 1905 // width in days ? 1906 if (awidth>=24) { 1907 awidth /= 24; timemulti *= 24; 1908 roundmode = 3; // round days (30) 1909 // width in months ? 1910 if (awidth>=30.43685) { // Mean month length in 1900. 1911 awidth /= 30.43685; timemulti *= 30.43685; 1912 roundmode = 2; // round months (12) 1913 // width in years ? 1914 if (awidth>=12) { 1915 awidth /= 12; timemulti *= 12; 1916 roundmode = 0; // round years (10) 1917 } 1918 } 1919 } 1920 } 1921 } 1922 // Get nominal bin width in exponential for m 1923 1924 jlog = int(::log10(awidth)); 1925 if (jlog <-200 || jlog > 200) { 1926 BinLow = 0; 1927 BinHigh = 1; 1928 BinWidth = 0.01; 1929 nbins = 100; 1930 return; 1931 } 1932 if (awidth <= 1 && (!OptionTime || timemulti==1) ) jlog--; 1933 sigfig = awidth* ::pow(10.,-jlog) -1e-10; 1934 //in the above statement, it is important to substract 1e-10 1935 //to avoid precision problems if the tests below 1936 1937 // Round mantissa 1938 1939 switch (roundmode) { 1940 1941 // Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes 1942 case 1: // case 60 1943 if (sigfig <= 1) siground = 1; 1944 else if (sigfig <= 1.5 && jlog==1) siground = 1.5; 1945 else if (sigfig <= 2) siground = 2; 1946 else if (sigfig <= 3 && jlog ==1) siground = 3; 1947 else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02) 1948 else if (jlog==0) {siground = 1; jlog++;} 1949 else siground = 6; 1950 break; 1951 case 2: // case 12 and 24 1952 1953 // Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months 1954 if (sigfig <= 1 && jlog==0) siground = 1; 1955 else if (sigfig <= 1.2 && jlog==1) siground = 1.2; 1956 else if (sigfig <= 2 && jlog==0) siground = 2; 1957 else if (sigfig <= 2.4 && jlog==1) siground = 2.4; 1958 else if (sigfig <= 3) siground = 3; 1959 else if (sigfig <= 6) siground = 6; 1960 else if (jlog==0) siground = 12; 1961 else siground = 2.4; 1962 break; 1963 1964 //- Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks) 1965 case 3: // case 30 1966 if (sigfig <= 1 && jlog==0) siground = 1; 1967 else if (sigfig <= 1.4 && jlog==1) siground = 1.4; 1968 else if (sigfig <= 3 && jlog ==1) siground = 3; 1969 else siground = 7; 1970 break; 1971 default : 1972 1973 // Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number 1974 if (sigfig <= 1) siground = 1; 1975 else if (sigfig <= 2) siground = 2; 1976 else if (sigfig <= 5 && (!OptionTime || jlog<1)) siground = 5; 1977 else if (sigfig <= 6 && OptionTime && jlog==1) siground = 6; 1978 else {siground = 1; jlog++; } 1979 break; 1980 } 1981 1982 BinWidth = siground* ::pow(10.,jlog); 1983 if (OptionTime) BinWidth *= timemulti; 1984 1985 // Get new bounds from new width BinWidth 1986 1987 L90: 1988 alb = AL/BinWidth; 1989 if (TMath_Abs(alb) > 1e9) { 1990 BinLow = AL; 1991 BinHigh = AH; 1992 if (nbins > 10*nold && nbins > 10000) nbins = nold; 1993 return; 1994 } 1995 lwid = int(alb); 1996 if (alb < 0) lwid--; 1997 BinLow = BinWidth*double(lwid); 1998 alb = AH/BinWidth + 1.00001; 1999 kwid = int(alb); 2000 if (alb < 0) kwid--; 2001 BinHigh = BinWidth*double(kwid); 2002 nbins = kwid - lwid; 2003 if (nold == -1) goto LOK; 2004 if (nold <= 5) { // Request for one bin is difficult case 2005 if (nold > 1 || nbins == 1)goto LOK; 2006 BinWidth = BinWidth*2; 2007 nbins = 1; 2008 goto LOK; 2009 } 2010 if (2*nbins == nold && !OptionTime) {ntemp++; goto L20; } 2011 2012 LOK: 2013 double oldBinLow = BinLow; 2014 double oldBinHigh = BinHigh; 2015 int oldnbins = nbins; 2016 2017 double atest = BinWidth*0.0001; 2018 //if (TMath_Abs(BinLow-A1) >= atest) { BinLow += BinWidth; nbins--; } //replaced by Damir in 3.10/02 2019 //if (TMath_Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth; nbins--; } //by the next two lines 2020 if (AL-BinLow >= atest) { BinLow += BinWidth; nbins--; } 2021 if (BinHigh-AH >= atest) { BinHigh -= BinWidth; nbins--; } 2022 if (!OptionTime && BinLow >= BinHigh) { 2023 //this case may happen when nbins <=5 2024 BinLow = oldBinLow; 2025 BinHigh = oldBinHigh; 2026 nbins = oldnbins; 2027 } 2028 else if (OptionTime && BinLow>=BinHigh) { 2029 nbins = 2*oldnbins; 2030 BinHigh = oldBinHigh; 2031 BinLow = oldBinLow; 2032 BinWidth = (oldBinHigh - oldBinLow)/nbins; 2033 atest = BinWidth*0.0001; 2034 if (AL-BinLow >= atest) { BinLow += BinWidth; nbins--; } 2035 if (BinHigh-AH >= atest) { BinHigh -= BinWidth; nbins--; } 2036 } 2037 } 2038 2039 static void adjustBinSize( 2040 double A1,double A2,int nold 2041 ,double &BinLow, double &BinHigh, int &nbins, double &BinWidth 2042 ){ 2043 // Axis labels optimisation 2044 // ======================== 2045 // 2046 // This routine adjusts the bining of the axis 2047 // in order to have integer values for the labels 2048 // 2049 // _Input parameters: 2050 // 2051 // A1,A2 : Old WMIN,WMAX . 2052 // BinLow,BinHigh : New WMIN,WMAX . 2053 // nold : Old NDIV (primary divisions) 2054 // nbins : New NDIV . 2055 // 2056 BinWidth = TMath_Abs(A2-A1)/double(nold); 2057 if (BinWidth <= 1) { BinWidth = 1; BinLow = int(A1); } 2058 else { 2059 int width = int(BinWidth/5) + 1; 2060 BinWidth = 5*width; 2061 BinLow = int(A1/BinWidth)*BinWidth ; 2062 2063 // We determine BinLow to have one tick mark at 0 2064 // if there are negative labels. 2065 2066 if (A1 < 0) { 2067 for (int ic=0; ic<1000; ic++) { 2068 double rbl = BinLow/BinWidth; 2069 int ibl = int(BinLow/BinWidth); 2070 if ( (rbl-ibl) == 0 || ic > width) { BinLow -= 5; break;} 2071 } 2072 } 2073 } 2074 BinHigh = int(A2); 2075 nbins = 0; 2076 double XB = BinLow; 2077 while (XB <= BinHigh) { 2078 XB += BinWidth; 2079 nbins++; 2080 } 2081 BinHigh = XB - BinWidth; 2082 } 2083 void setLabelOffset(float aValue) { fLabelOffset = aValue;} 2084 void setLabelSize(float aValue) { fLabelSize = aValue;} 2085 void setTitleOffset(float aValue) { fTitleOffset = aValue;} 2086 void setTitleSize(float aValue) { fTitleSize = aValue; } 2087 public: 2088 void set_tick_size(float aValue) { fTickSize = aValue;} 2089 2090 private: 2091 std::ostream& m_out; 2092 //int fMaxDigits; //!Number of digits above which the 10>N notation is used 2093 private: 2094 //TObject : 2095 unsigned int fBits; //bit field status word 2096 float fTickSize; //Size of primary tick mark in NDC 2097 float fLabelOffset; //Offset of label wrt axis 2098 float fLabelSize; //Size of labels in NDC 2099 float fTitleOffset; //Offset of title wrt axis 2100 float fTitleSize; //Size of title in NDC 2101 int fLabelFont; //Font for labels 2102 std::string fTitle; //axis title 2103 std::string fTimeFormat; //Time format, ex: 09/12/99 12:34:00 2104 }; 2105 2106 }} 2107 2108 #endif