Engauge Digitizer 2
Loading...
Searching...
No Matches
GridInitializer.cpp
Go to the documentation of this file.
2#include "EngaugeAssert.h"
3#include "GridInitializer.h"
4#include "Logger.h"
5#include <math.h>
6#include <qmath.h>
7#include "Transformation.h"
8
12
13void GridInitializer::axisScale (double xMin,
14 double xMax,
15 bool linearAxis,
16 double &xStart,
17 double &xStop,
18 double &xDelta,
19 int &xCount) const
20{
21 const double range_epsilon = 0.00000000001;
23 int nDigitRange;
24
25 // Define number of digits of precision. although value of 10 seems
26 // desirable, the sprintf statements elsewhere in this file, which
27 // operate on values with the specified precision, just lose it
28 // for more than 8 digits. example '%.7lg' on 40.000005 gives 40.00001
29 const int nDigitsPrecision = 8;
30
31 // sort the input values
32 if (xMin > xMax) {
33 double xTemp = xMin;
34 xMin = xMax;
35 xMax = xTemp;
36 }
37
38 // Scale the coordinates logarithmically if log flag is set
39 if (!linearAxis) {
42 xMin = log10(xMin);
43 xMax = log10(xMax);
44 }
45
46 // Round off average to first significant digit of range
47 xAverage = (xMin + xMax) / 2.0;
48 xRange = xMax - xMin;
49 if (qAbs (xRange) <= 0) {
50 xRange = fabs (xAverage / 10.0); // for null range use arbitrary range
51 }
53 xDelta = pow (10.0, double (nDigitRange));
55
56 if (xRange > range_epsilon) {
57 // Adjust stepsize if more points are needed, accounting for roundoff
58 while (fabs (xRange / xDelta) <= 2.000001) {
59 xDelta /= 2.0;
60 }
61 }
62
63 // Go down until min point is included
65 while (xStart > xMin) {
66 xStart -= xDelta;
67 }
68
69 // Go up until max point is included
71 while (xStop < xMax) {
72 xStop += xDelta;
73 }
74
75 xCount = 1 + qFloor ((xStop - xStart) / xDelta + 0.5);
76
77 if (!linearAxis) {
78
79 // Convert from log scale back to linear scale. We make sure to keep numbers like 10^-8 unmolested
80 xStart = pow(10.0, xStart);
81 xStop = pow(10.0, xStop);
82 xDelta = pow(10.0, xDelta);
83
84 } else {
85
86 // Roundoff to eliminate epsilons of 10^-10
88 xStart = roundOffToPower(xStart, power);
89 xStop = roundOffToPower(xStop, power);
90 xDelta = roundOffToPower(xDelta, power);
91
92 }
93}
94
96 double start,
97 double stop,
98 double step) const
99{
100 int count;
101
102 if (linearAxis) {
103 if (qAbs (step) <= 0) {
104 count = 1;
105 } else {
106 count = qFloor (1.0 + (stop - start) / step);
107 }
108 } else {
109 if ((start <= 0) || (step <= 0.0)) {
110 count = 1;
111 } else {
112 count = qFloor (1.0 + log10 (stop / start) / log10 (step));
113 }
114 }
115
116 return count;
117}
118
120 double stop,
121 double step,
122 int count) const
123{
124 double start;
125
126 if (linearAxis) {
127 start = stop - step * (count - 1);
128 } else {
129 start = stop / pow (step, double (count - 1));
130 }
131
132 return start;
133}
134
136 double start,
137 double stop,
138 int count) const
139{
140 double step;
141
142 if (linearAxis) {
143 if (count > 1) {
144 step = (stop - start) / (count - 1);
145 } else {
146 step = stop - start;
147 }
148 } else {
149 if (start <= 0.0) {
150 step = 1.0;
151 } else {
152 if (count > 1) {
153 step = pow (stop / start, 1.0 / double (count - 1));
154 } else {
155 step = stop / start;
156 }
157 }
158 }
159
160 return step;
161}
162
164 double start,
165 double step,
166 int count) const
167{
168 double stop;
169
170 if (linearAxis) {
171 stop = start + step * (count - 1);
172 } else {
173 stop = start * pow (step, double (count - 1));
174 }
175
176 return stop;
177}
178
180 const QPointF &boundingRectGraphMax,
181 const DocumentModelCoords &modelCoords) const
182{
183 LOG4CPP_INFO_S ((*mainCat)) << "GridInitializer::initializeWithNarrowCoverage";
184
185 DocumentModelGridDisplay modelGridDisplay;
186
187 int count;
188 double start, stop, step;
189
190 // X/theta coordinate
191 axisScale (boundingRectGraphMin.x(),
192 boundingRectGraphMax.x(),
193 (modelCoords.coordScaleXTheta() == COORD_SCALE_LINEAR),
194 start,
195 stop,
196 step,
197 count);
198
199 modelGridDisplay.setDisableX (GRID_COORD_DISABLE_COUNT);
200 modelGridDisplay.setCountX (unsigned (count));
201 modelGridDisplay.setStartX (start);
202 modelGridDisplay.setStepX (step);
203 modelGridDisplay.setStopX (stop);
204
205 // Y/radius coordinate
206 axisScale (boundingRectGraphMin.y(),
207 boundingRectGraphMax.y(),
208 (modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR),
209 start,
210 stop,
211 step,
212 count);
213
214 modelGridDisplay.setDisableY (GRID_COORD_DISABLE_COUNT);
215 modelGridDisplay.setCountY (unsigned (count));
216 modelGridDisplay.setStartY (start);
217 modelGridDisplay.setStepY (step);
218 modelGridDisplay.setStopY (stop);
219
220 modelGridDisplay.setStable (true);
221
222 return modelGridDisplay;
223}
224
226 const QPointF &boundingRectGraphMax,
227 const DocumentModelCoords &modelCoords,
228 const Transformation &transformation,
229 const QSize &imageSize) const
230{
231 LOG4CPP_INFO_S ((*mainCat)) << "GridInitializer::initializeWithWidePolarCoverage";
232
233 DocumentModelGridDisplay modelGridDisplay = initializeWithNarrowCoverage (boundingRectGraphMin,
234 boundingRectGraphMax,
235 modelCoords);
236
237 if (modelCoords.coordsType() == COORDS_TYPE_POLAR) {
238
239 overridePolarCoordinateSettings (modelCoords,
240 transformation,
241 modelGridDisplay,
242 imageSize);
243 }
244
245 return modelGridDisplay;
246}
247
248void GridInitializer::overridePolarCoordinateSettings (const DocumentModelCoords &modelCoords,
249 const Transformation &transformation,
250 DocumentModelGridDisplay &modelGridDisplay,
251 const QSize &imageSize) const
252{
254
255 // We make sure the angular range is over the entire circle, which is probably useful
256 // unless the orgin is very close to a corner of the graph, in which case the large range does not hurt anything
257 double startX = 0.0;
258 double stopX = 360.0;
259 double stepX = 30.0;
260 int countX = qFloor (0.5 + (stopX - startX) / stepX);
261 modelGridDisplay.setStartX (startX);
262 modelGridDisplay.setStepX (stepX);
263 modelGridDisplay.setStopX (stopX);
264 modelGridDisplay.setCountX (unsigned (countX));
265
266 // We extend the range to cover the four corners of the image, since otherwise
267 // areas around at least some graph corners are not covered by the grid lines
269 transformation.transformScreenToRawGraph (QPointF (0 , imageSize.height ()), posTL);
270 transformation.transformScreenToRawGraph (QPointF (0 , 0 ), posBL);
271 transformation.transformScreenToRawGraph (QPointF (imageSize.width (), imageSize.height ()), posTR);
272 transformation.transformScreenToRawGraph (QPointF (imageSize.width (), 0 ), posBR);
273
274 double radiusTL = qSqrt (posTL.x () * posTL.x () + posTL.y () * posTL.y ());
275 double radiusBL = qSqrt (posBL.x () * posBL.x () + posBL.y () * posBL.y ());
276 double radiusTR = qSqrt (posTR.x () * posTR.x () + posTR.y () * posTR.y ());
277 double radiusBR = qSqrt (posBR.x () * posBR.x () + posBR.y () * posBR.y ());
278
279 double radius = qMax (qMax (qMax (radiusTL, radiusBL), radiusTR), radiusBR);
280
281 double startY = (modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR ?
282 0.0 :
283 modelCoords.originRadius());
284 double stopY = radius;
285 double stepY = modelGridDisplay.stepY ();
286 double denominator = (modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR ?
287 stepY :
288 qLn (stepY));
289 int countY = 1;
290 if (qAbs (denominator) > 0) {
291 countY = (modelCoords.coordScaleYRadius() == COORD_SCALE_LINEAR ?
292 qFloor (0.5 + (stopY - startY) / denominator) :
293 qFloor (0.5 + (qLn (stopY) - qLn (startY)) / denominator));
294 }
295
296 modelGridDisplay.setStartY (startY);
297 modelGridDisplay.setStopY (stopY);
298 modelGridDisplay.setCountY (unsigned (countY));
299}
300
301double GridInitializer::roundOffToPower(double arg,
302 int power) const
303{
304 double powerOf10 = pow (10.0, power);
305 return powerOf10 * floor (arg / powerOf10 + 0.5);
306}
307
309{
310 const int minPower = -30; // MAX_DOUBLE is 10^38
311
312 double avalue = fabs(value);
313 if (avalue < pow(10.0, minPower)) {
314 return minPower;
315 } else {
316 return qFloor (log10 (avalue));
317 }
318}
@ COORD_SCALE_LINEAR
Definition CoordScale.h:13
@ COORDS_TYPE_POLAR
Definition CoordsType.h:14
const int INNER_RADIUS_MIN
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) define ENGAUGE...
@ GRID_COORD_DISABLE_COUNT
log4cpp::Category * mainCat
Definition Logger.cpp:14
Model for DlgSettingsCoords and CmdSettingsCoords.
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
CoordsType coordsType() const
Get method for coordinates type.
double originRadius() const
Get method for origin radius in polar mode.
Model for DlgSettingsGridDisplay and CmdSettingsGridDisplay.
void setStepX(double stepX)
Set method for x grid line increment.
void setStepY(double yStep)
Set method for y grid line increment.
void setStopX(double stopX)
Set method for x grid line upper bound (inclusive).
void setDisableX(GridCoordDisable disableX)
Set method for x grid line disabled variable.
void setStopY(double yStop)
Set method for y grid line upper bound (inclusive).
void setDisableY(GridCoordDisable disableY)
Set method for y grid line disabled variable.
double stepY() const
Get method for y grid line increment.
void setCountX(unsigned int countX)
Set method for x grid line count.
void setStartX(double startX)
Set method for x grid line lower bound (inclusive).
void setStable(bool stable)
Set method for stable flag.
void setStartY(double yStart)
Set method for y grid line lower bound (inclusive).
void setCountY(unsigned int countY)
Set method for y grid line count.
int valuePower(double value) const
Compute power of 10 for input value, rounding down to nearest integer solution of value>=10**solution...
double computeStep(bool linearAxis, double start, double stop, int count) const
Compute axis scale step from the other axis parameters.
double computeStart(bool linearAxis, double stop, double step, int count) const
Compute axis scale start from the other axis parameters.
int computeCount(bool linearAxis, double start, double stop, double step) const
Compute axis scale count from the other axis parameters.
GridInitializer()
Single constructor.
DocumentModelGridDisplay initializeWithNarrowCoverage(const QPointF &boundingRectGraphMin, const QPointF &boundingRectGraphMax, const DocumentModelCoords &modelCoords) const
Initialize given the boundaries of the graph coordinates.
DocumentModelGridDisplay initializeWithWidePolarCoverage(const QPointF &boundingRectGraphMin, const QPointF &boundingRectGraphMax, const DocumentModelCoords &modelCoords, const Transformation &transformation, const QSize &imageSize) const
Initialize given the boundaries of the graph coordinates, and then extra processing for polar coordin...
double computeStop(bool linearAxis, double start, double step, int count) const
Compute axis scale stop from the other axis parameters.
Affine transformation between screen and graph coordinates, based on digitized axis points.
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18