Grail (C++)  1.1.1
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},
49  points(std::move(points)),
50  tangents(std::move(tangents)),
51  epsilon{epsilon}
52  {
53  Initialize();
54  }
55 
56  virtual float Sample(float argument) const override final
57  {
58  if(argument <= points.front().x)
59  {
60  return points.front().y;
61  }
62  else if(argument > points.back().x)
63  {
64  return points.back().y;
65  }
66 
67  for(std::size_t i = 1; i < points.size(); ++i)
68  {
69  if(argument == points[i].x)
70  {
71  return points[i].y;
72  }
73 
74  if(argument > points[i - 1].x && argument < points[i].x)
75  {
76  float begin = 0;
77  float end = 1;
78  Vector2 result;
79 
80  do
81  {
82  float middle = (begin + end) / 2.0f;
83  result = BezierInterpolation(i - 1, i, middle);
84 
85  if(result.x < argument)
86  {
87  begin = middle;
88  }
89  else
90  {
91  end = middle;
92  }
93  }
94  while(end - begin > epsilon);
95 
96  return result.y;
97  }
98  }
99  return 0;
100  }
101 
106  std::vector<Vector2>& GetPoints() { return points; }
111  const std::vector<Vector2>& GetPoints() const { return points; }
112 
117  std::vector<Vector2>& GetTangents() { return tangents; }
122  const std::vector<Vector2>& GetTangents() const { return tangents; }
123 
124  virtual EvaluatorType GetEvaluatorType() const override final { return EvaluatorType::CURVE_BEZIER; }
125 
126  private:
127  void Initialize()
128  {
129  assert(points.size() > 1);
130  assert(points.size() == tangents.size());
131  Vector2 leftVelocity = tangents.front();
132  leftGradient = leftVelocity.x != 0 ?
133  leftVelocity.y / leftVelocity.x :
134  std::numeric_limits<float>::quiet_NaN();
135  leftIntercept = leftVelocity.y - leftGradient * leftVelocity.x;
136 
137  Vector2 rightVelocity = tangents.back();
138  rightGradient = rightVelocity.x != 0 ?
139  rightVelocity.y / rightVelocity.x :
140  std::numeric_limits<float>::quiet_NaN();
141  rightIntercept = rightVelocity.y - rightGradient * rightVelocity.x;
142  }
143 
144  Vector2 BezierInterpolation(const std::size_t beginIndex, const std::size_t endIndex, float t) const
145  {
146  static const float BINOMIAL_COEFFICIENTS[4] = {1, 3, 3, 1};
147  Vector2 p0 = points[beginIndex];
148  Vector2 p3 = points[endIndex];
149  Vector2 p1 = p0 + tangents[beginIndex];
150  Vector2 p2 = p3 - tangents[endIndex];
151  Vector2 interpPoints[4]{p0, p1, p2, p3};
152 
153  float tComponent = 1; //to start with t^0
154  float oneMinusT = 1 - t;
155  float oneMinusTComponent = oneMinusT * oneMinusT * oneMinusT; //to start with (1 - t)^3
156  Vector2 result{0, 0};
157  for(int pointIndex = 0; pointIndex < 4; ++pointIndex)
158  {
159  result += BINOMIAL_COEFFICIENTS[pointIndex] *
160  tComponent *
161  oneMinusTComponent *
162  interpPoints[pointIndex]; //p(i) * t^(3-i) * (1-t)^(i)
163  tComponent *= t; //increment exponent
164  oneMinusTComponent /= (1 - t); //decrement exponent
165  }
166 
167  return result;
168  }
169 
170  std::vector<Vector2> points{};
171  std::vector<Vector2> tangents{};
172  float epsilon = 0.0f;
173 
174  float leftGradient = 0.0f;
175  float leftIntercept = 0.0f;
176  float rightGradient = 0.0f;
177  float rightIntercept = 0.0f;
178  };
179  }
180 }
181 
182 #endif // GRAIL_BEZIER_SPLINE_H
grail::curves::Curve
The Curve class - Defines objects transforming one value into the other.
Definition: Curve.hh:19
grail::curves::BezierSpline
The BezierSpline class -Composite Cubic Bezier Curve.
Definition: BezierSpline.hh:18
grail::curves::BezierSpline::BezierSpline
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
grail::curves::BezierSpline::GetTangents
std::vector< Vector2 > & GetTangents()
GetTangents.
Definition: BezierSpline.hh:117
grail::curves::BezierSpline::Sample
virtual float Sample(float argument) const override final
Sample - Transforms argument into output value depending on the type of Curve.
Definition: BezierSpline.hh:56
grail::curves::BezierSpline::BezierSpline
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
grail::curves::BezierSpline::GetTangents
const std::vector< Vector2 > & GetTangents() const
GetTangents.
Definition: BezierSpline.hh:122
grail::curves::BezierSpline::GetPoints
std::vector< Vector2 > & GetPoints()
GetPoints.
Definition: BezierSpline.hh:106
grail::utility::Evaluator
The Evaluator class - base class being able to evaluate given context and output the result.
Definition: Evaluator.hh:20
grail::curves::BezierSpline::GetPoints
const std::vector< Vector2 > & GetPoints() const
GetPoints.
Definition: BezierSpline.hh:111