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
39 ExportAlignLinear alignLinear (xThetaMin,
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
56 ExportAlignLog alignLog (xThetaMin,
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
68 double xThetaFirstSimplestNumber, xThetaMin, xThetaMax;
69 firstSimplestNumberLinear (xThetaFirstSimplestNumber,
70 xThetaMin,
71 xThetaMax);
72
73 // Assuming user picks an appropriate interval increment, numbering starting at xThetaFirstSimplestNumber
74 // will give nice x/theta numbers
75 if (m_modelExport.pointsIntervalUnitsFunctions() == EXPORT_POINTS_INTERVAL_UNITS_GRAPH) {
76 return periodicLinearGraph(xThetaFirstSimplestNumber,
77 xThetaMin,
78 xThetaMax);
79 } else {
80 return periodicLinearScreen(xThetaMin,
81 xThetaMax);
82 }
83 } else {
84
85 ExportValuesXOrY emptyList;
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
97 ValuesVectorXOrY values;
98 double xTheta = xThetaFirstSimplestNumber;
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
129 QPointF posScreenFirst, posScreenLast;
130 m_transformation.transformRawGraphToScreen(QPointF (xThetaMin,
131 ARBITRARY_Y),
132 posScreenFirst);
133 m_transformation.transformRawGraphToScreen(QPointF (xThetaMax,
134 ARBITRARY_Y),
135 posScreenLast);
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) &&
142 (interval < deltaScreenX)) {
143 s = interval / deltaScreenX;
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
151 ValuesVectorXOrY values;
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
168 double xThetaFirstSimplestNumber, xThetaMin, xThetaMax;
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
175 if (m_modelExport.pointsIntervalUnitsFunctions() == EXPORT_POINTS_INTERVAL_UNITS_GRAPH) {
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
192 ValuesVectorXOrY values;
193 double xTheta = xThetaFirstSimplestNumber;
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
226 QPointF posScreenFirst, posScreenLast;
227 m_transformation.transformRawGraphToScreen(QPointF (xThetaMin,
228 ARBITRARY_Y),
229 posScreenFirst);
230 m_transformation.transformRawGraphToScreen(QPointF (xThetaMax,
231 ARBITRARY_Y),
232 posScreenLast);
233 double deltaScreenX = posScreenLast.x() - posScreenFirst.x();
234 double deltaScreenY = posScreenLast.y() - posScreenFirst.y();
235 double deltaScreen = qSqrt (deltaScreenX * deltaScreenX + deltaScreenY * deltaScreenY);
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)) {
242 s = 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
250 ValuesVectorXOrY values;
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
267 if (m_modelExport.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_PERIODIC) {
268
269 // Special case that occurs when there are no points
270 if (qAbs (m_modelExport.pointsIntervalFunctions()) <= 0) {
271
272 ExportValuesXOrY empty;
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
@ 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
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
Pick first simplest x value between specified min and max, for linear 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.
#define LOG4CPP_INFO_S(logger)
Definition convenience.h:18