1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
#include "qwt3d_helper.h"
#include "qwt3d_autoscaler.h"
using namespace Qwt3D;
namespace
{
double floorExt( int& exponent, double x, std::vector<double>& sortedmantissi)
{
if (x == 0.0)
{
exponent = 0;
return 0.0;
}
double sign = (x > 0) ? 1.0 : -1.0;
double lx = log10(fabs(x));
exponent = (int)floor(lx);
double fr = pow(10.0, lx - exponent);
if (fr >= 10.0)
{
fr = 1.0;
++exponent;
}
else
{
for (int i=(int)sortedmantissi.size()-1; i>=0;--i)
{
if (fr>=sortedmantissi[i])
{
fr = sortedmantissi[i];
break;
}
}
}
return sign * fr;
}
/*
\brief Find the largest value out of {1,2,5}*10^n with an integer number n
which is smaller than or equal to x
\param exponent n
\param x Input value
\return Mantissa
*/
double floor125( int& exponent, double x)
{
std::vector<double> m(2);
m[0] = 1;
m[1] = 2;
m[2] = 5;
return floorExt(exponent, x, m);
}
} // anon ns
//! Initializes with an {1,2,5} sequence of mantissas
LinearAutoScaler::LinearAutoScaler()
{
init(0,1,1);
mantissi_ = std::vector<double>(3);
mantissi_[0] = 1;
mantissi_[1] = 2;
mantissi_[2] = 5;
}
//! Initialize with interval [0,1] and one requested interval
/*!
val mantisse A increasing ordered vector of values representing
mantisse values between 1 and 9.
*/
LinearAutoScaler::LinearAutoScaler(std::vector<double>& mantisse)
{
init(0,1,1);
if (mantisse.empty())
{
mantissi_ = std::vector<double>(3);
mantissi_[0] = 1;
mantissi_[1] = 2;
mantissi_[2] = 5;
return;
}
mantissi_ = mantisse;
}
//! Initialize with interval [start,stop] and number of requested intervals
/**
Switchs start and stop, if stop < start and sets intervals = 1 if ivals < 1
*/
void LinearAutoScaler::init(double start, double stop, int ivals)
{
start_ = start;
stop_ = stop;
intervals_ = ivals;
if (start_ > stop_)
{
double tmp = start_;
start_ = stop_;
stop_ = tmp;
}
if (intervals_ < 1)
intervals_ = 1;
}
/*!
\return Anchor value
\verbatim
|_______|____________ _ _ _ _ _____|_____________|________________
0 m*10^n start anchor := c*m*10^n
c 'minimal' (anchor-start < m*10^n)
\endverbatim
*/
double LinearAutoScaler::anchorvalue(double start, double m, int n)
{
double stepval = m * pow(10.0, n);
return stepval * ceil(start / stepval);
}
/*!
\return New number of intervals (:= l_intervals + r_intervals)
\param l_intervals Number of intervals left from anchor
\param r_intervals Number of intervals right from anchor
\verbatim
-l_intervals * i -2 * i -i +r_intervals * i
|
|______|_______ _ _ _ ____|____|___ _ _ _ _ _ _ _|_______|_______|_ _ _ _ _ _ _____|__|_____
| | | |
0 i := m*10^n start anchor stop
c 'minimal' (anchor-start < m*10^n)
\endverbatim
*/
int LinearAutoScaler::segments(int& l_intervals, int& r_intervals, double start, double stop, double anchor, double m, int n)
{
double val = m * pow(10.0, n);
double delta = (stop - anchor) / val;
r_intervals = (int)floor(delta); // right side intervals
delta = (anchor - start) / val;
l_intervals = (int)floor(delta); // left side intervals
return r_intervals + l_intervals;
}
/*!
\brief Does the actual scaling
\return Number of intervals after rescaling. This will in the most cases differ
from the requested interval number! Always >0.
\param a Start value after scaling (always >= start)
\param b Stop value after scaling (always <= stop)
\param start Start value
\param stop Stop value
\param ivals Requested intervals
\return Number of intervals after autoscaling
If the given interval has zero length the function returns the current
interval number and a and b remain unchanged.
*/
int LinearAutoScaler::execute(double& a, double& b, double start, double stop, int ivals)
{
init(start,stop,ivals);
double delta = stop_ - start_;
if (isPracticallyZero(delta))
return intervals_;
double c;
int n;
c = floorExt(n, delta, mantissi_);
int l_ival, r_ival;
double anchor = anchorvalue(start_, c, n);
int ival = segments(l_ival, r_ival, start_, stop_, anchor, c, n);
if (ival >= intervals_)
{
a = anchor - l_ival * c * pow(10.0,n);
b = anchor + r_ival * c * pow(10.0,n);
intervals_ = ival;
return intervals_;
}
int prev_ival, prev_l_ival, prev_r_ival;
double prev_anchor;
double prev_c;
int prev_n;
while(1)
{
prev_c = c;
prev_n = n;
prev_anchor = anchor;
prev_ival = ival;
prev_l_ival = l_ival;
prev_r_ival = r_ival;
if (int(c) == 1)
{
c = mantissi_.back();
--n;
}
else
{
for (unsigned int i=mantissi_.size()-1; i>0; --i)
{
if (int(c) == mantissi_[i])
{
c = mantissi_[i-1];
break;
}
}
}
anchor = anchorvalue(start_, c, n);
ival = segments(l_ival, r_ival, start_, stop_, anchor, c, n);
int prev_diff = intervals_ - prev_ival;
int actual_diff = ival - intervals_;
if (prev_diff >= 0 && actual_diff >= 0)
{
if (prev_diff < actual_diff)
{
c = prev_c;
n = prev_n;
anchor = prev_anchor;
ival = prev_ival;
l_ival = prev_l_ival;
r_ival = prev_r_ival;
}
a = anchor - l_ival * c * pow(10.0,n);
b = anchor + r_ival * c * pow(10.0,n);
intervals_ = ival;
break;
}
}
return intervals_;
}
|