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 short TMath_Abs(short d) { return (d >= 0) ? d : -d; }
0110 static int TMath_Abs(int d) { return (d >= 0) ? d : -d; }
0111 //static long TMath_Abs(long d) { return (d >= 0) ? d : -d; }
0112 //static float TMath_Abs(float d) { return (d >= 0) ? d : -d; }
0113 static double TMath_Abs(double d) { return (d >= 0) ? d : -d; }
0114
0115 static void TGaxis_Rotate(
0116 double X, double Y, double CFI, double SFI
0117 ,double XT, double YT, double &U, double &V)
0118 {
0119 U = CFI*X-SFI*Y+XT;
0120 V = SFI*X+CFI*Y+YT;
0121 }
0122
0123 public:
0124 axis(std::ostream& a_out)
0125 :m_out(a_out)
0126 //,fMaxDigits(5)
0127 ,fBits(kNotDeleted)
0128 ,fTickSize(0.03F)
0129 ,fLabelOffset(0.005F)
0130 ,fLabelSize(0.04F)
0131 ,fTitleOffset(1)
0132 ,fTitleSize(0.04F)
0133 ,fLabelFont(62)
0134 {}
0135
0136 virtual ~axis(){}
0137 private: //to discourage inheriting that.
0138 axis(const axis& a_from):m_out(a_from.m_out){}
0139 axis& operator=(const axis&){return *this;}
0140 public:
0141 void set_title(const std::string& aTitle) {
0142 fTitle = aTitle;
0143 }
0144 private:
0145 bool testBit(unsigned int f) {
0146 return (bool) ((fBits & f) != 0);
0147 }
0148
0149 static void TGaxis_LabelsLimits(std::ostream& a_out,const char *label,
0150 int &first,int &last) {
0151 last = int(::strlen(label))-1;
0152 for (int i=0; i<=last; i++) {
0153 if (::strchr("1234567890-+.", label[i]) ) { first = i; return; }
0154 }
0155 out_error(a_out,"LabelsLimits", "attempt to draw a blank label");
0156 }
0157 static void SETOPT(const std::string& aCHOPT,char aChar,int& aOpt) {
0158 aOpt = aCHOPT.find(aChar)!=std::string::npos?1:0;
0159 }
0160
0161 public:
0162 void paint(double xmin, double ymin,
0163 double xmax, double ymax,
0164 double& wmin,double& wmax,
0165 int& ndiv,const std::string& aCHOPT,
0166 double gridlength,bool drawGridOnly,
0167 std::vector<float>& aLinesAxis, //n*(2+2)
0168 std::vector<float>& aLinesGrid, //n*(2+2)
0169 std::vector<_text>& aTexts){
0170 // Control function to draw an axis
0171 // ================================
0172 //
0173 //============> Original authors (O.Couet C.E.Vandoni N.Cremel-Somon)
0174 // largely modified and converted to C++ class by Rene Brun
0175 //
0176 // _Input parameters:
0177 //
0178 // xmin : X origin coordinate in WC space.
0179 // xmax : X end axis coordinate in WC space.
0180 // ymin : Y origin coordinate in WC space.
0181 // ymax : Y end axis coordinate in WC space.
0182 // wmin : Lowest value for the tick mark
0183 // labels written on the axis.
0184 // wmax : Highest value for the tick mark labels
0185 // written on the axis.
0186 // ndiv : Number of divisions.
0187 //
0188 // ndiv=N1 + 100*N2 + 10000*N3
0189 // N1=number of 1st divisions.
0190 // N2=number of 2nd divisions.
0191 // N3=number of 3rd divisions.
0192 // e.g.:
0193 // nndi=0 --> no tick marks.
0194 // nndi=2 --> 2 divisions, one tick mark in the middle
0195 // of the axis.
0196 //
0197 // chopt : Options (see below).
0198 //
0199 // chopt='G': loGarithmic scale, default is linear.
0200 // chopt='B': Blank axis. Useful to superpose axis.
0201 //
0202 // Orientation of tick marks on axis.
0203 // ----------------------------------
0204 //
0205 // Tick marks are normally drawn on the positive side of the axis,
0206 // however, if X0=X1, then negative.
0207 //
0208 // chopt='+': tick marks are drawn on Positive side. (default)
0209 // chopt='-': tick mark are drawn on the negative side.
0210 // i.e: '+-' --> tick marks are drawn on both sides of the axis.
0211 // chopt='U': Unlabeled axis, default is labeled.
0212 //
0213 // Size of tick marks
0214 // ------------------
0215 // By default, tick marks have a length equal to 3 per cent of the
0216 // axis length.
0217 // When the option "S" is specified, the length of the tick marks
0218 // is equal to fTickSize*axis_length, where fTickSize may be set
0219 // via TGaxis::SetTickSize.
0220 //
0221 // Position of labels on axis.
0222 // ---------------------------
0223 //
0224 // Labels are normally drawn on side opposite to tick marks.
0225 // However:
0226 //
0227 // chopt='=': on Equal side
0228 //
0229 // Orientation of labels on axis.
0230 // ------------------------------
0231 //
0232 // Labels are normally drawn parallel to the axis.
0233 // However if X0=X1, then Orthogonal
0234 // if Y0=Y1, then Parallel
0235 //
0236 // Position of labels on tick marks.
0237 // ---------------------------------
0238 //
0239 // Labels are centered on tick marks.
0240 // However , if X0=X1, then they are right adjusted.
0241 //
0242 // chopt='R': labels are Right adjusted on tick mark.
0243 // (default is centered)
0244 // chopt='L': labels are Left adjusted on tick mark.
0245 // chopt='C': labels are Centered on tick mark.
0246 // chopt='M': In the Middle of the divisions.
0247 //
0248 // Format of labels.
0249 // -----------------
0250 //
0251 // Blank characters are stripped, and then the
0252 // label is correctly aligned. the dot, if last
0253 // character of the string, is also stripped,
0254 // unless the option "." (a dot, or period) is specified.
0255 // if SetDecimals(true) has been called (bit TAxis_kDecimals set).
0256 // all labels have the same number of decimals after the "."
0257 // The same is true if gStyle->SetStripDecimals(false) has been called.
0258 //
0259 // In the following, we have some parameters, like
0260 // tick marks length and characters height (in percentage
0261 // of the length of the axis (WC))
0262 // The default values are as follows:
0263 //
0264 // Primary tick marks: 3.0 %
0265 // Secondary tick marks: 1.5 %
0266 // Third order tick marks: .75 %
0267 // Characters height for labels: 4%
0268 //
0269 // Labels offset: 1.0 %
0270 //
0271 // Optional grid.
0272 // --------------
0273 //
0274 // chopt='W': cross-Wire
0275 // In case of a log axis, the grid is only drawn for the primary
0276 // tick marks if the number of secondary and tertiary divisions is 0.
0277 //
0278 // Axis bining optimization.
0279 // -------------------------
0280 //
0281 // By default the axis bining is optimized .
0282 //
0283 // chopt='N': No bining optimization
0284 // chopt='I': Integer labelling
0285 //
0286 // Maximum Number of Digits for the axis labels
0287 // --------------------------------------------
0288 // See the static function TGaxis::SetMaxDigits
0289 //
0290 // Time representation.
0291 // --------------------
0292 //
0293 // Axis labels may be considered as times, plotted in a defined
0294 // time format.
0295 // The format is set with SetTimeFormat().
0296 // wmin and wmax are considered as two time values in seconds.
0297 // The time axis will be spread around the time offset value (set with
0298 // SetTimeOffset() ). Actually it will go from TimeOffset+wmin to
0299 // TimeOffset+wmax.
0300 // see examples in tutorials timeonaxis.C and timeonaxis2.C
0301 //
0302 // chopt='t': Plot times with a defined format instead of values
0303 //
0304
0305 aLinesAxis.clear();
0306 aLinesGrid.clear();
0307 aTexts.clear();
0308
0309 double alfa, beta, ratio1, ratio2, grid_side;
0310 double axis_lengthN = 0;
0311 double axis_length0 = 0;
0312 double axis_length1 = 0;
0313 double charheight;
0314 double phil, phi, sinphi, cosphi, asinphi, acosphi;
0315 double BinLow, BinLow2, BinLow3;
0316 double BinHigh, BinHigh2, BinHigh3;
0317 double BinWidth, BinWidth2, BinWidth3;
0318 double xpl1, xpl2, ypl1, ypl2;
0319 double Xtick = 0;
0320 double Xtick0, Xtick1, DXtick=0;
0321 double Ytick, Ytick0, Ytick1;
0322 double Wlabel, DWlabel;
0323 double Xlabel, Ylabel;
0324 double DXlabel;
0325 double X0, X1, Y0, Y1, XX0, XX1, YY0, YY1;
0326 XX0 = XX1 = YY0 = YY1 = 0;
0327 double Xxmin, Xxmax, Yymin, Yymax;
0328 Xxmin = Xxmax = Yymin = Yymax = 0;
0329 double XLside,XMside;
0330 double WW, AF, RNE;
0331 double XX, YY;
0332 double Y;
0333 double Xtwo;
0334 int i, j, k, l, decade, ltick;
0335 int Mside, Lside;
0336 int IF1, IF2, NA, NF, NCH;
0337 int OptionLog,OptionBlank,OptionVert,OptionPlus,OptionMinus;
0338 int OptionUnlab,OptionPara;
0339 int OptionDown,OptionRight,OptionLeft,OptionCent,OptionEqual;
0340 int OptionDecimals=0,OptionDot;
0341 int OptionY,OptionText,OptionGrid,OptionSize,OptionNoopt;
0342 int OptionInt,OptionM,OptionUp,OptionX;
0343 int OptionTime;
0344 int first,last;
0345 int nbins;
0346 int N1Aold = 0;
0347 int NN1old = 0;
0348 int Xalign,Yalign;
0349 int ndyn;
0350 char LABEL[256];
0351 char CHTEMP[256];
0352 double rangeOffset = 0;
0353
0354 double epsilon = 1e-5;
0355 const double kPI = pi(); //GB
0356 double textSize = 0.05; //GB
0357 short textAlign = 11; //GB
0358 BinWidth = 0; //GB
0359 BinWidth2 = 0; //GB
0360 BinWidth3 = 0; //GB
0361 nbins = 0; //GB
0362 BinHigh = 0; //GB
0363 BinHigh2 = 0; //GB
0364 BinHigh3 = 0; //GB
0365 BinLow = 0; //GB
0366 BinLow2 = 0; //GB
0367 BinLow3 = 0; //GB
0368 first = 0; //GB
0369 last = 0; //GB
0370
0371 double rwmi = wmin;
0372 double rwma = wmax;
0373
0374 //out_error(m_out,"android_debug","start");
0375
0376 bool noExponent = testBit(TAxis_kNoExponent);
0377
0378 // If MoreLogLabels = true more Log Intermediate Labels are drawn.
0379 bool MoreLogLabels = testBit(TAxis_kMoreLogLabels);
0380
0381 // the following parameters correspond to the pad range in NDC
0382 // and the WC coordinates in the pad
0383
0384 double padh = 1;//FIXME gPad->GetWh()*gPad->GetAbsHNDC();
0385 double RWxmin = 0;
0386 double RWxmax = 1;
0387 double RWymin = 0;
0388 double RWymax = 1;
0389
0390 SETOPT(aCHOPT,'G',OptionLog);
0391 SETOPT(aCHOPT,'B',OptionBlank);
0392 SETOPT(aCHOPT,'V',OptionVert);
0393 SETOPT(aCHOPT,'+',OptionPlus);
0394 SETOPT(aCHOPT,'-',OptionMinus);
0395 SETOPT(aCHOPT,'U',OptionUnlab);
0396 SETOPT(aCHOPT,'P',OptionPara);
0397 SETOPT(aCHOPT,'O',OptionDown);
0398 SETOPT(aCHOPT,'R',OptionRight);
0399 SETOPT(aCHOPT,'L',OptionLeft);
0400 SETOPT(aCHOPT,'C',OptionCent);
0401 SETOPT(aCHOPT,'=',OptionEqual);
0402 SETOPT(aCHOPT,'Y',OptionY);
0403 SETOPT(aCHOPT,'T',OptionText);
0404 SETOPT(aCHOPT,'W',OptionGrid);
0405 SETOPT(aCHOPT,'S',OptionSize);
0406 SETOPT(aCHOPT,'N',OptionNoopt);
0407 SETOPT(aCHOPT,'I',OptionInt);
0408 SETOPT(aCHOPT,'M',OptionM);
0409 SETOPT(aCHOPT,'0',OptionUp);
0410 SETOPT(aCHOPT,'X',OptionX);
0411 SETOPT(aCHOPT,'t',OptionTime);
0412 SETOPT(aCHOPT,'.',OptionDot);
0413
0414 if (testBit(TAxis_kTickPlus)) OptionPlus = 2;
0415 if (testBit(TAxis_kTickMinus)) OptionMinus = 2;
0416 if (testBit(TAxis_kCenterLabels)) OptionM = 1;
0417 if (testBit(TAxis_kDecimals)) OptionDecimals = 1;
0418 /*FIXME if (fAxis) {
0419 if (fAxis->GetLabels()) {
0420 OptionM = 1;
0421 OptionText = 1;
0422 ndiv = fAxis->GetLast()-fAxis->GetFirst()+1;
0423 }
0424 }*/
0425
0426 // Set the grid length
0427
0428 if (OptionGrid) {
0429 if (gridlength == 0) gridlength = 0.8;
0430 /*FIXME
0431 linegrid = new TLine();
0432 linegrid->SetLineColor(gStyle->GetGridColor());
0433 if (linegrid->GetLineColor() == 0)
0434 linegrid->SetLineColor(GetLineColor());
0435 linegrid->SetLineStyle(gStyle->GetGridStyle());
0436 linegrid->SetLineWidth(gStyle->GetGridWidth());*/
0437 }
0438
0439
0440 if (OptionTime) {
0441 //printf("debug : SbAxisHPLOT::paint : fTimeFormat : \"%s\"\n",
0442 // fTimeFormat.c_str());
0443 }
0444
0445 //out_error(m_out,"android_debug","0000");
0446 // Determine time format
0447 std::string timeformat;
0448 std::string::size_type IdF = fTimeFormat.find("%F");
0449 if (IdF!=std::string::npos) {
0450 timeformat = fTimeFormat.substr(0,IdF);
0451 } else {
0452 timeformat = fTimeFormat;
0453 }
0454
0455 //out_error(m_out,"android_debug","0001");
0456 // determine the time offset and correct for time offset not being integer
0457 double timeoffset = 0;
0458 if (OptionTime) {
0459 if (IdF!=std::string::npos) {
0460 int LnF = int(fTimeFormat.size());
0461 std::string stringtimeoffset = fTimeFormat.substr(IdF+2,LnF-(IdF+2));
0462 int yy, mm, dd, hh, mi, ss;
0463 if (::sscanf(stringtimeoffset.c_str(),
0464 "%d-%d-%d %d:%d:%d", &yy, &mm, &dd, &hh, &mi, &ss) == 6) {
0465 struct tm tp;
0466 struct tm* tptest;
0467 time_t timeoffsettest;
0468 tp.tm_year = yy-1900;
0469 tp.tm_mon = mm-1;
0470 tp.tm_mday = dd;
0471 tp.tm_hour = hh;
0472 tp.tm_min = mi;
0473 tp.tm_sec = ss;
0474 tp.tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages)
0475 timeoffset = double(mktime(&tp));
0476 // have to correct this time to go back to UTC
0477 timeoffsettest = (time_t)((long)timeoffset);
0478 tptest = gmtime(&timeoffsettest);
0479 timeoffset += timeoffsettest - mktime(tptest);
0480 // Add the time offset's decimal part if it is there
0481 std::string::size_type Ids = stringtimeoffset.find("s");
0482 if (Ids != std::string::npos) {
0483 float dp;
0484 size_t Lns = stringtimeoffset.size();
0485 std::string sdp = stringtimeoffset.substr(Ids+1,Lns-(Ids+1));
0486 ::sscanf(sdp.c_str(),"%g",&dp);
0487 timeoffset += dp;
0488 }
0489 // if OptionTime = 2 gmtime will be used instead of localtime
0490 if (stringtimeoffset.find("GMT")!=std::string::npos)
0491 OptionTime =2;
0492 } else {
0493 out_error(m_out,"PaintAxis", "Time offset has not the right format");
0494 }
0495 } else {
0496 out_error(m_out,"PaintAxis", "%%F not found in fTimeFormat.");
0497 //FIXME timeoffset = gStyle->GetTimeOffset();
0498 }
0499 wmin += timeoffset - (int)(timeoffset);
0500 wmax += timeoffset - (int)(timeoffset);
0501 // correct for time offset at a good limit (min, hour,
0502 // day, month, year)
0503 struct tm* tp0;
0504 time_t timetp = (time_t)((long)(timeoffset));
0505 double range = wmax - wmin;
0506 long rangeBase = 60;
0507 if (range>60) rangeBase = 60*20; // minutes
0508 if (range>3600) rangeBase = 3600*20; // hours
0509 if (range>86400) rangeBase = 86400*20; // days
0510 if (range>2419200) rangeBase = 31556736; // months (average # days)
0511 rangeOffset = (double) ((long)(timeoffset)%rangeBase);
0512 if (range>31536000) {
0513 tp0 = gmtime(&timetp);
0514 tp0->tm_mon = 0;
0515 tp0->tm_mday = 1;
0516 tp0->tm_hour = 0;
0517 tp0->tm_min = 0;
0518 tp0->tm_sec = 0;
0519 tp0->tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages)
0520 rangeBase = long(timetp-mktime(tp0)); // years
0521 rangeOffset = (double) (rangeBase);
0522 }
0523 wmax += rangeOffset;
0524 wmin += rangeOffset;
0525 }
0526
0527 // Determine number of divisions 1, 2 and 3
0528 int N1A = ndiv%100;
0529 int N2A = (ndiv%10000 - N1A)/100;
0530 int N3A = ndiv/10000;
0531 int NN3 = mx<int>(N3A,1);
0532 int NN2 = mx<int>(N2A,1)*NN3;
0533 int NN1 = mx<int>(N1A,1)*NN2+1;
0534 int Nticks= NN1;
0535
0536 // Axis bining optimization is ignored if:
0537 // - the first and the last label are equal
0538 // - the number of divisions is 0
0539 // - less than 1 primary division is requested
0540 // - logarithmic scale is requested
0541
0542 if (wmin == wmax || ndiv == 0 || N1A <= 1 || OptionLog) {
0543 OptionNoopt = 1;
0544 OptionInt = 0;
0545 }
0546
0547 // Axis bining optimization
0548 if ( (wmax-wmin) < 1 && OptionInt) {
0549 out_error(m_out,"PaintAxis", "option I not available");
0550 OptionInt = 0;
0551 }
0552 //out_error(m_out,"android_debug","0002");
0553 if (!OptionNoopt || OptionInt ) {
0554
0555 // Primary divisions optimization
0556 // When integer labelling is required, Optimize is invoked first
0557 // and only if the result is not an integer labelling, AdjustBinSize
0558 // is invoked.
0559
0560 optimizeLimits(wmin,wmax,N1A,
0561 BinLow,BinHigh,nbins,BinWidth,
0562 aCHOPT);
0563 if (OptionInt) {
0564 if (BinLow != double(int(BinLow)) ||
0565 BinWidth != double(int(BinWidth))) {
0566 adjustBinSize(wmin,wmax,N1A,BinLow,BinHigh,nbins,BinWidth);
0567 }
0568 }
0569 if ((wmin-BinLow) > epsilon) { BinLow += BinWidth; nbins--; }
0570 if ((BinHigh-wmax) > epsilon) { BinHigh -= BinWidth; nbins--; }
0571 if (xmax == xmin) {
0572 double rtyw = (ymax-ymin)/(wmax-wmin);
0573 Xxmin = xmin;
0574 Xxmax = xmax;
0575 Yymin = rtyw*(BinLow-wmin) + ymin;
0576 Yymax = rtyw*(BinHigh-wmin) + ymin;
0577 } else {
0578 double rtxw = (xmax-xmin)/(wmax-wmin);
0579 Xxmin = rtxw*(BinLow-wmin) + xmin;
0580 Xxmax = rtxw*(BinHigh-wmin) + xmin;
0581 if (ymax == ymin) {
0582 Yymin = ymin;
0583 Yymax = ymax;
0584 } else {
0585 alfa = (ymax-ymin)/(xmax-xmin);
0586 beta = (ymin*xmax-ymax*xmin)/(xmax-xmin);
0587 Yymin = alfa*Xxmin + beta;
0588 Yymax = alfa*Xxmax + beta;
0589 }
0590 }
0591 /*GB if (fFunction) {
0592 Yymin = ymin;
0593 Yymax = ymax;
0594 Xxmin = xmin;
0595 Xxmax = xmax;
0596 } else*/ {
0597 wmin = BinLow;
0598 wmax = BinHigh;
0599 }
0600
0601 // Secondary divisions optimization
0602 int NB2 = N2A;
0603 if (!OptionNoopt && N2A > 1 && BinWidth > 0) {
0604 optimizeLimits(wmin,wmin+BinWidth,N2A,
0605 BinLow2,BinHigh2,NB2,BinWidth2,
0606 aCHOPT);
0607 }
0608
0609 // Tertiary divisions optimization
0610 int NB3 = N3A;
0611 if (!OptionNoopt && N3A > 1 && BinWidth2 > 0) {
0612 optimizeLimits(BinLow2,BinLow2+BinWidth2,N3A,
0613 BinLow3,BinHigh3,NB3,BinWidth3,
0614 aCHOPT);
0615 }
0616 N1Aold = N1A;
0617 NN1old = NN1;
0618 N1A = nbins;
0619 NN3 = mx<int>(NB3,1);
0620 NN2 = mx<int>(NB2,1)*NN3;
0621 NN1 = mx<int>(N1A,1)*NN2+1;
0622 Nticks = NN1;
0623 }
0624
0625 //out_error(m_out,"android_debug","0003");
0626 // Coordinates are normalized
0627
0628 ratio1 = 1/(RWxmax-RWxmin);
0629 ratio2 = 1/(RWymax-RWymin);
0630 X0 = ratio1*(xmin-RWxmin);
0631 X1 = ratio1*(xmax-RWxmin);
0632 Y0 = ratio2*(ymin-RWymin);
0633 Y1 = ratio2*(ymax-RWymin);
0634 if (!OptionNoopt || OptionInt ) {
0635 XX0 = ratio1*(Xxmin-RWxmin);
0636 XX1 = ratio1*(Xxmax-RWxmin);
0637 YY0 = ratio2*(Yymin-RWymin);
0638 YY1 = ratio2*(Yymax-RWymin);
0639 }
0640
0641 //out_error(m_out,"android_debug","0004");
0642 if ((X0 == X1) && (Y0 == Y1)) {
0643 out_error(m_out,"PaintAxis", "length of axis is 0");
0644 return;
0645 }
0646
0647 // Return wmin, wmax and the number of primary divisions
0648 if (OptionX) {
0649 ndiv = N1A;
0650 return;
0651 }
0652
0653 int maxDigits = 5;
0654 //FIXME if (fAxis) maxDigits = fMaxDigits;
0655
0656 /*FIXME
0657 TLatex *textaxis = new TLatex();
0658 lineaxis->SetLineColor(GetLineColor());
0659 lineaxis->SetLineStyle(1);
0660 lineaxis->SetLineWidth(GetLineWidth());
0661 textaxis->SetTextColor(GetTextColor());
0662 textaxis->SetTextFont(GetTextFont());
0663
0664 if (!gPad->IsBatch()) {
0665 float chupxvsav, chupyvsav;
0666 gVirtualX->GetCharacterUp(chupxvsav, chupyvsav);
0667 gVirtualX->SetClipOFF(gPad->GetCanvasID());
0668 }
0669 */
0670
0671 // Compute length of axis
0672 double axis_length = ::sqrt((X1-X0)*(X1-X0)+(Y1-Y0)*(Y1-Y0));
0673 if (axis_length == 0) {
0674 out_error(m_out,"PaintAxis", "length of axis is 0");
0675 return; //goto L210;
0676 }
0677
0678 //out_error(m_out,"android_debug","0005");
0679 if (!OptionNoopt || OptionInt) {
0680 axis_lengthN = ::sqrt((XX1-XX0)*(XX1-XX0)+(YY1-YY0)*(YY1-YY0));
0681 axis_length0 = ::sqrt((XX0-X0)*(XX0-X0)+(YY0-Y0)*(YY0-Y0));
0682 axis_length1 = ::sqrt((X1-XX1)*(X1-XX1)+(Y1-YY1)*(Y1-YY1));
0683 if (axis_lengthN < epsilon) {
0684 OptionNoopt = 1;
0685 OptionInt = 0;
0686 wmin = rwmi;
0687 wmax = rwma;
0688 N1A = N1Aold;
0689 NN1 = NN1old;
0690 Nticks = NN1;
0691 if (OptionTime) {
0692 wmin += timeoffset - (int)(timeoffset) + rangeOffset;
0693 wmax += timeoffset - (int)(timeoffset) + rangeOffset;
0694 }
0695 }
0696 }
0697
0698 //out_error(m_out,"android_debug","0006");
0699 if (X0 == X1) {
0700 phi = 0.5*kPI;
0701 phil = phi;
0702 } else {
0703 phi = TMath_ATan2((Y1-Y0),(X1-X0));
0704 int px0 = 0;//FIXME gPad->UtoPixel(X0);
0705 int py0 = 0;//FIXME gPad->VtoPixel(Y0);
0706 int px1 = 0;//FIXME gPad->UtoPixel(X1);
0707 int py1 = 0;//FIXME gPad->VtoPixel(Y1);
0708 if (X0 < X1) phil = TMath_ATan2(double(py0-py1), double(px1-px0));
0709 else phil = TMath_ATan2(double(py1-py0), double(px0-px1));
0710 }
0711 cosphi = ::cos(phi);
0712 sinphi = ::sin(phi);
0713 acosphi = TMath_Abs(cosphi);
0714 asinphi = TMath_Abs(sinphi);
0715 if (acosphi <= epsilon) { acosphi = 0; cosphi = 0; }
0716 if (asinphi <= epsilon) { asinphi = 0; sinphi = 0; }
0717
0718 //out_error(m_out,"android_debug","0007");
0719 // Mside positive, tick marks on positive side
0720 // Mside negative, tick marks on negative side
0721 // Mside zero, tick marks on both sides
0722 // Default is positive except for vertical axis
0723
0724 Mside=1;
0725 if (X0 == X1 && Y1 > Y0) Mside = -1;
0726 if (OptionPlus) Mside = 1;
0727 if (OptionMinus) Mside = -1;
0728 if (OptionPlus && OptionMinus) Mside = 0;
0729 XMside = Mside;
0730 Lside = -Mside;
0731 if (OptionEqual) Lside = Mside;
0732 if (OptionPlus && OptionMinus) {
0733 Lside = -1;
0734 if (OptionEqual) Lside=1;
0735 }
0736 XLside = Lside;
0737
0738 // Tick marks size
0739 double tick_side;
0740 if(XMside >= 0) tick_side = 1;
0741 else tick_side = -1;
0742
0743 double atick[3];
0744 if (OptionSize) atick[0] = tick_side*axis_length*fTickSize;
0745 else atick[0] = tick_side*axis_length*0.03;
0746
0747 atick[1] = 0.5*atick[0];
0748 atick[2] = 0.5*atick[1];
0749
0750 // Set the side of the grid
0751 if ((X0 == X1) && (Y1 > Y0)) grid_side =-1;
0752 else grid_side = 1;
0753
0754
0755 //out_error(m_out,"android_debug","0008");
0756 // Compute Values if Function is given
0757 /*GB if(fFunction) {
0758 rwmi = fFunction->Eval(wmin);
0759 rwma = fFunction->Eval(wmax);
0760 if(rwmi > rwma) {
0761 double t = rwma;
0762 rwma = rwmi;
0763 rwmi = t;
0764 }
0765 }*/
0766
0767 // Draw the axis if needed...
0768 if (!OptionBlank) {
0769 xpl1 = X0;
0770 xpl2 = X1;
0771 ypl1 = Y0;
0772 ypl2 = Y1;
0773 aLinesAxis.push_back((float)xpl1);
0774 aLinesAxis.push_back((float)ypl1);
0775 aLinesAxis.push_back((float)xpl2);
0776 aLinesAxis.push_back((float)ypl2);
0777 }
0778
0779 //out_error(m_out,"android_debug","0009");
0780 // No bining
0781
0782 if (ndiv == 0) return; //goto L210;
0783 if (wmin == wmax) {
0784 out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f)", wmin, wmax);
0785 return; //goto L210;
0786 }
0787
0788 // Draw axis title if it exists
0789 if (!drawGridOnly && fTitle.size()) {
0790 textSize = fTitleSize;
0791 charheight = fTitleSize;
0792 if ((GetTextFont() % 10) > 2) {
0793 //FIXME charheight = charheight/gPad->GetWh();
0794 }
0795 double toffset = fTitleOffset;
0796 if (toffset < 0.1) toffset = 1;
0797 if (X1 == X0) Ylabel = XLside*1.6*charheight*toffset;
0798 else Ylabel = XLside*1.3*charheight*toffset;
0799 if (Y1 == Y0) Ylabel = XLside*1.6*charheight*toffset;
0800 double axispos;
0801 if (testBit(TAxis_kCenterTitle)) axispos = 0.5*axis_length;
0802 else axispos = axis_length;
0803 if (testBit(TAxis_kRotateTitle)) {
0804 if (X1 >= X0) {
0805 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0806 else textAlign = 12;
0807 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0808 } else {
0809 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0810 else textAlign = 32;
0811 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0812 }
0813 out_error(m_out,"PaintAxis","debug : texts : dummy : 000\n");
0814 aTexts.push_back(_text(xpl1,ypl1,
0815 phil=(kPI+phil)*180/kPI,
0816 fTitleSize,
0817 fTitle,textAlign));
0818 } else {
0819 if (X1 >= X0) {
0820 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0821 else textAlign = 32;
0822 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0823 } else {
0824 if (testBit(TAxis_kCenterTitle)) textAlign = 22;
0825 else textAlign = 12;
0826 TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
0827 }
0828 aTexts.push_back(_text(xpl1,ypl1,
0829 phil*180/kPI,fTitleSize,
0830 fTitle,textAlign));
0831 }
0832 }
0833
0834 //out_error(m_out,"android_debug","0010");
0835 // Labels preparation:
0836 // Get character height
0837 // Compute the labels orientation in case of overlaps
0838 // with alphanumeric labels for horizontal axis).
0839
0840 charheight = fLabelSize;
0841 if (OptionText) charheight *= 0.66666;
0842 //FIXME textaxis->SetTextFont(fLabelFont);
0843 //FIXME textaxis->SetTextColor(GetLabelColor());
0844 textSize = charheight;
0845 //FIXME textaxis->SetTextAngle(GetTextAngle());
0846 if (fLabelFont%10 > 2) {
0847 charheight /= padh;
0848 }
0849 if (!OptionUp && !OptionDown && !OptionY) {
0850 if (!drawGridOnly && OptionText && ((ymin == ymax) || (xmin == xmax))) {
0851 textAlign = 32;
0852 OptionText = 2;
0853 //int nl = 0;//FIXME fAxis->GetLast()-fAxis->GetFirst()+1;
0854 //double angle = 0;
0855 out_error(m_out,"PaintAxis","debug : FIXME : 000\n");
0856 /*FIXME
0857 for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
0858 textaxis->SetText(0,0,fAxis->GetBinLabel(i));
0859 if (textaxis->GetXsize() < (xmax-xmin)/nl) continue;
0860 angle = -20;
0861 break;
0862 }
0863 for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
0864 if ((!::strcmp(fAxis->GetName(),"xaxis") && !gPad->testBit(kHori))
0865 ||(!::strcmp(fAxis->GetName(),"yaxis") && gPad->testBit(kHori))) {
0866 if (nl > 50) angle = 90;
0867 if (fAxis->testBit(TAxis_kLabelsHori)) angle = 0;
0868 if (fAxis->testBit(TAxis_kLabelsVert)) angle = 90;
0869 if (fAxis->testBit(TAxis_kLabelsUp)) angle = 20;
0870 if (fAxis->testBit(TAxis_kLabelsDown)) angle =-20;
0871 if (angle== 0) textAlign = 23;
0872 if (angle== -20) textAlign = 12;
0873 out_error(m_out,"PaintAxis","debug : texts : dummy : 002\n");
0874 textaxis->PaintLatex(
0875 fAxis->GetBinCenter(i),
0876 gPad->GetUymin() - 3*fAxis->GetLabelOffset()*
0877 (gPad->GetUymax()-gPad->GetUymin()),
0878 angle,
0879 charheight,
0880 fAxis->GetBinLabel(i));
0881 } else if ((!::strcmp(fAxis->GetName(),"yaxis") && !gPad->testBit(kHori))
0882 || (!::strcmp(fAxis->GetName(),"xaxis") && gPad->testBit(kHori))) {
0883 out_error(m_out,"PaintAxis","debug : texts : dummy : 003\n");
0884 textaxis->PaintLatex(
0885 gPad->GetUxmin() - 3*fAxis->GetLabelOffset()*
0886 (gPad->GetUxmax()-gPad->GetUxmin()),
0887 fAxis->GetBinCenter(i),
0888 0,
0889 charheight,
0890 fAxis->GetBinLabel(i));
0891 } else {
0892 out_error(m_out,"PaintAxis","debug : texts : dummy : 004\n");
0893 textaxis->PaintLatex(
0894 xmin - 3*fAxis->GetLabelOffset()*
0895 (gPad->GetUxmax()-gPad->GetUxmin()),
0896 ymin +(i-0.5)*(ymax-ymin)/nl,
0897 0,
0898 charheight,
0899 fAxis->GetBinLabel(i));
0900 }
0901 }*/
0902 }
0903 }
0904
0905 //out_error(m_out,"android_debug","0011");
0906 // Now determine orientation of labels on axis
0907 /*FIXME
0908 if (!gPad->IsBatch()) {
0909 if (cosphi > 0) gVirtualX->SetCharacterUp(-sinphi,cosphi);
0910 else gVirtualX->SetCharacterUp(sinphi,-cosphi);
0911 if (X0 == X1) gVirtualX->SetCharacterUp(0,1);
0912 if (OptionVert) gVirtualX->SetCharacterUp(0,1);
0913 if (OptionPara) gVirtualX->SetCharacterUp(-sinphi,cosphi);
0914 if (OptionDown) gVirtualX->SetCharacterUp(cosphi,sinphi);
0915 }*/
0916
0917 // Now determine text alignment
0918 Xalign = 2;
0919 Yalign = 1;
0920 if (X0 == X1) Xalign = 3;
0921 if (Y0 != Y1) Yalign = 2;
0922 if (OptionCent) Xalign = 2;
0923 if (OptionRight) Xalign = 3;
0924 if (OptionLeft) Xalign = 1;
0925 if (TMath_Abs(cosphi) > 0.9) {
0926 Xalign = 2;
0927 } else {
0928 if (cosphi*sinphi > 0) Xalign = 1;
0929 if (cosphi*sinphi < 0) Xalign = 3;
0930 }
0931 textAlign = 10*Xalign+Yalign;
0932
0933 //out_error(m_out,"android_debug","0012");
0934 // Position of labels in Y
0935 if (X0 == X1) {
0936 if (OptionPlus && !OptionMinus) {
0937 if (OptionEqual) Ylabel = fLabelOffset/2 + atick[0];
0938 else Ylabel = -fLabelOffset;
0939 } else {
0940 Ylabel = fLabelOffset;
0941 if (Lside < 0) Ylabel += atick[0];
0942 }
0943 } else if (Y0 == Y1) {
0944 if (OptionMinus && !OptionPlus) {
0945 Ylabel = fLabelOffset+0.5*fLabelSize;
0946 Ylabel += TMath_Abs(atick[0]);
0947 } else {
0948 Ylabel = -fLabelOffset;
0949 if (Mside <= 0) Ylabel -= TMath_Abs(atick[0]);
0950 }
0951 if (OptionLog) Ylabel -= 0.5*charheight;
0952 } else {
0953 if (Mside+Lside >= 0) Ylabel = fLabelOffset;
0954 else Ylabel = -fLabelOffset;
0955 }
0956 if (OptionText) Ylabel /= 2;
0957
0958 //out_error(m_out,"android_debug","0013");
0959 // Draw the linear tick marks if needed...
0960 if (!OptionLog) {
0961 if (ndiv) {
0962 /*GB if (fFunction) {
0963 if (OptionNoopt && !OptionInt) {
0964 DXtick=(BinHigh-BinLow)/double(Nticks-1);
0965 } else {
0966 DXtick=(BinHigh-BinLow)/double(Nticks-1);
0967 }
0968 } else */ {
0969 if (OptionNoopt && !OptionInt) DXtick=axis_length/double(Nticks-1);
0970 else DXtick=axis_lengthN/double(Nticks-1);
0971 }
0972 for (k=0;k<Nticks; k++) {
0973 ltick = 2;
0974 if (k%NN3 == 0) ltick = 1;
0975 if (k%NN2 == 0) ltick = 0;
0976 /*GB if (fFunction) {
0977 double xx = BinLow+double(k)*DXtick;
0978 double zz = fFunction->Eval(xx)-rwmi;
0979 Xtick = zz* axis_length / TMath_Abs(rwma-rwmi);
0980 } else */ {
0981 Xtick = double(k)*DXtick;
0982 }
0983 Ytick = 0;
0984 if (!Mside) Ytick -= atick[ltick];
0985 if ( OptionNoopt && !OptionInt) {
0986 TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,X0,Y0,xpl2,ypl2);
0987 TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,X0,Y0,xpl1,ypl1);
0988 }
0989 else {
0990 TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,XX0,YY0,xpl2,ypl2);
0991 TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,XX0,YY0,xpl1,ypl1);
0992 }
0993 if (OptionVert) {
0994 if ((X0 != X1) && (Y0 != Y1)) {
0995 if (Mside) {
0996 xpl1 = xpl2;
0997 if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
0998 else ypl1 = ypl2 - atick[ltick];
0999 }
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