Engauge Digitizer  2
 All Classes Functions Variables Typedefs Enumerations Friends Pages
SplineDrawer.cpp
1 /******************************************************************************************************
2  * (C) 2018 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 "EngaugeAssert.h"
8 #include <qmath.h>
9 #include "Spline.h"
10 #include "SplineDrawer.h"
11 
13  m_transformation (transformation)
14 {
15 }
16 
17 void SplineDrawer::bindToSpline (int numSegments,
18  const Spline &spline)
19 {
20  m_segmentOperations.resize (numSegments);
21 
22  // Loop through segments to get move/draw choice. We do not need to worry about
23  // applying a move (versus a draw) for the first segment since that first point
24  // is handled by external code
25  for (int segment = 0; segment < numSegments; segment++) {
26 
27  bool itsAKeeper = true;
28  if (m_transformation.transformIsDefined()) {
29 
30  // We have the graph<->screen transformation so let's use it
31  if (segmentIsMultiValued (spline,
32  numSegments,
33  segment)) {
34  itsAKeeper = false;
35  }
36 
37  // Invisible or visible?
38  m_segmentOperations [segment] = (itsAKeeper ?
39  SPLINE_DRAWER_ENUM_VISIBLE_DRAW :
40  SPLINE_DRAWER_ENUM_INVISIBLE_MOVE);
41  }
42  }
43 }
44 
45 bool SplineDrawer::segmentIsMultiValued (const Spline &spline,
46  int numSegments,
47  int segment) const
48 {
49  ENGAUGE_ASSERT (m_transformation.transformIsDefined());
50 
51  if ((0 < segment) &&
52  (segment < numSegments - 1)) {
53 
54  // Not at very start or very end
55  double tI = (double) segment;
56  double tIp1 = (double) (segment + 1);
57 
58  // Compute number of pixels between endpoints
59  SplinePair posScreenStart = spline.interpolateCoeff (tI);
60  SplinePair posScreenEnd = spline.interpolateCoeff (tIp1);
61 
62  int deltaX = posScreenEnd.x() - posScreenStart.x();
63  int deltaY = posScreenEnd.y() - posScreenStart.y();
64  double pixelDistance = qSqrt (deltaX * deltaX + deltaY * deltaY);
65  double numSteps = pixelDistance;
66 
67  // Search through a sufficiently large number of points to verify single-valuedness
68  double tIDelta = 1.0 / numSteps;
69  for (int itI = 1; itI < numSteps - 1; itI++) {
70 
71  double tIm1 = segment + (itI - 1) * tIDelta;
72  double tI = segment + (itI ) * tIDelta;
73  double tIp1 = segment + (itI + 1) * tIDelta;
74 
75  SplinePair spBefore = spline.interpolateCoeff (tIm1);
76  SplinePair spCurrent = spline.interpolateCoeff (tI);
77  SplinePair spAfter = spline.interpolateCoeff (tIp1);
78 
79  QPointF posScreenBefore (spBefore.x(), spBefore.y());
80  QPointF posScreenCurrent (spCurrent.x(), spCurrent.y());
81  QPointF posScreenAfter (spAfter.x(), spAfter.y());
82 
83  QPointF posGraphBefore, posGraphCurrent, posGraphAfter;
84  m_transformation.transformScreenToRawGraph (posScreenBefore,
85  posGraphBefore);
86  m_transformation.transformScreenToRawGraph (posScreenCurrent,
87  posGraphCurrent);
88  m_transformation.transformScreenToRawGraph (posScreenAfter,
89  posGraphAfter);
90 
91  // In between the start and end points we look for deltaXBefore>0 and deltaXAfter<0,
92  // or deltaXBefore<0 and deltaXAfter>0, either of those two cases indicates multi-valued
93  double deltaXBefore = posGraphCurrent.x() - posGraphBefore.x();
94  double deltaXAfter = posGraphAfter.x() - posGraphCurrent.x();
95 
96  if ((deltaXBefore > 0 && deltaXAfter < 0) ||
97  (deltaXBefore < 0 && deltaXAfter > 0)) {
98 
99  // Multi-valued
100  return true;
101  }
102  }
103  }
104 
105  return false;
106 }
107 
108 SplineDrawerOperation SplineDrawer::segmentOperation (int segment) const
109 {
110  if (segment < m_segmentOperations.count()) {
111  return m_segmentOperations.at (segment);
112  } else {
113  return SPLINE_DRAWER_ENUM_INVISIBLE_MOVE;
114  }
115 }
void transformScreenToRawGraph(const QPointF &coordScreen, QPointF &coordGraph) const
Transform from cartesian pixel screen coordinates to cartesian/polar graph coordinates.
SplinePair interpolateCoeff(double t) const
Return interpolated y for specified x.
Definition: Spline.cpp:214
Cubic interpolation given independent and dependent value vectors.
Definition: Spline.h:29
double y() const
Get method for y.
Definition: SplinePair.cpp:80
void bindToSpline(int numSegments, const Spline &spline)
Analyze each segment in the Spline.
SplineDrawerOperation segmentOperation(int segment) const
Indicate if, and how, segment is to be drawn.
SplineDrawer(const Transformation &transformation)
Single constructor.
Affine transformation between screen and graph coordinates, based on digitized axis points...
bool transformIsDefined() const
Transform is defined when at least three axis points have been digitized.
double x() const
Get method for x.
Definition: SplinePair.cpp:75
Single X/Y pair for cubic spline interpolation initialization and calculations.
Definition: SplinePair.h:13