Engauge Digitizer 2
Loading...
Searching...
No Matches
ExportOrdinalsSmooth.cpp
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 "ExportOrdinalsSmooth.h"
8#include "Logger.h"
9#include <qdebug.h>
10#include <qmath.h>
11#include <QPointF>
12#include "Spline.h"
13#include "Transformation.h"
14
15using namespace std;
16
20
22 vector<double> &t,
23 vector<SplinePair> &xy) const
24{
25 LOG4CPP_INFO_S ((*mainCat)) << "ExportOrdinalsSmooth::loadSplinePairsWithoutTransformation";
26
27 Points::const_iterator itrP;
28 for (itrP = points.begin(); itrP != points.end(); itrP++) {
29 const Point &point = *itrP;
30 QPointF posScreen = point.posScreen();
31
32 t.push_back (point.ordinal ());
33 xy.push_back (SplinePair (posScreen.x(),
34 posScreen.y()));
35 }
36}
37
39 const Transformation &transformation,
40 vector<double> &t,
41 vector<SplinePair> &xy) const
42{
43 LOG4CPP_INFO_S ((*mainCat)) << "ExportOrdinalsSmooth::loadSplinePairsWithTransformation";
44
45 Points::const_iterator itrP;
46 for (itrP = points.begin(); itrP != points.end(); itrP++) {
47 const Point &point = *itrP;
48 QPointF posScreen = point.posScreen();
49 QPointF posGraph;
50 transformation.transformScreenToRawGraph (posScreen,
51 posGraph);
52
53 t.push_back (point.ordinal ());
54 xy.push_back (SplinePair (posGraph.x(),
55 posGraph.y()));
56 }
57}
58
59ExportValuesOrdinal ExportOrdinalsSmooth::ordinalsAtIntervalsGraph (const vector<double> &t,
60 const vector<SplinePair> &xy,
61 double pointsInterval) const
62{
63 LOG4CPP_INFO_S ((*mainCat)) << "ExportOrdinalsSmooth::ordinalsAtIntervalsGraph";
64
65 const double NUM_SMALLER_INTERVALS = 1000;
66
67 // Results. Initially empty, but at the end it will have tMin, ..., tMax
68 ExportValuesOrdinal ordinals;
69
70 // Fit a spline
71 Spline spline (t,
72 xy);
73
74 // Integrate the distances for the subintervals
75 double integratedSeparation = 0;
76 QPointF posLast (xy [0].x(),
77 xy [0].y());
78
79 // Simplest method to find the intervals is to break up the curve into many smaller intervals, and then aggregate them
80 // into intervals that, as much as possible, have the desired length. Simplicity wins out over accuracy in this
81 // approach - accuracy is sacrificed to achieve simplicity
82 double tMin = t.front();
83 double tMax = t.back();
84
85 double tLast = 0.0;
86 int iTLastInterval = 0;
87 for (int iT = 0; iT < NUM_SMALLER_INTERVALS; iT++) {
88
89 double t = tMin + ((tMax - tMin) * iT) / (NUM_SMALLER_INTERVALS - 1.0);
90
91 SplinePair pairNew = spline.interpolateCoeff(t);
92
93 QPointF posNew = QPointF (pairNew.x(),
94 pairNew.y());
95
96 QPointF posDelta = posNew - posLast;
97 double integratedSeparationDelta = qSqrt (posDelta.x() * posDelta.x() + posDelta.y() * posDelta.y());
98 integratedSeparation += integratedSeparationDelta;
99
100 while (integratedSeparation >= pointsInterval) {
101
102 // End of current interval, and start of next interval. For better accuracy without having to crank up
103 // the number of points by orders of magnitude, we use linear interpolation
104 double sInterp;
105 if (iT == 0) {
106 sInterp = 0.0;
107 } else {
108 sInterp = (double) pointsInterval / (double) integratedSeparation;
109 }
110 double tInterp = (1.0 - sInterp) * tLast + sInterp * t;
111
112 integratedSeparation -= pointsInterval; // Part of delta that was not used gets applied to next interval
113
114 tLast = tInterp;
115 ordinals.push_back (tInterp);
116 iTLastInterval = iT;
117 }
118
119 tLast = t;
120 posLast = posNew;
121 }
122
123 if (iTLastInterval < NUM_SMALLER_INTERVALS - 1) {
124
125 // Add last point so we end up at tMax
126 ordinals.push_back (tMax);
127
128 }
129
130 return ordinals;
131}
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...
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.
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...
ExportOrdinalsSmooth()
Single constructor.
Class that represents one digitized point. The screen-to-graph coordinate transformation is always ex...
Definition Point.h:24
QPointF posScreen() const
Accessor for screen position.
Definition Point.cpp:392
double ordinal(ApplyHasCheck applyHasCheck=KEEP_HAS_CHECK) const
Get method for ordinal. Skip check if copying one instance to another.
Definition Point.cpp:374
Single X/Y pair for cubic spline interpolation initialization and calculations.
Definition SplinePair.h:12
double y() const
Get method for y.
double x() const
Get method for x.
Cubic interpolation given independent and dependent value vectors.
Definition Spline.h:22
SplinePair interpolateCoeff(double t) const
Return interpolated y for specified x.
Definition Spline.cpp:127
Affine transformation between screen and graph coordinates, based on digitized axis points.
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.