Engauge Digitizer  2
 All Classes Files Functions Variables Enumerations Enumerator Friends Pages
ExportXThetaValuesMergedFunctions.cpp
1 #include "ExportXThetaValuesMergedFunctions.h"
2 #include "ExportAlignLinear.h"
3 #include "ExportAlignLog.h"
4 #include "ExportLayoutFunctions.h"
5 #include "ExportPointsSelectionFunctions.h"
6 #include "Logger.h"
7 #include "Point.h"
8 #include <qmath.h>
9 #include "Transformation.h"
10 
11 using namespace std;
12 
14  const ValuesVectorXOrY &xThetaValuesRaw,
15  const Transformation &transformation) :
16  m_modelExport (modelExport),
17  m_xThetaValuesRaw (xThetaValuesRaw),
18  m_transformation (transformation)
19 {
20 }
21 
22 void ExportXThetaValuesMergedFunctions::firstSimplestNumberLinear (double &xThetaFirstSimplestNumber,
23  double &xThetaMin,
24  double &xThetaMax) const
25 {
26  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::firstSimplestNumberLinear";
27 
28  // X/theta range
29  xThetaMin = m_xThetaValuesRaw.firstKey();
30  xThetaMax = m_xThetaValuesRaw.lastKey();
31 
32  // Compute offset that gives the simplest numbers
33  ExportAlignLinear alignLinear (xThetaMin,
34  xThetaMax);
35 
36  xThetaFirstSimplestNumber = alignLinear.firstSimplestNumber();
37 }
38 
39 void ExportXThetaValuesMergedFunctions::firstSimplestNumberLog (double &xThetaFirstSimplestNumber,
40  double &xThetaMin,
41  double &xThetaMax) const
42 {
43  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::firstSimplestNumberLog";
44 
45  // X/theta range
46  xThetaMin = m_xThetaValuesRaw.firstKey();
47  xThetaMax = m_xThetaValuesRaw.lastKey();
48 
49  // Compute offset that gives the simplest numbers
50  ExportAlignLog alignLog (xThetaMin,
51  xThetaMax);
52 
53  xThetaFirstSimplestNumber = alignLog.firstSimplestNumber();
54 }
55 
56 ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLinear() const
57 {
58  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLinear";
59 
60  if (m_xThetaValuesRaw.count () > 0) {
61 
62  double xThetaFirstSimplestNumber, xThetaMin, xThetaMax;
63  firstSimplestNumberLinear (xThetaFirstSimplestNumber,
64  xThetaMin,
65  xThetaMax);
66 
67  // Assuming user picks an appropriate interval increment, numbering starting at xThetaFirstSimplestNumber
68  // will give nice x/theta numbers
69  if (m_modelExport.pointsIntervalUnitsFunctions() == EXPORT_POINTS_INTERVAL_UNITS_GRAPH) {
70  return periodicLinearGraph(xThetaFirstSimplestNumber,
71  xThetaMin,
72  xThetaMax);
73  } else {
74  return periodicLinearScreen(xThetaMin,
75  xThetaMax);
76  }
77  } else {
78 
79  ExportValuesXOrY emptyList;
80  return emptyList;
81  }
82 }
83 
84 ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLinearGraph(double xThetaFirstSimplestNumber,
85  double xThetaMin,
86  double xThetaMax) const
87 {
88  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLinearGraph";
89 
90  // Convert the gathered values into a periodic sequence
91  ValuesVectorXOrY values;
92  double xTheta = xThetaFirstSimplestNumber;
93  while (xTheta > xThetaMin) {
94  xTheta -= m_modelExport.pointsIntervalFunctions(); // Go backwards until reaching or passing minimum
95  }
96  if (xTheta < xThetaMin) {
97  values [xThetaMin] = true; // We passed minimum so insert point right at xThetaMin
98  }
99 
100  xTheta += m_modelExport.pointsIntervalFunctions();
101  while (xTheta <= xThetaMax) {
102  values [xTheta] = true;
103  xTheta += m_modelExport.pointsIntervalFunctions(); // Insert point at a simple number
104  }
105 
106  if (xTheta > xThetaMax) {
107  values [xThetaMax] = true; // We passed maximum so insert point right at xThetaMax
108  }
109 
110  return values.keys();
111 }
112 
113 ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLinearScreen (double xThetaMin,
114  double xThetaMax) const
115 {
116  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLinearScreen";
117 
118  const double ARBITRARY_Y = 0.0;
119 
120  // Screen coordinates of endpoints
121  QPointF posScreenFirst, posScreenLast;
122  m_transformation.transformRawGraphToScreen(QPointF (xThetaMin,
123  ARBITRARY_Y),
124  posScreenFirst);
125  m_transformation.transformRawGraphToScreen(QPointF (xThetaMax,
126  ARBITRARY_Y),
127  posScreenLast);
128  double deltaScreenX = posScreenLast.x() - posScreenFirst.x();
129  double deltaScreenY = posScreenLast.y() - posScreenFirst.y();
130  double deltaScreen = qSqrt (deltaScreenX * deltaScreenX + deltaScreenY * deltaScreenY);
131 
132  // Need calculations to find the scaling to be applied to successive points
133  double s = 1.0;
134  double interval = m_modelExport.pointsIntervalFunctions();
135  if ((interval > 0) &&
136  (interval < deltaScreen)) {
137  s = interval / deltaScreen;
138  }
139 
140  // Example: xThetaMin=0.1 and xThetaMax=100 (points are 0.1, 1, 10, 100) with s=1/3 so scale should be 10
141  // which multiples 0.1 to get 1. This uses s=(log(xNext)-log(xMin))/(log(xMax)-log(xMin))
142  double xNext = xThetaMin + s * (xThetaMax - xThetaMin);
143  double delta = xNext - xThetaMin;
144 
145  ValuesVectorXOrY values;
146 
147  double xTheta = xThetaMin;
148  while (xTheta <= xThetaMax) {
149 
150  values [xTheta] = true;
151 
152  xTheta += delta;
153  }
154 
155  return values.keys();
156 }
157 
158 ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLog() const
159 {
160  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLog";
161 
162  double xThetaFirstSimplestNumber, xThetaMin, xThetaMax;
163  firstSimplestNumberLog (xThetaFirstSimplestNumber,
164  xThetaMin,
165  xThetaMax);
166 
167  // Assuming user picks an appropriate interval increment, numbering starting at xThetaFirstSimplestNumber
168  // will give nice x/theta numbers
169  if (m_modelExport.pointsIntervalUnitsFunctions() == EXPORT_POINTS_INTERVAL_UNITS_GRAPH) {
170  return periodicLogGraph(xThetaFirstSimplestNumber,
171  xThetaMin,
172  xThetaMax);
173  } else {
174  return periodicLogScreen(xThetaMin,
175  xThetaMax);
176  }
177 }
178 
179 ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLogGraph (double xThetaFirstSimplestNumber,
180  double xThetaMin,
181  double xThetaMax) const
182 {
183  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLogGraph";
184 
185  // Convert the gathered values into a periodic sequence
186  ValuesVectorXOrY values;
187  double xTheta = xThetaFirstSimplestNumber;
188  while (xTheta > xThetaMin) {
189  xTheta /= m_modelExport.pointsIntervalFunctions(); // Go backwards until reaching or passing minimum
190  }
191  if (xTheta < xThetaMin) {
192  values [xThetaMin] = true; // We passed minimum so insert point right at xThetaMin
193  }
194 
195  xTheta *= m_modelExport.pointsIntervalFunctions();
196  while (xTheta <= xThetaMax) {
197  values [xTheta] = true;
198  xTheta *= m_modelExport.pointsIntervalFunctions(); // Insert point at a simple number
199  }
200 
201  if (xTheta > xThetaMax) {
202  values [xThetaMax] = true; // We passed maximum so insert point right at xThetaMax
203  }
204 
205  return values.keys();
206 }
207 
208 ExportValuesXOrY ExportXThetaValuesMergedFunctions::periodicLogScreen (double xThetaMin,
209  double xThetaMax) const
210 {
211  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::periodicLogScreen";
212 
213  const double ARBITRARY_Y = 0.0;
214 
215  // Screen coordinates of endpoints
216  QPointF posScreenFirst, posScreenLast;
217  m_transformation.transformRawGraphToScreen(QPointF (xThetaMin,
218  ARBITRARY_Y),
219  posScreenFirst);
220  m_transformation.transformRawGraphToScreen(QPointF (xThetaMax,
221  ARBITRARY_Y),
222  posScreenLast);
223  double deltaScreenX = posScreenLast.x() - posScreenFirst.x();
224  double deltaScreenY = posScreenLast.y() - posScreenFirst.y();
225  double deltaScreen = qSqrt (deltaScreenX * deltaScreenX + deltaScreenY * deltaScreenY);
226 
227  // Need calculations to find the scaling to be applied to successive points
228  double s = 1.0;
229  double interval = m_modelExport.pointsIntervalFunctions();
230  if ((interval > 0) &&
231  (interval < deltaScreen)) {
232  s = interval / deltaScreen;
233  }
234 
235  // Example: xThetaMin=0.1 and xThetaMax=100 (points are 0.1, 1, 10, 100) with s=1/3 so scale should be 10
236  // which multiples 0.1 to get 1. This uses s=(log(xNext)-log(xMin))/(log(xMax)-log(xMin))
237  double xNext = qExp (qLn (xThetaMin) + s * (qLn (xThetaMax) - qLn (xThetaMin)));
238  double scale = xNext / xThetaMin;
239 
240  ValuesVectorXOrY values;
241 
242  double xTheta = xThetaMin;
243  while (xTheta <= xThetaMax) {
244 
245  values [xTheta] = true;
246 
247  xTheta *= scale;
248  }
249 
250  return values.keys();
251 }
252 
254 {
255  LOG4CPP_INFO_S ((*mainCat)) << "ExportXThetaValuesMergedFunctions::xThetaValues";
256 
257  if (m_modelExport.pointsSelectionFunctions() == EXPORT_POINTS_SELECTION_FUNCTIONS_INTERPOLATE_PERIODIC) {
258 
259  // Special case that occurs when there are no points
260  if (m_modelExport.pointsIntervalFunctions() == 0) {
261 
262  ExportValuesXOrY empty;
263  return empty;
264 
265  } else {
266 
267  bool isLinear = (m_transformation.modelCoords().coordScaleXTheta() == COORD_SCALE_LINEAR);
268  if (isLinear) {
269  return periodicLinear ();
270  } else {
271  return periodicLog ();
272  }
273  }
274  } else {
275 
276  // Return the gathered values
277  return m_xThetaValuesRaw.keys();
278 
279  }
280 }
ExportPointsSelectionFunctions pointsSelectionFunctions() const
Get method for point selection for functions.
ExportXThetaValuesMergedFunctions(const DocumentModelExportFormat &modelExport, const ValuesVectorXOrY &xThetaValuesRaw, const Transformation &transformation)
Single constructor.
ExportPointsIntervalUnits pointsIntervalUnitsFunctions() const
Get method for points interval units for functions.
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
ExportValuesXOrY xThetaValues() const
Resulting x/theta values for all included functions.
Pick first simplest x value between specified min and max, for linear scaling.
double pointsIntervalFunctions() const
Get method for points interval for functions.
Pick first simplest x value between specified min and max, for log scaling.
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Affine transformation between screen and graph coordinates, based on digitized axis points...
CoordScale coordScaleXTheta() const
Get method for linear/log scale on x/theta.
void transformRawGraphToScreen(const QPointF &pointRaw, QPointF &pointScreen) const
Transform from raw graph coordinates to linear cartesian graph coordinates, then to screen coordinate...