ndm  0.1.2
Axis.cc
1 #include <iostream>
2 #include <cmath>
3 
4 #include <ndm.hh>
5 #include "Utils.hh"
6 
7 #include "Axis.hh"
8 
9 namespace NDM {
10 Axis::Axis(double min, double max, EMode mode, double delta) : mMin(min), mMax(max), mMode(mode), mMinDelta(delta)
11 {
15 
16  // Chcek if min is higher then max. If it is switch min with max
17  if (min > max) {
18  spdlog::warn("Swaping min[{}] and max[{}] values entered by user, because min is higher then max !!!", min,
19  max);
20  mMax = min;
21  mMin = max;
22  }
23 
25 }
27 {
31 }
32 
34 {
38 
39  // Checking for numer of decimels after dot
40  int decimalsMin = decimels_right(mMin);
41  int decimalsMax = decimels_right(mMax);
42 
43  // If both decimels are zero then we check, if we can divide to lower number
44  if (decimalsMin == 0 && decimalsMax == 0) {
45 
46  // Checking for numer of decimels before dot
47  decimalsMin = decimels_left(mMin);
48  decimalsMax = decimels_left(mMax);
49 
50  // Calculate decimel minimum
51  int m = std::min(decimalsMin, decimalsMax);
52 
53  // Sets coresponding values for mMultiply and mShift
54  mMultiply = 1 / std::pow(10, m);
55  mShift = mMin * mMultiply;
56  }
57  else {
58 
59  // Calculate decimel maximum
60  int m = std::max(decimalsMin, decimalsMax);
61 
62  // Sets coresponding values for mMultiply and mShift
63  mMultiply = std::pow(10, m);
64  mShift = mMin * mMultiply;
65  }
66 
67  // Handle mode setting
68  if (mMode == kAligned)
69  mMaxB = std::pow(2, ceil(log2(maxb_user())));
70  else
71  mMaxB = maxb_user();
72 }
73 
74 void Axis::minmax(double min, double max)
75 {
79  mMin = min;
80  mMax = max;
81 }
82 
83 void Axis::find(double v, double & min, double & max, std::string & path, int levelrequest, int levelmax)
84 {
88 
89  spdlog::trace("Finding value[{}] levelrequest[{}] levelmas[{}]...", v, levelrequest, levelmax);
90 
91  // Reseting path
92  path = "";
93 
94  int currentlevel = 0;
95  min = 0;
96  max = maxb();
97 
98  if (v < mMin || v > mMax || NDM::Utils::is_equal(v, mMax)) {
99  spdlog::warn("Value '{}' is out of range <{},{}) !!!", v, mMin, mMax);
100  min = max = 0;
101  return;
102  }
103 
104  v = to_internal(v);
105 
106  find(v, levelrequest, levelmax, currentlevel, min, max, path);
107  if (max > to_internal(mMax)) max = to_internal(mMax);
108 
109  // We should convert min and max to user format
110  min = to_user(min);
111  max = to_user(max);
112  spdlog::trace("Result value[{}] <{},{}) path[{}] level[{}] internal[<{},{})] ...", to_user(v), min, max, path,
113  currentlevel, to_internal(min), to_internal(max));
114 }
115 
116 void Axis::find(double & v, int & levelrequest, int & levelmax, int & currentlevel, double & min, double & max,
117  std::string & path)
118 {
122 
123  if (NDM::Utils::is_equal(v, min)) {
124  if (currentlevel >= levelrequest) return;
125  }
126  if (NDM::Utils::is_equal(v, max)) {
127  if (currentlevel == 0) return;
128  double oldmax = max;
129  max += (max - min);
130  min = oldmax;
131  return;
132  }
133 
134  if ((max - min) < mMinDelta) return;
135 
136  if (currentlevel > levelmax) return;
137 
138  currentlevel++;
139 
140  double avg = (max + min) / 2;
141  spdlog::trace("min[{}]({}) max[{}]({}) avg[{}]({}) value[{}] ...", min, to_user(min), max, to_user(max), avg,
142  to_user(avg), to_user(v));
143  if (v >= avg) {
144  min = avg;
145  path += "1";
146  }
147  else {
148  max = avg;
149  path += "0";
150  }
151 
152  spdlog::trace("level=[{}] path={}...", currentlevel, path);
153  find(v, levelrequest, levelmax, currentlevel, min, max, path);
154 }
155 
156 void Axis::expand(char direction, int power)
157 {
161  modify_range(direction, std::abs(power));
162 }
163 
164 void Axis::shrink(char direction, int power)
165 {
169  modify_range(direction, -std::abs(power));
170 }
171 
172 void Axis::modify_range(char direction, int power)
173 {
177 
178  if (power == 0) {
179  spdlog::warn("Power is zero !!! Doing nothing ...");
180  return;
181  }
182 
183  if ((power < 0) && std::pow(2, std::abs(power)) > mMaxB) {
184  print();
185  spdlog::warn("Divide is not possible !!! Reason : mMaxB[{}] < divide[{}]", mMaxB, std::pow(2, std::abs(power)));
186  return;
187  }
188 
189  if (direction == '>') {
190  if (power > 0) {
191  for (int i = 0; i < power; ++i) mMax += (mMax - mMin);
192  }
193  else if (power < 0) {
194 
195  for (int i = 0; i < std::abs(power); ++i) mMax -= (mMax - mMin) / 2;
196  }
197  }
198  else if (direction == '<') {
199  if (power > 0) {
200  for (int i = 0; i < power; ++i) mMin -= (mMax - mMin);
201  }
202  else if (power < 0) {
203 
204  for (int i = 0; i < std::abs(power); ++i) mMin += (mMax - mMin) / 2;
205  }
206  }
207  else {
208  spdlog::error("Direction '{}' is not supported !!!");
209  spdlog::error(" Hint: Try '>' for right or '<' for left.");
210  }
211 
213 }
214 
215 void Axis::print() const
216 {
220 
221  spdlog::info("min[{}] max[{}] maxb[{}({})] mode[{}] level[{}] shift[{}] multiply[{}]", mMin, mMax, mMaxB, maxb_user(),
223 }
224 
225 int Axis::decimels_right(double num, double mult, double min, double max)
226 {
230 
231  int n = 0;
232  double fractpart, intpart, tmp;
233  fractpart = modf(num, &intpart);
234  spdlog::trace("L1 : num[{}] tmp[{}] intpart[{}] fractpart[{}]", num, tmp, intpart, fractpart);
235  while (fractpart > min && fractpart < max) {
236  tmp = fractpart * mult;
237  fractpart = modf(tmp, &intpart);
238  spdlog::trace("L2 : num[{}] tmp[{}] intpart[{}] fractpart[{}]", num, tmp, intpart, fractpart);
239  n++;
240  }
241 
242  return n;
243 }
244 
245 int Axis::decimels_left(double num, double mult, double min)
246 {
250 
251  if (num < 0.01) return 0;
252 
253  int n = 0;
254  double fractpart, intpart, tmp;
255  fractpart = modf(num, &intpart);
256  spdlog::trace("H1 : num[{}] tmp[{}] intpart[{}] fractpart[{}]", num, tmp, intpart, fractpart);
257  while (fractpart < min) {
258  tmp = intpart / mult;
259  fractpart = modf(tmp, &intpart);
260  spdlog::trace("H2 : num[{}] tmp[{}] intpart[{}] fractpart[{}]", num, tmp, intpart, fractpart);
261  n++;
262  }
263  return n - 1;
264 }
265 
266 void Axis::split(std::vector<double> & mins, int level)
267 {
271  mins.clear();
272  double p2 = pow(2, level);
273  if (p2 > mMaxB) {
274  spdlog::error("Cannot split histogram with {} bins into {} levels because (2^{}={}) > {}. Stop.", mMaxB, level,
275  level, p2, mMaxB);
276  return;
277  }
278  double step = mMaxB / p2;
279 
280  spdlog::debug("split: level[{}] max[{}] step[{}]", level, mMaxB, step);
281 
282  for (double iMins = 0; iMins < mMaxB; iMins += step) {
283  if (iMins >= to_internal(mMax)) break;
284  mins.push_back(to_user(iMins));
285  }
286 }
287 
288 } // namespace NDM
void print() const
Prints axis info.
Definition: Axis.cc:215
void split(std::vector< double > &mins, int level)
Definition: Axis.cc:266
double mMaxB
Internal maximum.
Definition: Axis.hh:65
void minmax(double min, double max)
Sets user defined minimum and maximum.
Definition: Axis.cc:74
int decimels_right(double num, double mult=10, double min=0.01, double max=0.99)
Definition: Axis.cc:225
void find(double v, double &min, double &max, std::string &path, int levelrequest=-1, int levelmax=100)
Find bin and print info for given value.
Definition: Axis.cc:83
double mMinDelta
Minimal delta of axis range.
Definition: Axis.hh:69
double maxb_user() const
Returns internal maximum2.
Definition: Axis.hh:45
unsigned int mLevel
Level of division.
Definition: Axis.hh:68
EMode
Mode for axis.
Definition: Axis.hh:15
unsigned int level() const
Returns level.
Definition: Axis.hh:58
double maxb() const
Returns internal maximum.
Definition: Axis.hh:43
double min() const
Returns user defined minimum.
Definition: Axis.hh:39
double max() const
Returns user defined maximum.
Definition: Axis.hh:41
void shrink(char direction='>', int power=1)
Shrink range.
Definition: Axis.cc:164
double mMin
User defined minimum.
Definition: Axis.hh:62
void expand(char direction='>', int power=1)
Expand range.
Definition: Axis.cc:156
double mShift
Shift to the internal min/max parameters.
Definition: Axis.hh:66
double to_user(double v) const
Convert interal to user format.
Definition: Axis.hh:53
void recalculate_range()
Definition: Axis.cc:33
double mMultiply
Multiply to the internal min/max parameters.
Definition: Axis.hh:67
EMode mMode
Axis mode.
Definition: Axis.hh:64
double to_internal(double v) const
Convert user to internal format.
Definition: Axis.hh:55
virtual ~Axis()
Definition: Axis.cc:26
void modify_range(char direction='>', int power=1)
Definition: Axis.cc:172
double mMax
User defined maximum.
Definition: Axis.hh:63
Axis(double min=0.0, double max=1.0, EMode mode=kAligned, double delta=1)
Definition: Axis.cc:10
int decimels_left(double num, double mult=10, double min=0.01)
Definition: Axis.cc:245