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