Engauge Digitizer  2
GridInitializer.cpp
Go to the documentation of this file.
1 #include "DocumentModelCoords.h"
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 
10 {
11 }
12 
13 void 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;
22  double xAverage, xAverageRoundedUp, xRange;
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) {
40  ENGAUGE_ASSERT(xMin > 0);
41  ENGAUGE_ASSERT(xMax > 0);
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  }
52  nDigitRange = valuePower (xRange);
53  xDelta = pow (10.0, double (nDigitRange));
54  xAverageRoundedUp = xDelta * floor ((xAverage + xDelta / 2.0) / xDelta);
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
64  xStart = xAverageRoundedUp;
65  while (xStart > xMin) {
66  xStart -= xDelta;
67  }
68 
69  // Go up until max point is included
70  xStop = xAverageRoundedUp;
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
87  int power = valuePower (xDelta) - nDigitsPrecision;
88  xStart = roundOffToPower(xStart, power);
89  xStop = roundOffToPower(xStop, power);
90  xDelta = roundOffToPower(xDelta, power);
91 
92  }
93 }
94 
95 int GridInitializer::computeCount (bool linearAxis,
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 
119 double GridInitializer::computeStart (bool linearAxis,
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 
135 double GridInitializer::computeStep (bool linearAxis,
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 
163 double GridInitializer::computeStop (bool linearAxis,
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 
248 void GridInitializer::overridePolarCoordinateSettings (const DocumentModelCoords &modelCoords,
249  const Transformation &transformation,
250  DocumentModelGridDisplay &modelGridDisplay,
251  const QSize &imageSize) const
252 {
253  ENGAUGE_ASSERT (modelCoords.coordsType() == COORDS_TYPE_POLAR);
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
268  QPointF posTL, posBL, posTR, posBR;
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 
301 double 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 
308 int GridInitializer::valuePower(double value) const
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 }
GridInitializer::computeStart
double computeStart(bool linearAxis, double stop, double step, int count) const
Compute axis scale start from the other axis parameters.
Definition: GridInitializer.cpp:119
COORD_SCALE_LINEAR
Definition: CoordScale.h:15
GridInitializer::computeCount
int computeCount(bool linearAxis, double start, double stop, double step) const
Compute axis scale count from the other axis parameters.
Definition: GridInitializer.cpp:95
DocumentModelGridDisplay::setStepY
void setStepY(double yStep)
Set method for y grid line increment.
Definition: DocumentModelGridDisplay.cpp:252
DocumentModelGridDisplay
Model for DlgSettingsGridDisplay and CmdSettingsGridDisplay.
Definition: DocumentModelGridDisplay.h:17
GridInitializer::initializeWithNarrowCoverage
DocumentModelGridDisplay initializeWithNarrowCoverage(const QPointF &boundingRectGraphMin, const QPointF &boundingRectGraphMax, const DocumentModelCoords &modelCoords) const
Initialize given the boundaries of the graph coordinates.
Definition: GridInitializer.cpp:179
Transformation
Affine transformation between screen and graph coordinates, based on digitized axis points.
Definition: Transformation.h:30
EngaugeAssert.h
COORDS_TYPE_POLAR
Definition: CoordsType.h:16
DocumentModelGridDisplay::setStable
void setStable(bool stable)
Set method for stable flag.
Definition: DocumentModelGridDisplay.cpp:232
DocumentModelGridDisplay::setStartX
void setStartX(double startX)
Set method for x grid line lower bound (inclusive).
Definition: DocumentModelGridDisplay.cpp:237
GridInitializer::valuePower
int valuePower(double value) const
Compute power of 10 for input value, rounding down to nearest integer solution of value>=10**solution...
Definition: GridInitializer.cpp:308
DocumentModelGridDisplay::setStepX
void setStepX(double stepX)
Set method for x grid line increment.
Definition: DocumentModelGridDisplay.cpp:247
GridInitializer::initializeWithWidePolarCoverage
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...
Definition: GridInitializer.cpp:225
GRID_COORD_DISABLE_COUNT
Definition: GridCoordDisable.h:15
DocumentModelGridDisplay::setDisableX
void setDisableX(GridCoordDisable disableX)
Set method for x grid line disabled variable.
Definition: DocumentModelGridDisplay.cpp:217
GridInitializer.h
Transformation.h
Logger.h
DocumentModelGridDisplay::setStartY
void setStartY(double yStart)
Set method for y grid line lower bound (inclusive).
Definition: DocumentModelGridDisplay.cpp:242
LOG4CPP_INFO_S
#define LOG4CPP_INFO_S(logger)
Definition: convenience.h:18
DocumentModelGridDisplay::stepY
double stepY() const
Get method for y grid line increment.
Definition: DocumentModelGridDisplay.cpp:287
DocumentModelCoords::coordScaleYRadius
CoordScale coordScaleYRadius() const
Get method for linear/log scale on y/radius.
Definition: DocumentModelCoords.cpp:89
GridInitializer::computeStop
double computeStop(bool linearAxis, double start, double step, int count) const
Compute axis scale stop from the other axis parameters.
Definition: GridInitializer.cpp:163
DocumentModelGridDisplay::setStopX
void setStopX(double stopX)
Set method for x grid line upper bound (inclusive).
Definition: DocumentModelGridDisplay.cpp:257
mainCat
log4cpp::Category * mainCat
Definition: Logger.cpp:14
DocumentModelCoords::originRadius
double originRadius() const
Get method for origin radius in polar mode.
Definition: DocumentModelCoords.cpp:175
Transformation::transformScreenToRawGraph
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
Definition: Transformation.cpp:453
DocumentModelCoords::coordScaleXTheta
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
Definition: DocumentModelCoords.cpp:84
GridInitializer::computeStep
double computeStep(bool linearAxis, double start, double stop, int count) const
Compute axis scale step from the other axis parameters.
Definition: GridInitializer.cpp:135
DocumentModelGridDisplay::setStopY
void setStopY(double yStop)
Set method for y grid line upper bound (inclusive).
Definition: DocumentModelGridDisplay.cpp:262
DocumentModelGridDisplay::setDisableY
void setDisableY(GridCoordDisable disableY)
Set method for y grid line disabled variable.
Definition: DocumentModelGridDisplay.cpp:222
DocumentModelCoords
Model for DlgSettingsCoords and CmdSettingsCoords.
Definition: DocumentModelCoords.h:19
DocumentModelCoords::coordsType
CoordsType coordsType() const
Get method for coordinates type.
Definition: DocumentModelCoords.cpp:94
GridInitializer::GridInitializer
GridInitializer()
Single constructor.
Definition: GridInitializer.cpp:9
DocumentModelCoords.h
DocumentModelGridDisplay::setCountX
void setCountX(unsigned int countX)
Set method for x grid line count.
Definition: DocumentModelGridDisplay.cpp:207
DocumentModelGridDisplay::setCountY
void setCountY(unsigned int countY)
Set method for y grid line count.
Definition: DocumentModelGridDisplay.cpp:212
ENGAUGE_ASSERT
#define ENGAUGE_ASSERT(cond)
Drop in replacement for Q_ASSERT if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) define ENGAUGE...
Definition: EngaugeAssert.h:19