(C++)  1.1.0
A multi-platform, modular, universal engine for embedding advanced AI in games.
BezierSpline.hh
1 #ifndef GRAIL_BEZIER_SPLINE_H
2 #define GRAIL_BEZIER_SPLINE_H
3 
4 #include "Curve.hh"
5 #include "../../libs/vector2/vector2.h"
6 
7 #include <cassert>
8 
9 namespace grail
10 {
11  namespace curves
12  {
13  template <typename ContextType>
18  class BezierSpline final : public Curve<ContextType>
19  {
20  public:
28  BezierSpline(std::shared_ptr<utility::Evaluator<ContextType>> childEvaluator,
29  const std::vector<Vector2>& points,
30  const std::vector<Vector2>& tangents,
31  float epsilon = 0.001f)
32  : Curve<ContextType>{childEvaluator}, points(points), tangents{ tangents }, epsilon{ epsilon }
33  {
34  Initialize();
35  }
36 
44  BezierSpline(std::shared_ptr<utility::Evaluator<ContextType>> childEvaluator,
45  std::vector<Vector2>&& points,
46  std::vector<Vector2>&& tangents,
47  float epsilon = 0.001f)
48  : Curve<ContextType>{childEvaluator}, points(std::move(points)), tangents(std::move(tangents)), epsilon{ epsilon }
49  {
50  Initialize();
51  }
52 
53  virtual float Sample(float argument) const override final
54  {
55  if (argument <= points.front().x)
56  return points.front().y;
57  else if (argument > points.back().x)
58  return points.back().y;
59 
60  for (std::size_t i = 1; i < points.size(); ++i)
61  {
62  if (argument == points[i].x)
63  return points[i].y;
64 
65  if (argument > points[i - 1].x && argument < points[i].x)
66  {
67  float begin = 0;
68  float end = 1;
69  Vector2 result;
70 
71  do
72  {
73  float middle = (begin + end) / 2.0f;
74  result = BezierInterpolation(i - 1, i, middle);
75 
76  if (result.x < argument)
77  begin = middle;
78  else
79  end = middle;
80  }
81  while (end - begin > epsilon);
82 
83  return result.y;
84  }
85  }
86  return 0;
87  }
88 
93  std::vector<Vector2>& GetPoints() { return points; }
98  const std::vector<Vector2>& GetPoints() const { return points; }
99 
104  std::vector<Vector2>& GetTangents() { return tangents; }
109  const std::vector<Vector2>& GetTangents() const { return tangents; }
110 
111  EvaluatorType GetEvaluatorType() const override final { return EvaluatorType::CURVE_BEZIER; }
112 
113  private:
114  void Initialize()
115  {
116  assert(points.size() > 1);
117  assert(points.size() == tangents.size());
118  Vector2 leftVelocity = tangents.front();
119  leftGradient = leftVelocity.x != 0 ? leftVelocity.y / leftVelocity.x : std::numeric_limits<float>::quiet_NaN();
120  leftIntercept = leftVelocity.y - leftGradient * leftVelocity.x;
121 
122  Vector2 rightVelocity = tangents.back();
123  rightGradient = rightVelocity.x != 0 ? rightVelocity.y / rightVelocity.x : std::numeric_limits<float>::quiet_NaN();
124  rightIntercept = rightVelocity.y - rightGradient * rightVelocity.x;
125  }
126 
127  Vector2 BezierInterpolation(const std::size_t beginIndex, const std::size_t endIndex, float t) const
128  {
129  static const float BINOMIAL_COEFFICIENTS[4] = { 1, 3, 3, 1 };
130  Vector2 p0 = points[beginIndex];
131  Vector2 p3 = points[endIndex];
132  Vector2 p1 = p0 + tangents[beginIndex];
133  Vector2 p2 = p3 - tangents[endIndex];
134  Vector2 interpPoints[4]{ p0, p1, p2, p3 };
135 
136  float tComponent = 1; //to start with t^0
137  float oneMinusT = 1 - t;
138  float oneMinusTComponent = oneMinusT * oneMinusT * oneMinusT; //to start with (1 - t)^3
139  Vector2 result{ 0, 0 };
140  for (int pointIndex = 0; pointIndex < 4; ++pointIndex)
141  {
142  result += BINOMIAL_COEFFICIENTS[pointIndex] *
143  tComponent *
144  oneMinusTComponent *
145  interpPoints[pointIndex]; //p(i) * t^(3-i) * (1-t)^(i)
146  tComponent *= t; //increment exponent
147  oneMinusTComponent /= (1 - t); //decrement exponent
148  }
149 
150  return result;
151  }
152 
153  std::vector<Vector2> points{};
154  std::vector<Vector2> tangents{};
155  float epsilon = 0.0f;
156 
157  float leftGradient = 0.0f;
158  float leftIntercept = 0.0f;
159  float rightGradient = 0.0f;
160  float rightIntercept = 0.0f;
161  };
162  }
163 }
164 
165 #endif // GRAIL_BEZIER_SPLINE_H
The BezierSpline class -Composite Cubic Bezier Curve.
Definition: BezierSpline.hh:19
std::vector< Vector2 > & GetPoints()
GetPoints.
Definition: BezierSpline.hh:93
virtual float Sample(float argument) const override final
Sample - Transforms argument into output value depending on the type of Curve.
Definition: BezierSpline.hh:53
const std::vector< Vector2 > & GetTangents() const
GetTangents.
Definition: BezierSpline.hh:109
BezierSpline(std::shared_ptr< utility::Evaluator< ContextType >> childEvaluator, const std::vector< Vector2 > &points, const std::vector< Vector2 > &tangents, float epsilon=0.001f)
BezierSpline - Constructor.
Definition: BezierSpline.hh:28
std::vector< Vector2 > & GetTangents()
GetTangents.
Definition: BezierSpline.hh:104
BezierSpline(std::shared_ptr< utility::Evaluator< ContextType >> childEvaluator, std::vector< Vector2 > &&points, std::vector< Vector2 > &&tangents, float epsilon=0.001f)
BezierSpline - Constructor.
Definition: BezierSpline.hh:44
const std::vector< Vector2 > & GetPoints() const
GetPoints.
Definition: BezierSpline.hh:98
The Curve class - Defines objects transforming one value into the other.
Definition: Curve.hh:21
The Evaluator class - base class being able to evaluate given context and output the result.
Definition: Evaluator.hh:21