Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/hplot is written in an unsupported language. File is not indexed.

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