SPH
Curve.cpp
Go to the documentation of this file.
1 #include "math/Curve.h"
2 #include <algorithm>
3 
5 
6 class Vector4 {
7 private:
8  Float v[4];
9 
10 public:
11  Vector4(const Float x1, const Float x2, const Float x3, const Float x4)
12  : v{ x1, x2, x3, x4 } {}
13 
14  INLINE Float operator[](const Size i) const {
15  SPH_ASSERT(unsigned(i) < 4);
16  return v[i];
17  }
18 };
19 
20 static Float dot(const Vector4& v1, const Vector4& v2) {
21  return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
22 }
23 
24 class Matrix4 {
25 private:
26  Vector4 rows[4];
27 
28 public:
29  Matrix4(const Vector4& v1, const Vector4& v2, const Vector4& v3, const Vector4& v4)
30  : rows{ v1, v2, v3, v4 } {}
31 
32  Vector4 row(const Size i) const {
33  return rows[i];
34  }
35 
36  Vector4 operator*(const Vector4& v) const {
37  return Vector4(dot(rows[0], v), dot(rows[1], v), dot(rows[2], v), dot(rows[3], v));
38  }
39 };
40 
42  { 1.f, 0.f, 0.f, 0.f },
43  { 0.f, 0.f, 1.f, 0.f },
44  { -3.f, 3.f, -2.f, -1.f },
45  { 2.f, -2.f, 1.f, 1.f },
46 };
47 
48 static Float getDist(const CurvePoint& p1, const CurvePoint& p2) {
49  return sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y));
50 }
51 
52 static Float getDerivative(const CurvePoint& p1, const CurvePoint& p2) {
53  return (p2.y - p1.y) / (p2.x - p1.x);
54 }
55 
56 static Float getDerivative(const CurvePoint& p0, const CurvePoint& p1, const CurvePoint& p2) {
57  // centripetal parametrization -> weight by the squared root of the distance
58  const Float d1 = sqrt(getDist(p0, p1));
59  const Float d2 = sqrt(getDist(p1, p2));
60  return lerp(getDerivative(p0, p1), getDerivative(p1, p2), d1 / (d1 + d2));
61 }
62 
63 
65  points = {
66  { { 0.f, 0.f }, true },
67  { { 1.f, 1.f }, true },
68  };
69 }
70 
71 Curve::Curve(const Interval& rangeX, const Interval& rangeY) {
72  points = {
73  { { float(rangeX.lower()), float(rangeY.lower()) }, true },
74  { { float(rangeX.upper()), float(rangeY.upper()) }, true },
75  };
76 }
77 
79  points.resize(curve.size());
80  for (Size i = 0; i < curve.size(); ++i) {
81  points[i] = std::make_pair(curve[i], true);
82  }
83  this->sort();
84 }
85 
86 Curve::Curve(const Curve& curve) {
87  *this = curve;
88 }
89 
90 Curve& Curve::operator=(const Curve& curve) {
91  points = curve.points.clone();
92  return *this;
93 }
94 
96  return points.size();
97 }
98 
99 const CurvePoint& Curve::getPoint(const Size idx) const {
100  return points[idx].first;
101 }
102 
103 void Curve::setPoint(const Size idx, const CurvePoint& newPoint) {
104  points[idx].first = newPoint;
105  this->sort();
106 }
107 
108 void Curve::addPoint(const CurvePoint& newPoint) {
109  auto iter = std::lower_bound(points.begin(),
110  points.end(),
111  newPoint,
112  [](const std::pair<CurvePoint, bool>& p, const CurvePoint& q) { return p.first.x < q.x; });
113  if (iter == points.end()) {
114  points.emplaceBack(newPoint, points[points.size() - 2].second);
115  } else {
116  points.insert(iter - points.begin(), std::make_pair(newPoint, (iter - 1)->second));
117  }
118 }
119 
120 void Curve::deletePoint(const Size idx) {
121  if (points.size() > 2) {
122  points.remove(idx);
123  }
124 }
125 
126 bool Curve::getSegment(const Size idx) const {
127  return points[idx].second;
128 }
129 
130 void Curve::setSegment(const Size idx, const bool cubic) {
131  points[idx].second = cubic;
132 }
133 
135  Interval range;
136  for (const auto& p : points) {
137  range.extend(p.first.x);
138  }
139  return range;
140 }
141 
143  Interval range;
144  for (const auto& p : points) {
145  range.extend(p.first.y);
146  }
147  return range;
148 }
149 
150 Float Curve::operator()(const Float x) const {
151  auto lowerBoundIter = std::lower_bound(
152  points.begin(), points.end(), x, [](const std::pair<CurvePoint, bool>& p, const Float x) {
153  return p.first.x < x;
154  });
155  Size idx;
156  if (lowerBoundIter == points.end() || lowerBoundIter == points.begin()) {
157  idx = 0;
158  } else {
159  idx = lowerBoundIter - points.begin() - 1;
160  }
161 
162  auto leftDy = [this, idx] {
163  return points[idx - 1].second
164  ? getDerivative(points[idx - 1].first, points[idx].first, points[idx + 1].first)
165  : getDerivative(points[idx - 1].first, points[idx].first);
166  };
167  auto rightDy = [this, idx] {
168  return points[idx + 1].second
169  ? getDerivative(points[idx].first, points[idx + 1].first, points[idx + 2].first)
170  : getDerivative(points[idx + 1].first, points[idx + 2].first);
171  };
172 
173  if (points[idx].second && points.size() > 2) {
174  if (idx == 0) {
175  return cubic(points[idx].first,
176  points[idx + 1].first,
177  getDerivative(points[idx].first, points[idx + 1].first),
178  rightDy(),
179  x);
180  } else if (idx == points.size() - 2) {
181  return cubic(points[idx].first,
182  points[idx + 1].first,
183  leftDy(),
184  getDerivative(points[idx].first, points[idx + 1].first),
185  x);
186  } else {
187  return cubic(points[idx].first, points[idx + 1].first, leftDy(), rightDy(), x);
188  }
189  } else {
190  return linear(points[idx].first, points[idx + 1].first, x);
191  }
192 }
193 
194 Float Curve::linear(const CurvePoint& p1, const CurvePoint& p2, const Float x) const {
195  return p1.y + (x - p1.x) / (p2.x - p1.x) * (p2.y - p1.y);
196 }
197 
198 Float Curve::cubic(const CurvePoint& p1,
199  const CurvePoint& p2,
200  const Float dy1,
201  const Float dy2,
202  const Float x) const {
203  const Float d = p2.x - p1.x;
204  const Float t = (x - p1.x) / d;
205  const Vector4 ts(1._f, t, pow<2>(t), pow<3>(t));
206  const Vector4 ys(p1.y, p2.y, dy1 * d, dy2 * d);
207  return dot(ts, CURVE_MATRIX * ys);
208 }
209 
210 void Curve::sort() {
211  std::sort(points.begin(),
212  points.end(),
213  [](const std::pair<CurvePoint, bool>& p1, const std::pair<CurvePoint, bool>& p2) {
214  return p1.first.x < p2.first.x;
215  });
216 }
217 
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
const Matrix4 CURVE_MATRIX
Definition: Curve.cpp:41
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Definition: Globals.h:13
INLINE T lerp(const T v1, const T v2, const TAmount amount)
Definition: MathUtils.h:341
constexpr INLINE T sqr(const T &f) noexcept
Return a squared value.
Definition: MathUtils.h:67
INLINE T sqrt(const T f)
Return a squared root of a value.
Definition: MathUtils.h:78
constexpr INLINE Float pow< 3 >(const Float v)
Definition: MathUtils.h:132
constexpr INLINE Float pow< 2 >(const Float v)
Definition: MathUtils.h:128
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define NAMESPACE_SPH_END
Definition: Object.h:12
Generic dynamically allocated resizable storage.
Definition: Array.h:43
void resize(const TCounter newSize)
Resizes the array to new size.
Definition: Array.h:215
INLINE Iterator< StorageType > end() noexcept
Definition: Array.h:462
StorageType & emplaceBack(TArgs &&... args)
Constructs a new element at the end of the array in place, using the provided arguments.
Definition: Array.h:332
void remove(const TCounter idx)
Removes an element with given index from the array.
Definition: Array.h:383
void insert(const TCounter position, U &&value)
Inserts a new element to given position in the array.
Definition: Array.h:345
INLINE TCounter size() const noexcept
Definition: Array.h:193
INLINE Iterator< StorageType > begin() noexcept
Definition: Array.h:450
Array clone() const
Performs a deep copy of all elements of the array.
Definition: Array.h:147
Represents a user-defined function, defined by a set of points interpolated by either piecewise linea...
Definition: Curve.h:19
const CurvePoint & getPoint(const Size idx) const
Returns the position of idx-th point.
Definition: Curve.cpp:99
Interval rangeY() const
Returns the extent of the curve in y-direction.
Definition: Curve.cpp:142
Curve & operator=(const Curve &curve)
Definition: Curve.cpp:90
void setPoint(const Size idx, const CurvePoint &newPoint)
Modifies the position of idx-th points.
Definition: Curve.cpp:103
Size getPointCnt() const
Returns the number of points defining the curve.
Definition: Curve.cpp:95
void addPoint(const CurvePoint &newPoint)
Adds a new point to the curve.
Definition: Curve.cpp:108
void setSegment(const Size idx, const bool cubic)
Modifies the interpolation type of idx-th segment.
Definition: Curve.cpp:130
Interval rangeX() const
Returns the extent of the curve in x-direction.
Definition: Curve.cpp:134
Float operator()(const Float x) const
Evaluates the function and returns the result.
Definition: Curve.cpp:150
bool getSegment(const Size idx) const
Returns the interpolation type of idx-th segment.
Definition: Curve.cpp:126
Curve()
Creates an identity function, defined in interval [0, 1].
Definition: Curve.cpp:64
void deletePoint(const Size idx)
Removes idx-th point from curve.
Definition: Curve.cpp:120
Object representing a 1D interval of real numbers.
Definition: Interval.h:17
INLINE Float lower() const
Returns lower bound of the interval.
Definition: Interval.h:74
INLINE void extend(const Float &value)
Extends the interval to contain given value.
Definition: Interval.h:41
INLINE Float upper() const
Returns upper bound of the interval.
Definition: Interval.h:79
Vector4 row(const Size i) const
Definition: Curve.cpp:32
Vector4 operator*(const Vector4 &v) const
Definition: Curve.cpp:36
Matrix4(const Vector4 &v1, const Vector4 &v2, const Vector4 &v3, const Vector4 &v4)
Definition: Curve.cpp:29
Definition: Curve.cpp:6
INLINE Float operator[](const Size i) const
Definition: Curve.cpp:14
Vector4(const Float x1, const Float x2, const Float x3, const Float x4)
Definition: Curve.cpp:11
Float x
Definition: Curve.h:9
Float y
Definition: Curve.h:10