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