2109 lines
77 KiB
Plaintext
2109 lines
77 KiB
Plaintext
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
|
// See the file tools.license for terms.
|
|
|
|
#ifndef tools_hplot
|
|
#define tools_hplot
|
|
|
|
// Used in exlib::sg::axis.
|
|
//
|
|
// Code extracted from ROOT-4.03.02/root/graf/stc/TGaxis.cxx.
|
|
// Itself built from code extracted from HPLOT.
|
|
//
|
|
// Take care, all the below is highly disgusting...
|
|
// (You can even find.. gotos !)
|
|
//
|
|
// Except for the public methods we let the style "as it".
|
|
|
|
#include "mnmx"
|
|
#include "lina/vec3f"
|
|
#include "mathd" //pi
|
|
#include "snpf"
|
|
#include "out_error"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <cstring>
|
|
#include <ctime>
|
|
#include <cmath>
|
|
#include <cfloat>
|
|
|
|
namespace tools {
|
|
namespace hplot {
|
|
|
|
class _text {
|
|
public:
|
|
_text(double aX,double aY,
|
|
double aAngle,double aSize,
|
|
const std::string& aString,
|
|
short aAlign)
|
|
:fX(aX),fY(aY)
|
|
,fAngle(aAngle),fSize(aSize)
|
|
,fString(aString),fAlign(aAlign)
|
|
{}
|
|
virtual ~_text(){}
|
|
public:
|
|
_text(const _text& aFrom)
|
|
:fX(aFrom.fX),fY(aFrom.fY)
|
|
,fAngle(aFrom.fAngle),fSize(aFrom.fSize)
|
|
,fString(aFrom.fString)
|
|
,fAlign(aFrom.fAlign)
|
|
{}
|
|
_text& operator=(const _text& aFrom){
|
|
fX = aFrom.fX;
|
|
fY = aFrom.fY;
|
|
fAngle = aFrom.fAngle;
|
|
fSize = aFrom.fSize;
|
|
fString = aFrom.fString;
|
|
fAlign = aFrom.fAlign;
|
|
return *this;
|
|
}
|
|
public:
|
|
double fX;
|
|
double fY;
|
|
double fAngle; //Degree
|
|
double fSize;
|
|
std::string fString;
|
|
short fAlign;
|
|
};
|
|
|
|
|
|
class axis {
|
|
|
|
// Ok, you really want to read all that. You had been warned...
|
|
|
|
enum {
|
|
TAxis_kTickPlus = (1<<(9)),
|
|
TAxis_kTickMinus = (1<<(10)),
|
|
TAxis_kAxisRange = (1<<(11)),
|
|
TAxis_kCenterTitle = (1<<(12)),
|
|
TAxis_kCenterLabels = (1<<(14)), //bit 13 is used by TObject
|
|
TAxis_kRotateTitle = (1<<(15)),
|
|
TAxis_kPalette = (1<<(16)),
|
|
TAxis_kNoExponent = (1<<(17)),
|
|
TAxis_kLabelsHori = (1<<(18)),
|
|
TAxis_kLabelsVert = (1<<(19)),
|
|
TAxis_kLabelsDown = (1<<(20)),
|
|
TAxis_kLabelsUp = (1<<(21)),
|
|
TAxis_kIsInteger = (1<<(22)),
|
|
TAxis_kMoreLogLabels = (1<<(23)),
|
|
TAxis_kDecimals = (1<<(11))
|
|
}; //in fBits2
|
|
|
|
enum {
|
|
kIsOnHeap = 0x01000000, // object is on heap
|
|
kNotDeleted = 0x02000000, // object has not been deleted
|
|
kZombie = 0x04000000, // object ctor failed
|
|
kBitMask = 0x00ffffff
|
|
};
|
|
|
|
static int GetTextFont() { return 132;}
|
|
|
|
static double TMath_ATan2(double y, double x) {
|
|
if (x != 0) return ::atan2(y, x);
|
|
if (y == 0) return 0;
|
|
if (y > 0) return tools::half_pi();
|
|
else return -tools::half_pi();
|
|
}
|
|
|
|
//static short TMath_Abs(short d) { return (d >= 0) ? d : -d; }
|
|
static int TMath_Abs(int d) { return (d >= 0) ? d : -d; }
|
|
//static long TMath_Abs(long d) { return (d >= 0) ? d : -d; }
|
|
//static float TMath_Abs(float d) { return (d >= 0) ? d : -d; }
|
|
static double TMath_Abs(double d) { return (d >= 0) ? d : -d; }
|
|
|
|
static void TGaxis_Rotate(
|
|
double X, double Y, double CFI, double SFI
|
|
,double XT, double YT, double &U, double &V)
|
|
{
|
|
U = CFI*X-SFI*Y+XT;
|
|
V = SFI*X+CFI*Y+YT;
|
|
}
|
|
|
|
public:
|
|
axis(std::ostream& a_out)
|
|
:m_out(a_out)
|
|
//,fMaxDigits(5)
|
|
,fBits(kNotDeleted)
|
|
,fTickSize(0.03F)
|
|
,fLabelOffset(0.005F)
|
|
,fLabelSize(0.04F)
|
|
,fTitleOffset(1)
|
|
,fTitleSize(0.04F)
|
|
,fLabelFont(62)
|
|
{}
|
|
|
|
virtual ~axis(){}
|
|
private: //to discourage inheriting that.
|
|
axis(const axis& a_from):m_out(a_from.m_out){}
|
|
axis& operator=(const axis&){return *this;}
|
|
public:
|
|
void set_title(const std::string& aTitle) {
|
|
fTitle = aTitle;
|
|
}
|
|
private:
|
|
bool testBit(unsigned int f) {
|
|
return (bool) ((fBits & f) != 0);
|
|
}
|
|
|
|
static void TGaxis_LabelsLimits(std::ostream& a_out,const char *label,
|
|
int &first,int &last) {
|
|
last = int(::strlen(label))-1;
|
|
for (int i=0; i<=last; i++) {
|
|
if (::strchr("1234567890-+.", label[i]) ) { first = i; return; }
|
|
}
|
|
out_error(a_out,"LabelsLimits", "attempt to draw a blank label");
|
|
}
|
|
static void SETOPT(const std::string& aCHOPT,char aChar,int& aOpt) {
|
|
aOpt = aCHOPT.find(aChar)!=std::string::npos?1:0;
|
|
}
|
|
|
|
public:
|
|
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, //n*(2+2)
|
|
std::vector<float>& aLinesGrid, //n*(2+2)
|
|
std::vector<_text>& aTexts){
|
|
// Control function to draw an axis
|
|
// ================================
|
|
//
|
|
//============> Original authors (O.Couet C.E.Vandoni N.Cremel-Somon)
|
|
// largely modified and converted to C++ class by Rene Brun
|
|
//
|
|
// _Input parameters:
|
|
//
|
|
// xmin : X origin coordinate in WC space.
|
|
// xmax : X end axis coordinate in WC space.
|
|
// ymin : Y origin coordinate in WC space.
|
|
// ymax : Y end axis coordinate in WC space.
|
|
// wmin : Lowest value for the tick mark
|
|
// labels written on the axis.
|
|
// wmax : Highest value for the tick mark labels
|
|
// written on the axis.
|
|
// ndiv : Number of divisions.
|
|
//
|
|
// ndiv=N1 + 100*N2 + 10000*N3
|
|
// N1=number of 1st divisions.
|
|
// N2=number of 2nd divisions.
|
|
// N3=number of 3rd divisions.
|
|
// e.g.:
|
|
// nndi=0 --> no tick marks.
|
|
// nndi=2 --> 2 divisions, one tick mark in the middle
|
|
// of the axis.
|
|
//
|
|
// chopt : Options (see below).
|
|
//
|
|
// chopt='G': loGarithmic scale, default is linear.
|
|
// chopt='B': Blank axis. Useful to superpose axis.
|
|
//
|
|
// Orientation of tick marks on axis.
|
|
// ----------------------------------
|
|
//
|
|
// Tick marks are normally drawn on the positive side of the axis,
|
|
// however, if X0=X1, then negative.
|
|
//
|
|
// chopt='+': tick marks are drawn on Positive side. (default)
|
|
// chopt='-': tick mark are drawn on the negative side.
|
|
// i.e: '+-' --> tick marks are drawn on both sides of the axis.
|
|
// chopt='U': Unlabeled axis, default is labeled.
|
|
//
|
|
// Size of tick marks
|
|
// ------------------
|
|
// By default, tick marks have a length equal to 3 per cent of the
|
|
// axis length.
|
|
// When the option "S" is specified, the length of the tick marks
|
|
// is equal to fTickSize*axis_length, where fTickSize may be set
|
|
// via TGaxis::SetTickSize.
|
|
//
|
|
// Position of labels on axis.
|
|
// ---------------------------
|
|
//
|
|
// Labels are normally drawn on side opposite to tick marks.
|
|
// However:
|
|
//
|
|
// chopt='=': on Equal side
|
|
//
|
|
// Orientation of labels on axis.
|
|
// ------------------------------
|
|
//
|
|
// Labels are normally drawn parallel to the axis.
|
|
// However if X0=X1, then Orthogonal
|
|
// if Y0=Y1, then Parallel
|
|
//
|
|
// Position of labels on tick marks.
|
|
// ---------------------------------
|
|
//
|
|
// Labels are centered on tick marks.
|
|
// However , if X0=X1, then they are right adjusted.
|
|
//
|
|
// chopt='R': labels are Right adjusted on tick mark.
|
|
// (default is centered)
|
|
// chopt='L': labels are Left adjusted on tick mark.
|
|
// chopt='C': labels are Centered on tick mark.
|
|
// chopt='M': In the Middle of the divisions.
|
|
//
|
|
// Format of labels.
|
|
// -----------------
|
|
//
|
|
// Blank characters are stripped, and then the
|
|
// label is correctly aligned. the dot, if last
|
|
// character of the string, is also stripped,
|
|
// unless the option "." (a dot, or period) is specified.
|
|
// if SetDecimals(true) has been called (bit TAxis_kDecimals set).
|
|
// all labels have the same number of decimals after the "."
|
|
// The same is true if gStyle->SetStripDecimals(false) has been called.
|
|
//
|
|
// In the following, we have some parameters, like
|
|
// tick marks length and characters height (in percentage
|
|
// of the length of the axis (WC))
|
|
// The default values are as follows:
|
|
//
|
|
// Primary tick marks: 3.0 %
|
|
// Secondary tick marks: 1.5 %
|
|
// Third order tick marks: .75 %
|
|
// Characters height for labels: 4%
|
|
//
|
|
// Labels offset: 1.0 %
|
|
//
|
|
// Optional grid.
|
|
// --------------
|
|
//
|
|
// chopt='W': cross-Wire
|
|
// In case of a log axis, the grid is only drawn for the primary
|
|
// tick marks if the number of secondary and tertiary divisions is 0.
|
|
//
|
|
// Axis bining optimization.
|
|
// -------------------------
|
|
//
|
|
// By default the axis bining is optimized .
|
|
//
|
|
// chopt='N': No bining optimization
|
|
// chopt='I': Integer labelling
|
|
//
|
|
// Maximum Number of Digits for the axis labels
|
|
// --------------------------------------------
|
|
// See the static function TGaxis::SetMaxDigits
|
|
//
|
|
// Time representation.
|
|
// --------------------
|
|
//
|
|
// Axis labels may be considered as times, plotted in a defined
|
|
// time format.
|
|
// The format is set with SetTimeFormat().
|
|
// wmin and wmax are considered as two time values in seconds.
|
|
// The time axis will be spread around the time offset value (set with
|
|
// SetTimeOffset() ). Actually it will go from TimeOffset+wmin to
|
|
// TimeOffset+wmax.
|
|
// see examples in tutorials timeonaxis.C and timeonaxis2.C
|
|
//
|
|
// chopt='t': Plot times with a defined format instead of values
|
|
//
|
|
|
|
aLinesAxis.clear();
|
|
aLinesGrid.clear();
|
|
aTexts.clear();
|
|
|
|
double alfa, beta, ratio1, ratio2, grid_side;
|
|
double axis_lengthN = 0;
|
|
double axis_length0 = 0;
|
|
double axis_length1 = 0;
|
|
double charheight;
|
|
double phil, phi, sinphi, cosphi, asinphi, acosphi;
|
|
double BinLow, BinLow2, BinLow3;
|
|
double BinHigh, BinHigh2, BinHigh3;
|
|
double BinWidth, BinWidth2, BinWidth3;
|
|
double xpl1, xpl2, ypl1, ypl2;
|
|
double Xtick = 0;
|
|
double Xtick0, Xtick1, DXtick=0;
|
|
double Ytick, Ytick0, Ytick1;
|
|
double Wlabel, DWlabel;
|
|
double Xlabel, Ylabel;
|
|
double DXlabel;
|
|
double X0, X1, Y0, Y1, XX0, XX1, YY0, YY1;
|
|
XX0 = XX1 = YY0 = YY1 = 0;
|
|
double Xxmin, Xxmax, Yymin, Yymax;
|
|
Xxmin = Xxmax = Yymin = Yymax = 0;
|
|
double XLside,XMside;
|
|
double WW, AF, RNE;
|
|
double XX, YY;
|
|
double Y;
|
|
double Xtwo;
|
|
int i, j, k, l, decade, ltick;
|
|
int Mside, Lside;
|
|
int IF1, IF2, NA, NF, NCH;
|
|
int OptionLog,OptionBlank,OptionVert,OptionPlus,OptionMinus;
|
|
int OptionUnlab,OptionPara;
|
|
int OptionDown,OptionRight,OptionLeft,OptionCent,OptionEqual;
|
|
int OptionDecimals=0,OptionDot;
|
|
int OptionY,OptionText,OptionGrid,OptionSize,OptionNoopt;
|
|
int OptionInt,OptionM,OptionUp,OptionX;
|
|
int OptionTime;
|
|
int first,last;
|
|
int nbins;
|
|
int N1Aold = 0;
|
|
int NN1old = 0;
|
|
int Xalign,Yalign;
|
|
int ndyn;
|
|
char LABEL[256];
|
|
char CHTEMP[256];
|
|
double rangeOffset = 0;
|
|
|
|
double epsilon = 1e-5;
|
|
const double kPI = tools::pi(); //GB
|
|
double textSize = 0.05; //GB
|
|
short textAlign = 11; //GB
|
|
BinWidth = 0; //GB
|
|
BinWidth2 = 0; //GB
|
|
BinWidth3 = 0; //GB
|
|
nbins = 0; //GB
|
|
BinHigh = 0; //GB
|
|
BinHigh2 = 0; //GB
|
|
BinHigh3 = 0; //GB
|
|
BinLow = 0; //GB
|
|
BinLow2 = 0; //GB
|
|
BinLow3 = 0; //GB
|
|
first = 0; //GB
|
|
last = 0; //GB
|
|
|
|
double rwmi = wmin;
|
|
double rwma = wmax;
|
|
|
|
//out_error(m_out,"android_debug","start");
|
|
|
|
bool noExponent = testBit(TAxis_kNoExponent);
|
|
|
|
// If MoreLogLabels = true more Log Intermediate Labels are drawn.
|
|
bool MoreLogLabels = testBit(TAxis_kMoreLogLabels);
|
|
|
|
// the following parameters correspond to the pad range in NDC
|
|
// and the WC coordinates in the pad
|
|
|
|
double padh = 1;//FIXME gPad->GetWh()*gPad->GetAbsHNDC();
|
|
double RWxmin = 0;
|
|
double RWxmax = 1;
|
|
double RWymin = 0;
|
|
double RWymax = 1;
|
|
|
|
SETOPT(aCHOPT,'G',OptionLog);
|
|
SETOPT(aCHOPT,'B',OptionBlank);
|
|
SETOPT(aCHOPT,'V',OptionVert);
|
|
SETOPT(aCHOPT,'+',OptionPlus);
|
|
SETOPT(aCHOPT,'-',OptionMinus);
|
|
SETOPT(aCHOPT,'U',OptionUnlab);
|
|
SETOPT(aCHOPT,'P',OptionPara);
|
|
SETOPT(aCHOPT,'O',OptionDown);
|
|
SETOPT(aCHOPT,'R',OptionRight);
|
|
SETOPT(aCHOPT,'L',OptionLeft);
|
|
SETOPT(aCHOPT,'C',OptionCent);
|
|
SETOPT(aCHOPT,'=',OptionEqual);
|
|
SETOPT(aCHOPT,'Y',OptionY);
|
|
SETOPT(aCHOPT,'T',OptionText);
|
|
SETOPT(aCHOPT,'W',OptionGrid);
|
|
SETOPT(aCHOPT,'S',OptionSize);
|
|
SETOPT(aCHOPT,'N',OptionNoopt);
|
|
SETOPT(aCHOPT,'I',OptionInt);
|
|
SETOPT(aCHOPT,'M',OptionM);
|
|
SETOPT(aCHOPT,'0',OptionUp);
|
|
SETOPT(aCHOPT,'X',OptionX);
|
|
SETOPT(aCHOPT,'t',OptionTime);
|
|
SETOPT(aCHOPT,'.',OptionDot);
|
|
|
|
if (testBit(TAxis_kTickPlus)) OptionPlus = 2;
|
|
if (testBit(TAxis_kTickMinus)) OptionMinus = 2;
|
|
if (testBit(TAxis_kCenterLabels)) OptionM = 1;
|
|
if (testBit(TAxis_kDecimals)) OptionDecimals = 1;
|
|
/*FIXME if (fAxis) {
|
|
if (fAxis->GetLabels()) {
|
|
OptionM = 1;
|
|
OptionText = 1;
|
|
ndiv = fAxis->GetLast()-fAxis->GetFirst()+1;
|
|
}
|
|
}*/
|
|
|
|
// Set the grid length
|
|
|
|
if (OptionGrid) {
|
|
if (gridlength == 0) gridlength = 0.8;
|
|
/*FIXME
|
|
linegrid = new TLine();
|
|
linegrid->SetLineColor(gStyle->GetGridColor());
|
|
if (linegrid->GetLineColor() == 0)
|
|
linegrid->SetLineColor(GetLineColor());
|
|
linegrid->SetLineStyle(gStyle->GetGridStyle());
|
|
linegrid->SetLineWidth(gStyle->GetGridWidth());*/
|
|
}
|
|
|
|
|
|
if (OptionTime) {
|
|
//printf("debug : SbAxisHPLOT::paint : fTimeFormat : \"%s\"\n",
|
|
// fTimeFormat.c_str());
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0000");
|
|
// Determine time format
|
|
std::string timeformat;
|
|
std::string::size_type IdF = fTimeFormat.find("%F");
|
|
if (IdF!=std::string::npos) {
|
|
timeformat = fTimeFormat.substr(0,IdF);
|
|
} else {
|
|
timeformat = fTimeFormat;
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0001");
|
|
// determine the time offset and correct for time offset not being integer
|
|
double timeoffset = 0;
|
|
if (OptionTime) {
|
|
if (IdF!=std::string::npos) {
|
|
int LnF = int(fTimeFormat.size());
|
|
std::string stringtimeoffset = fTimeFormat.substr(IdF+2,LnF-(IdF+2));
|
|
int yy, mm, dd, hh, mi, ss;
|
|
if (::sscanf(stringtimeoffset.c_str(),
|
|
"%d-%d-%d %d:%d:%d", &yy, &mm, &dd, &hh, &mi, &ss) == 6) {
|
|
struct tm tp;
|
|
struct tm* tptest;
|
|
time_t timeoffsettest;
|
|
tp.tm_year = yy-1900;
|
|
tp.tm_mon = mm-1;
|
|
tp.tm_mday = dd;
|
|
tp.tm_hour = hh;
|
|
tp.tm_min = mi;
|
|
tp.tm_sec = ss;
|
|
tp.tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages)
|
|
timeoffset = double(mktime(&tp));
|
|
// have to correct this time to go back to UTC
|
|
timeoffsettest = (time_t)((long)timeoffset);
|
|
tptest = gmtime(&timeoffsettest);
|
|
timeoffset += timeoffsettest - mktime(tptest);
|
|
// Add the time offset's decimal part if it is there
|
|
std::string::size_type Ids = stringtimeoffset.find("s");
|
|
if (Ids != std::string::npos) {
|
|
float dp;
|
|
size_t Lns = stringtimeoffset.size();
|
|
std::string sdp = stringtimeoffset.substr(Ids+1,Lns-(Ids+1));
|
|
::sscanf(sdp.c_str(),"%g",&dp);
|
|
timeoffset += dp;
|
|
}
|
|
// if OptionTime = 2 gmtime will be used instead of localtime
|
|
if (stringtimeoffset.find("GMT")!=std::string::npos)
|
|
OptionTime =2;
|
|
} else {
|
|
out_error(m_out,"PaintAxis", "Time offset has not the right format");
|
|
}
|
|
} else {
|
|
out_error(m_out,"PaintAxis", "%%F not found in fTimeFormat.");
|
|
//FIXME timeoffset = gStyle->GetTimeOffset();
|
|
}
|
|
wmin += timeoffset - (int)(timeoffset);
|
|
wmax += timeoffset - (int)(timeoffset);
|
|
// correct for time offset at a good limit (min, hour,
|
|
// day, month, year)
|
|
struct tm* tp0;
|
|
time_t timetp = (time_t)((long)(timeoffset));
|
|
double range = wmax - wmin;
|
|
long rangeBase = 60;
|
|
if (range>60) rangeBase = 60*20; // minutes
|
|
if (range>3600) rangeBase = 3600*20; // hours
|
|
if (range>86400) rangeBase = 86400*20; // days
|
|
if (range>2419200) rangeBase = 31556736; // months (average # days)
|
|
rangeOffset = (double) ((long)(timeoffset)%rangeBase);
|
|
if (range>31536000) {
|
|
tp0 = gmtime(&timetp);
|
|
tp0->tm_mon = 0;
|
|
tp0->tm_mday = 1;
|
|
tp0->tm_hour = 0;
|
|
tp0->tm_min = 0;
|
|
tp0->tm_sec = 0;
|
|
tp0->tm_isdst = 0; // daylight saving time is not in effect (see mktime man pages)
|
|
rangeBase = long(timetp-mktime(tp0)); // years
|
|
rangeOffset = (double) (rangeBase);
|
|
}
|
|
wmax += rangeOffset;
|
|
wmin += rangeOffset;
|
|
}
|
|
|
|
// Determine number of divisions 1, 2 and 3
|
|
int N1A = ndiv%100;
|
|
int N2A = (ndiv%10000 - N1A)/100;
|
|
int N3A = ndiv/10000;
|
|
int NN3 = tools::mx(N3A,1);
|
|
int NN2 = tools::mx(N2A,1)*NN3;
|
|
int NN1 = tools::mx(N1A,1)*NN2+1;
|
|
int Nticks= NN1;
|
|
|
|
// Axis bining optimization is ignored if:
|
|
// - the first and the last label are equal
|
|
// - the number of divisions is 0
|
|
// - less than 1 primary division is requested
|
|
// - logarithmic scale is requested
|
|
|
|
if (wmin == wmax || ndiv == 0 || N1A <= 1 || OptionLog) {
|
|
OptionNoopt = 1;
|
|
OptionInt = 0;
|
|
}
|
|
|
|
// Axis bining optimization
|
|
if ( (wmax-wmin) < 1 && OptionInt) {
|
|
out_error(m_out,"PaintAxis", "option I not available");
|
|
OptionInt = 0;
|
|
}
|
|
//out_error(m_out,"android_debug","0002");
|
|
if (!OptionNoopt || OptionInt ) {
|
|
|
|
// Primary divisions optimization
|
|
// When integer labelling is required, Optimize is invoked first
|
|
// and only if the result is not an integer labelling, AdjustBinSize
|
|
// is invoked.
|
|
|
|
optimizeLimits(wmin,wmax,N1A,
|
|
BinLow,BinHigh,nbins,BinWidth,
|
|
aCHOPT);
|
|
if (OptionInt) {
|
|
if (BinLow != double(int(BinLow)) ||
|
|
BinWidth != double(int(BinWidth))) {
|
|
adjustBinSize(wmin,wmax,N1A,BinLow,BinHigh,nbins,BinWidth);
|
|
}
|
|
}
|
|
if ((wmin-BinLow) > epsilon) { BinLow += BinWidth; nbins--; }
|
|
if ((BinHigh-wmax) > epsilon) { BinHigh -= BinWidth; nbins--; }
|
|
if (xmax == xmin) {
|
|
double rtyw = (ymax-ymin)/(wmax-wmin);
|
|
Xxmin = xmin;
|
|
Xxmax = xmax;
|
|
Yymin = rtyw*(BinLow-wmin) + ymin;
|
|
Yymax = rtyw*(BinHigh-wmin) + ymin;
|
|
} else {
|
|
double rtxw = (xmax-xmin)/(wmax-wmin);
|
|
Xxmin = rtxw*(BinLow-wmin) + xmin;
|
|
Xxmax = rtxw*(BinHigh-wmin) + xmin;
|
|
if (ymax == ymin) {
|
|
Yymin = ymin;
|
|
Yymax = ymax;
|
|
} else {
|
|
alfa = (ymax-ymin)/(xmax-xmin);
|
|
beta = (ymin*xmax-ymax*xmin)/(xmax-xmin);
|
|
Yymin = alfa*Xxmin + beta;
|
|
Yymax = alfa*Xxmax + beta;
|
|
}
|
|
}
|
|
/*GB if (fFunction) {
|
|
Yymin = ymin;
|
|
Yymax = ymax;
|
|
Xxmin = xmin;
|
|
Xxmax = xmax;
|
|
} else*/ {
|
|
wmin = BinLow;
|
|
wmax = BinHigh;
|
|
}
|
|
|
|
// Secondary divisions optimization
|
|
int NB2 = N2A;
|
|
if (!OptionNoopt && N2A > 1 && BinWidth > 0) {
|
|
optimizeLimits(wmin,wmin+BinWidth,N2A,
|
|
BinLow2,BinHigh2,NB2,BinWidth2,
|
|
aCHOPT);
|
|
}
|
|
|
|
// Tertiary divisions optimization
|
|
int NB3 = N3A;
|
|
if (!OptionNoopt && N3A > 1 && BinWidth2 > 0) {
|
|
optimizeLimits(BinLow2,BinLow2+BinWidth2,N3A,
|
|
BinLow3,BinHigh3,NB3,BinWidth3,
|
|
aCHOPT);
|
|
}
|
|
N1Aold = N1A;
|
|
NN1old = NN1;
|
|
N1A = nbins;
|
|
NN3 = tools::mx(NB3,1);
|
|
NN2 = tools::mx(NB2,1)*NN3;
|
|
NN1 = tools::mx(N1A,1)*NN2+1;
|
|
Nticks = NN1;
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0003");
|
|
// Coordinates are normalized
|
|
|
|
ratio1 = 1/(RWxmax-RWxmin);
|
|
ratio2 = 1/(RWymax-RWymin);
|
|
X0 = ratio1*(xmin-RWxmin);
|
|
X1 = ratio1*(xmax-RWxmin);
|
|
Y0 = ratio2*(ymin-RWymin);
|
|
Y1 = ratio2*(ymax-RWymin);
|
|
if (!OptionNoopt || OptionInt ) {
|
|
XX0 = ratio1*(Xxmin-RWxmin);
|
|
XX1 = ratio1*(Xxmax-RWxmin);
|
|
YY0 = ratio2*(Yymin-RWymin);
|
|
YY1 = ratio2*(Yymax-RWymin);
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0004");
|
|
if ((X0 == X1) && (Y0 == Y1)) {
|
|
out_error(m_out,"PaintAxis", "length of axis is 0");
|
|
return;
|
|
}
|
|
|
|
// Return wmin, wmax and the number of primary divisions
|
|
if (OptionX) {
|
|
ndiv = N1A;
|
|
return;
|
|
}
|
|
|
|
int maxDigits = 5;
|
|
//FIXME if (fAxis) maxDigits = fMaxDigits;
|
|
|
|
/*FIXME
|
|
TLatex *textaxis = new TLatex();
|
|
lineaxis->SetLineColor(GetLineColor());
|
|
lineaxis->SetLineStyle(1);
|
|
lineaxis->SetLineWidth(GetLineWidth());
|
|
textaxis->SetTextColor(GetTextColor());
|
|
textaxis->SetTextFont(GetTextFont());
|
|
|
|
if (!gPad->IsBatch()) {
|
|
float chupxvsav, chupyvsav;
|
|
gVirtualX->GetCharacterUp(chupxvsav, chupyvsav);
|
|
gVirtualX->SetClipOFF(gPad->GetCanvasID());
|
|
}
|
|
*/
|
|
|
|
// Compute length of axis
|
|
double axis_length = ::sqrt((X1-X0)*(X1-X0)+(Y1-Y0)*(Y1-Y0));
|
|
if (axis_length == 0) {
|
|
out_error(m_out,"PaintAxis", "length of axis is 0");
|
|
return; //goto L210;
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0005");
|
|
if (!OptionNoopt || OptionInt) {
|
|
axis_lengthN = ::sqrt((XX1-XX0)*(XX1-XX0)+(YY1-YY0)*(YY1-YY0));
|
|
axis_length0 = ::sqrt((XX0-X0)*(XX0-X0)+(YY0-Y0)*(YY0-Y0));
|
|
axis_length1 = ::sqrt((X1-XX1)*(X1-XX1)+(Y1-YY1)*(Y1-YY1));
|
|
if (axis_lengthN < epsilon) {
|
|
OptionNoopt = 1;
|
|
OptionInt = 0;
|
|
wmin = rwmi;
|
|
wmax = rwma;
|
|
N1A = N1Aold;
|
|
NN1 = NN1old;
|
|
Nticks = NN1;
|
|
if (OptionTime) {
|
|
wmin += timeoffset - (int)(timeoffset) + rangeOffset;
|
|
wmax += timeoffset - (int)(timeoffset) + rangeOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0006");
|
|
if (X0 == X1) {
|
|
phi = 0.5*kPI;
|
|
phil = phi;
|
|
} else {
|
|
phi = TMath_ATan2((Y1-Y0),(X1-X0));
|
|
int px0 = 0;//FIXME gPad->UtoPixel(X0);
|
|
int py0 = 0;//FIXME gPad->VtoPixel(Y0);
|
|
int px1 = 0;//FIXME gPad->UtoPixel(X1);
|
|
int py1 = 0;//FIXME gPad->VtoPixel(Y1);
|
|
if (X0 < X1) phil = TMath_ATan2(double(py0-py1), double(px1-px0));
|
|
else phil = TMath_ATan2(double(py1-py0), double(px0-px1));
|
|
}
|
|
cosphi = ::cos(phi);
|
|
sinphi = ::sin(phi);
|
|
acosphi = TMath_Abs(cosphi);
|
|
asinphi = TMath_Abs(sinphi);
|
|
if (acosphi <= epsilon) { acosphi = 0; cosphi = 0; }
|
|
if (asinphi <= epsilon) { asinphi = 0; sinphi = 0; }
|
|
|
|
//out_error(m_out,"android_debug","0007");
|
|
// Mside positive, tick marks on positive side
|
|
// Mside negative, tick marks on negative side
|
|
// Mside zero, tick marks on both sides
|
|
// Default is positive except for vertical axis
|
|
|
|
Mside=1;
|
|
if (X0 == X1 && Y1 > Y0) Mside = -1;
|
|
if (OptionPlus) Mside = 1;
|
|
if (OptionMinus) Mside = -1;
|
|
if (OptionPlus && OptionMinus) Mside = 0;
|
|
XMside = Mside;
|
|
Lside = -Mside;
|
|
if (OptionEqual) Lside = Mside;
|
|
if (OptionPlus && OptionMinus) {
|
|
Lside = -1;
|
|
if (OptionEqual) Lside=1;
|
|
}
|
|
XLside = Lside;
|
|
|
|
// Tick marks size
|
|
double tick_side;
|
|
if(XMside >= 0) tick_side = 1;
|
|
else tick_side = -1;
|
|
|
|
double atick[3];
|
|
if (OptionSize) atick[0] = tick_side*axis_length*fTickSize;
|
|
else atick[0] = tick_side*axis_length*0.03;
|
|
|
|
atick[1] = 0.5*atick[0];
|
|
atick[2] = 0.5*atick[1];
|
|
|
|
// Set the side of the grid
|
|
if ((X0 == X1) && (Y1 > Y0)) grid_side =-1;
|
|
else grid_side = 1;
|
|
|
|
|
|
//out_error(m_out,"android_debug","0008");
|
|
// Compute Values if Function is given
|
|
/*GB if(fFunction) {
|
|
rwmi = fFunction->Eval(wmin);
|
|
rwma = fFunction->Eval(wmax);
|
|
if(rwmi > rwma) {
|
|
double t = rwma;
|
|
rwma = rwmi;
|
|
rwmi = t;
|
|
}
|
|
}*/
|
|
|
|
// Draw the axis if needed...
|
|
if (!OptionBlank) {
|
|
xpl1 = X0;
|
|
xpl2 = X1;
|
|
ypl1 = Y0;
|
|
ypl2 = Y1;
|
|
aLinesAxis.push_back((float)xpl1);
|
|
aLinesAxis.push_back((float)ypl1);
|
|
aLinesAxis.push_back((float)xpl2);
|
|
aLinesAxis.push_back((float)ypl2);
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0009");
|
|
// No bining
|
|
|
|
if (ndiv == 0) return; //goto L210;
|
|
if (wmin == wmax) {
|
|
out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f)", wmin, wmax);
|
|
return; //goto L210;
|
|
}
|
|
|
|
// Draw axis title if it exists
|
|
if (!drawGridOnly && fTitle.size()) {
|
|
textSize = fTitleSize;
|
|
charheight = fTitleSize;
|
|
if ((GetTextFont() % 10) > 2) {
|
|
//FIXME charheight = charheight/gPad->GetWh();
|
|
}
|
|
double toffset = fTitleOffset;
|
|
if (toffset < 0.1) toffset = 1;
|
|
if (X1 == X0) Ylabel = XLside*1.6*charheight*toffset;
|
|
else Ylabel = XLside*1.3*charheight*toffset;
|
|
if (Y1 == Y0) Ylabel = XLside*1.6*charheight*toffset;
|
|
double axispos;
|
|
if (testBit(TAxis_kCenterTitle)) axispos = 0.5*axis_length;
|
|
else axispos = axis_length;
|
|
if (testBit(TAxis_kRotateTitle)) {
|
|
if (X1 >= X0) {
|
|
if (testBit(TAxis_kCenterTitle)) textAlign = 22;
|
|
else textAlign = 12;
|
|
TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
} else {
|
|
if (testBit(TAxis_kCenterTitle)) textAlign = 22;
|
|
else textAlign = 32;
|
|
TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
}
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 000\n");
|
|
aTexts.push_back(_text(xpl1,ypl1,
|
|
phil=(kPI+phil)*180/kPI,
|
|
fTitleSize,
|
|
fTitle,textAlign));
|
|
} else {
|
|
if (X1 >= X0) {
|
|
if (testBit(TAxis_kCenterTitle)) textAlign = 22;
|
|
else textAlign = 32;
|
|
TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
} else {
|
|
if (testBit(TAxis_kCenterTitle)) textAlign = 22;
|
|
else textAlign = 12;
|
|
TGaxis_Rotate(axispos,Ylabel,cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
}
|
|
aTexts.push_back(_text(xpl1,ypl1,
|
|
phil*180/kPI,fTitleSize,
|
|
fTitle,textAlign));
|
|
}
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0010");
|
|
// Labels preparation:
|
|
// Get character height
|
|
// Compute the labels orientation in case of overlaps
|
|
// with alphanumeric labels for horizontal axis).
|
|
|
|
charheight = fLabelSize;
|
|
if (OptionText) charheight *= 0.66666;
|
|
//FIXME textaxis->SetTextFont(fLabelFont);
|
|
//FIXME textaxis->SetTextColor(GetLabelColor());
|
|
textSize = charheight;
|
|
//FIXME textaxis->SetTextAngle(GetTextAngle());
|
|
if (fLabelFont%10 > 2) {
|
|
charheight /= padh;
|
|
}
|
|
if (!OptionUp && !OptionDown && !OptionY) {
|
|
if (!drawGridOnly && OptionText && ((ymin == ymax) || (xmin == xmax))) {
|
|
textAlign = 32;
|
|
OptionText = 2;
|
|
//int nl = 0;//FIXME fAxis->GetLast()-fAxis->GetFirst()+1;
|
|
//double angle = 0;
|
|
out_error(m_out,"PaintAxis","debug : FIXME : 000\n");
|
|
/*FIXME
|
|
for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
|
|
textaxis->SetText(0,0,fAxis->GetBinLabel(i));
|
|
if (textaxis->GetXsize() < (xmax-xmin)/nl) continue;
|
|
angle = -20;
|
|
break;
|
|
}
|
|
for (i=fAxis->GetFirst(); i<=fAxis->GetLast(); i++) {
|
|
if ((!::strcmp(fAxis->GetName(),"xaxis") && !gPad->testBit(kHori))
|
|
||(!::strcmp(fAxis->GetName(),"yaxis") && gPad->testBit(kHori))) {
|
|
if (nl > 50) angle = 90;
|
|
if (fAxis->testBit(TAxis_kLabelsHori)) angle = 0;
|
|
if (fAxis->testBit(TAxis_kLabelsVert)) angle = 90;
|
|
if (fAxis->testBit(TAxis_kLabelsUp)) angle = 20;
|
|
if (fAxis->testBit(TAxis_kLabelsDown)) angle =-20;
|
|
if (angle== 0) textAlign = 23;
|
|
if (angle== -20) textAlign = 12;
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 002\n");
|
|
textaxis->PaintLatex(
|
|
fAxis->GetBinCenter(i),
|
|
gPad->GetUymin() - 3*fAxis->GetLabelOffset()*
|
|
(gPad->GetUymax()-gPad->GetUymin()),
|
|
angle,
|
|
charheight,
|
|
fAxis->GetBinLabel(i));
|
|
} else if ((!::strcmp(fAxis->GetName(),"yaxis") && !gPad->testBit(kHori))
|
|
|| (!::strcmp(fAxis->GetName(),"xaxis") && gPad->testBit(kHori))) {
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 003\n");
|
|
textaxis->PaintLatex(
|
|
gPad->GetUxmin() - 3*fAxis->GetLabelOffset()*
|
|
(gPad->GetUxmax()-gPad->GetUxmin()),
|
|
fAxis->GetBinCenter(i),
|
|
0,
|
|
charheight,
|
|
fAxis->GetBinLabel(i));
|
|
} else {
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 004\n");
|
|
textaxis->PaintLatex(
|
|
xmin - 3*fAxis->GetLabelOffset()*
|
|
(gPad->GetUxmax()-gPad->GetUxmin()),
|
|
ymin +(i-0.5)*(ymax-ymin)/nl,
|
|
0,
|
|
charheight,
|
|
fAxis->GetBinLabel(i));
|
|
}
|
|
}*/
|
|
}
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0011");
|
|
// Now determine orientation of labels on axis
|
|
/*FIXME
|
|
if (!gPad->IsBatch()) {
|
|
if (cosphi > 0) gVirtualX->SetCharacterUp(-sinphi,cosphi);
|
|
else gVirtualX->SetCharacterUp(sinphi,-cosphi);
|
|
if (X0 == X1) gVirtualX->SetCharacterUp(0,1);
|
|
if (OptionVert) gVirtualX->SetCharacterUp(0,1);
|
|
if (OptionPara) gVirtualX->SetCharacterUp(-sinphi,cosphi);
|
|
if (OptionDown) gVirtualX->SetCharacterUp(cosphi,sinphi);
|
|
}*/
|
|
|
|
// Now determine text alignment
|
|
Xalign = 2;
|
|
Yalign = 1;
|
|
if (X0 == X1) Xalign = 3;
|
|
if (Y0 != Y1) Yalign = 2;
|
|
if (OptionCent) Xalign = 2;
|
|
if (OptionRight) Xalign = 3;
|
|
if (OptionLeft) Xalign = 1;
|
|
if (TMath_Abs(cosphi) > 0.9) {
|
|
Xalign = 2;
|
|
} else {
|
|
if (cosphi*sinphi > 0) Xalign = 1;
|
|
if (cosphi*sinphi < 0) Xalign = 3;
|
|
}
|
|
textAlign = 10*Xalign+Yalign;
|
|
|
|
//out_error(m_out,"android_debug","0012");
|
|
// Position of labels in Y
|
|
if (X0 == X1) {
|
|
if (OptionPlus && !OptionMinus) {
|
|
if (OptionEqual) Ylabel = fLabelOffset/2 + atick[0];
|
|
else Ylabel = -fLabelOffset;
|
|
} else {
|
|
Ylabel = fLabelOffset;
|
|
if (Lside < 0) Ylabel += atick[0];
|
|
}
|
|
} else if (Y0 == Y1) {
|
|
if (OptionMinus && !OptionPlus) {
|
|
Ylabel = fLabelOffset+0.5*fLabelSize;
|
|
Ylabel += TMath_Abs(atick[0]);
|
|
} else {
|
|
Ylabel = -fLabelOffset;
|
|
if (Mside <= 0) Ylabel -= TMath_Abs(atick[0]);
|
|
}
|
|
if (OptionLog) Ylabel -= 0.5*charheight;
|
|
} else {
|
|
if (Mside+Lside >= 0) Ylabel = fLabelOffset;
|
|
else Ylabel = -fLabelOffset;
|
|
}
|
|
if (OptionText) Ylabel /= 2;
|
|
|
|
//out_error(m_out,"android_debug","0013");
|
|
// Draw the linear tick marks if needed...
|
|
if (!OptionLog) {
|
|
if (ndiv) {
|
|
/*GB if (fFunction) {
|
|
if (OptionNoopt && !OptionInt) {
|
|
DXtick=(BinHigh-BinLow)/double(Nticks-1);
|
|
} else {
|
|
DXtick=(BinHigh-BinLow)/double(Nticks-1);
|
|
}
|
|
} else */ {
|
|
if (OptionNoopt && !OptionInt) DXtick=axis_length/double(Nticks-1);
|
|
else DXtick=axis_lengthN/double(Nticks-1);
|
|
}
|
|
for (k=0;k<Nticks; k++) {
|
|
ltick = 2;
|
|
if (k%NN3 == 0) ltick = 1;
|
|
if (k%NN2 == 0) ltick = 0;
|
|
/*GB if (fFunction) {
|
|
double xx = BinLow+double(k)*DXtick;
|
|
double zz = fFunction->Eval(xx)-rwmi;
|
|
Xtick = zz* axis_length / TMath_Abs(rwma-rwmi);
|
|
} else */ {
|
|
Xtick = double(k)*DXtick;
|
|
}
|
|
Ytick = 0;
|
|
if (!Mside) Ytick -= atick[ltick];
|
|
if ( OptionNoopt && !OptionInt) {
|
|
TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,X0,Y0,xpl2,ypl2);
|
|
TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
}
|
|
else {
|
|
TGaxis_Rotate(Xtick,Ytick,cosphi,sinphi,XX0,YY0,xpl2,ypl2);
|
|
TGaxis_Rotate(Xtick,atick[ltick],cosphi,sinphi,XX0,YY0,xpl1,ypl1);
|
|
}
|
|
if (OptionVert) {
|
|
if ((X0 != X1) && (Y0 != Y1)) {
|
|
if (Mside) {
|
|
xpl1 = xpl2;
|
|
if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
|
|
else ypl1 = ypl2 - atick[ltick];
|
|
}
|
|
else {
|
|
xpl1 = 0.5*(xpl1 + xpl2);
|
|
xpl2 = xpl1;
|
|
ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
|
|
ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
|
|
}
|
|
}
|
|
}
|
|
if (!drawGridOnly) {
|
|
aLinesAxis.push_back((float)xpl1);
|
|
aLinesAxis.push_back((float)ypl1);
|
|
aLinesAxis.push_back((float)xpl2);
|
|
aLinesAxis.push_back((float)ypl2);
|
|
}
|
|
|
|
if (OptionGrid) {
|
|
if (ltick == 0) {
|
|
if (OptionNoopt && !OptionInt) {
|
|
TGaxis_Rotate(Xtick,0,cosphi,sinphi,X0,Y0 ,xpl2,ypl2);
|
|
TGaxis_Rotate
|
|
(Xtick,grid_side*gridlength,cosphi,sinphi,X0,Y0,
|
|
xpl1,ypl1);
|
|
} else {
|
|
TGaxis_Rotate(Xtick,0,cosphi ,sinphi,XX0,YY0,xpl2,ypl2);
|
|
TGaxis_Rotate
|
|
(Xtick,grid_side*gridlength ,cosphi,sinphi,XX0,YY0,
|
|
xpl1,ypl1);
|
|
}
|
|
aLinesGrid.push_back((float)xpl1);
|
|
aLinesGrid.push_back((float)ypl1);
|
|
aLinesGrid.push_back((float)xpl2);
|
|
aLinesGrid.push_back((float)ypl2);
|
|
}
|
|
}
|
|
}
|
|
Xtick0 = 0;
|
|
Xtick1 = Xtick;
|
|
|
|
if ((!OptionNoopt || OptionInt) && axis_length0) {
|
|
int Nticks0;
|
|
/*GB if (fFunction) Nticks0 = int((BinLow-wmin)/DXtick);
|
|
else */ Nticks0 = int(axis_length0/DXtick);
|
|
if (Nticks0 > 1000) Nticks0 = 1000;
|
|
for (k=0; k<=Nticks0; k++) {
|
|
ltick = 2;
|
|
if (k%NN3 == 0) ltick = 1;
|
|
if (k%NN2 == 0) ltick = 0;
|
|
Ytick0 = 0;
|
|
if (!Mside) Ytick0 -= atick[ltick];
|
|
/*GB if (fFunction) {
|
|
Xtick0 = (fFunction->Eval(BinLow - double(k)*DXtick)-rwmi)
|
|
* axis_length / TMath_Abs(rwma-rwmi);
|
|
}*/
|
|
TGaxis_Rotate(Xtick0,Ytick0,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2);
|
|
TGaxis_Rotate(Xtick0,atick[ltick],cosphi,sinphi,XX0,YY0 ,xpl1,ypl1);
|
|
if (OptionVert) {
|
|
if ((X0 != X1) && (Y0 != Y1)) {
|
|
if (Mside) {
|
|
xpl1 = xpl2;
|
|
if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
|
|
else ypl1 = ypl2 - atick[ltick];
|
|
}
|
|
else {
|
|
xpl1 = 0.5*(xpl1 + xpl2);
|
|
xpl2 = xpl1;
|
|
ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
|
|
ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
|
|
}
|
|
}
|
|
}
|
|
if(!drawGridOnly) {
|
|
aLinesAxis.push_back((float)xpl1);
|
|
aLinesAxis.push_back((float)ypl1);
|
|
aLinesAxis.push_back((float)xpl2);
|
|
aLinesAxis.push_back((float)ypl2);
|
|
}
|
|
|
|
if (OptionGrid) {
|
|
if (ltick == 0) {
|
|
TGaxis_Rotate(Xtick0,0,cosphi,sinphi,XX0,YY0,xpl2,ypl2);
|
|
TGaxis_Rotate
|
|
(Xtick0,grid_side*gridlength,cosphi,sinphi,XX0,YY0,
|
|
xpl1,ypl1);
|
|
aLinesGrid.push_back((float)xpl1);
|
|
aLinesGrid.push_back((float)ypl1);
|
|
aLinesGrid.push_back((float)xpl2);
|
|
aLinesGrid.push_back((float)ypl2);
|
|
}
|
|
}
|
|
Xtick0 -= DXtick;
|
|
}
|
|
}
|
|
|
|
if ((!OptionNoopt || OptionInt) && axis_length1) {
|
|
int Nticks1;
|
|
/*GB if (fFunction) Nticks1 = int((wmax-BinHigh)/DXtick);
|
|
else */ Nticks1 = int(axis_length1/DXtick);
|
|
if (Nticks1 > 1000) Nticks1 = 1000;
|
|
for (k=0; k<=Nticks1; k++) {
|
|
ltick = 2;
|
|
if (k%NN3 == 0) ltick = 1;
|
|
if (k%NN2 == 0) ltick = 0;
|
|
Ytick1 = 0;
|
|
if (!Mside) Ytick1 -= atick[ltick];
|
|
/*GB if (fFunction) {
|
|
Xtick1 = (fFunction->Eval(BinHigh + double(k)*DXtick)-rwmi)
|
|
* axis_length / TMath_Abs(rwma-rwmi);
|
|
}*/
|
|
TGaxis_Rotate(Xtick1,Ytick1,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2);
|
|
TGaxis_Rotate(Xtick1,atick[ltick],cosphi,sinphi,XX0,YY0 ,xpl1,ypl1);
|
|
if (OptionVert) {
|
|
if ((X0 != X1) && (Y0 != Y1)) {
|
|
if (Mside) {
|
|
xpl1 = xpl2;
|
|
if (cosphi > 0) ypl1 = ypl2 + atick[ltick];
|
|
else ypl1 = ypl2 - atick[ltick];
|
|
}
|
|
else {
|
|
xpl1 = 0.5*(xpl1 + xpl2);
|
|
xpl2 = xpl1;
|
|
ypl1 = 0.5*(ypl1 + ypl2) + atick[ltick];
|
|
ypl2 = 0.5*(ypl1 + ypl2) - atick[ltick];
|
|
}
|
|
}
|
|
}
|
|
if(!drawGridOnly) {
|
|
aLinesAxis.push_back((float)xpl1);
|
|
aLinesAxis.push_back((float)ypl1);
|
|
aLinesAxis.push_back((float)xpl2);
|
|
aLinesAxis.push_back((float)ypl2);
|
|
}
|
|
|
|
if (OptionGrid) {
|
|
if (ltick == 0) {
|
|
TGaxis_Rotate(Xtick1,0,cosphi,sinphi,XX0,YY0 ,xpl2,ypl2);
|
|
TGaxis_Rotate
|
|
(Xtick1,grid_side*gridlength,cosphi,sinphi,XX0,YY0,
|
|
xpl1,ypl1);
|
|
aLinesGrid.push_back((float)xpl1);
|
|
aLinesGrid.push_back((float)ypl1);
|
|
aLinesGrid.push_back((float)xpl2);
|
|
aLinesGrid.push_back((float)ypl2);
|
|
}
|
|
}
|
|
Xtick1 += DXtick;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//out_error(m_out,"android_debug","0014");
|
|
// Draw the numeric labels if needed...
|
|
if (!drawGridOnly && !OptionUnlab) {
|
|
if (!OptionLog) {
|
|
if (N1A) {
|
|
// Spacing of labels
|
|
if ((wmin == wmax) || (ndiv == 0)) {
|
|
out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax);
|
|
return; //goto L210;
|
|
}
|
|
Wlabel = wmin;
|
|
DWlabel = (wmax-wmin)/double(N1A);
|
|
if (OptionNoopt && !OptionInt) DXlabel = axis_length/double(N1A);
|
|
else DXlabel = axis_lengthN/double(N1A);
|
|
|
|
char CHCODED[8];
|
|
int NEXE = 0;
|
|
bool FLEXE = false;
|
|
if (!OptionText && !OptionTime) {
|
|
|
|
// We have to decide what format to generate
|
|
// for numeric labels only)
|
|
// Test the magnitude, decide format
|
|
FLEXE = false;
|
|
NEXE = 0;
|
|
bool FLEXPO = false;
|
|
bool FLEXNE = false;
|
|
WW = tools::mx(TMath_Abs(wmin),TMath_Abs(wmax));
|
|
|
|
// First case : (wmax-wmin)/N1A less than 0.001
|
|
// 0.001 fMaxDigits of 5 (fMaxDigits) characters).
|
|
// Then we use x 10 n
|
|
// format. If AF >=0 x10 n cannot be used
|
|
double xmicros = 0.00099;
|
|
if (maxDigits) xmicros = ::pow(10.,-maxDigits);
|
|
if (!noExponent && (TMath_Abs(wmax-wmin)/double(N1A)) < xmicros) {
|
|
AF = ::log10(WW) + epsilon;
|
|
if (AF < 0) {
|
|
FLEXE = true;
|
|
NEXE = int(AF);
|
|
int IEXE = TMath_Abs(NEXE);
|
|
if (IEXE%3 == 1) IEXE += 2;
|
|
else if(IEXE%3 == 2) IEXE += 1;
|
|
if (NEXE < 0) NEXE = -IEXE;
|
|
else NEXE = IEXE;
|
|
Wlabel = Wlabel*::pow(10.,IEXE);
|
|
DWlabel = DWlabel*::pow(10.,IEXE);
|
|
IF1 = maxDigits;
|
|
IF2 = maxDigits-2;
|
|
goto L110;
|
|
}
|
|
}
|
|
if (WW >= 1) AF = ::log10(WW);
|
|
else AF = ::log10(WW*0.0001);
|
|
AF += epsilon;
|
|
NF = int(AF)+1;
|
|
if (!noExponent && NF > maxDigits) FLEXPO = true;
|
|
if (!noExponent && NF < -maxDigits) FLEXNE = true;
|
|
|
|
// Use x 10 n format. (only powers of 3 allowed)
|
|
|
|
if (FLEXPO) {
|
|
FLEXE = true;
|
|
while (1) {
|
|
NEXE++;
|
|
WW /= 10;
|
|
Wlabel /= 10;
|
|
DWlabel /= 10;
|
|
if (NEXE%3 == 0 && WW <= ::pow(10.,maxDigits-1)) break;
|
|
}
|
|
}
|
|
|
|
if (FLEXNE) {
|
|
FLEXE = true;
|
|
RNE = 1/::pow(10.,maxDigits-2);
|
|
while (1) {
|
|
NEXE--;
|
|
WW *= 10;
|
|
Wlabel *= 10;
|
|
DWlabel *= 10;
|
|
if (NEXE%3 == 0 && WW >= RNE) break;
|
|
}
|
|
}
|
|
|
|
NA = 0;
|
|
for (i=maxDigits-1; i>0; i--) {
|
|
if (TMath_Abs(WW) < ::pow(10.,i)) NA = maxDigits-i;
|
|
}
|
|
ndyn = N1A;
|
|
while (ndyn) {
|
|
double wdyn = TMath_Abs((wmax-wmin)/ndyn);
|
|
if (wdyn <= 0.999 && NA < maxDigits-2) {
|
|
NA++;
|
|
ndyn /= 10;
|
|
}
|
|
else break;
|
|
}
|
|
|
|
IF2 = NA;
|
|
IF1 = tools::mx(NF+NA,maxDigits)+1;
|
|
L110:
|
|
if (tools::mn(wmin,wmax) < 0)IF1 = IF1+1;
|
|
IF1 = tools::mn(IF1,32);
|
|
|
|
// In some cases, IF1 and IF2 are too small....
|
|
while (DWlabel < ::pow(10.,-IF2)) {
|
|
IF1++;
|
|
IF2++;
|
|
}
|
|
//char* CODED = &CHCODED[0]; //GB : comment out.
|
|
if (IF1 > 14) IF1=14;
|
|
if (IF2 > 14) IF2=14;
|
|
if(IF2)snpf(CHCODED,sizeof(CHCODED),"%%%d.%df",IF1,IF2);
|
|
else snpf(CHCODED,sizeof(CHCODED),"%%%d.%df",IF1+1,1);
|
|
}
|
|
|
|
// We draw labels
|
|
|
|
snpf(CHTEMP,sizeof(CHTEMP),"%g",DWlabel);
|
|
|
|
size_t ndecimals = 0;
|
|
if (OptionDecimals) {
|
|
char *dot = ::strchr(CHTEMP,'.');
|
|
if (dot) ndecimals = CHTEMP + ::strlen(CHTEMP) -dot;
|
|
}
|
|
int Nlabels;
|
|
if (OptionM) Nlabels = N1A-1;
|
|
else Nlabels = N1A;
|
|
double wTimeIni = Wlabel;
|
|
for ( k=0; k<=Nlabels; k++) {
|
|
/*FIXME if (fFunction) {
|
|
double xx = BinLow+double(k*NN2)*DXtick;
|
|
double zz = fFunction->Eval(xx)-rwmi;
|
|
Wlabel = xx;
|
|
Xlabel = zz* axis_length / TMath_Abs(rwma-rwmi);
|
|
} else */{
|
|
Xlabel = DXlabel*k;
|
|
}
|
|
if (OptionM) Xlabel += 0.5*DXlabel;
|
|
|
|
if (!OptionText && !OptionTime) {
|
|
snpf(LABEL,sizeof(LABEL),&CHCODED[0],Wlabel);
|
|
LABEL[28] = 0;
|
|
Wlabel += DWlabel;
|
|
|
|
TGaxis_LabelsLimits(m_out,LABEL,first,last); //Eliminate blanks
|
|
|
|
if (LABEL[first] == '.') { //check if '.' is preceeded by a digit
|
|
::strcpy(CHTEMP, "0");
|
|
::strcat(CHTEMP, &LABEL[first]);
|
|
::strcpy(LABEL, CHTEMP);
|
|
first = 1; last = int(::strlen(LABEL));
|
|
}
|
|
if (LABEL[first] == '-' && LABEL[first+1] == '.') {
|
|
::strcpy(CHTEMP, "-0");
|
|
::strcat(CHTEMP, &LABEL[first+1]);
|
|
::strcpy(LABEL, CHTEMP);
|
|
first = 1; last = int(::strlen(LABEL));
|
|
}
|
|
|
|
// We eliminate the non significant 0 after '.'
|
|
if (ndecimals) {
|
|
char *adot = ::strchr(LABEL,'.');
|
|
if (adot) adot[ndecimals] = 0;
|
|
} else {
|
|
while (LABEL[last] == '0') { LABEL[last] = 0; last--;}
|
|
}
|
|
// We eliminate the dot, unless dot is forced.
|
|
if (LABEL[last] == '.') {
|
|
if (!OptionDot) { LABEL[last] = 0; last--;}
|
|
}
|
|
}
|
|
|
|
// Generate the time labels
|
|
|
|
if (OptionTime) {
|
|
double timed = Wlabel + (int)(timeoffset) - rangeOffset;
|
|
time_t timelabel = (time_t)((long)(timed));
|
|
struct tm* utctis;
|
|
if (OptionTime == 1) {
|
|
utctis = localtime(&timelabel);
|
|
} else {
|
|
utctis = gmtime(&timelabel);
|
|
}
|
|
std::string timeformattmp;
|
|
if (timeformat.size() < 220) timeformattmp = timeformat;
|
|
else timeformattmp = "#splitline{Format}{too long}";
|
|
|
|
// Appends fractionnal part if seconds displayed
|
|
if (DWlabel<0.9) {
|
|
double tmpdb;
|
|
size_t tmplast;
|
|
snpf(LABEL,sizeof(LABEL),"%%S%7.5f",modf(timed,&tmpdb));
|
|
tmplast = ::strlen(LABEL)-1;
|
|
|
|
// We eliminate the non significiant 0 after '.'
|
|
while (LABEL[tmplast] == '0') {
|
|
LABEL[tmplast] = 0; tmplast--;
|
|
}
|
|
|
|
//FIXME timeformattmp.ReplaceAll("%S",LABEL);
|
|
// Replace the "0." at the begining by "s"
|
|
//FIXME timeformattmp.ReplaceAll("%S0.","%Ss");
|
|
|
|
}
|
|
|
|
::strftime(LABEL,256,timeformattmp.c_str(),utctis);
|
|
::strcpy(CHTEMP,&LABEL[0]);
|
|
first = 0; last=int(::strlen(LABEL))-1;
|
|
Wlabel = wTimeIni + (k+1)*DWlabel;
|
|
}
|
|
|
|
// We generate labels (numeric or alphanumeric).
|
|
|
|
if (OptionNoopt && !OptionInt)
|
|
TGaxis_Rotate (Xlabel,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
|
|
else TGaxis_Rotate (Xlabel,Ylabel,cosphi,sinphi,XX0,YY0,XX,YY);
|
|
if (Y0 == Y1 && !OptionDown && !OptionUp) {
|
|
YY -= 0.80*charheight;
|
|
}
|
|
if (OptionVert) {
|
|
if (X0 != X1 && Y0 != Y1) {
|
|
if (OptionNoopt && !OptionInt)
|
|
TGaxis_Rotate (Xlabel,0,cosphi,sinphi,X0,Y0,XX,YY);
|
|
else TGaxis_Rotate (Xlabel,0,cosphi,sinphi,XX0,YY0,XX,YY);
|
|
if (cosphi > 0 ) YY += Ylabel;
|
|
if (cosphi < 0 ) YY -= Ylabel;
|
|
}
|
|
}
|
|
if (!OptionY || (X0 == X1)) {
|
|
if (!OptionText) {
|
|
if (first > last) ::strcpy(CHTEMP, " ");
|
|
else ::strcpy(CHTEMP, &LABEL[first]);
|
|
aTexts.push_back(_text(XX,YY,
|
|
0,textSize,CHTEMP,
|
|
textAlign));
|
|
}
|
|
else {
|
|
if (OptionText == 1) {
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 006\n");
|
|
/*textaxis->PaintLatex
|
|
(gPad->GetX1() + XX*(gPad->GetX2() - gPad->GetX1()),
|
|
gPad->GetY1() + YY*(gPad->GetY2() - gPad->GetY1()),
|
|
0,
|
|
textaxis->GetTextSize(),
|
|
fAxis->GetBinLabel(k+fAxis->GetFirst()));*/
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
// Text alignment is down
|
|
int LNLEN = 0;
|
|
if (!OptionText) LNLEN = last-first+1;
|
|
else {
|
|
int NHILAB = 0;
|
|
if (k+1 > NHILAB) LNLEN = 0;
|
|
}
|
|
for ( l=1; l<=LNLEN; l++) {
|
|
if (!OptionText) *CHTEMP = LABEL[first+l-2];
|
|
else {
|
|
if (LNLEN == 0) ::strcpy(CHTEMP, " ");
|
|
else ::strcpy(CHTEMP, "1");
|
|
}
|
|
aTexts.push_back(_text(XX,YY,
|
|
0,textSize,CHTEMP,
|
|
textAlign));
|
|
YY -= charheight*1.3;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We use the format x 10 ** n
|
|
|
|
if (FLEXE && !OptionText && NEXE) {
|
|
//G.Barrand ::sprintf(LABEL,"#times10^{%d}", NEXE);
|
|
snpf(LABEL,sizeof(LABEL),
|
|
"x10^%d!", NEXE); //G.Barrand : PAW encoding.
|
|
double Xfactor, Yfactor;
|
|
if (X0 != X1) { Xfactor = X1-X0+0.1*charheight; Yfactor = 0; }
|
|
else { Xfactor = Y1-Y0+0.1*charheight; Yfactor = 0; }
|
|
TGaxis_Rotate (Xfactor,Yfactor,cosphi,sinphi,X0,Y0,XX,YY);
|
|
textAlign = 11;
|
|
aTexts.push_back(_text(XX,YY,
|
|
0,textSize,LABEL,
|
|
textAlign));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Log axis
|
|
|
|
//out_error(m_out,"android_debug","0015");
|
|
if (OptionLog && ndiv) {
|
|
unsigned int xi1=0,xi2 = 0,wi = 0,yi1=0,yi2,hi = 0;
|
|
bool firstintlab = true, overlap = false;
|
|
if ((wmin == wmax) || (ndiv == 0)) {
|
|
out_error(m_out,"PaintAxis", "wmin (%f) == wmax (%f), or ndiv == 0", wmin, wmax);
|
|
return; //goto L210;
|
|
}
|
|
if (wmin <= 0) {
|
|
out_error(m_out,"PaintAxis", "negative logarithmic axis");
|
|
return; //goto L210;
|
|
}
|
|
if (wmax <= 0) {
|
|
out_error(m_out,"PaintAxis", "negative logarithmic axis");
|
|
return; //goto L210;
|
|
}
|
|
double XMNLOG = ::log10(wmin);
|
|
if (XMNLOG > 0) XMNLOG += 1.E-6;
|
|
else XMNLOG -= 1.E-6;
|
|
double X00 = 0;
|
|
double X11 = axis_length;
|
|
double H2 = ::log10(wmax);
|
|
double H2SAV = H2;
|
|
if (H2 > 0) H2 += 1.E-6;
|
|
else H2 -= 1.E-6;
|
|
int IH1 = int(XMNLOG);
|
|
int IH2 = 1+int(H2);
|
|
int NBININ = IH2-IH1+1;
|
|
double AXMUL = (X11-X00)/(H2SAV-XMNLOG);
|
|
|
|
// Plot decade and intermediate tick marks
|
|
decade = IH1-2;
|
|
int labelnumber = IH1;
|
|
if ( XMNLOG > 0 && (XMNLOG-double(IH1) > 0) ) labelnumber++;
|
|
for (j=1; j<=NBININ; j++) {
|
|
|
|
// Plot decade
|
|
firstintlab = true, overlap = false;
|
|
decade++;
|
|
if (X0 == X1 && j == 1) Ylabel += charheight*0.33;
|
|
if (Y0 == Y1 && j == 1) Ylabel -= charheight*0.65;
|
|
double Xone = X00+AXMUL*(double(decade)-XMNLOG);
|
|
//the following statement is a trick to circumvent a gcc bug
|
|
//GB if (j < 0) ::printf("j=%d\n",j); //G.Barrand : ???
|
|
if (X00 > Xone) goto L160;
|
|
if (Xone > X11) break;
|
|
Xtwo = Xone;
|
|
Y = 0;
|
|
if (!Mside) Y -= atick[0];
|
|
TGaxis_Rotate(Xone,Y,cosphi,sinphi,X0,Y0,xpl2,ypl2);
|
|
TGaxis_Rotate(Xtwo,atick[0],cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
if (OptionVert) {
|
|
if ((X0 != X1) && (Y0 != Y1)) {
|
|
if (Mside) {
|
|
xpl1=xpl2;
|
|
if (cosphi > 0) ypl1 = ypl2 + atick[0];
|
|
else ypl1 = ypl2 - atick[0];
|
|
}
|
|
else {
|
|
xpl1 = 0.5*(xpl1 + xpl2);
|
|
xpl2 = xpl1;
|
|
ypl1 = 0.5*(ypl1 + ypl2) + atick[0];
|
|
ypl2 = 0.5*(ypl1 + ypl2) - atick[0];
|
|
}
|
|
}
|
|
}
|
|
if (!drawGridOnly) {
|
|
aLinesAxis.push_back((float)xpl1);
|
|
aLinesAxis.push_back((float)ypl1);
|
|
aLinesAxis.push_back((float)xpl2);
|
|
aLinesAxis.push_back((float)ypl2);
|
|
}
|
|
|
|
if (OptionGrid) {
|
|
TGaxis_Rotate(Xone,0,cosphi,sinphi,X0,Y0,xpl2,ypl2);
|
|
TGaxis_Rotate(Xone,grid_side*gridlength,cosphi,sinphi,X0,Y0,
|
|
xpl1,ypl1);
|
|
aLinesGrid.push_back((float)xpl1);
|
|
aLinesGrid.push_back((float)ypl1);
|
|
aLinesGrid.push_back((float)xpl2);
|
|
aLinesGrid.push_back((float)ypl2);
|
|
}
|
|
|
|
if (!drawGridOnly && !OptionUnlab) {
|
|
|
|
// We generate labels (numeric only).
|
|
if (noExponent) {
|
|
double rlab = ::pow(10.,labelnumber);
|
|
snpf(LABEL,sizeof(LABEL), "%f", rlab);
|
|
TGaxis_LabelsLimits(m_out,LABEL,first,last);
|
|
while (last > first) {
|
|
if (LABEL[last] != '0') break;
|
|
LABEL[last] = 0;
|
|
last--;
|
|
}
|
|
if (LABEL[last] == '.') {LABEL[last] = 0; last--;}
|
|
} else {
|
|
snpf(LABEL,sizeof(LABEL), "%d", labelnumber);
|
|
TGaxis_LabelsLimits(m_out,LABEL,first,last);
|
|
}
|
|
TGaxis_Rotate (Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
|
|
if ((X0 == X1) && !OptionPara) {
|
|
if (Lside < 0) {
|
|
if (Mside < 0) {
|
|
if (labelnumber == 0) NCH=1;
|
|
else NCH=2;
|
|
XX += NCH*charheight;
|
|
} else {
|
|
if (labelnumber >= 0) XX += 0.25*charheight;
|
|
else XX += 0.50*charheight;
|
|
}
|
|
}
|
|
XX += 0.25*charheight;
|
|
}
|
|
if ((Y0 == Y1) && !OptionDown && !OptionUp) {
|
|
if (noExponent) YY += 0.33*charheight;
|
|
}
|
|
if (N1A == 0) return; //goto L210;
|
|
int KMOD = NBININ/N1A;
|
|
if (KMOD == 0) KMOD=1000000;
|
|
if ((NBININ <= N1A) || (j == 1) || (j == NBININ) || ((NBININ > N1A)
|
|
&& (j%KMOD == 0))) {
|
|
if (labelnumber == 0) {
|
|
aTexts.push_back(_text(XX,YY,
|
|
0,textSize,"1",
|
|
textAlign));
|
|
} else if (labelnumber == 1) {
|
|
aTexts.push_back(_text(XX,YY,
|
|
0,textSize,"10",
|
|
textAlign));
|
|
} else {
|
|
if (noExponent) {
|
|
out_error(m_out,"PaintAxis","debug : texts : FIXME : 003\n");
|
|
//FIXME textaxis->PaintTextNDC(XX,YY,&LABEL[first]);
|
|
} else {
|
|
//FIXME : support CERN-ROOT Latex encoding ?
|
|
// ::sprintf(CHTEMP, "10^{%d}", labelnumber);
|
|
snpf(CHTEMP,sizeof(CHTEMP),
|
|
"10^%d?", labelnumber); //PAW encoding.
|
|
aTexts.push_back(_text(XX,YY,
|
|
0,textSize,CHTEMP,
|
|
textAlign));
|
|
}
|
|
}
|
|
}
|
|
labelnumber++;
|
|
}
|
|
L160:
|
|
for (k=2;k<10;k++) {
|
|
|
|
// Plot intermediate tick marks
|
|
//double Xone; //rm shadow warning.
|
|
Xone = X00+AXMUL*(::log10(double(k))+double(decade)-XMNLOG);
|
|
if (X00 > Xone) continue;
|
|
if (Xone > X11) goto L200;
|
|
Y = 0;
|
|
if (!Mside) Y -= atick[1];
|
|
Xtwo = Xone;
|
|
TGaxis_Rotate(Xone,Y,cosphi,sinphi,X0,Y0,xpl2,ypl2);
|
|
TGaxis_Rotate(Xtwo,atick[1],cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
if (OptionVert) {
|
|
if ((X0 != X1) && (Y0 != Y1)) {
|
|
if (Mside) {
|
|
xpl1 = xpl2;
|
|
if (cosphi > 0) ypl1 = ypl2 + atick[1];
|
|
else ypl1 = ypl2 - atick[1];
|
|
}
|
|
else {
|
|
xpl1 = 0.5*(xpl1+xpl2);
|
|
xpl2 = xpl1;
|
|
ypl1 = 0.5*(ypl1+ypl2) + atick[1];
|
|
ypl2 = 0.5*(ypl1+ypl2) - atick[1];
|
|
}
|
|
}
|
|
}
|
|
int IDN = N1A*2;
|
|
if ((NBININ <= IDN) || ((NBININ > IDN) && (k == 5))) {
|
|
if(!drawGridOnly) {
|
|
aLinesAxis.push_back((float)xpl1);
|
|
aLinesAxis.push_back((float)ypl1);
|
|
aLinesAxis.push_back((float)xpl2);
|
|
aLinesAxis.push_back((float)ypl2);
|
|
}
|
|
|
|
// Draw the intermediate LOG labels if requested
|
|
|
|
if (MoreLogLabels && !OptionUnlab &&
|
|
!drawGridOnly && !overlap) {
|
|
if (noExponent) {
|
|
double rlab = double(k)*::pow(10.,labelnumber-1);
|
|
snpf(CHTEMP,sizeof(CHTEMP), "%g", rlab);
|
|
} else {
|
|
if (labelnumber-1 == 0) {
|
|
snpf(CHTEMP,sizeof(CHTEMP), "%d", k);
|
|
} else if (labelnumber-1 == 1) {
|
|
snpf(CHTEMP,sizeof(CHTEMP), "%d", 10*k);
|
|
} else {
|
|
//G.Barrand :
|
|
//::sprintf(CHTEMP, "%d#times10^{%d}", k, labelnumber-1);
|
|
snpf(CHTEMP,sizeof(CHTEMP),
|
|
"%dx10^%d!",k,labelnumber-1);//G.Barrand
|
|
}
|
|
}
|
|
TGaxis_Rotate (Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
|
|
if ((Y0 == Y1) && !OptionDown && !OptionUp) {
|
|
if (noExponent) YY += 0.33*charheight;
|
|
}
|
|
if (X0 == X1) XX += 0.25*charheight;
|
|
if (OptionVert) {
|
|
if ((X0 != X1) && (Y0 != Y1)) {
|
|
TGaxis_Rotate(Xone,Ylabel,cosphi,sinphi,X0,Y0,XX,YY);
|
|
if (cosphi > 0) YY += Ylabel;
|
|
else YY -= Ylabel;
|
|
}
|
|
}
|
|
//FIXME textaxis->SetTitle(CHTEMP);
|
|
double u = XX;
|
|
double v = YY;
|
|
if (firstintlab) {
|
|
//FIXME textaxis->GetBoundingBox(wi, hi); wi=(Uint)(wi*1.3); hi*=(Uint)(hi*1.3);
|
|
xi1 = 0;//FIXME gPad->XtoAbsPixel(u);
|
|
yi1 = 0;//FIXME gPad->YtoAbsPixel(v);
|
|
firstintlab = false;
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 010\n");
|
|
aTexts.push_back(_text(u,v,
|
|
0,textSize,CHTEMP,
|
|
textAlign));
|
|
} else {
|
|
xi2 = 0;//FIXME gPad->XtoAbsPixel(u);
|
|
yi2 = 0;//FIXME gPad->YtoAbsPixel(v);
|
|
if ((X0 == X1 && yi1-hi <= yi2) || (Y0 == Y1 && xi1+wi >= xi2)){
|
|
overlap = true;
|
|
} else {
|
|
xi1 = xi2;
|
|
yi1 = yi2;
|
|
//FIXME textaxis->GetBoundingBox(wi, hi); wi=(Uint)(wi*1.3); hi*=(Uint)(hi*1.3);
|
|
out_error(m_out,"PaintAxis","debug : texts : dummy : 011\n");
|
|
aTexts.push_back(_text(u,v,
|
|
0,textSize,CHTEMP,
|
|
textAlign));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw the intermediate LOG grid if only three
|
|
// decades are requested
|
|
if (OptionGrid && NBININ <= 5 && ndiv > 100) {
|
|
TGaxis_Rotate(Xone,0,cosphi,sinphi,X0,Y0,xpl2, ypl2);
|
|
TGaxis_Rotate
|
|
(Xone,grid_side*gridlength,cosphi,sinphi,X0,Y0,xpl1,ypl1);
|
|
aLinesGrid.push_back((float)xpl1);
|
|
aLinesGrid.push_back((float)ypl1);
|
|
aLinesGrid.push_back((float)xpl2);
|
|
aLinesGrid.push_back((float)ypl2);
|
|
}
|
|
} //endif ((NBININ <= IDN) ||
|
|
} //endfor (k=2;k<10;k++)
|
|
} //endfor (j=1; j<=NBININ; j++)
|
|
L200:
|
|
int kuku=0; if (kuku) { }
|
|
} //endif (OptionLog && ndiv)
|
|
|
|
|
|
//out_error(m_out,"android_debug","end");
|
|
//L210:
|
|
}
|
|
|
|
/*
|
|
void TGaxis_SetDecimals(bool dot)
|
|
{
|
|
// Set the Decimals flag
|
|
// By default, blank characters are stripped, and then the
|
|
// label is correctly aligned. The dot, if last character of the string,
|
|
// is also stripped, unless this option is specified.
|
|
// One can disable the option by calling axis.SetDecimals(true).
|
|
// Note the bit is set in fBits (as opposed to fBits2 in TAxis!)
|
|
|
|
if (dot) SetBit(TAxis_kDecimals);
|
|
else ResetBit(TAxis_kDecimals);
|
|
}
|
|
|
|
void TGaxis_SetMaxDigits(int maxd)
|
|
{
|
|
// static function to set fMaxDigits for axis with the bin content
|
|
// (y axis for 1-d histogram, z axis for 2-d histogram)
|
|
//fMaxDigits is the maximum number of digits permitted for the axis
|
|
//labels above which the notation with 10^N is used.
|
|
//For example, to accept 6 digits number like 900000 on an axis
|
|
//call TGaxis::SetMaxDigits(6). The default value is 5.
|
|
//fMaxDigits must be greater than 0.
|
|
|
|
fMaxDigits = maxd;
|
|
if (maxd < 1) fMaxDigits = 1;
|
|
}
|
|
|
|
void TGaxis_SetMoreLogLabels(bool more)
|
|
{
|
|
// Set the kMoreLogLabels bit flag
|
|
// When this option is selected more labels are drawn when in log scale
|
|
// and there is a small number of decades (<3).
|
|
// Note that this option is automatically inherited from TAxis
|
|
|
|
if (more) SetBit(TAxis_kMoreLogLabels);
|
|
else ResetBit(TAxis_kMoreLogLabels);
|
|
}
|
|
void TGaxis_SetNoExponent(bool noExponent)
|
|
{
|
|
// Set the NoExponent flag
|
|
// By default, an exponent of the form 10^N is used when the label values
|
|
// are either all very small or very large.
|
|
// One can disable the exponent by calling axis.SetNoExponent(true).
|
|
|
|
if (noExponent) SetBit(TAxis_kNoExponent);
|
|
else ResetBit(TAxis_kNoExponent);
|
|
}
|
|
void TGaxis_SetOption(const std::string& option)
|
|
{
|
|
fCHOPT = option;
|
|
}
|
|
*/
|
|
|
|
void set_time_format(const std::string& a_format)
|
|
// Change the format used for time plotting
|
|
// ========================================
|
|
// The format string for date and time use the same options as the one used
|
|
// in the standard strftime C function, i.e. :
|
|
// for date :
|
|
// %a abbreviated weekday name
|
|
// %b abbreviated month name
|
|
// %d day of the month (01-31)
|
|
// %m month (01-12)
|
|
// %y year without century
|
|
//
|
|
// for time :
|
|
// %H hour (24-hour clock)
|
|
// %I hour (12-hour clock)
|
|
// %p local equivalent of AM or PM
|
|
// %M minute (00-59)
|
|
// %S seconds (00-61)
|
|
// %% %
|
|
//
|
|
{
|
|
if (a_format.find("%F")!=std::string::npos || !a_format.size()) {
|
|
fTimeFormat = a_format;
|
|
//::printf("debug : SbAxisHPLOT::setTimeFormat : 000 : \"%s\"\n",
|
|
// fTimeFormat.c_str());
|
|
return;
|
|
}
|
|
|
|
std::string::size_type IdF = fTimeFormat.find("%F");
|
|
if (IdF!=std::string::npos) {
|
|
size_t LnF = fTimeFormat.size();
|
|
std::string stringtimeoffset = fTimeFormat.substr(IdF,LnF-IdF);
|
|
fTimeFormat = a_format;
|
|
fTimeFormat += stringtimeoffset;
|
|
//::printf("debug : SbAxisHPLOT::setTimeFormat : 001 : \"%s\"\n",
|
|
// fTimeFormat.c_str());
|
|
} else {
|
|
fTimeFormat = a_format;
|
|
|
|
// In CERN-ROOT :
|
|
//SetTimeOffset(gStyle->GetTimeOffset());
|
|
//TAxis::fTimeOffset = 788918400; // UTC time at 01/01/95
|
|
//double UTC_time_1995_01_01__00_00_00 = 788918400; //CERN-ROOT
|
|
//setTimeOffset(UTC_time_1995_01_01__00_00_00);
|
|
|
|
//Be consistent with SoAxis::timeOffset being 0.
|
|
double UTC_time_1970_01_01__00_00_00 = 0; //UNIX
|
|
set_time_offset(UTC_time_1970_01_01__00_00_00);
|
|
|
|
//::printf("debug : SbAxisHPLOT::setTimeFormat : 002 : \"%s\"\n",
|
|
// fTimeFormat.c_str());
|
|
}
|
|
}
|
|
|
|
void set_time_offset(double toffset,bool a_is_gmt = false) {
|
|
// Change the time offse t
|
|
|
|
std::string::size_type IdF = fTimeFormat.find("%F");
|
|
if (IdF!=std::string::npos) {
|
|
fTimeFormat = fTimeFormat.substr(0,IdF);
|
|
}
|
|
fTimeFormat += "%F";
|
|
|
|
time_t timeoff = (time_t)((long)(toffset));
|
|
struct tm* utctis = ::gmtime(&timeoff);
|
|
|
|
char tmp[256];
|
|
::strftime(tmp,256,"%Y-%m-%d %H:%M:%S",utctis);
|
|
fTimeFormat += tmp;
|
|
|
|
// append the decimal part of the time offset
|
|
double ds = toffset-(int)toffset;
|
|
if(ds!= 0) {
|
|
snpf(tmp,sizeof(tmp),"s%g",ds);
|
|
fTimeFormat += tmp;
|
|
}
|
|
|
|
// If the time is GMT, stamp fTimeFormat
|
|
if (a_is_gmt) fTimeFormat += " GMT";
|
|
|
|
//::printf("debug : SbAxisHPLOT::setTimeOffset : \"%s\"\n",
|
|
// fTimeFormat.c_str());
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
private:
|
|
static void optimizeLimits(
|
|
double A1,double A2,int nold
|
|
,double &BinLow, double &BinHigh
|
|
,int &nbins, double &BinWidth
|
|
,const std::string& aCHOPT
|
|
){
|
|
// static function to compute reasonable axis limits
|
|
//
|
|
// Input parameters:
|
|
//
|
|
// A1,A2 : Old WMIN,WMAX .
|
|
// BinLow,BinHigh : New WMIN,WMAX .
|
|
// nold : Old NDIV .
|
|
// nbins : New NDIV .
|
|
|
|
int lwid, kwid;
|
|
int ntemp = 0;
|
|
int jlog = 0;
|
|
double siground = 0;
|
|
double alb, awidth, sigfig;
|
|
double timemulti = 1;
|
|
int roundmode =0;
|
|
|
|
int OptionTime;
|
|
SETOPT(aCHOPT,'t',OptionTime);
|
|
|
|
double AL = tools::mn(A1,A2);
|
|
double AH = tools::mx(A1,A2);
|
|
if (AL == AH) AH = AL+1;
|
|
// if nold == -1 , program uses binwidth input from calling routine
|
|
if (nold == -1 && BinWidth > 0 ) goto L90;
|
|
ntemp = tools::mx(nold,2);
|
|
if (ntemp < 1) ntemp = 1;
|
|
|
|
L20:
|
|
awidth = (AH-AL)/double(ntemp);
|
|
timemulti = 1;
|
|
if (awidth >= FLT_MAX) goto LOK; //in float.h
|
|
if (awidth <= 0) goto LOK;
|
|
|
|
// If time representation, bin width should be rounded to seconds
|
|
// minutes, hours or days
|
|
|
|
if (OptionTime && awidth>=60) { // if width in seconds, treat it as normal
|
|
// width in minutes
|
|
awidth /= 60; timemulti *=60;
|
|
roundmode = 1; // round minutes (60)
|
|
// width in hours ?
|
|
if (awidth>=60) {
|
|
awidth /= 60; timemulti *= 60;
|
|
roundmode = 2; // round hours (24)
|
|
// width in days ?
|
|
if (awidth>=24) {
|
|
awidth /= 24; timemulti *= 24;
|
|
roundmode = 3; // round days (30)
|
|
// width in months ?
|
|
if (awidth>=30.43685) { // Mean month length in 1900.
|
|
awidth /= 30.43685; timemulti *= 30.43685;
|
|
roundmode = 2; // round months (12)
|
|
// width in years ?
|
|
if (awidth>=12) {
|
|
awidth /= 12; timemulti *= 12;
|
|
roundmode = 0; // round years (10)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Get nominal bin width in exponential for m
|
|
|
|
jlog = int(::log10(awidth));
|
|
if (jlog <-200 || jlog > 200) {
|
|
BinLow = 0;
|
|
BinHigh = 1;
|
|
BinWidth = 0.01;
|
|
nbins = 100;
|
|
return;
|
|
}
|
|
if (awidth <= 1 && (!OptionTime || timemulti==1) ) jlog--;
|
|
sigfig = awidth* ::pow(10.,-jlog) -1e-10;
|
|
//in the above statement, it is important to substract 1e-10
|
|
//to avoid precision problems if the tests below
|
|
|
|
// Round mantissa
|
|
|
|
switch (roundmode) {
|
|
|
|
// Round mantissa up to 1, 1.5, 2, 3, or 6 in case of minutes
|
|
case 1: // case 60
|
|
if (sigfig <= 1) siground = 1;
|
|
else if (sigfig <= 1.5 && jlog==1) siground = 1.5;
|
|
else if (sigfig <= 2) siground = 2;
|
|
else if (sigfig <= 3 && jlog ==1) siground = 3;
|
|
else if (sigfig <= 5 && sigfig>3 && jlog ==0) siground = 5; //added (Damir in 3.10/02)
|
|
else if (jlog==0) {siground = 1; jlog++;}
|
|
else siground = 6;
|
|
break;
|
|
case 2: // case 12 and 24
|
|
|
|
// Round mantissa up to 1, 1.2, 2, 2.4, 3 or 6 in case of hours or months
|
|
if (sigfig <= 1 && jlog==0) siground = 1;
|
|
else if (sigfig <= 1.2 && jlog==1) siground = 1.2;
|
|
else if (sigfig <= 2 && jlog==0) siground = 2;
|
|
else if (sigfig <= 2.4 && jlog==1) siground = 2.4;
|
|
else if (sigfig <= 3) siground = 3;
|
|
else if (sigfig <= 6) siground = 6;
|
|
else if (jlog==0) siground = 12;
|
|
else siground = 2.4;
|
|
break;
|
|
|
|
//- Round mantissa up to 1, 1.4, 2, or 7 in case of days (weeks)
|
|
case 3: // case 30
|
|
if (sigfig <= 1 && jlog==0) siground = 1;
|
|
else if (sigfig <= 1.4 && jlog==1) siground = 1.4;
|
|
else if (sigfig <= 3 && jlog ==1) siground = 3;
|
|
else siground = 7;
|
|
break;
|
|
default :
|
|
|
|
// Round mantissa up to 1, 2, 2.5, 5, or 10 in case of decimal number
|
|
if (sigfig <= 1) siground = 1;
|
|
else if (sigfig <= 2) siground = 2;
|
|
else if (sigfig <= 5 && (!OptionTime || jlog<1)) siground = 5;
|
|
else if (sigfig <= 6 && OptionTime && jlog==1) siground = 6;
|
|
else {siground = 1; jlog++; }
|
|
break;
|
|
}
|
|
|
|
BinWidth = siground* ::pow(10.,jlog);
|
|
if (OptionTime) BinWidth *= timemulti;
|
|
|
|
// Get new bounds from new width BinWidth
|
|
|
|
L90:
|
|
alb = AL/BinWidth;
|
|
if (TMath_Abs(alb) > 1e9) {
|
|
BinLow = AL;
|
|
BinHigh = AH;
|
|
if (nbins > 10*nold && nbins > 10000) nbins = nold;
|
|
return;
|
|
}
|
|
lwid = int(alb);
|
|
if (alb < 0) lwid--;
|
|
BinLow = BinWidth*double(lwid);
|
|
alb = AH/BinWidth + 1.00001;
|
|
kwid = int(alb);
|
|
if (alb < 0) kwid--;
|
|
BinHigh = BinWidth*double(kwid);
|
|
nbins = kwid - lwid;
|
|
if (nold == -1) goto LOK;
|
|
if (nold <= 5) { // Request for one bin is difficult case
|
|
if (nold > 1 || nbins == 1)goto LOK;
|
|
BinWidth = BinWidth*2;
|
|
nbins = 1;
|
|
goto LOK;
|
|
}
|
|
if (2*nbins == nold && !OptionTime) {ntemp++; goto L20; }
|
|
|
|
LOK:
|
|
double oldBinLow = BinLow;
|
|
double oldBinHigh = BinHigh;
|
|
int oldnbins = nbins;
|
|
|
|
double atest = BinWidth*0.0001;
|
|
//if (TMath_Abs(BinLow-A1) >= atest) { BinLow += BinWidth; nbins--; } //replaced by Damir in 3.10/02
|
|
//if (TMath_Abs(BinHigh-A2) >= atest) { BinHigh -= BinWidth; nbins--; } //by the next two lines
|
|
if (AL-BinLow >= atest) { BinLow += BinWidth; nbins--; }
|
|
if (BinHigh-AH >= atest) { BinHigh -= BinWidth; nbins--; }
|
|
if (!OptionTime && BinLow >= BinHigh) {
|
|
//this case may happen when nbins <=5
|
|
BinLow = oldBinLow;
|
|
BinHigh = oldBinHigh;
|
|
nbins = oldnbins;
|
|
}
|
|
else if (OptionTime && BinLow>=BinHigh) {
|
|
nbins = 2*oldnbins;
|
|
BinHigh = oldBinHigh;
|
|
BinLow = oldBinLow;
|
|
BinWidth = (oldBinHigh - oldBinLow)/nbins;
|
|
atest = BinWidth*0.0001;
|
|
if (AL-BinLow >= atest) { BinLow += BinWidth; nbins--; }
|
|
if (BinHigh-AH >= atest) { BinHigh -= BinWidth; nbins--; }
|
|
}
|
|
}
|
|
|
|
static void adjustBinSize(
|
|
double A1,double A2,int nold
|
|
,double &BinLow, double &BinHigh, int &nbins, double &BinWidth
|
|
){
|
|
// Axis labels optimisation
|
|
// ========================
|
|
//
|
|
// This routine adjusts the bining of the axis
|
|
// in order to have integer values for the labels
|
|
//
|
|
// _Input parameters:
|
|
//
|
|
// A1,A2 : Old WMIN,WMAX .
|
|
// BinLow,BinHigh : New WMIN,WMAX .
|
|
// nold : Old NDIV (primary divisions)
|
|
// nbins : New NDIV .
|
|
//
|
|
BinWidth = TMath_Abs(A2-A1)/double(nold);
|
|
if (BinWidth <= 1) { BinWidth = 1; BinLow = int(A1); }
|
|
else {
|
|
int width = int(BinWidth/5) + 1;
|
|
BinWidth = 5*width;
|
|
BinLow = int(A1/BinWidth)*BinWidth ;
|
|
|
|
// We determine BinLow to have one tick mark at 0
|
|
// if there are negative labels.
|
|
|
|
if (A1 < 0) {
|
|
for (int ic=0; ic<1000; ic++) {
|
|
double rbl = BinLow/BinWidth;
|
|
int ibl = int(BinLow/BinWidth);
|
|
if ( (rbl-ibl) == 0 || ic > width) { BinLow -= 5; break;}
|
|
}
|
|
}
|
|
}
|
|
BinHigh = int(A2);
|
|
nbins = 0;
|
|
double XB = BinLow;
|
|
while (XB <= BinHigh) {
|
|
XB += BinWidth;
|
|
nbins++;
|
|
}
|
|
BinHigh = XB - BinWidth;
|
|
}
|
|
void setLabelOffset(float aValue) { fLabelOffset = aValue;}
|
|
void setLabelSize(float aValue) { fLabelSize = aValue;}
|
|
void setTitleOffset(float aValue) { fTitleOffset = aValue;}
|
|
void setTitleSize(float aValue) { fTitleSize = aValue; }
|
|
public:
|
|
void set_tick_size(float aValue) { fTickSize = aValue;}
|
|
|
|
private:
|
|
std::ostream& m_out;
|
|
//int fMaxDigits; //!Number of digits above which the 10>N notation is used
|
|
private:
|
|
//TObject :
|
|
unsigned int fBits; //bit field status word
|
|
float fTickSize; //Size of primary tick mark in NDC
|
|
float fLabelOffset; //Offset of label wrt axis
|
|
float fLabelSize; //Size of labels in NDC
|
|
float fTitleOffset; //Offset of title wrt axis
|
|
float fTitleSize; //Size of title in NDC
|
|
int fLabelFont; //Font for labels
|
|
std::string fTitle; //axis title
|
|
std::string fTimeFormat; //Time format, ex: 09/12/99 12:34:00
|
|
};
|
|
|
|
}}
|
|
|
|
#endif
|