Engauge Digitizer  2
ExportFileRelations.cpp
1 #include "CurveConnectAs.h"
2 #include "Document.h"
3 #include "EngaugeAssert.h"
4 #include "ExportFileRelations.h"
5 #include "ExportLayoutFunctions.h"
6 #include "ExportOrdinalsSmooth.h"
7 #include "ExportOrdinalsStraight.h"
8 #include "FormatCoordsUnits.h"
9 #include "Logger.h"
10 #include <qdebug.h>
11 #include <qmath.h>
12 #include <QTextStream>
13 #include <QVector>
14 #include "Spline.h"
15 #include "SplinePair.h"
16 #include "Transformation.h"
17 #include <vector>
18 
19 using namespace std;
20 
21 const int COLUMNS_PER_CURVE = 2;
22 
24 {
25 }
26 
27 void ExportFileRelations::exportAllPerLineXThetaValuesMerged (const DocumentModelExportFormat &modelExportOverride,
28  const Document &document,
29  const QStringList &curvesIncluded,
30  const QString &delimiter,
31  const Transformation &transformation,
32  QTextStream &str) const
33 {
34  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::exportAllPerLineXThetaValuesMerged";
35 
36  int curveCount = curvesIncluded.count();
37  int maxColumnSize = maxColumnSizeAllocation (modelExportOverride,
38  document,
39  transformation,
40  curvesIncluded);
41 
42  // Skip if every curve was a function
43  if (maxColumnSize > 0) {
44 
45  QVector<QVector<QString*> > xThetaYRadiusValues (COLUMNS_PER_CURVE * curveCount, QVector<QString*> (maxColumnSize));
46  initializeXThetaYRadiusValues (curvesIncluded,
47  xThetaYRadiusValues);
48  loadXThetaYRadiusValues (modelExportOverride,
49  document,
50  curvesIncluded,
51  transformation,
52  xThetaYRadiusValues);
53  outputXThetaYRadiusValues (modelExportOverride,
54  curvesIncluded,
55  xThetaYRadiusValues,
56  delimiter,
57  str);
58  destroy2DArray (xThetaYRadiusValues);
59  }
60 }
61 
62 void ExportFileRelations::exportOnePerLineXThetaValuesMerged (const DocumentModelExportFormat &modelExportOverride,
63  const Document &document,
64  const QStringList &curvesIncluded,
65  const QString &delimiter,
66  const Transformation &transformation,
67  QTextStream &str) const
68 {
69  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::exportOnePerLineXThetaValuesMerged";
70 
71  QStringList::const_iterator itr;
72  for (itr = curvesIncluded.begin(); itr != curvesIncluded.end(); itr++) {
73 
74  QString curveIncluded = *itr;
75 
76  exportAllPerLineXThetaValuesMerged (modelExportOverride,
77  document,
78  QStringList (curveIncluded),
79  delimiter,
80  transformation,
81  str);
82  }
83 }
84 
86  const Document &document,
87  const Transformation &transformation,
88  QTextStream &str) const
89 {
90  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::exportToFile";
91 
92  // Identify curves to be included
93  QStringList curvesIncluded = curvesToInclude (modelExportOverride,
94  document,
95  document.curvesGraphsNames(),
96  CONNECT_AS_RELATION_SMOOTH,
97  CONNECT_AS_RELATION_STRAIGHT);
98 
99  // Delimiter
100  const QString delimiter = exportDelimiterToText (modelExportOverride.delimiter());
101 
102  // Export in one of two layouts
103  if (modelExportOverride.layoutFunctions() == EXPORT_LAYOUT_ALL_PER_LINE) {
104  exportAllPerLineXThetaValuesMerged (modelExportOverride,
105  document,
106  curvesIncluded,
107  delimiter,
108  transformation,
109  str);
110  } else {
111  exportOnePerLineXThetaValuesMerged (modelExportOverride,
112  document,
113  curvesIncluded,
114  delimiter,
115  transformation,
116  str);
117  }
118 }
119 
120 void ExportFileRelations::initializeXThetaYRadiusValues (const QStringList &curvesIncluded,
121  QVector<QVector<QString*> > &xThetaYRadiusValues) const
122 {
123  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::initializeXThetaYRadiusValues";
124 
125  // Initialize every entry with empty string
126  int curveCount = curvesIncluded.count();
127  int xThetaCount = xThetaYRadiusValues [0].count();
128  for (int row = 0; row < xThetaCount; row++) {
129  for (int col = 0; col < COLUMNS_PER_CURVE * curveCount; col++) {
130  xThetaYRadiusValues [col] [row] = new QString;
131  }
132  }
133 }
134 
135 QPointF ExportFileRelations::linearlyInterpolate (const Points &points,
136  double ordinal,
137  const Transformation &transformation) const
138 {
139  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::linearlyInterpolate";
140 
141  double xTheta = 0, yRadius = 0;
142  double ordinalBefore = 0; // Not set until ip=1
143  QPointF posGraphBefore; // Not set until ip=1
144  bool foundIt = false;
145  for (int ip = 0; ip < points.count(); ip++) {
146 
147  const Point &point = points.at (ip);
148  QPointF posGraph;
149  transformation.transformScreenToRawGraph (point.posScreen(),
150  posGraph);
151 
152  if (ordinal <= point.ordinal()) {
153 
154  foundIt = true;
155  if (ip == 0) {
156 
157  // Use first point
158  xTheta = posGraph.x();
159  yRadius = posGraph.y();
160 
161  } else {
162 
163  // Between posGraphBefore and posGraph. Note that if posGraph.x()=posGraphBefore.x() then
164  // previous iteration of loop would have been used for interpolation, and then the loop was exited
165  double s = (ordinal - ordinalBefore) / (point.ordinal() - ordinalBefore);
166  xTheta = (1.0 - s) * posGraphBefore.x() + s * posGraph.x();
167  yRadius = (1.0 - s) * posGraphBefore.y() + s * posGraph.y();
168  }
169 
170  break;
171  }
172 
173  ordinalBefore = point.ordinal();
174  posGraphBefore = posGraph;
175  }
176 
177  if (!foundIt) {
178 
179  // Use last point
180  xTheta = posGraphBefore.x();
181  yRadius = posGraphBefore.y();
182 
183  }
184 
185  return QPointF (xTheta,
186  yRadius);
187 }
188 
189 void ExportFileRelations::loadXThetaYRadiusValues (const DocumentModelExportFormat &modelExportOverride,
190  const Document &document,
191  const QStringList &curvesIncluded,
192  const Transformation &transformation,
193  QVector<QVector<QString*> > &xThetaYRadiusValues) const
194 {
195  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::loadXThetaYRadiusValues";
196 
197  // The curve processing logic here is mirrored in maxColumnSizeAllocation so the array allocations are in sync
198  for (int ic = 0; ic < curvesIncluded.count(); ic++) {
199 
200  int colXTheta = 2 * ic;
201  int colYRadius = 2 * ic + 1;
202 
203  const QString curveName = curvesIncluded.at (ic);
204 
205  const Curve *curve = document.curveForCurveName (curveName);
206  const Points points = curve->points ();
207 
208  if (modelExportOverride.pointsSelectionRelations() == EXPORT_POINTS_SELECTION_RELATIONS_RAW) {
209 
210  // No interpolation. Raw points
211  loadXThetaYRadiusValuesForCurveRaw (document.modelCoords(),
212  points,
213  xThetaYRadiusValues [colXTheta],
214  xThetaYRadiusValues [colYRadius],
215  transformation);
216  } else {
217 
218  const LineStyle &lineStyle = document.modelCurveStyles().lineStyle(curveName);
219 
220  // Interpolation. Points are taken approximately every every modelExport.pointsIntervalRelations
221  ExportValuesOrdinal ordinals = ordinalsAtIntervals (modelExportOverride.pointsIntervalRelations(),
222  modelExportOverride.pointsIntervalUnitsRelations(),
223  lineStyle.curveConnectAs(),
224  transformation,
225  points);
226 
227  if (curve->curveStyle().lineStyle().curveConnectAs() == CONNECT_AS_RELATION_SMOOTH) {
228 
229  loadXThetaYRadiusValuesForCurveInterpolatedSmooth (document.modelCoords(),
230  points,
231  ordinals,
232  xThetaYRadiusValues [colXTheta],
233  xThetaYRadiusValues [colYRadius],
234  transformation);
235 
236  } else {
237 
238  loadXThetaYRadiusValuesForCurveInterpolatedStraight (document.modelCoords(),
239  points,
240  ordinals,
241  xThetaYRadiusValues [colXTheta],
242  xThetaYRadiusValues [colYRadius],
243  transformation);
244  }
245  }
246  }
247 }
248 
249 void ExportFileRelations::loadXThetaYRadiusValuesForCurveInterpolatedSmooth (const DocumentModelCoords &modelCoords,
250  const Points &points,
251  const ExportValuesOrdinal &ordinals,
252  QVector<QString*> &xThetaValues,
253  QVector<QString*> &yRadiusValues,
254  const Transformation &transformation) const
255 {
256  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::loadXThetaYRadiusValuesForCurveInterpolatedSmooth";
257 
258  vector<double> t;
259  vector<SplinePair> xy;
260  ExportOrdinalsSmooth ordinalsSmooth;
261 
262  ordinalsSmooth.loadSplinePairsWithTransformation (points,
263  transformation,
264  t,
265  xy);
266 
267  // Fit a spline
268  Spline spline (t,
269  xy);
270 
271  FormatCoordsUnits format;
272 
273  // Extract the points
274  for (int row = 0; row < ordinals.count(); row++) {
275 
276  double ordinal = ordinals.at (row);
277  SplinePair splinePairFound = spline.interpolateCoeff(ordinal);
278  double xTheta = splinePairFound.x ();
279  double yRadius = splinePairFound.y ();
280 
281  // Save values for this row into xThetaValues and yRadiusValues, after appropriate formatting
282  format.unformattedToFormatted (xTheta,
283  yRadius,
284  modelCoords,
285  *(xThetaValues [row]),
286  *(yRadiusValues [row]),
287  transformation);
288  }
289 }
290 
291 void ExportFileRelations::loadXThetaYRadiusValuesForCurveInterpolatedStraight (const DocumentModelCoords &modelCoords,
292  const Points &points,
293  const ExportValuesOrdinal &ordinals,
294  QVector<QString*> &xThetaValues,
295  QVector<QString*> &yRadiusValues,
296  const Transformation &transformation) const
297 {
298  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::loadXThetaYRadiusValuesForCurveInterpolatedStraight";
299 
300  FormatCoordsUnits format;
301 
302  // Get value at desired points
303  for (int row = 0; row < ordinals.count(); row++) {
304 
305  double ordinal = ordinals.at (row);
306 
307  QPointF pointInterpolated = linearlyInterpolate (points,
308  ordinal,
309  transformation);
310 
311  // Save values for this row into xThetaValues and yRadiusValues, after appropriate formatting
312  format.unformattedToFormatted (pointInterpolated.x(),
313  pointInterpolated.y(),
314  modelCoords,
315  *(xThetaValues [row]),
316  *(yRadiusValues [row]),
317  transformation);
318  }
319 }
320 
321 void ExportFileRelations::loadXThetaYRadiusValuesForCurveRaw (const DocumentModelCoords &modelCoords,
322  const Points &points,
323  QVector<QString*> &xThetaValues,
324  QVector<QString*> &yRadiusValues,
325  const Transformation &transformation) const
326 {
327  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::loadXThetaYRadiusValuesForCurveRaw";
328 
329  FormatCoordsUnits format;
330 
331  for (int pt = 0; pt < points.count(); pt++) {
332 
333  const Point &point = points.at (pt);
334 
335  QPointF posGraph;
336  transformation.transformScreenToRawGraph (point.posScreen(),
337  posGraph);
338 
339  // Save values for this row into xThetaValues and yRadiusValues, after appropriate formatting
340  format.unformattedToFormatted (posGraph.x(),
341  posGraph.y(),
342  modelCoords,
343  *(xThetaValues [pt]),
344  *(yRadiusValues [pt]),
345  transformation);
346  }
347 }
348 
349 int ExportFileRelations::maxColumnSizeAllocation (const DocumentModelExportFormat &modelExport,
350  const Document &document,
351  const Transformation &transformation,
352  const QStringList &curvesIncluded) const
353 {
354  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::maxColumnSizeAllocation";
355 
356  int maxColumnSize = 0;
357 
358  // The curve processing logic here is mirrored in loadXThetaYRadiusValues so the array allocations are in sync
359  for (int ic = 0; ic < curvesIncluded.count(); ic++) {
360 
361  const QString curveName = curvesIncluded.at (ic);
362 
363  const Curve *curve = document.curveForCurveName (curveName);
364  const Points points = curve->points ();
365 
366  if (modelExport.pointsSelectionRelations() == EXPORT_POINTS_SELECTION_RELATIONS_RAW) {
367 
368  // No interpolation. Raw points
369  maxColumnSize = qMax (maxColumnSize,
370  points.count());
371 
372  } else {
373 
374  const LineStyle &lineStyle = document.modelCurveStyles().lineStyle(curveName);
375 
376  // Interpolation. Points are taken approximately every every modelExport.pointsIntervalRelations
377  ExportValuesOrdinal ordinals = ordinalsAtIntervals (modelExport.pointsIntervalRelations(),
378  modelExport.pointsIntervalUnitsRelations(),
379  lineStyle.curveConnectAs(),
380  transformation,
381  points);
382 
383  maxColumnSize = qMax (maxColumnSize,
384  ordinals.count());
385  }
386  }
387 
388  return maxColumnSize;
389 }
390 
391 ExportValuesOrdinal ExportFileRelations::ordinalsAtIntervals (double pointsIntervalRelations,
392  ExportPointsIntervalUnits pointsIntervalUnits,
393  CurveConnectAs curveConnectAs,
394  const Transformation &transformation,
395  const Points &points) const
396 {
397  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::ordinalsAtIntervals";
398 
399  if (pointsIntervalUnits == EXPORT_POINTS_INTERVAL_UNITS_GRAPH) {
400  if (curveConnectAs == CONNECT_AS_RELATION_SMOOTH) {
401 
402  return ordinalsAtIntervalsSmoothGraph (pointsIntervalRelations,
403  transformation,
404  points);
405 
406  } else {
407 
408  return ordinalsAtIntervalsStraightGraph (pointsIntervalRelations,
409  transformation,
410  points);
411 
412  }
413  } else {
414 
415  if (curveConnectAs == CONNECT_AS_RELATION_SMOOTH) {
416 
417  return ordinalsAtIntervalsSmoothScreen (pointsIntervalRelations,
418  points);
419 
420  } else {
421 
422  return ordinalsAtIntervalsStraightScreen (pointsIntervalRelations,
423  points);
424 
425  }
426  }
427 }
428 
429 ExportValuesOrdinal ExportFileRelations::ordinalsAtIntervalsSmoothGraph (double pointsIntervalRelations,
430  const Transformation &transformation,
431  const Points &points) const
432 {
433  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::ordinalsAtIntervalsSmoothGraph";
434 
435  ExportValuesOrdinal ordinals;
436 
437  // Prevent infinite loop when there are no points or will be too many points
438  if ((pointsIntervalRelations > 0) &&
439  (points.count() > 0)) {
440 
441  vector<double> t;
442  vector<SplinePair> xy;
443  ExportOrdinalsSmooth ordinalsSmooth;
444 
445  ordinalsSmooth.loadSplinePairsWithTransformation (points,
446  transformation,
447  t,
448  xy);
449 
450  ordinals = ordinalsSmooth.ordinalsAtIntervalsGraph (t,
451  xy,
452  pointsIntervalRelations);
453  }
454 
455  return ordinals;
456 }
457 
458 ExportValuesOrdinal ExportFileRelations::ordinalsAtIntervalsSmoothScreen (double pointsIntervalRelations,
459  const Points &points) const
460 {
461  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::ordinalsAtIntervalsSmoothScreen"
462  << " pointCount=" << points.count();
463 
464  // Results
465  ExportValuesOrdinal ordinals;
466 
467  // Prevent infinite loop when there are no points or will be too many points
468  if ((pointsIntervalRelations > 0) &&
469  (points.count() > 0)) {
470 
471  vector<double> t;
472  vector<SplinePair> xy;
473  ExportOrdinalsSmooth ordinalsSmooth;
474 
475  ordinalsSmooth.loadSplinePairsWithoutTransformation (points,
476  t,
477  xy);
478 
479  ordinals = ordinalsSmooth.ordinalsAtIntervalsGraph (t,
480  xy,
481  pointsIntervalRelations);
482  }
483 
484  return ordinals;
485 }
486 
487 ExportValuesOrdinal ExportFileRelations::ordinalsAtIntervalsStraightGraph (double pointsIntervalRelations,
488  const Transformation &transformation,
489  const Points &points) const
490 {
491  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::ordinalsAtIntervalsStraightGraph";
492 
493  ExportValuesOrdinal ordinals;
494 
495  // Prevent infinite loop when there are no points or will be too many points
496  if ((pointsIntervalRelations > 0) &&
497  (points.count() > 0)) {
498 
499  ExportOrdinalsStraight ordinalsStraight;
500 
501  ordinals = ordinalsStraight.ordinalsAtIntervalsGraphWithTransformation (points,
502  transformation,
503  pointsIntervalRelations);
504  }
505 
506  return ordinals;
507 }
508 
509 ExportValuesOrdinal ExportFileRelations::ordinalsAtIntervalsStraightScreen (double pointsIntervalRelations,
510  const Points &points) const
511 {
512  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::ordinalsAtIntervalsStraightScreen"
513  << " pointCount=" << points.count();
514 
515  // Results
516  ExportValuesOrdinal ordinals;
517 
518  // Prevent infinite loop when there are no points or will be too many points
519  if ((pointsIntervalRelations > 0) &&
520  (points.count() > 0)) {
521 
522  ExportOrdinalsStraight ordinalsStraight;
523 
524  ordinals = ordinalsStraight.ordinalsAtIntervalsGraphWithoutTransformation (points,
525  pointsIntervalRelations);
526  }
527 
528  return ordinals;
529 }
530 
531 void ExportFileRelations::outputXThetaYRadiusValues (const DocumentModelExportFormat &modelExportOverride,
532  const QStringList &curvesIncluded,
533  QVector<QVector<QString*> > &xThetaYRadiusValues,
534  const QString &delimiter,
535  QTextStream &str) const
536 {
537  LOG4CPP_INFO_S ((*mainCat)) << "ExportFileRelations::outputXThetaYRadiusValues";
538 
539  // Header
540  if (modelExportOverride.header() != EXPORT_HEADER_NONE) {
541  if (modelExportOverride.header() == EXPORT_HEADER_GNUPLOT) {
542  str << curveSeparator(str.string());
543  str << gnuplotComment();
544  }
545  QString delimiterForRow;
546  QStringList::const_iterator itr;
547  for (itr = curvesIncluded.begin(); itr != curvesIncluded.end(); itr++) {
548  QString curveName = *itr;
549  str << delimiterForRow << modelExportOverride.xLabel();
550  delimiterForRow = delimiter;
551  str << delimiterForRow << curveName;
552  }
553  str << "\n";
554  }
555 
556  for (int row = 0; row < xThetaYRadiusValues [0].count(); row++) {
557 
558  QString delimiterForRow;
559  for (int col = 0; col < xThetaYRadiusValues.count(); col++) {
560 
561  str << delimiterForRow << *(xThetaYRadiusValues [col] [row]);
562  delimiterForRow = delimiter;
563  }
564 
565  str << "\n";
566  }
567 }
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
ExportLayoutFunctions layoutFunctions() const
Get method for functions layout.
Cubic interpolation given independent and dependent value vectors.
Definition: Spline.h:15
ExportPointsIntervalUnits pointsIntervalUnitsRelations() const
Get method for points interval units for relations.
void exportToFile(const DocumentModelExportFormat &modelExportOverride, const Document &document, const Transformation &transformation, QTextStream &str) const
Export Document points according to the settings.
const Points points() const
Return a shallow copy of the Points.
Definition: Curve.cpp:307
Model for DlgSettingsExportFormat and CmdSettingsExportFormat.
LineStyle lineStyle() const
Get method for LineStyle.
Definition: CurveStyle.cpp:20
DocumentModelCoords modelCoords() const
Get method for DocumentModelCoords.
Definition: Document.cpp:447
double y() const
Get method for y.
Definition: SplinePair.cpp:65
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
Definition: Point.h:17
QPointF posScreen() const
Accessor for screen position.
Definition: Point.cpp:342
void unformattedToFormatted(double xThetaUnformatted, double yRadiusUnformatted, const DocumentModelCoords &modelCoords, QString &xThetaFormatted, QString &yRadiusFormatted, const Transformation &transformation) const
Convert unformatted numeric value to formatted string. Transformation is used to determine best resol...
ExportHeader header() const
Get method for header.
const LineStyle lineStyle(const QString &curveName) const
Get method for copying one line style in one step.
Definition: CurveStyles.cpp:90
Affine transformation between screen and graph coordinates, based on digitized axis points...
ExportValuesOrdinal ordinalsAtIntervalsGraphWithoutTransformation(const Points &points, double pointsInterval) const
Compute ordinals, without any conversion to graph coordinates.
QString xLabel() const
Get method for x label.
CurveStyles modelCurveStyles() const
Get method for CurveStyles.
Definition: Document.cpp:452
void loadSplinePairsWithTransformation(const Points &points, const Transformation &transformation, std::vector< double > &t, std::vector< SplinePair > &xy) const
Load t (=ordinal) and xy (=screen position) spline pairs, converting screen coordinates to graph coor...
void loadSplinePairsWithoutTransformation(const Points &points, std::vector< double > &t, std::vector< SplinePair > &xy) const
Load t (=ordinal) and xy (=screen position) spline pairs, without any conversion to graph coordinates...
Utility class to interpolate points spaced evenly along a piecewise defined curve with fitted spline...
ExportDelimiter delimiter() const
Get method for delimiter.
Model for DlgSettingsCoords and CmdSettingsCoords.
double pointsIntervalRelations() const
Get method for relations interval for relations.
Storage of one imported image and the data attached to that image.
Definition: Document.h:28
Container for one set of digitized Points.
Definition: Curve.h:24
ExportValuesOrdinal ordinalsAtIntervalsGraph(const std::vector< double > &t, const std::vector< SplinePair > &xy, double pointsInterval) const
Perform the interpolation on the arrays loaded by the other methods.
Details for a specific Line.
Definition: LineStyle.h:13
QStringList curvesGraphsNames() const
See CurvesGraphs::curvesGraphsNames.
Definition: Document.cpp:317
Highest-level wrapper around other Formats classes.
Utility class to interpolate points spaced evenly along a piecewise defined curve with line segments ...
double x() const
Get method for x.
Definition: SplinePair.cpp:60
const Curve * curveForCurveName(const QString &curveName) const
See CurvesGraphs::curveForCurveNames, although this also works for AXIS_CURVE_NAME.
Definition: Document.cpp:299
CurveStyle curveStyle() const
Return the curve style.
Definition: Curve.cpp:70
double ordinal(ApplyHasCheck applyHasCheck=KEEP_HAS_CHECK) const
Get method for ordinal. Skip check if copying one instance to another.
Definition: Point.cpp:324
ExportFileRelations()
Single constructor.
CurveConnectAs curveConnectAs() const
Get method for connect type.
Definition: LineStyle.cpp:43
ExportValuesOrdinal ordinalsAtIntervalsGraphWithTransformation(const Points &points, const Transformation &transformation, double pointsInterval) const
Compute ordinals, converting screen coordinates to graph coordinates.
Single X/Y pair for cubic spline interpolation initialization and calculations.
Definition: SplinePair.h:5
ExportPointsSelectionRelations pointsSelectionRelations() const
Get method for point selection for relations.