Engauge Digitizer 2
Loading...
Searching...
No Matches
ExportXThetaValuesMergedFunctions.cpp
Go to the documentation of this file.
1/******************************************************************************************************
2 * (C) 2014 markummitchell@github.com. This file is part of Engauge Digitizer, which is released *
3 * under GNU General Public License version 2 (GPLv2) or (at your option) any later version. See file *
4 * LICENSE or go to gnu.org/licenses for details. Distribution requires prior written permission. *
5 ******************************************************************************************************/
6
7#include "ExportAlignLinear.h"
8#include "ExportAlignLog.h"
12#include "Logger.h"
13#include "Point.h"
14#include <qmath.h>
15#include "Transformation.h"
16
17using namespace std;
18
20 const ValuesVectorXOrY &xThetaValuesRaw,
21 const Transformation &transformation) :
22 m_modelExport (modelExport),
23 m_xThetaValuesRaw (xThetaValuesRaw),
24 m_transformation (transformation)
25{
26}
27
28void ExportXThetaValuesMergedFunctions::firstSimplestNumberLinear (double &xThetaFirstSimplestNumber,
29 double &xThetaMin,
30 double &xThetaMax) const
31{
32 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::firstSimplestNumberLinear";
33
34 // X/theta range
35 xThetaMin = m_xThetaValuesRaw.firstKey();
36 xThetaMax = m_xThetaValuesRaw.lastKey();
37
38 // Compute offset that gives the simplest numbers
40 xThetaMax);
41
42 xThetaFirstSimplestNumber = alignLinear.firstSimplestNumber ();
43}
44
45void ExportXThetaValuesMergedFunctions::firstSimplestNumberLog (double &xThetaFirstSimplestNumber,
46 double &xThetaMin,
47 double &xThetaMax) const
48{
49 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::firstSimplestNumberLog";
50
51 // X/theta range
52 xThetaMin = m_xThetaValuesRaw.firstKey();
53 xThetaMax = m_xThetaValuesRaw.lastKey();
54
55 // Compute offset that gives the simplest numbers
57 xThetaMax);
58
59 xThetaFirstSimplestNumber = alignLog.firstSimplestNumber();
60}
61
62ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLinear() const
63{
64 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLinear";
65
66 if (m_xThetaValuesRaw.count () > 0) {
67
69 firstSimplestNumberLinear (xThetaFirstSimplestNumber,
71 xThetaMax);
72
73 // Assuming user picks an appropriate interval increment, numbering starting at xThetaFirstSimplestNumber
74 // will give nice x/theta numbers
76 return periodicLinearGraph(xThetaFirstSimplestNumber,
78 xThetaMax);
79 } else {
80 return periodicLinearScreen(xThetaMin,
81 xThetaMax);
82 }
83 } else {
84
86 return emptyList;
87 }
88}
89
90ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLinearGraph(double xThetaFirstSimplestNumber,
91 double xThetaMin,
92 double xThetaMax) const
93{
94 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLinearGraph";
95
96 // Convert the gathered values into a periodic sequence
99 while (xTheta > xThetaMin) {
100 xTheta -= m_modelExport.pointsIntervalFunctions(); // Go backwards until reaching or passing minimum
101 }
102 if (xTheta < xThetaMin) {
103 values [xThetaMin] = true; // We passed minimum so insert point right at xThetaMin
104 }
105
106 xTheta += m_modelExport.pointsIntervalFunctions();
107 while (xTheta <= xThetaMax) {
108 values [xTheta] = true;
109 xTheta += m_modelExport.pointsIntervalFunctions(); // Insert point at a simple number
110 }
111
112 if (xTheta > xThetaMax) {
113 values [xThetaMax] = true; // We passed maximum so insert point right at xThetaMax
114 }
115
116 return values.keys();
117}
118
119ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLinearScreen (double xThetaMin,
120 double xThetaMax) const
121{
122 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLinearScreen";
123
124 // This must be greater than zero. Otherwise, logarithmic y axis will trigger errors in the
125 // transform, which cascades into NaN values for the x coordinates below
126 const double ARBITRARY_Y = 1.0;
127
128 // Screen coordinates of endpoints
136 double deltaScreenX = posScreenLast.x() - posScreenFirst.x();
137
138 // Need calculations to find the scaling to be applied to successive points
139 double s = 1.0;
140 double interval = m_modelExport.pointsIntervalFunctions();
141 if ((interval > 0) &&
144 }
145
146 // Example: xThetaMin=0.1 and xThetaMax=100 (points are 0.1, 1, 10, 100) with s=1/3 so scale should be 10
147 // which multiples 0.1 to get 1. This uses s=(log(xNext)-log(xMin))/(log(xMax)-log(xMin))
148 double xNext = xThetaMin + s * (xThetaMax - xThetaMin);
149 double delta = xNext - xThetaMin;
150
152
153 double xTheta = xThetaMin;
154 while (xTheta <= xThetaMax) {
155
156 values [xTheta] = true;
157
158 xTheta += delta;
159 }
160
161 return values.keys();
162}
163
164ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLog() const
165{
166 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLog";
167
169 firstSimplestNumberLog (xThetaFirstSimplestNumber,
170 xThetaMin,
171 xThetaMax);
172
173 // Assuming user picks an appropriate interval increment, numbering starting at xThetaFirstSimplestNumber
174 // will give nice x/theta numbers
176 return periodicLogGraph(xThetaFirstSimplestNumber,
177 xThetaMin,
178 xThetaMax);
179 } else {
180 return periodicLogScreen(xThetaMin,
181 xThetaMax);
182 }
183}
184
185ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLogGraph (double xThetaFirstSimplestNumber,
186 double xThetaMin,
187 double xThetaMax) const
188{
189 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLogGraph";
190
191 // Convert the gathered values into a periodic sequence
194 if (m_modelExport.pointsIntervalFunctions() > 1) { // Safe to iterate
195 while (xTheta > xThetaMin) {
196 xTheta /= m_modelExport.pointsIntervalFunctions(); // Go backwards until reaching or passing minimum
197 }
198 }
199 if (xTheta < xThetaMin) {
200 values [xThetaMin] = true; // We passed minimum so insert point right at xThetaMin
201 }
202
203 if (m_modelExport.pointsIntervalFunctions() > 1) { // Safe to iterate
204 xTheta *= m_modelExport.pointsIntervalFunctions();
205 while (xTheta <= xThetaMax) {
206 values [xTheta] = true;
207 xTheta *= m_modelExport.pointsIntervalFunctions(); // Insert point at a simple number
208 }
209 }
210
211 if (xTheta > xThetaMax) {
212 values [xThetaMax] = true; // We passed maximum so insert point right at xThetaMax
213 }
214
215 return values.keys();
216}
217
218ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLogScreen (double xThetaMin,
219 double xThetaMax) const
220{
221 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLogScreen";
222
223 const double ARBITRARY_Y = 0.0;
224
225 // Screen coordinates of endpoints
233 double deltaScreenX = posScreenLast.x() - posScreenFirst.x();
234 double deltaScreenY = posScreenLast.y() - posScreenFirst.y();
236
237 // Need calculations to find the scaling to be applied to successive points
238 double s = 1.0;
239 double interval = m_modelExport.pointsIntervalFunctions();
240 if ((interval > 0) &&
241 (interval < deltaScreen)) {
243 }
244
245 // Example: xThetaMin=0.1 and xThetaMax=100 (points are 0.1, 1, 10, 100) with s=1/3 so scale should be 10
246 // which multiples 0.1 to get 1. This uses s=(log(xNext)-log(xMin))/(log(xMax)-log(xMin))
247 double xNext = qExp (qLn (xThetaMin) + s * (qLn (xThetaMax) - qLn (xThetaMin)));
248 double scale = xNext / xThetaMin;
249
251
252 double xTheta = xThetaMin;
253 while (xTheta <= xThetaMax) {
254
255 values [xTheta] = true;
256
257 xTheta *= scale;
258 }
259
260 return values.keys();
261}
262
264{
265 LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::xThetaValues";
266
268
269 // Special case that occurs when there are no points
270 if (qAbs (m_modelExport.pointsIntervalFunctions()) <= 0) {
271
273 return empty;
274
275 } else {
276
277 bool isLinear = (m_transformation.modelCoords().coordScaleXTheta() == COORD_SCALE_LINEAR);
278 if (isLinear) {
279 return periodicLinear ();
280 } else {
281 return periodicLog ();
282 }
283 }
284 } else {
285
286 // Return the gathered values
287 return m_xThetaValuesRaw.keys();
288
289 }
290}
@ COORD_SCALE_LINEAR
Definition CoordScale.h:13
const int INNER_RADIUS_MIN
@ EXPORT_POINTS_INTERVAL_UNITS_GRAPH
@ EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_PERIODIC
QList< double > ExportValuesXOrY
log4cpp::Category * mainCat
Definition Logger.cpp:14
QMap< double, bool > ValuesVectorXOrY
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
ExportPointsSelectionFunctions pointsSelectionFunctions() const
Get method for point selection for functions.
double pointsIntervalFunctions() const
Get method for points interval for functions.
ExportPointsIntervalUnits pointsIntervalUnitsFunctions() const
Get method for points interval units for functions.
Pick first simplest x value between specified min and max, for linear scaling.
Pick first simplest x value between specified min and max, for log scaling.
ExportValuesXOrY xThetaValues() const
Resulting x/theta values for all included functions.
ExportXThetaValuesMergedFunctions(const DocumentModelExportFormat &modelExport, const ValuesVectorXOrY &xThetaValuesRaw, const Transformation &transformation)
Single constructor.
Affine transformation between screen and graph coordinates, based on digitized axis points.
void transformRawGraphToScreen(const QPointF &pointRaw, QPointF &pointScreen) const
Transform from raw graph coordinates to linear cartesian graph coordinates, then to screen coordinate...
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18