Warning, /include/Geant4/tools/hplot is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_hplot
0005 #define tools_hplot
0006
0007 // Used in tools::sg::axis.
0008 //
0009 // Code extracted from ROOT-4.03.02/root/graf/stc/TGaxis.cxx.
0010 // Itself built from code extracted from HPLOT.
0011 //
0012 // Take care, all the below is highly disgusting...
0013 // (You can even find.. gotos !)
0014 //
0015 // Except for the public methods we let the style "as it".
0016
0017 #include "mnmx"
0018 #include "lina/vec3f"
0019 #include "mathd" //pi
0020 #include "snpf"
0021 #include "out_error"
0022
0023 #include <string>
0024 #include <vector>
0025
0026 #include <cstring>
0027 #include <ctime>
0028 #include <cmath>
0029 #include <cfloat>
0030
0031 namespace tools {
0032 namespace hplot {
0033
0034 class _text {
0035 public:
0036 _text(double aX,double aY,
0037 double aAngle,double aSize,
0038 const std::string& aString,
0039 short aAlign)
0040 :fX(aX),fY(aY)
0041 ,fAngle(aAngle),fSize(aSize)
0042 ,fString(aString),fAlign(aAlign)
0043 {}
0044 virtual ~_text(){}
0045 public:
0046 _text(const _text& aFrom)
0047 :fX(aFrom.fX),fY(aFrom.fY)
0048 ,fAngle(aFrom.fAngle),fSize(aFrom.fSize)
0049 ,fString(aFrom.fString)
0050 ,fAlign(aFrom.fAlign)
0051 {}
0052 _text& operator=(const _text& aFrom){
0053 fX = aFrom.fX;
0054 fY = aFrom.fY;
0055 fAngle = aFrom.fAngle;
0056 fSize = aFrom.fSize;
0057 fString = aFrom.fString;
0058 fAlign = aFrom.fAlign;
0059 return *this;
0060 }
0061 public:
0062 double fX;
0063 double fY;
0064 double fAngle; //Degree
0065 double fSize;
0066 std::string fString;
0067 short fAlign;
0068 };
0069
0070
0071 class axis {
0072
0073 // Ok, you really want to read all that. You had been warned...
0074
0075 enum {
0076 TAxis_kTickPlus = (1<<(9)),
0077 TAxis_kTickMinus = (1<<(10)),
0078 TAxis_kAxisRange = (1<<(11)),
0079 TAxis_kCenterTitle = (1<<(12)),
0080 TAxis_kCenterLabels = (1<<(14)), //bit 13 is used by TObject
0081 TAxis_kRotateTitle = (1<<(15)),
0082 TAxis_kPalette = (1<<(16)),
0083 TAxis_kNoExponent = (1<<(17)),
0084 TAxis_kLabelsHori = (1<<(18)),
0085 TAxis_kLabelsVert = (1<<(19)),
0086 TAxis_kLabelsDown = (1<<(20)),
0087 TAxis_kLabelsUp = (1<<(21)),
0088 TAxis_kIsInteger = (1<<(22)),
0089 TAxis_kMoreLogLabels = (1<<(23)),
0090 TAxis_kDecimals = (1<<(11))
0091 }; //in fBits2
0092
0093 enum {
0094 kIsOnHeap = 0x01000000, // object is on heap
0095 kNotDeleted = 0x02000000, // object has not been deleted
0096 kZombie = 0x04000000, // object ctor failed
0097 kBitMask = 0x00ffffff
0098 };
0099
0100 static int GetTextFont() { return 132;}
0101
0102 static double TMath_ATan2(double y, double x) {
0103 if (x != 0) return ::atan2(y, x);
0104 if (y == 0) return 0;
0105 if (y > 0) return half_pi();
0106 else return -half_pi();
0107 }
0108
0109 static int TMath_Abs(int d) { return (d >= 0) ? d : -d; }
0110 static double TMath_Abs(double d) { return (d >= 0) ? d : -d; }
0111
0112 static void TGaxis_Rotate(
0113 double X, double Y, double CFI, double SFI
0114 ,double XT, double YT, double &U, double &V)
0115 {
0116 U = CFI*X-SFI*Y+XT;
0117 V = SFI*X+CFI*Y+YT;
0118 }
0119
0120 public:
0121 axis(std::ostream& a_out)
0122 :m_out(a_out)
0123 //,fMaxDigits(5)
0124 ,fBits(kNotDeleted)
0125 ,fTickSize(0.03F)
0126 ,fLabelOffset(0.005F)
0127 ,fLabelSize(0.04F)
0128 ,fTitleOffset(1)
0129 ,fTitleSize(0.04F)
0130 ,fLabelFont(62)
0131 {}
0132
0133 virtual ~axis(){}
0134 private: //to discourage inheriting that.
0135 axis(const axis& a_from):m_out(a_from.m_out){}
0136 axis& operator=(const axis&){return *this;}
0137 public:
0138 void set_title(const std::string& aTitle) {
0139 fTitle = aTitle;
0140 }
0141 private:
0142 bool testBit(unsigned int f) {
0143 return (bool) ((fBits & f) != 0);
0144 }
0145
0146 static void TGaxis_LabelsLimits(std::ostream& a_out,const char *label,
0147 int &first,int &last) {
0148 last = int(::strlen(label))-1;
0149 for (int i=0; i<=last; i++) {
0150 if (::strchr("1234567890-+.", label[i]) ) { first = i; return; }
0151 }
0152 out_error(a_out,"LabelsLimits", "attempt to draw a blank label");
0153 }
0154 static void SETOPT(const std::string& aCHOPT,char aChar,int& aOpt) {
0155 aOpt = aCHOPT.find(aChar)!=std::string::npos?1:0;
0156 }
0157
0158 public:
0159 void paint(double xmin, double ymin,
0160 double xmax, double ymax,
0161 double& wmin,double& wmax,
0162 int& ndiv,const std::string& aCHOPT,
0163 double gridlength,bool drawGridOnly,
0164 std::vector<float>& aLinesAxis, //n*(2+2)
0165 std::vector<float>& aLinesGrid, //n*(2+2)
0166 std::vector<_text>& aTexts){
0167 // Control function to draw an axis
0168 // ================================
0169 //
0170 //============> Original authors (O.Couet C.E.Vandoni N.Cremel-Somon)
0171 // largely modified and converted to C++ class by Rene Brun
0172 //
0173 // _Input parameters:
0174 //
0175 // xmin : X origin coordinate in WC space.
0176 // xmax : X end axis coordinate in WC space.
0177 // ymin : Y origin coordinate in WC space.
0178 // ymax : Y end axis coordinate in WC space.
0179 // wmin : Lowest value for the tick mark
0180 // labels written on the axis.
0181 // wmax : Highest value for the tick mark labels
0182 // written on the axis.
0183 // ndiv : Number of divisions.
0184 //
0185 // ndiv=N1 + 100*N2 + 10000*N3
0186 // N1=number of 1st divisions.
0187 // N2=number of 2nd divisions.
0188 // N3=number of 3rd divisions.
0189 // e.g.:
0190 // nndi=0 --> no tick marks.
0191 // nndi=2 --> 2 divisions, one tick mark in the middle
0192 // of the axis.
0193 //
0194 // chopt : Options (see below).
0195 //
0196 // chopt='G': loGarithmic scale, default is linear.
0197 // chopt='B': Blank axis. Useful to superpose axis.
0198 //
0199 // Orientation of tick marks on axis.
0200 // ----------------------------------
0201 //
0202 // Tick marks are normally drawn on the positive side of the axis,
0203 // however, if X0=X1, then negative.
0204 //
0205 // chopt='+': tick marks are drawn on Positive side. (default)
0206 // chopt='-': tick mark are drawn on the negative side.
0207 // i.e: '+-' --> tick marks are drawn on both sides of the axis.
0208 // chopt='U': Unlabeled axis, default is labeled.
0209 //
0210 // Size of tick marks
0211 // ------------------
0212 // By default, tick marks have a length equal to 3 per cent of the
0213 // axis length.
0214 // When the option "S" is specified, the length of the tick marks
0215 // is equal to fTickSize*axis_length, where fTickSize may be set
0216 // via TGaxis::SetTickSize.
0217 //
0218 // Position of labels on axis.
0219 // ---------------------------
0220 //
0221 // Labels are normally drawn on side opposite to tick marks.
0222 // However:
0223 //
0224 // chopt='=': on Equal side
0225 //
0226 // Orientation of labels on axis.
0227 // ------------------------------
0228 //
0229 // Labels are normally drawn parallel to the axis.
0230 // However if X0=X1, then Orthogonal
0231 // if Y0=Y1, then Parallel
0232 //
0233 // Position of labels on tick marks.
0234 // ---------------------------------
0235 //
0236 // Labels are centered on tick marks.
0237 // However , if X0=X1, then they are right adjusted.
0238 //
0239 // chopt='R': labels are Right adjusted on tick mark.
0240 // (default is centered)
0241 // chopt='L': labels are Left adjusted on tick mark.
0242 // chopt='C': labels are Centered on tick mark.
0243 // chopt='M': In the Middle of the divisions.
0244 //
0245 // Format of labels.
0246 // -----------------
0247 //
0248 // Blank characters are stripped, and then the
0249 // label is correctly aligned. the dot, if last
0250 // character of the string, is also stripped,
0251 // unless the option "." (a dot, or period) is specified.
0252 // if SetDecimals(true) has been called (bit TAxis_kDecimals set).
0253 // all labels have the same number of decimals after the "."
0254 // The same is true if gStyle->SetStripDecimals(false) has been called.
0255 //
0256 // In the following, we have some parameters, like
0257 // tick marks length and characters height (in percentage
0258 // of the length of the axis (WC))
0259 // The default values are as follows:
0260 //
0261 // Primary tick marks: 3.0 %
0262 // Secondary tick marks: 1.5 %
0263 // Third order tick marks: .75 %
0264 // Characters height for labels: 4%
0265 //
0266 // Labels offset: 1.0 %
0267 //
0268 // Optional grid.
0269 // --------------
0270 //
0271 // chopt='W': cross-Wire
0272 // In case of a log axis, the grid is only drawn for the primary
0273 // tick marks if the number of secondary and tertiary divisions is 0.
0274 //
0275 // Axis bining optimization.
0276 // -------------------------
0277 //
0278 // By default the axis bining is optimized .
0279 //
0280 // chopt='N': No bining optimization
0281 // chopt='I': Integer labelling
0282 //
0283 // Maximum Number of Digits for the axis labels
0284 // --------------------------------------------
0285 // See the static function TGaxis::SetMaxDigits
0286 //
0287 // Time representation.
0288 // --------------------
0289 //
0290 // Axis labels may be considered as times, plotted in a defined
0291 // time format.
0292 // The format is set with SetTimeFormat().
0293 // wmin and wmax are considered as two time values in seconds.
0294 // The time axis will be spread around the time offset value (set with
0295 // SetTimeOffset() ). Actually it will go from TimeOffset+wmin to
0296 // TimeOffset+wmax.
0297 // see examples in tutorials timeonaxis.C and timeonaxis2.C
0298 //
0299 // chopt='t': Plot times with a defined format instead of values
0300 //
0301
0302 aLinesAxis.clear();
0303 aLinesGrid.clear();
0304 aTexts.clear();
0305
0306 double alfa, beta, ratio1, ratio2, grid_side;
0307 double axis_lengthN = 0;
0308 double axis_length0 = 0;
0309 double axis_length1 = 0;
0310 double charheight;
0311 double phil, phi, sinphi, cosphi, asinphi, acosphi;
0312 double BinLow, BinLow2, BinLow3;
0313 double BinHigh, BinHigh2, BinHigh3;
0314 double BinWidth, BinWidth2, BinWidth3;
0315 double xpl1, xpl2, ypl1, ypl2;
0316 double Xtick = 0;
0317 double Xtick0, Xtick1, DXtick=0;
0318 double Ytick, Ytick0, Ytick1;
0319 double Wlabel, DWlabel;
0320 double Xlabel, Ylabel;
0321 double DXlabel;
0322 double X0, X1, Y0, Y1, XX0, XX1, YY0, YY1;
0323 XX0 = XX1 = YY0 = YY1 = 0;
0324 double Xxmin, Xxmax, Yymin, Yymax;
0325 Xxmin = Xxmax = Yymin = Yymax = 0;
0326 double XLside,XMside;
0327 double WW, AF, RNE;
0328 double XX, YY;
0329 double Y;
0330 double Xtwo;
0331 int i, j, k, l, decade, ltick;
0332 int Mside, Lside;
0333 int IF1, IF2, NA, NF, NCH;
0334 int OptionLog,OptionBlank,OptionVert,OptionPlus,OptionMinus;
0335 int OptionUnlab,OptionPara;
0336 int OptionDown,OptionRight,OptionLeft,OptionCent,OptionEqual;
0337 int OptionDecimals=0,OptionDot;
0338 int OptionY,OptionText,OptionGrid,OptionSize,OptionNoopt;
0339 int OptionInt,OptionM,OptionUp,OptionX;
0340 int OptionTime;
0341 int first,last;
0342 int nbins;
0343 int N1Aold = 0;
0344 int NN1old = 0;
0345 int Xalign,Yalign;
0346 int ndyn;
0347 char LABEL[256];
0348 char CHTEMP[256];
0349 double rangeOffset = 0;
0350
0351 double epsilon = 1e-5;
0352 const double kPI = pi(); //GB
0353 double textSize = 0.05; //GB
0354 short textAlign = 11; //GB
0355 BinWidth = 0; //GB
0356 BinWidth2 = 0; //GB
0357 BinWidth3 = 0; //GB
0358 nbins = 0; //GB
0359 BinHigh = 0; //GB
0360 BinHigh2 = 0; //GB
0361 BinHigh3 = 0; //GB
0362 BinLow = 0; //GB
0363 BinLow2 = 0; //GB
0364 BinLow3 = 0; //GB
0365 first = 0; //GB
0366 last = 0; //GB
0367
0368 double rwmi = wmin;
0369 double rwma = wmax;
0370
0371 bool noExponent = testBit(TAxis_kNoExponent);
0372
0373 // If MoreLogLabels = true more Log Intermediate Labels are drawn.
0374 bool MoreLogLabels = testBit(TAxis_kMoreLogLabels);
0375
0376 // the following parameters correspond to the pad range in NDC
0377 // and the WC coordinates in the pad
0378
0379 double padh = 1;//FIXME gPad->GetWh()*gPad->GetAbsHNDC();
0380 double RWxmin = 0;
0381 double RWxmax = 1;
0382 double RWymin = 0;
0383 double RWymax = 1;
0384
0385 SETOPT(aCHOPT,'G',OptionLog);
0386 SETOPT(aCHOPT,'B',OptionBlank);
0387 SETOPT(aCHOPT,'V',OptionVert);
0388 SETOPT(aCHOPT,'+',OptionPlus);
0389 SETOPT(aCHOPT,'-',OptionMinus);
0390 SETOPT(aCHOPT,'U',OptionUnlab);
0391 SETOPT(aCHOPT,'P',OptionPara);
0392 SETOPT(aCHOPT,'O',OptionDown);
0393 SETOPT(aCHOPT,'R',OptionRight);
0394 SETOPT(aCHOPT,'L',OptionLeft);
0395 SETOPT(aCHOPT,'C',OptionCent);
0396 SETOPT(aCHOPT,'=',OptionEqual);
0397 SETOPT(aCHOPT,'Y',OptionY);
0398 SETOPT(aCHOPT,'T',OptionText);
0399 SETOPT(aCHOPT,'W',OptionGrid);
0400 SETOPT(aCHOPT,'S',OptionSize);
0401 SETOPT(aCHOPT,'N',OptionNoopt);
0402 SETOPT(aCHOPT,'I',OptionInt);
0403 SETOPT(aCHOPT,'M',OptionM);
0404 SETOPT(aCHOPT,'0',OptionUp);
0405 SETOPT(aCHOPT,'X',OptionX);
0406 SETOPT(aCHOPT,'t',OptionTime);
0407 SETOPT(aCHOPT,'.',OptionDot);
0408
0409 if (testBit(TAxis_kTickPlus)) OptionPlus = 2;
0410 if (testBit(TAxis_kTickMinus)) OptionMinus = 2;
0411 if (testBit(TAxis_kCenterLabels)) OptionM = 1;
0412 if (testBit(TAxis_kDecimals)) OptionDecimals = 1;
0413 /*FIXME if (fAxis) {
0414 if (fAxis->GetLabels()) {
0415 OptionM = 1;
0416 OptionText = 1;
0417 ndiv = fAxis->GetLast()-fAxis->GetFirst()+1;
0418 }
0419 }*/
0420
0421 // Set the grid length
0422
0423 if (OptionGrid) {
0424 if (gridlength == 0) gridlength = 0.8;
0425 /*FIXME
0426 linegrid = new TLine();
0427 linegrid->SetLineColor(gStyle->GetGridColor());
0428 if (linegrid->GetLineColor() == 0)
0429 linegrid->SetLineColor(GetLineColor());
0430 linegrid->SetLineStyle(gStyle->GetGridStyle());
0431 linegrid->SetLineWidth(gStyle->GetGridWidth());*/
0432 }
0433
0434
0435 if (OptionTime) {
0436 //printf("debug : SbAxisHPLOT::paint : fTimeFormat : \"%s\"\n",
0437 // fTimeFormat.c_str());
0438 }
0439
0440 // Determine time format
0441 std::string timeformat;
0442 std::string::size_type IdF = fTimeFormat.find("%F");
0443 if (IdF!=std::string::npos) {
0444 timeformat = fTimeFormat.substr(0,IdF);
0445 } else {
0446 timeformat = fTimeFormat;
0447 }
0448
0449 // determine the time offset and correct for time offset not being integer
0450 double timeoffset = 0;
0451 if (OptionTime) {
0452 if (IdF!=std::string::npos) {
0453 int LnF = int(fTimeFormat.size());
0454 std::string stringtimeoffset = fTimeFormat.substr(IdF+2,LnF-(IdF+2));
0455 int yy, mm, dd, hh, mi, ss;
0456 if (::sscanf(stringtimeoffset.c_str(),
0457 "%d-%d-%d %d:%d:%d", &yy, &mm, &dd, &hh, &mi, &ss) == 6) {
0458 struct tm tp;
0459 struct tm* tptest;
0460 time_t timeoffsettest;
0461 tp.tm_year = yy-1900;
0462 tp.tm_mon = mm-1;
0463 tp.tm_mday = dd;
0464 tp.tm_hour = hh;
0465 tp.tm_min = mi;
0466 tp.tm_sec = ss;
0467 tp.tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages)
0468 timeoffset = double(mktime(&tp));
0469 // have to correct this time to go back to UTC
0470 timeoffsettest = (time_t)((long)timeoffset);
0471 tptest = gmtime(&timeoffsettest);
0472 timeoffset += timeoffsettest - mktime(tptest);
0473 // Add the time offset's decimal part if it is there
0474 std::string::size_type Ids = stringtimeoffset.find("s");
0475 if (Ids != std::string::npos) {
0476 float dp;
0477 size_t Lns = stringtimeoffset.size();
0478 std::string sdp = stringtimeoffset.substr(Ids+1,Lns-(Ids+1));
0479 ::sscanf(sdp.c_str(),"%g",&dp);
0480 timeoffset += dp;
0481 }
0482 // if OptionTime = 2 gmtime will be used instead of localtime
0483 if (stringtimeoffset.find("GMT")!=std::string::npos)
0484 OptionTime =2;
0485 } else {
0486 out_error(m_out,"PaintAxis", "Time offset has not the right format");
0487 }
0488 } else {
0489 out_error(m_out,"PaintAxis", "%%F not found in fTimeFormat.");
0490 //FIXME timeoffset = gStyle->GetTimeOffset();
0491 }
0492 wmin += timeoffset - (int)(timeoffset);
0493 wmax += timeoffset - (int)(timeoffset);
0494 // correct for time offset at a good limit (min, hour,
0495 // day, month, year)
0496 struct tm* tp0;
0497 time_t timetp = (time_t)((long)(timeoffset));
0498 double range = wmax - wmin;
0499 long rangeBase = 60;
0500 if (range>60) rangeBase = 60*20; // minutes
0501 if (range>3600) rangeBase = 3600*20; // hours
0502 if (range>86400) rangeBase = 86400*20; // days
0503 if (range>2419200) rangeBase = 31556736; // months (average # days)
0504 rangeOffset = (double) ((long)(timeoffset)%rangeBase);
0505 if (range>31536000) {
0506 tp0 = gmtime(&timetp);
0507 tp0->tm_mon = 0;
0508 tp0->tm_mday = 1;
0509 tp0->tm_hour = 0;
0510 tp0->tm_min = 0;
0511 tp0->tm_sec = 0;
0512 tp0->tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages)
0513 rangeBase = long(timetp-mktime(tp0)); // years
0514 rangeOffset = (double) (rangeBase);
0515 }
0516 wmax += rangeOffset;
0517 wmin += rangeOffset;
0518 }
0519
0520 // Determine number of divisions 1, 2 and 3
0521 int N1A = ndiv%100;
0522 int N2A = (ndiv%10000 - N1A)/100;
0523 int N3A = ndiv/10000;
0524 int NN3 = max_of<int>(N3A,1);
0525 int NN2 = max_of<int>(N2A,1)*NN3;
0526 int NN1 = max_of<int>(N1A,1)*NN2+1;
0527 int Nticks= NN1;
0528
0529 // Axis bining optimization is ignored if:
0530 // - the first and the last label are equal
0531 // - the number of divisions is 0
0532 // - less than 1 primary division is requested
0533 // - logarithmic scale is requested
0534
0535 if (wmin == wmax || ndiv == 0 || N1A <= 1 || OptionLog) {
0536 OptionNoopt = 1;
0537 OptionInt = 0;
0538 }
0539
0540 // Axis bining optimization
0541 if ( (wmax-wmin) < 1 && OptionInt) {
0542 out_error(m_out,"PaintAxis", "option I not available");
0543 OptionInt = 0;
0544 }
0545 if (!OptionNoopt || OptionInt ) {
0546
0547 // Primary divisions optimization
0548 // When integer labelling is required, Optimize is invoked first
0549 // and only if the result is not an integer labelling, AdjustBinSize
0550 // is invoked.
0551
0552 optimizeLimits(wmin,wmax,N1A,
0553 BinLow,BinHigh,nbins,BinWidth,
0554 aCHOPT);
0555 if (OptionInt) {
0556 if (BinLow != double(int(BinLow)) ||
0557 BinWidth != double(int(BinWidth))) {
0558 adjustBinSize(wmin,wmax,N1A,BinLow,BinHigh,nbins,BinWidth);
0559 }
0560 }
0561 if ((wmin-BinLow) > epsilon) { BinLow += BinWidth; nbins--; }
0562 if ((BinHigh-wmax) > epsilon) { BinHigh -= BinWidth; nbins--; }
0563 if (xmax == xmin) {
0564 double rtyw = (ymax-ymin)/(wmax-wmin);
0565 Xxmin = xmin;
0566 Xxmax = xmax;
0567 Yymin = rtyw*(BinLow-wmin) + ymin;
0568 Yymax = rtyw*(BinHigh-wmin) + ymin;
0569 } else {
0570 double rtxw = (xmax-xmin)/(wmax-wmin);
0571 Xxmin = rtxw*(BinLow-wmin) + xmin;
0572 Xxmax = rtxw*(BinHigh-wmin) + xmin;
0573 if (ymax == ymin) {
0574 Yymin = ymin;
0575 Yymax = ymax;
0576 } else {
0577 alfa = (ymax-ymin)/(xmax-xmin);
0578 beta = (ymin*xmax-ymax*xmin)/(xmax-xmin);
0579 Yymin = alfa*Xxmin + beta;
0580 Yymax = alfa*Xxmax + beta;
0581 }
0582 }
0583 /*GB if (fFunction) {
0584 Yymin = ymin;
0585 Yymax = ymax;
0586 Xxmin = xmin;
0587 Xxmax = xmax;
0588 } else*/ {
0589 wmin = BinLow;
0590 wmax = BinHigh;
0591 }
0592
0593 // Secondary divisions optimization
0594 int NB2 = N2A;
0595 if (!OptionNoopt && N2A > 1 && BinWidth > 0) {
0596 optimizeLimits(wmin,wmin+BinWidth,N2A,
0597 BinLow2,BinHigh2,NB2,BinWidth2,
0598 aCHOPT);
0599 }
0600
0601 // Tertiary divisions optimization
0602 int NB3 = N3A;
0603 if (!OptionNoopt && N3A > 1 && BinWidth2 > 0) {
0604 optimizeLimits(BinLow2,BinLow2+BinWidth2,N3A,
0605 BinLow3,BinHigh3,NB3,BinWidth3,
0606 aCHOPT);
0607 }
0608 N1Aold = N1A;
0609 NN1old = NN1;
0610 N1A = nbins;
0611 NN3 = max_of<int>(NB3,1);
0612 NN2 = max_of<int>(NB2,1)*NN3;
0613 NN1 = max_of<int>(N1A,1)*NN2+1;
0614 Nticks = NN1;
0615 }
0616
0617 // Coordinates are normalized
0618
0619 ratio1 = 1/(RWxmax-RWxmin);
0620 ratio2 = 1/(RWymax-RWymin);
0621 X0 = ratio1*(xmin-RWxmin);
0622 X1 = ratio1*(xmax-RWxmin);
0623 Y0 = ratio2*(ymin-RWymin);
0624 Y1 = ratio2*(ymax-RWymin);
0625 if (!OptionNoopt || OptionInt ) {
0626 XX0 = ratio1*(Xxmin-RWxmin);
0627 XX1 = ratio1*(Xxmax-RWxmin);
0628 YY0 = ratio2*(Yymin-RWymin);
0629 YY1 = ratio2*(Yymax-RWymin);
0630 }
0631
0632 if ((X0 == X1) && (Y0 == Y1)) {
0633 out_error(m_out,"PaintAxis", "length of axis is 0");
0634 return;
0635 }
0636
0637 // Return wmin, wmax and the number of primary divisions
0638 if (OptionX) {
0639 ndiv = N1A;
0640 return;
0641 }
0642
0643 int maxDigits = 5;
0644 //FIXME if (fAxis) maxDigits = fMaxDigits;
0645
0646 /*FIXME
0647 TLatex *textaxis = new TLatex();
0648 lineaxis->SetLineColor(GetLineColor());
0649 lineaxis->SetLineStyle(1);
0650 lineaxis->SetLineWidth(GetLineWidth());
0651 textaxis->SetTextColor(GetTextColor());
0652 textaxis->SetTextFont(GetTextFont());
0653
0654 if (!gPad->IsBatch()) {
0655 float chupxvsav, chupyvsav;
0656 gVirtualX->GetCharacterUp(chupxvsav, chupyvsav);
0657 gVirtualX->SetClipOFF(gPad->GetCanvasID());
0658 }
0659 */
0660
0661 // Compute length of axis
0662 double axis_length = ::sqrt((X1-X0)*(X1-X0)+(Y1-Y0)*(Y1-Y0));
0663 if (axis_length == 0) {
0664 out_error(m_out,"PaintAxis", "length of axis is 0");
0665 return; //goto L210;
0666 }
0667
0668 if (!OptionNoopt || OptionInt) {
0669 axis_lengthN = ::sqrt((XX1-XX0)*(XX1-XX0)+(YY1-YY0)*(YY1-YY0));
0670 axis_length0 = ::sqrt((XX0-X0)*(XX0-X0)+(YY0-Y0)*(YY0-Y0));
0671 axis_length1 = ::sqrt((X1-XX1)*(X1-XX1)+(Y1-YY1)*(Y1-YY1));
0672 if (axis_lengthN < epsilon) {
0673 OptionNoopt = 1;
0674 OptionInt = 0;
0675 wmin = rwmi;
0676 wmax = rwma;
0677 N1A = N1Aold;
0678 NN1 = NN1old;
0679 Nticks = NN1;
0680 if (OptionTime) {
0681 wmin += timeoffset - (int)(timeoffset) + rangeOffset;
0682 wmax += timeoffset - (int)(timeoffset) + rangeOffset;
0683 }
0684 }
0685 }
0686
0687 if (X0 == X1) {
0688 phi = 0.5*kPI;
0689 phil = phi;
0690 } else {
0691 phi = TMath_ATan2((Y1-Y0),(X1-X0));
0692 int px0 = 0;//FIXME gPad->UtoPixel(X0);
0693 int py0 = 0;//FIXME gPad->VtoPixel(Y0);
0694 int px1 = 0;//FIXME gPad->UtoPixel(X1);
0695 int py1 = 0;//FIXME gPad->VtoPixel(Y1);
0696 if (X0 < X1) phil = TMath_ATan2(double(py0-py1), double(px1-px0));
0697 else phil = TMath_ATan2(double(py1-py0), double(px0-px1));
0698 }
0699 cosphi = ::cos(phi);
0700 sinphi = ::sin(phi);
0701 acosphi = TMath_Abs(cosphi);
0702 asinphi = TMath_Abs(sinphi);
0703 if (acosphi <= epsilon) { acosphi = 0; cosphi = 0; }
0704 if (asinphi <= epsilon) { asinphi = 0; sinphi = 0; }
0705
0706 // Mside positive, tick marks on positive side
0707 // Mside negative, tick marks on negative side
0708 // Mside zero, tick marks on both sides
0709 // Default is positive except for vertical axis
0710
0711 Mside=1;
0712 if (X0 == X1 && Y1 > Y0) Mside = -1;
0713 if (OptionPlus) Mside = 1;
0714 if (OptionMinus) Mside = -1;
0715 if (OptionPlus && OptionMinus) Mside = 0;
0716 XMside = Mside;
0717 Lside = -Mside;
0718 if (OptionEqual) Lside = Mside;
0719 if (OptionPlus && OptionMinus) {
0720 Lside = -1;
0721 if (OptionEqual) Lside=1;
0722 }
0723 XLside = Lside;
0724
0725 // Tick marks size
0726 double tick_side;
0727 if(XMside >= 0) tick_side = 1;
0728 else tick_side = -1;
0729
0730 double atick[3];
0731 if (OptionSize) atick[0] = tick_side*axis_length*fTickSize;
0732 else atick[0] = tick_side*axis_length*0.03;
0733
0734 atick[1] = 0.5*atick[0];
0735 atick[2] = 0.5*atick[1];
0736
0737 // Set the side of the grid
0738 if ((X0 == X1) && (Y1 > Y0)) grid_side =-1;
0739 else grid_side = 1;
0740
0741
0742 // Compute Values if Function is given
0743 /*GB if(fFunction) {
0744 rwmi = fFunction->Eval(wmin);
0745 rwma = fFunction->Eval(wmax);
0746 if(rwmi > rwma) {
0747 double t = rwma;
0748 rwma = rwmi;
0749 rwmi = t;
0750 }
0751 }*/
0752
0753 // Draw the axis if needed...
0754 if (!OptionBlank) {
0755 xpl1 = X0;
0756 xpl2 = X1;
0757 ypl1 = Y0;
0758 ypl2 = Y1;
0759 aLinesAxis.push_back((float)xpl1);
0760 aLinesAxis.push_back((float)ypl1);
0761 aLinesAxis.push_back((float)xpl2);
0762 aLinesAxis.push_back((float)ypl2);
0763 }
0764
0765 // No bining
0766
0767 if (ndiv == 0) return; //goto L210;
0768 if (wmin == wmax) {
0769 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f)", wmin, wmax);
0770 return; //goto L210;
0771 }
0772
0773 // Draw axis title if it exists
0774 if (!drawGridOnly && fTitle.size()) {
0775 textSize = fTitleSize;
0776 charheight = fTitleSize;
0777 if ((GetTextFont() % 10) > 2) {
0778 //FIXME charheight = charheight/gPad->GetWh();
0779 }
0780 double toffset = fTitleOffset;
0781 if (toffset < 0.1) toffset = 1;
0782 if (X1 == X0) Ylabel = XLside*1.6*charheight*toffset;
0783 else Ylabel = XLside*1.3*charheight*toffset;
0784 if (Y1 == Y0) Ylabel = XLside*1.6*charheight*toffset;
0785 double axispos;
0786 if (testBit(TAxis_kCenterTitle)) axispos = 0.5*axis_length;
0787 else axispos = axis_length;
0788 if (testBit(TAxis_kRotateTitle)) {
0789 if (X1 >= X0) {
0790 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0791 else textAlign = 12;
0792 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0793 } else {
0794 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0795 else textAlign = 32;
0796 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0797 }
0798 out_error(m_out,"PaintAxis","debug : texts : dummy : 000\n");
0799 aTexts.push_back(_text(xpl1,ypl1,
0800 phil=(kPI+phil)*180/kPI,
0801 fTitleSize,
0802 fTitle,textAlign));
0803 } else {
0804 if (X1 >= X0) {
0805 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0806 else textAlign = 32;
0807 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0808 } else {
0809 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0810 else textAlign = 12;
0811 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0812 }
0813 aTexts.push_back(_text(xpl1,ypl1,
0814 phil*180/kPI,fTitleSize,
0815 fTitle,textAlign));
0816 }
0817 }
0818
0819 // Labels preparation:
0820 // Get character height
0821 // Compute the labels orientation in case of overlaps
0822 // with alphanumeric labels for horizontal axis).
0823
0824 charheight = fLabelSize;
0825 if (OptionText) charheight *= 0.66666;
0826 //FIXME textaxis->SetTextFont(fLabelFont);
0827 //FIXME textaxis->SetTextColor(GetLabelColor());
0828 textSize = charheight;
0829 //FIXME textaxis->SetTextAngle(GetTextAngle());
0830 if (fLabelFont%10 > 2) {
0831 charheight /= padh;
0832 }
0833 if (!OptionUp && !OptionDown && !OptionY) {
0834 if (!drawGridOnly && OptionText && ((ymin == ymax) || (xmin == xmax))) {
0835 textAlign = 32;
0836 OptionText = 2;
0837 //int nl = 0;//FIXME fAxis->GetLast()-fAxis->GetFirst()+1;
0838 //double angle = 0;
0839 out_error(m_out,"PaintAxis","debug : FIXME : 000\n");
0840 /*FIXME
0841 for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
0842 textaxis->SetText(0,0,fAxis->GetBinLabel(i));
0843 if (textaxis->GetXsize() < (xmax-xmin)/nl) continue;
0844 angle = -20;
0845 break;
0846 }
0847 for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
0848 if ((!::strcmp(fAxis->GetName(),"xaxis") && !gPad->testBit(kHori))
0849 ||(!::strcmp(fAxis->GetName(),"yaxis") && gPad->testBit(kHori))) {
0850 if (nl > 50) angle = 90;
0851 if (fAxis->testBit(TAxis_kLabelsHori)) angle = 0;
0852 if (fAxis->testBit(TAxis_kLabelsVert)) angle = 90;
0853 if (fAxis->testBit(TAxis_kLabelsUp)) angle = 20;
0854 if (fAxis->testBit(TAxis_kLabelsDown)) angle =-20;
0855 if (angle== 0) textAlign = 23;
0856 if (angle== -20) textAlign = 12;
0857 out_error(m_out,"PaintAxis","debug : texts : dummy : 002\n");
0858 textaxis->PaintLatex(
0859 fAxis->GetBinCenter(i),
0860 gPad->GetUymin() - 3*fAxis->GetLabelOffset()*
0861 (gPad->GetUymax()-gPad->GetUymin()),
0862 angle,
0863 charheight,
0864 fAxis->GetBinLabel(i));
0865 } else if ((!::strcmp(fAxis->GetName(),"yaxis") && !gPad->testBit(kHori))
0866 || (!::strcmp(fAxis->GetName(),"xaxis") && gPad->testBit(kHori))) {
0867 out_error(m_out,"PaintAxis","debug : texts : dummy : 003\n");
0868 textaxis->PaintLatex(
0869 gPad->GetUxmin() - 3*fAxis->GetLabelOffset()*
0870 (gPad->GetUxmax()-gPad->GetUxmin()),
0871 fAxis->GetBinCenter(i),
0872 0,
0873 charheight,
0874 fAxis->GetBinLabel(i));
0875 } else {
0876 out_error(m_out,"PaintAxis","debug : texts : dummy : 004\n");
0877 textaxis->PaintLatex(
0878 xmin - 3*fAxis->GetLabelOffset()*
0879 (gPad->GetUxmax()-gPad->GetUxmin()),
0880 ymin +(i-0.5)*(ymax-ymin)/nl,
0881 0,
0882 charheight,
0883 fAxis->GetBinLabel(i));
0884 }
0885 }*/
0886 }
0887 }
0888
0889 // Now determine orientation of labels on axis
0890 /*FIXME
0891 if (!gPad->IsBatch()) {
0892 if (cosphi > 0) gVirtualX->SetCharacterUp(-sinphi,cosphi);
0893 else gVirtualX->SetCharacterUp(sinphi,-cosphi);
0894 if (X0 == X1) gVirtualX->SetCharacterUp(0,1);
0895 if (OptionVert) gVirtualX->SetCharacterUp(0,1);
0896 if (OptionPara) gVirtualX->SetCharacterUp(-sinphi,cosphi);
0897 if (OptionDown) gVirtualX->SetCharacterUp(cosphi,sinphi);
0898 }*/
0899
0900 // Now determine text alignment
0901 Xalign = 2;
0902 Yalign = 1;
0903 if (X0 == X1) Xalign = 3;
0904 if (Y0 != Y1) Yalign = 2;
0905 if (OptionCent) Xalign = 2;
0906 if (OptionRight) Xalign = 3;
0907 if (OptionLeft) Xalign = 1;
0908 if (TMath_Abs(cosphi) > 0.9) {
0909 Xalign = 2;
0910 } else {
0911 if (cosphi*sinphi > 0) Xalign = 1;
0912 if (cosphi*sinphi < 0) Xalign = 3;
0913 }
0914 textAlign = 10*Xalign+Yalign;
0915
0916 // Position of labels in Y
0917 if (X0 == X1) {
0918 if (OptionPlus && !OptionMinus) {
0919 if (OptionEqual) Ylabel = fLabelOffset/2 + atick[0];
0920 else Ylabel = -fLabelOffset;
0921 } else {
0922 Ylabel = fLabelOffset;
0923 if (Lside < 0) Ylabel += atick[0];
0924 }
0925 } else if (Y0 == Y1) {
0926 if (OptionMinus && !OptionPlus) {
0927 Ylabel = fLabelOffset+0.5*fLabelSize;
0928 Ylabel += TMath_Abs(atick[0]);
0929 } else {
0930 Ylabel = -fLabelOffset;
0931 if (Mside <= 0) Ylabel -= TMath_Abs(atick[0]);
0932 }
0933 if (OptionLog) Ylabel -= 0.5*charheight;
0934 } else {
0935 if (Mside+Lside >= 0) Ylabel = fLabelOffset;
0936 else Ylabel = -fLabelOffset;
0937 }
0938 if (OptionText) Ylabel /= 2;
0939
0940 // Draw the linear tick marks if needed...
0941 if (!OptionLog) {
0942 if (ndiv) {
0943 /*GB if (fFunction) {
0944 if (OptionNoopt && !OptionInt) {
0945 DXtick=(BinHigh-BinLow)/double(Nticks-1);
0946 } else {
0947 DXtick=(BinHigh-BinLow)/double(Nticks-1);
0948 }
0949 } else */ {
0950 if (OptionNoopt && !OptionInt) DXtick=axis_length/double(Nticks-1);
0951 else DXtick=axis_lengthN/double(Nticks-1);
0952 }
0953 for (k=0;k<Nticks; k++) {
0954 ltick = 2;
0955 if (k%NN3 == 0) ltick = 1;
0956 if (k%NN2 == 0) ltick = 0;
0957 /*GB if (fFunction) {
0958 double xx = BinLow+double(k)*DXtick;
0959 double zz = fFunction->Eval(xx)-rwmi;
0960 Xtick = zz* axis_length / TMath_Abs(rwma-rwmi);
0961 } else */ {
0962 Xtick = double(k)*DXtick;
0963 }
0964 Ytick = 0;
0965 if (!Mside) Ytick -= atick[ltick];
0966 if ( OptionNoopt && !OptionInt) {
0967 TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,X0,Y0,xpl2,ypl2);
0968 TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,X0,Y0,xpl1,ypl1);
0969 }
0970 else {
0971 TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,XX0,YY0,xpl2,ypl2);
0972 TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,XX0,YY0,xpl1,ypl1);
0973 }
0974 if (OptionVert) {
0975 if ((X0 != X1) && (Y0 != Y1)) {
0976 if (Mside) {
0977 xpl1 = xpl2;
0978 if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
0979 else ypl1 = ypl2 - atick[ltick];
0980 }
0981 else {
0982 xpl1 = 0.5*(xpl1 + xpl2);
0983 xpl2 = xpl1;
0984 ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
0985 ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
0986 }
0987 }
0988 }
0989 if (!drawGridOnly) {
0990 aLinesAxis.push_back((float)xpl1);
0991 aLinesAxis.push_back((float)ypl1);
0992 aLinesAxis.push_back((float)xpl2);
0993 aLinesAxis.push_back((float)ypl2);
0994 }
0995
0996 if (OptionGrid) {
0997 if (ltick == 0) {
0998 if (OptionNoopt && !OptionInt) {
0999 TGaxis_Rotate(Xtick,0,cosphi,sinphi,X0,Y0 ,xpl2,ypl2);
1000 TGaxis_Rotate
1001 (Xtick,grid_side*gridlength,cosphi,sinphi,X0,Y0,
1002 xpl1,ypl1);
1003 } else {
1004 TGaxis_Rotate(Xtick,0,cosphi ,sinphi,XX0,YY0,xpl2,ypl2);
1005 TGaxis_Rotate
1006 (Xtick,grid_side*gridlength ,cosphi,sinphi,XX0,YY0,
1007 xpl1,ypl1);
1008 }
1009 aLinesGrid.push_back((float)xpl1);
1010 aLinesGrid.push_back((float)ypl1);
1011 aLinesGrid.push_back((float)xpl2);
1012 aLinesGrid.push_back((float)ypl2);
1013 }
1014 }
1015 }
1016 Xtick0 = 0;
1017 Xtick1 = Xtick;
1018
1019 if ((!OptionNoopt || OptionInt) && axis_length0) {
1020 int Nticks0;
1021 /*GB if (fFunction) Nticks0 = int((BinLow-wmin)/DXtick);
1022 else */ Nticks0 = int(axis_length0/DXtick);
1023 if (Nticks0 > 1000) Nticks0 = 1000;
1024 for (k=0; k<=Nticks0; k++) {
1025 ltick = 2;
1026 if (k%NN3 == 0) ltick = 1;
1027 if (k%NN2 == 0) ltick = 0;
1028 Ytick0 = 0;
1029 if (!Mside) Ytick0 -= atick[ltick];
1030 /*GB if (fFunction) {
1031 Xtick0 = (fFunction->Eval(BinLow - double(k)*DXtick)-rwmi)
1032 * axis_length / TMath_Abs(rwma-rwmi);
1033 }*/
1034 TGaxis_Rotate(Xtick0,Ytick0,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2);
1035 TGaxis_Rotate(Xtick0,atick[ltick],cosphi,sinphi,XX0,YY0 ,xpl1,ypl1);
1036 if (OptionVert) {
1037 if ((X0 != X1) && (Y0 != Y1)) {
1038 if (Mside) {
1039 xpl1 = xpl2;
1040 if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
1041 else ypl1 = ypl2 - atick[ltick];
1042 }
1043 else {
1044 xpl1 = 0.5*(xpl1 + xpl2);
1045 xpl2 = xpl1;
1046 ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
1047 ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
1048 }
1049 }
1050 }
1051 if(!drawGridOnly) {
1052 aLinesAxis.push_back((float)xpl1);
1053 aLinesAxis.push_back((float)ypl1);
1054 aLinesAxis.push_back((float)xpl2);
1055 aLinesAxis.push_back((float)ypl2);
1056 }
1057
1058 if (OptionGrid) {
1059 if (ltick == 0) {
1060 TGaxis_Rotate(Xtick0,0,cosphi,sinphi,XX0,YY0,xpl2,ypl2);
1061 TGaxis_Rotate
1062 (Xtick0,grid_side*gridlength,cosphi,sinphi,XX0,YY0,
1063 xpl1,ypl1);
1064 aLinesGrid.push_back((float)xpl1);
1065 aLinesGrid.push_back((float)ypl1);
1066 aLinesGrid.push_back((float)xpl2);
1067 aLinesGrid.push_back((float)ypl2);
1068 }
1069 }
1070 Xtick0 -= DXtick;
1071 }
1072 }
1073
1074 if ((!OptionNoopt || OptionInt) && axis_length1) {
1075 int Nticks1;
1076 /*GB if (fFunction) Nticks1 = int((wmax-BinHigh)/DXtick);
1077 else */ Nticks1 = int(axis_length1/DXtick);
1078 if (Nticks1 > 1000) Nticks1 = 1000;
1079 for (k=0; k<=Nticks1; k++) {
1080 ltick = 2;
1081 if (k%NN3 == 0) ltick = 1;
1082 if (k%NN2 == 0) ltick = 0;
1083 Ytick1 = 0;
1084 if (!Mside) Ytick1 -= atick[ltick];
1085 /*GB if (fFunction) {
1086 Xtick1 = (fFunction->Eval(BinHigh + double(k)*DXtick)-rwmi)
1087 * axis_length / TMath_Abs(rwma-rwmi);
1088 }*/
1089 TGaxis_Rotate(Xtick1,Ytick1,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2);
1090 TGaxis_Rotate(Xtick1,atick[ltick],cosphi,sinphi,XX0,YY0 ,xpl1,ypl1);
1091 if (OptionVert) {
1092 if ((X0 != X1) && (Y0 != Y1)) {
1093 if (Mside) {
1094 xpl1 = xpl2;
1095 if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
1096 else ypl1 = ypl2 - atick[ltick];
1097 }
1098 else {
1099 xpl1 = 0.5*(xpl1 + xpl2);
1100 xpl2 = xpl1;
1101 ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
1102 ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
1103 }
1104 }
1105 }
1106 if(!drawGridOnly) {
1107 aLinesAxis.push_back((float)xpl1);
1108 aLinesAxis.push_back((float)ypl1);
1109 aLinesAxis.push_back((float)xpl2);
1110 aLinesAxis.push_back((float)ypl2);
1111 }
1112
1113 if (OptionGrid) {
1114 if (ltick == 0) {
1115 TGaxis_Rotate(Xtick1,0,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2);
1116 TGaxis_Rotate
1117 (Xtick1,grid_side*gridlength,cosphi,sinphi,XX0,YY0,
1118 xpl1,ypl1);
1119 aLinesGrid.push_back((float)xpl1);
1120 aLinesGrid.push_back((float)ypl1);
1121 aLinesGrid.push_back((float)xpl2);
1122 aLinesGrid.push_back((float)ypl2);
1123 }
1124 }
1125 Xtick1 += DXtick;
1126 }
1127 }
1128 }
1129 }
1130
1131 // Draw the numeric labels if needed...
1132 if (!drawGridOnly && !OptionUnlab) {
1133 if (!OptionLog) {
1134 if (N1A) {
1135 // Spacing of labels
1136 if ((wmin == wmax) || (ndiv == 0)) {
1137 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax);
1138 return; //goto L210;
1139 }
1140 Wlabel = wmin;
1141 DWlabel = (wmax-wmin)/double(N1A);
1142 if (OptionNoopt && !OptionInt) DXlabel = axis_length/double(N1A);
1143 else DXlabel = axis_lengthN/double(N1A);
1144
1145 char CHCODED[8];
1146 int NEXE = 0;
1147 bool FLEXE = false;
1148 if (!OptionText && !OptionTime) {
1149
1150 // We have to decide what format to generate
1151 // for numeric labels only)
1152 // Test the magnitude, decide format
1153 FLEXE = false;
1154 NEXE = 0;
1155 bool FLEXPO = false;
1156 bool FLEXNE = false;
1157 WW = max_of<double>(TMath_Abs(wmin),TMath_Abs(wmax));
1158
1159 // First case : (wmax-wmin)/N1A less than 0.001
1160 // 0.001 fMaxDigits of 5 (fMaxDigits) characters).
1161 // Then we use x 10 n
1162 // format. If AF >=0 x10 n cannot be used
1163 double xmicros = 0.00099;
1164 if (maxDigits) xmicros = ::pow(10.,-maxDigits);
1165 if (!noExponent && (TMath_Abs(wmax-wmin)/double(N1A)) < xmicros) {
1166 AF = ::log10(WW) + epsilon;
1167 if (AF < 0) {
1168 FLEXE = true;
1169 NEXE = int(AF);
1170 int IEXE = TMath_Abs(NEXE);
1171 if (IEXE%3 == 1) IEXE += 2;
1172 else if(IEXE%3 == 2) IEXE += 1;
1173 if (NEXE < 0) NEXE = -IEXE;
1174 else NEXE = IEXE;
1175 Wlabel = Wlabel*::pow(10.,IEXE);
1176 DWlabel = DWlabel*::pow(10.,IEXE);
1177 IF1 = maxDigits;
1178 IF2 = maxDigits-2;
1179 goto L110;
1180 }
1181 }
1182 if (WW >= 1) AF = ::log10(WW);
1183 else AF = ::log10(WW*0.0001);
1184 AF += epsilon;
1185 NF = int(AF)+1;
1186 if (!noExponent && NF > maxDigits) FLEXPO = true;
1187 if (!noExponent && NF < -maxDigits) FLEXNE = true;
1188
1189 // Use x 10 n format. (only powers of 3 allowed)
1190
1191 if (FLEXPO) {
1192 FLEXE = true;
1193 while (1) {
1194 NEXE++;
1195 WW /= 10;
1196 Wlabel /= 10;
1197 DWlabel /= 10;
1198 if (NEXE%3 == 0 && WW <= ::pow(10.,maxDigits-1)) break;
1199 }
1200 }
1201
1202 if (FLEXNE) {
1203 FLEXE = true;
1204 RNE = 1/::pow(10.,maxDigits-2);
1205 while (1) {
1206 NEXE--;
1207 WW *= 10;
1208 Wlabel *= 10;
1209 DWlabel *= 10;
1210 if (NEXE%3 == 0 && WW >= RNE) break;
1211 }
1212 }
1213
1214 NA = 0;
1215 for (i=maxDigits-1; i>0; i--) {
1216 if (TMath_Abs(WW) < ::pow(10.,i)) NA = maxDigits-i;
1217 }
1218 ndyn = N1A;
1219 while (ndyn) {
1220 double wdyn = TMath_Abs((wmax-wmin)/ndyn);
1221 if (wdyn <= 0.999 && NA < maxDigits-2) {
1222 NA++;
1223 ndyn /= 10;
1224 }
1225 else break;
1226 }
1227
1228 IF2 = NA;
1229 IF1 = max_of<int>(NF+NA,maxDigits)+1;
1230 L110:
1231 if (min_of<double>(wmin,wmax) < 0)IF1 = IF1+1;
1232 IF1 = min_of<int>(IF1,32);
1233
1234 // In some cases, IF1 and IF2 are too small....
1235 while (DWlabel < ::pow(10.,-IF2)) {
1236 IF1++;
1237 IF2++;
1238 }
1239 //char* CODED = &CHCODED[0]; //GB : comment out.
1240 if (IF1 > 14) IF1=14;
1241 if (IF2 > 14) IF2=14;
1242 if(IF2)snpf(CHCODED,sizeof(CHCODED),"%%%d.%df",IF1,IF2);
1243 else snpf(CHCODED,sizeof(CHCODED),"%%%d.%df",IF1+1,1);
1244 }
1245
1246 // We draw labels
1247
1248 snpf(CHTEMP,sizeof(CHTEMP),"%g",DWlabel);
1249
1250 size_t ndecimals = 0;
1251 if (OptionDecimals) {
1252 char *dot = ::strchr(CHTEMP,'.');
1253 if (dot) ndecimals = CHTEMP + ::strlen(CHTEMP) -dot;
1254 }
1255 int Nlabels;
1256 if (OptionM) Nlabels = N1A-1;
1257 else Nlabels = N1A;
1258 double wTimeIni = Wlabel;
1259 for ( k=0; k<=Nlabels; k++) {
1260 /*FIXME if (fFunction) {
1261 double xx = BinLow+double(k*NN2)*DXtick;
1262 double zz = fFunction->Eval(xx)-rwmi;
1263 Wlabel = xx;
1264 Xlabel = zz* axis_length / TMath_Abs(rwma-rwmi);
1265 } else */{
1266 Xlabel = DXlabel*k;
1267 }
1268 if (OptionM) Xlabel += 0.5*DXlabel;
1269
1270 if (!OptionText && !OptionTime) {
1271 snpf(LABEL,sizeof(LABEL),&CHCODED[0],Wlabel);
1272 LABEL[28] = 0;
1273 Wlabel += DWlabel;
1274
1275 TGaxis_LabelsLimits(m_out,LABEL,first,last); //Eliminate blanks
1276
1277 if (LABEL[first] == '.') { //check if '.' is preceeded by a digit
1278 ::strcpy(CHTEMP, "0");
1279 ::strcat(CHTEMP, &LABEL[first]);
1280 ::strcpy(LABEL, CHTEMP);
1281 first = 1; last = int(::strlen(LABEL));
1282 }
1283 if (LABEL[first] == '-' && LABEL[first+1] == '.') {
1284 ::strcpy(CHTEMP, "-0");
1285 ::strcat(CHTEMP, &LABEL[first+1]);
1286 ::strcpy(LABEL, CHTEMP);
1287 first = 1; last = int(::strlen(LABEL));
1288 }
1289
1290 // We eliminate the non significant 0 after '.'
1291 if (ndecimals) {
1292 char *adot = ::strchr(LABEL,'.');
1293 if (adot) adot[ndecimals] = 0;
1294 } else {
1295 while (LABEL[last] == '0') { LABEL[last] = 0; last--;}
1296 }
1297 // We eliminate the dot, unless dot is forced.
1298 if (LABEL[last] == '.') {
1299 if (!OptionDot) { LABEL[last] = 0; last--;}
1300 }
1301 }
1302
1303 // Generate the time labels
1304
1305 if (OptionTime) {
1306 double timed = Wlabel + (int)(timeoffset) - rangeOffset;
1307 time_t timelabel = (time_t)((long)(timed));
1308 struct tm* utctis;
1309 if (OptionTime == 1) {
1310 utctis = localtime(&timelabel);
1311 } else {
1312 utctis = gmtime(&timelabel);
1313 }
1314 std::string timeformattmp;
1315 if (timeformat.size() < 220) timeformattmp = timeformat;
1316 else timeformattmp = "#splitline{Format}{too long}";
1317
1318 // Appends fractionnal part if seconds displayed
1319 if (DWlabel<0.9) {
1320 double tmpdb;
1321 size_t tmplast;
1322 snpf(LABEL,sizeof(LABEL),"%%S%7.5f",modf(timed,&tmpdb));
1323 tmplast = ::strlen(LABEL)-1;
1324
1325 // We eliminate the non significiant 0 after '.'
1326 while (LABEL[tmplast] == '0') {
1327 LABEL[tmplast] = 0; tmplast--;
1328 }
1329
1330 //FIXME timeformattmp.ReplaceAll("%S",LABEL);
1331 // Replace the "0." at the begining by "s"
1332 //FIXME timeformattmp.ReplaceAll("%S0.","%Ss");
1333
1334 }
1335
1336 ::strftime(LABEL,256,timeformattmp.c_str(),utctis);
1337 ::strcpy(CHTEMP,&LABEL[0]);
1338 first = 0; last=int(::strlen(LABEL))-1;
1339 Wlabel = wTimeIni + (k+1)*DWlabel;
1340 }
1341
1342 // We generate labels (numeric or alphanumeric).
1343
1344 if (OptionNoopt && !OptionInt)
1345 TGaxis_Rotate (Xlabel,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
1346 else TGaxis_Rotate (Xlabel,Ylabel,cosphi,sinphi,XX0,YY0,XX,YY);
1347 if (Y0 == Y1 && !OptionDown && !OptionUp) {
1348 YY -= 0.80*charheight;
1349 }
1350 if (OptionVert) {
1351 if (X0 != X1 && Y0 != Y1) {
1352 if (OptionNoopt && !OptionInt)
1353 TGaxis_Rotate (Xlabel,0,cosphi,sinphi,X0,Y0,XX,YY);
1354 else TGaxis_Rotate (Xlabel,0,cosphi,sinphi,XX0,YY0,XX,YY);
1355 if (cosphi > 0 ) YY += Ylabel;
1356 if (cosphi < 0 ) YY -= Ylabel;
1357 }
1358 }
1359 if (!OptionY || (X0 == X1)) {
1360 if (!OptionText) {
1361 if (first > last) ::strcpy(CHTEMP, " ");
1362 else ::strcpy(CHTEMP, &LABEL[first]);
1363 aTexts.push_back(_text(XX,YY,
1364 0,textSize,CHTEMP,
1365 textAlign));
1366 }
1367 else {
1368 if (OptionText == 1) {
1369 out_error(m_out,"PaintAxis","debug : texts : dummy : 006\n");
1370 /*textaxis->PaintLatex
1371 (gPad->GetX1() + XX*(gPad->GetX2() - gPad->GetX1()),
1372 gPad->GetY1() + YY*(gPad->GetY2() - gPad->GetY1()),
1373 0,
1374 textaxis->GetTextSize(),
1375 fAxis->GetBinLabel(k+fAxis->GetFirst()));*/
1376 }
1377 }
1378 }
1379 else {
1380
1381 // Text alignment is down
1382 int LNLEN = 0;
1383 if (!OptionText) LNLEN = last-first+1;
1384 else {
1385 int NHILAB = 0;
1386 if (k+1 > NHILAB) LNLEN = 0;
1387 }
1388 for ( l=1; l<=LNLEN; l++) {
1389 if (!OptionText) *CHTEMP = LABEL[first+l-2];
1390 else {
1391 if (LNLEN == 0) ::strcpy(CHTEMP, " ");
1392 else ::strcpy(CHTEMP, "1");
1393 }
1394 aTexts.push_back(_text(XX,YY,
1395 0,textSize,CHTEMP,
1396 textAlign));
1397 YY -= charheight*1.3;
1398 }
1399 }
1400 }
1401
1402 // We use the format x 10 ** n
1403
1404 if (FLEXE && !OptionText && NEXE) {
1405 //G.Barrand ::sprintf(LABEL,"#times10^{%d}", NEXE);
1406 snpf(LABEL,sizeof(LABEL),
1407 "x10^%d!", NEXE); //G.Barrand : PAW encoding.
1408 double Xfactor, Yfactor;
1409 if (X0 != X1) { Xfactor = X1-X0+0.1*charheight; Yfactor = 0; }
1410 else { Xfactor = Y1-Y0+0.1*charheight; Yfactor = 0; }
1411 TGaxis_Rotate (Xfactor,Yfactor,cosphi,sinphi,X0,Y0,XX,YY);
1412 textAlign = 11;
1413 aTexts.push_back(_text(XX,YY,
1414 0,textSize,LABEL,
1415 textAlign));
1416 }
1417 }
1418 }
1419 }
1420
1421 // Log axis
1422
1423 if (OptionLog && ndiv) {
1424 unsigned int xi1=0,xi2 = 0,wi = 0,yi1=0,yi2,hi = 0;
1425 bool firstintlab = true, overlap = false;
1426 if ((wmin == wmax) || (ndiv == 0)) {
1427 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax);
1428 return; //goto L210;
1429 }
1430 if (wmin <= 0) {
1431 out_error(m_out,"PaintAxis", "negative logarithmic axis");
1432 return; //goto L210;
1433 }
1434 if (wmax <= 0) {
1435 out_error(m_out,"PaintAxis", "negative logarithmic axis");
1436 return; //goto L210;
1437 }
1438 double XMNLOG = ::log10(wmin);
1439 if (XMNLOG > 0) XMNLOG += 1.E-6;
1440 else XMNLOG -= 1.E-6;
1441 double X00 = 0;
1442 double X11 = axis_length;
1443 double H2 = ::log10(wmax);
1444 double H2SAV = H2;
1445 if (H2 > 0) H2 += 1.E-6;
1446 else H2 -= 1.E-6;
1447 int IH1 = int(XMNLOG);
1448 int IH2 = 1+int(H2);
1449 int NBININ = IH2-IH1+1;
1450 double AXMUL = (X11-X00)/(H2SAV-XMNLOG);
1451
1452 // Plot decade and intermediate tick marks
1453 decade = IH1-2;
1454 int labelnumber = IH1;
1455 if ( XMNLOG > 0 && (XMNLOG-double(IH1) > 0) ) labelnumber++;
1456 for (j=1; j<=NBININ; j++) {
1457
1458 // Plot decade
1459 firstintlab = true, overlap = false;
1460 decade++;
1461 if (X0 == X1 && j == 1) Ylabel += charheight*0.33;
1462 if (Y0 == Y1 && j == 1) Ylabel -= charheight*0.65;
1463 double Xone = X00+AXMUL*(double(decade)-XMNLOG);
1464 //the following statement is a trick to circumvent a gcc bug
1465 //GB if (j < 0) ::printf("j=%d\n",j); //G.Barrand : ???
1466 if (X00 > Xone) goto L160;
1467 if (Xone > X11) break;
1468 Xtwo = Xone;
1469 Y = 0;
1470 if (!Mside) Y -= atick[0];
1471 TGaxis_Rotate(Xone,Y,cosphi,sinphi,X0,Y0,xpl2,ypl2);
1472 TGaxis_Rotate(Xtwo,atick[0],cosphi,sinphi,X0,Y0,xpl1,ypl1);
1473 if (OptionVert) {
1474 if ((X0 != X1) && (Y0 != Y1)) {
1475 if (Mside) {
1476 xpl1=xpl2;
1477 if (cosphi > 0) ypl1 = ypl2 + atick[0];
1478 else ypl1 = ypl2 - atick[0];
1479 }
1480 else {
1481 xpl1 = 0.5*(xpl1 + xpl2);
1482 xpl2 = xpl1;
1483 ypl1 = 0.5*(ypl1 + ypl2) + atick[0];
1484 ypl2 = 0.5*(ypl1 + ypl2) - atick[0];
1485 }
1486 }
1487 }
1488 if (!drawGridOnly) {
1489 aLinesAxis.push_back((float)xpl1);
1490 aLinesAxis.push_back((float)ypl1);
1491 aLinesAxis.push_back((float)xpl2);
1492 aLinesAxis.push_back((float)ypl2);
1493 }
1494
1495 if (OptionGrid) {
1496 TGaxis_Rotate(Xone,0,cosphi,sinphi,X0,Y0,xpl2,ypl2);
1497 TGaxis_Rotate(Xone,grid_side*gridlength,cosphi,sinphi,X0,Y0,
1498 xpl1,ypl1);
1499 aLinesGrid.push_back((float)xpl1);
1500 aLinesGrid.push_back((float)ypl1);
1501 aLinesGrid.push_back((float)xpl2);
1502 aLinesGrid.push_back((float)ypl2);
1503 }
1504
1505 if (!drawGridOnly && !OptionUnlab) {
1506
1507 // We generate labels (numeric only).
1508 if (noExponent) {
1509 double rlab = ::pow(10.,labelnumber);
1510 snpf(LABEL,sizeof(LABEL), "%f", rlab);
1511 TGaxis_LabelsLimits(m_out,LABEL,first,last);
1512 while (last > first) {
1513 if (LABEL[last] != '0') break;
1514 LABEL[last] = 0;
1515 last--;
1516 }
1517 if (LABEL[last] == '.') {LABEL[last] = 0; last--;}
1518 } else {
1519 snpf(LABEL,sizeof(LABEL), "%d", labelnumber);
1520 TGaxis_LabelsLimits(m_out,LABEL,first,last);
1521 }
1522 TGaxis_Rotate (Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
1523 if ((X0 == X1) && !OptionPara) {
1524 if (Lside < 0) {
1525 if (Mside < 0) {
1526 if (labelnumber == 0) NCH=1;
1527 else NCH=2;
1528 XX += NCH*charheight;
1529 } else {
1530 if (labelnumber >= 0) XX += 0.25*charheight;
1531 else XX += 0.50*charheight;
1532 }
1533 }
1534 XX += 0.25*charheight;
1535 }
1536 if ((Y0 == Y1) && !OptionDown && !OptionUp) {
1537 if (noExponent) YY += 0.33*charheight;
1538 }
1539 if (N1A == 0) return; //goto L210;
1540 int KMOD = NBININ/N1A;
1541 if (KMOD == 0) KMOD=1000000;
1542 if ((NBININ <= N1A) || (j == 1) || (j == NBININ) || ((NBININ > N1A)
1543 && (j%KMOD == 0))) {
1544 if (labelnumber == 0) {
1545 aTexts.push_back(_text(XX,YY,
1546 0,textSize,"1",
1547 textAlign));
1548 } else if (labelnumber == 1) {
1549 aTexts.push_back(_text(XX,YY,
1550 0,textSize,"10",
1551 textAlign));
1552 } else {
1553 if (noExponent) {
1554 out_error(m_out,"PaintAxis","debug : texts : FIXME : 003\n");
1555 //FIXME textaxis->PaintTextNDC(XX,YY,&LABEL[first]);
1556 } else {
1557 //FIXME : support CERN-ROOT Latex encoding ?
1558 // ::sprintf(CHTEMP, "10^{%d}", labelnumber);
1559 snpf(CHTEMP,sizeof(CHTEMP),
1560 "10^%d?", labelnumber); //PAW encoding.
1561 aTexts.push_back(_text(XX,YY,
1562 0,textSize,CHTEMP,
1563 textAlign));
1564 }
1565 }
1566 }
1567 labelnumber++;
1568 }
1569 L160:
1570 for (k=2;k<10;k++) {
1571
1572 // Plot intermediate tick marks
1573 //double Xone; //rm shadow warning.
1574 Xone = X00+AXMUL*(::log10(double(k))+double(decade)-XMNLOG);
1575 if (X00 > Xone) continue;
1576 if (Xone > X11) goto L200;
1577 Y = 0;
1578 if (!Mside) Y -= atick[1];
1579 Xtwo = Xone;
1580 TGaxis_Rotate(Xone,Y,cosphi,sinphi,X0,Y0,xpl2,ypl2);
1581 TGaxis_Rotate(Xtwo,atick[1],cosphi,sinphi,X0,Y0,xpl1,ypl1);
1582 if (OptionVert) {
1583 if ((X0 != X1) && (Y0 != Y1)) {
1584 if (Mside) {
1585 xpl1 = xpl2;
1586 if (cosphi > 0) ypl1 = ypl2 + atick[1];
1587 else ypl1 = ypl2 - atick[1];
1588 }
1589 else {
1590 xpl1 = 0.5*(xpl1+xpl2);
1591 xpl2 = xpl1;
1592 ypl1 = 0.5*(ypl1+ypl2) + atick[1];
1593 ypl2 = 0.5*(ypl1+ypl2) - atick[1];
1594 }
1595 }
1596 }
1597 int IDN = N1A*2;
1598 if ((NBININ <= IDN) || ((NBININ > IDN) && (k == 5))) {
1599 if(!drawGridOnly) {
1600 aLinesAxis.push_back((float)xpl1);
1601 aLinesAxis.push_back((float)ypl1);
1602 aLinesAxis.push_back((float)xpl2);
1603 aLinesAxis.push_back((float)ypl2);
1604 }
1605
1606 // Draw the intermediate LOG labels if requested
1607
1608 if (MoreLogLabels && !OptionUnlab &&
1609 !drawGridOnly && !overlap) {
1610 if (noExponent) {
1611 double rlab = double(k)*::pow(10.,labelnumber-1);
1612 snpf(CHTEMP,sizeof(CHTEMP), "%g", rlab);
1613 } else {
1614 if (labelnumber-1 == 0) {
1615 snpf(CHTEMP,sizeof(CHTEMP), "%d", k);
1616 } else if (labelnumber-1 == 1) {
1617 snpf(CHTEMP,sizeof(CHTEMP), "%d", 10*k);
1618 } else {
1619 //G.Barrand :
1620 //::sprintf(CHTEMP, "%d#times10^{%d}", k, labelnumber-1);
1621 snpf(CHTEMP,sizeof(CHTEMP),
1622 "%dx10^%d!",k,labelnumber-1);//G.Barrand
1623 }
1624 }
1625 TGaxis_Rotate (Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
1626 if ((Y0 == Y1) && !OptionDown && !OptionUp) {
1627 if (noExponent) YY += 0.33*charheight;
1628 }
1629 if (X0 == X1) XX += 0.25*charheight;
1630 if (OptionVert) {
1631 if ((X0 != X1) && (Y0 != Y1)) {
1632 TGaxis_Rotate(Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
1633 if (cosphi > 0) YY += Ylabel;
1634 else YY -= Ylabel;
1635 }
1636 }
1637 //FIXME textaxis->SetTitle(CHTEMP);
1638 double u = XX;
1639 double v = YY;
1640 if (firstintlab) {
1641 //FIXME textaxis->GetBoundingBox(wi, hi); wi=(Uint)(wi*1.3); hi*=(Uint)(hi*1.3);
1642 xi1 = 0;//FIXME gPad->XtoAbsPixel(u);
1643 yi1 = 0;//FIXME gPad->YtoAbsPixel(v);
1644 firstintlab = false;
1645 out_error(m_out,"PaintAxis","debug : texts : dummy : 010\n");
1646 aTexts.push_back(_text(u,v,
1647 0,textSize,CHTEMP,
1648 textAlign));
1649 } else {
1650 xi2 = 0;//FIXME gPad->XtoAbsPixel(u);
1651 yi2 = 0;//FIXME gPad->YtoAbsPixel(v);
1652 if ((X0 == X1 && yi1-hi <= yi2) || (Y0 == Y1 && xi1+wi >= xi2)){
1653 overlap = true;
1654 } else {
1655 xi1 = xi2;
1656 yi1 = yi2;
1657 //FIXME textaxis->GetBoundingBox(wi, hi); wi=(Uint)(wi*1.3); hi*=(Uint)(hi*1.3);
1658 out_error(m_out,"PaintAxis","debug : texts : dummy : 011\n");
1659 aTexts.push_back(_text(u,v,
1660 0,textSize,CHTEMP,
1661 textAlign));
1662 }
1663 }
1664 }
1665
1666 // Draw the intermediate LOG grid if only three
1667 // decades are requested
1668 if (OptionGrid && NBININ <= 5 && ndiv > 100) {
1669 TGaxis_Rotate(Xone,0,cosphi,sinphi,X0,Y0,xpl2, ypl2);
1670 TGaxis_Rotate
1671 (Xone,grid_side*gridlength,cosphi,sinphi,X0,Y0,xpl1,ypl1);
1672 aLinesGrid.push_back((float)xpl1);
1673 aLinesGrid.push_back((float)ypl1);
1674 aLinesGrid.push_back((float)xpl2);
1675 aLinesGrid.push_back((float)ypl2);
1676 }
1677 } //endif ((NBININ <= IDN) ||
1678 } //endfor (k=2;k<10;k++)
1679 } //endfor (j=1; j<=NBININ; j++)
1680 L200:
1681 int kuku=0; if (kuku) { }
1682 } //endif (OptionLog && ndiv)
1683
1684
1685 //L210:
1686 }
1687
1688 /*
1689 void TGaxis_SetDecimals(bool dot)
1690 {
1691 // Set the Decimals flag
1692 // By default, blank characters are stripped, and then the
1693 // label is correctly aligned. The dot, if last character of the string,
1694 // is also stripped, unless this option is specified.
1695 // One can disable the option by calling axis.SetDecimals(true).
1696 // Note the bit is set in fBits (as opposed to fBits2 in TAxis!)
1697
1698 if (dot) SetBit(TAxis_kDecimals);
1699 else ResetBit(TAxis_kDecimals);
1700 }
1701
1702 void TGaxis_SetMaxDigits(int maxd)
1703 {
1704 // static function to set fMaxDigits for axis with the bin content
1705 // (y axis for 1-d histogram, z axis for 2-d histogram)
1706 //fMaxDigits is the maximum number of digits permitted for the axis
1707 //labels above which the notation with 10^N is used.
1708 //For example, to accept 6 digits number like 900000 on an axis
1709 //call TGaxis::SetMaxDigits(6). The default value is 5.
1710 //fMaxDigits must be greater than 0.
1711
1712 fMaxDigits = maxd;
1713 if (maxd < 1) fMaxDigits = 1;
1714 }
1715
1716 void TGaxis_SetMoreLogLabels(bool more)
1717 {
1718 // Set the kMoreLogLabels bit flag
1719 // When this option is selected more labels are drawn when in log scale
1720 // and there is a small number of decades (<3).
1721 // Note that this option is automatically inherited from TAxis
1722
1723 if (more) SetBit(TAxis_kMoreLogLabels);
1724 else ResetBit(TAxis_kMoreLogLabels);
1725 }
1726 void TGaxis_SetNoExponent(bool noExponent)
1727 {
1728 // Set the NoExponent flag
1729 // By default, an exponent of the form 10^N is used when the label values
1730 // are either all very small or very large.
1731 // One can disable the exponent by calling axis.SetNoExponent(true).
1732
1733 if (noExponent) SetBit(TAxis_kNoExponent);
1734 else ResetBit(TAxis_kNoExponent);
1735 }
1736 void TGaxis_SetOption(const std::string& option)
1737 {
1738 fCHOPT = option;
1739 }
1740 */
1741
1742 void set_time_format(const std::string& a_format)
1743 // Change the format used for time plotting
1744 // ========================================
1745 // The format string for date and time use the same options as the one used
1746 // in the standard strftime C function, i.e. :
1747 // for date :
1748 // %a abbreviated weekday name
1749 // %b abbreviated month name
1750 // %d day of the month (01-31)
1751 // %m month (01-12)
1752 // %y year without century
1753 //
1754 // for time :
1755 // %H hour (24-hour clock)
1756 // %I hour (12-hour clock)
1757 // %p local equivalent of AM or PM
1758 // %M minute (00-59)
1759 // %S seconds (00-61)
1760 // %% %
1761 //
1762 {
1763 if (a_format.find("%F")!=std::string::npos || !a_format.size()) {
1764 fTimeFormat = a_format;
1765 //::printf("debug : SbAxisHPLOT::setTimeFormat : 000 : \"%s\"\n",
1766 // fTimeFormat.c_str());
1767 return;
1768 }
1769
1770 std::string::size_type IdF = fTimeFormat.find("%F");
1771 if (IdF!=std::string::npos) {
1772 size_t LnF = fTimeFormat.size();
1773 std::string stringtimeoffset = fTimeFormat.substr(IdF,LnF-IdF);
1774 fTimeFormat = a_format;
1775 fTimeFormat += stringtimeoffset;
1776 //::printf("debug : SbAxisHPLOT::setTimeFormat : 001 : \"%s\"\n",
1777 // fTimeFormat.c_str());
1778 } else {
1779 fTimeFormat = a_format;
1780
1781 // In CERN-ROOT :
1782 //SetTimeOffset(gStyle->GetTimeOffset());
1783 //TAxis::fTimeOffset = 788918400; // UTC time at 01/01/95
1784 //double UTC_time_1995_01_01__00_00_00 = 788918400; //CERN-ROOT
1785 //setTimeOffset(UTC_time_1995_01_01__00_00_00);
1786
1787 //Be consistent with SoAxis::timeOffset being 0.
1788 double UTC_time_1970_01_01__00_00_00 = 0; //UNIX
1789 set_time_offset(UTC_time_1970_01_01__00_00_00);
1790
1791 //::printf("debug : SbAxisHPLOT::setTimeFormat : 002 : \"%s\"\n",
1792 // fTimeFormat.c_str());
1793 }
1794 }
1795
1796 void set_time_offset(double toffset,bool a_is_gmt = false) {
1797 // Change the time offse t
1798
1799 std::string::size_type IdF = fTimeFormat.find("%F");
1800 if (IdF!=std::string::npos) {
1801 fTimeFormat = fTimeFormat.substr(0,IdF);
1802 }
1803 fTimeFormat += "%F";
1804
1805 time_t timeoff = (time_t)((long)(toffset));
1806 struct tm* utctis = ::gmtime(&timeoff);
1807
1808 char tmp[256];
1809 ::strftime(tmp,256,"%Y-%m-%d %H:%M:%S",utctis);
1810 fTimeFormat += tmp;
1811
1812 // append the decimal part of the time offset
1813 double ds = toffset-(int)toffset;
1814 if(ds!= 0) {
1815 snpf(tmp,sizeof(tmp),"s%g",ds);
1816 fTimeFormat += tmp;
1817 }
1818
1819 // If the time is GMT, stamp fTimeFormat
1820 if (a_is_gmt) fTimeFormat += " GMT";
1821
1822 //::printf("debug : SbAxisHPLOT::setTimeOffset : \"%s\"\n",
1823 // fTimeFormat.c_str());
1824 }
1825
1826
1827
1828 ////////////////////////////////////////////////////////////////////////////
1829 ////////////////////////////////////////////////////////////////////////////
1830 ////////////////////////////////////////////////////////////////////////////
1831 private:
1832 static void optimizeLimits(
1833 double A1,double A2,int nold
1834 ,double &BinLow, double &BinHigh
1835 ,int &nbins, double &BinWidth
1836 ,const std::string& aCHOPT
1837 ){
1838 // static function to compute reasonable axis limits
1839 //
1840 // Input parameters:
1841 //
1842 // A1,A2 : Old WMIN,WMAX .
1843 // BinLow,BinHigh : New WMIN,WMAX .
1844 // nold : Old NDIV .
1845 // nbins : New NDIV .
1846
1847 int lwid, kwid;
1848 int ntemp = 0;
1849 int jlog = 0;
1850 double siground = 0;
1851 double alb, awidth, sigfig;
1852 double timemulti = 1;
1853 int roundmode =0;
1854
1855 int OptionTime;
1856 SETOPT(aCHOPT,'t',OptionTime);
1857
1858 double AL = min_of<double>(A1,A2);
1859 double AH = max_of<double>(A1,A2);
1860 if (AL == AH) AH = AL+1;
1861 // if nold == -1 , program uses binwidth input from calling routine
1862 if (nold == -1 && BinWidth > 0 ) goto L90;
1863 ntemp = (int)max_of<double>(nold,2);
1864 if (ntemp < 1) ntemp = 1;
1865
1866 L20:
1867 awidth = (AH-AL)/double(ntemp);
1868 timemulti = 1;
1869 if (awidth >= FLT_MAX) goto LOK; //in float.h
1870 if (awidth <= 0) goto LOK;
1871
1872 // If time representation, bin width should be rounded to seconds
1873 // minutes, hours or days
1874
1875 if (OptionTime && awidth>=60) { // if width in seconds, treat it as normal
1876 // width in minutes
1877 awidth /= 60; timemulti *=60;
1878 roundmode = 1; // round minutes (60)
1879 // width in hours ?
1880 if (awidth>=60) {
1881 awidth /= 60; timemulti *= 60;
1882 roundmode = 2; // round hours (24)
1883 // width in days ?
1884 if (awidth>=24) {
1885 awidth /= 24; timemulti *= 24;
1886 roundmode = 3; // round days (30)
1887 // width in months ?
1888 if (awidth>=30.43685) { // Mean month length in 1900.
1889 awidth /= 30.43685; timemulti *= 30.43685;
1890 roundmode = 2; // round months (12)
1891 // width in years ?
1892 if (awidth>=12) {
1893 awidth /= 12; timemulti *= 12;
1894 roundmode = 0; // round years (10)
1895 }
1896 }
1897 }
1898 }
1899 }
1900 // Get nominal bin width in exponential for m
1901
1902 jlog = int(::log10(awidth));
1903 if (jlog <-200 || jlog > 200) {
1904 BinLow = 0;
1905 BinHigh = 1;
1906 BinWidth = 0.01;
1907 nbins = 100;
1908 return;
1909 }
1910 if (awidth <= 1 && (!OptionTime || timemulti==1) ) jlog--;
1911 sigfig = awidth* ::pow(10.,-jlog) -1e-10;
1912 //in the above statement, it is important to substract 1e-10
1913 //to avoid precision problems if the tests below
1914
1915 // Round mantissa
1916
1917 switch (roundmode) {
1918
1919 // Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes
1920 case 1: // case 60
1921 if (sigfig <= 1) siground = 1;
1922 else if (sigfig <= 1.5 && jlog==1) siground = 1.5;
1923 else if (sigfig <= 2) siground = 2;
1924 else if (sigfig <= 3 && jlog ==1) siground = 3;
1925 else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02)
1926 else if (jlog==0) {siground = 1; jlog++;}
1927 else siground = 6;
1928 break;
1929 case 2: // case 12 and 24
1930
1931 // Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months
1932 if (sigfig <= 1 && jlog==0) siground = 1;
1933 else if (sigfig <= 1.2 && jlog==1) siground = 1.2;
1934 else if (sigfig <= 2 && jlog==0) siground = 2;
1935 else if (sigfig <= 2.4 && jlog==1) siground = 2.4;
1936 else if (sigfig <= 3) siground = 3;
1937 else if (sigfig <= 6) siground = 6;
1938 else if (jlog==0) siground = 12;
1939 else siground = 2.4;
1940 break;
1941
1942 //- Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks)
1943 case 3: // case 30
1944 if (sigfig <= 1 && jlog==0) siground = 1;
1945 else if (sigfig <= 1.4 && jlog==1) siground = 1.4;
1946 else if (sigfig <= 3 && jlog ==1) siground = 3;
1947 else siground = 7;
1948 break;
1949 default :
1950
1951 // Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number
1952 if (sigfig <= 1) siground = 1;
1953 else if (sigfig <= 2) siground = 2;
1954 else if (sigfig <= 5 && (!OptionTime || jlog<1)) siground = 5;
1955 else if (sigfig <= 6 && OptionTime && jlog==1) siground = 6;
1956 else {siground = 1; jlog++; }
1957 break;
1958 }
1959
1960 BinWidth = siground* ::pow(10.,jlog);
1961 if (OptionTime) BinWidth *= timemulti;
1962
1963 // Get new bounds from new width BinWidth
1964
1965 L90:
1966 alb = AL/BinWidth;
1967 if (TMath_Abs(alb) > 1e9) {
1968 BinLow = AL;
1969 BinHigh = AH;
1970 if (nbins > 10*nold && nbins > 10000) nbins = nold;
1971 return;
1972 }
1973 lwid = int(alb);
1974 if (alb < 0) lwid--;
1975 BinLow = BinWidth*double(lwid);
1976 alb = AH/BinWidth + 1.00001;
1977 kwid = int(alb);
1978 if (alb < 0) kwid--;
1979 BinHigh = BinWidth*double(kwid);
1980 nbins = kwid - lwid;
1981 if (nold == -1) goto LOK;
1982 if (nold <= 5) { // Request for one bin is difficult case
1983 if (nold > 1 || nbins == 1)goto LOK;
1984 BinWidth = BinWidth*2;
1985 nbins = 1;
1986 goto LOK;
1987 }
1988 if (2*nbins == nold && !OptionTime) {ntemp++; goto L20; }
1989
1990 LOK:
1991 double oldBinLow = BinLow;
1992 double oldBinHigh = BinHigh;
1993 int oldnbins = nbins;
1994
1995 double atest = BinWidth*0.0001;
1996 //if (TMath_Abs(BinLow-A1) >= atest) { BinLow += BinWidth; nbins--; } //replaced by Damir in 3.10/02
1997 //if (TMath_Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth; nbins--; } //by the next two lines
1998 if (AL-BinLow >= atest) { BinLow += BinWidth; nbins--; }
1999 if (BinHigh-AH >= atest) { BinHigh -= BinWidth; nbins--; }
2000 if (!OptionTime && BinLow >= BinHigh) {
2001 //this case may happen when nbins <=5
2002 BinLow = oldBinLow;
2003 BinHigh = oldBinHigh;
2004 nbins = oldnbins;
2005 }
2006 else if (OptionTime && BinLow>=BinHigh) {
2007 nbins = 2*oldnbins;
2008 BinHigh = oldBinHigh;
2009 BinLow = oldBinLow;
2010 BinWidth = (oldBinHigh - oldBinLow)/nbins;
2011 atest = BinWidth*0.0001;
2012 if (AL-BinLow >= atest) { BinLow += BinWidth; nbins--; }
2013 if (BinHigh-AH >= atest) { BinHigh -= BinWidth; nbins--; }
2014 }
2015 }
2016
2017 static void adjustBinSize(
2018 double A1,double A2,int nold
2019 ,double &BinLow, double &BinHigh, int &nbins, double &BinWidth
2020 ){
2021 // Axis labels optimisation
2022 // ========================
2023 //
2024 // This routine adjusts the bining of the axis
2025 // in order to have integer values for the labels
2026 //
2027 // _Input parameters:
2028 //
2029 // A1,A2 : Old WMIN,WMAX .
2030 // BinLow,BinHigh : New WMIN,WMAX .
2031 // nold : Old NDIV (primary divisions)
2032 // nbins : New NDIV .
2033 //
2034 BinWidth = TMath_Abs(A2-A1)/double(nold);
2035 if (BinWidth <= 1) { BinWidth = 1; BinLow = int(A1); }
2036 else {
2037 int width = int(BinWidth/5) + 1;
2038 BinWidth = 5*width;
2039 BinLow = int(A1/BinWidth)*BinWidth ;
2040
2041 // We determine BinLow to have one tick mark at 0
2042 // if there are negative labels.
2043
2044 if (A1 < 0) {
2045 for (int ic=0; ic<1000; ic++) {
2046 double rbl = BinLow/BinWidth;
2047 int ibl = int(BinLow/BinWidth);
2048 if ( (rbl-ibl) == 0 || ic > width) { BinLow -= 5; break;}
2049 }
2050 }
2051 }
2052 BinHigh = int(A2);
2053 nbins = 0;
2054 double XB = BinLow;
2055 while (XB <= BinHigh) {
2056 XB += BinWidth;
2057 nbins++;
2058 }
2059 BinHigh = XB - BinWidth;
2060 }
2061 void setLabelOffset(float aValue) { fLabelOffset = aValue;}
2062 void setLabelSize(float aValue) { fLabelSize = aValue;}
2063 void setTitleOffset(float aValue) { fTitleOffset = aValue;}
2064 void setTitleSize(float aValue) { fTitleSize = aValue; }
2065 public:
2066 void set_tick_size(float aValue) { fTickSize = aValue;}
2067
2068 private:
2069 std::ostream& m_out;
2070 //int fMaxDigits; //!Number of digits above which the 10>N notation is used
2071 private:
2072 //TObject :
2073 unsigned int fBits; //bit field status word
2074 float fTickSize; //Size of primary tick mark in NDC
2075 float fLabelOffset; //Offset of label wrt axis
2076 float fLabelSize; //Size of labels in NDC
2077 float fTitleOffset; //Offset of title wrt axis
2078 float fTitleSize; //Size of title in NDC
2079 int fLabelFont; //Font for labels
2080 std::string fTitle; //axis title
2081 std::string fTimeFormat; //Time format, ex: 09/12/99 12:34:00
2082 };
2083
2084 }}
2085
2086 #endif