3 #ifndef GRAIL_BEZIER_SPLINE_H
4 #define GRAIL_BEZIER_SPLINE_H
7 #include "../../libs/vector2/vector2.h"
15 template <
typename ContextType>
31 const std::vector<Vector2>& points,
32 const std::vector<Vector2>& tangents,
33 float epsilon = 0.001f)
34 :
Curve<ContextType>{childEvaluator}, points(points), tangents{tangents}, epsilon{epsilon}
47 std::vector<Vector2>&& points,
48 std::vector<Vector2>&& tangents,
49 float epsilon = 0.001f)
50 :
Curve<ContextType>{childEvaluator},
51 points(std::move(points)),
52 tangents(std::move(tangents)),
58 virtual float Sample(
float argument)
const override final
60 if(argument <= points.front().x)
62 return points.front().y;
64 else if(argument > points.back().x)
66 return points.back().y;
69 for(std::size_t i = 1; i < points.size(); ++i)
71 if(argument == points[i].x)
76 if(argument > points[i - 1].x && argument < points[i].x)
84 float middle = (begin + end) / 2.0f;
85 result = BezierInterpolation(i - 1, i, middle);
87 if(result.x < argument)
96 while(end - begin > epsilon);
113 const std::vector<Vector2>&
GetPoints()
const {
return points; }
124 const std::vector<Vector2>&
GetTangents()
const {
return tangents; }
126 virtual data::EvaluatorType GetEvaluatorType() const override final {
return data::EvaluatorType::CURVE_BEZIER; }
131 assert(points.size() > 1);
132 assert(points.size() == tangents.size());
133 Vector2 leftVelocity = tangents.front();
134 leftGradient = leftVelocity.x != 0 ?
135 leftVelocity.y / leftVelocity.x :
136 std::numeric_limits<float>::quiet_NaN();
137 leftIntercept = leftVelocity.y - leftGradient * leftVelocity.x;
139 Vector2 rightVelocity = tangents.back();
140 rightGradient = rightVelocity.x != 0 ?
141 rightVelocity.y / rightVelocity.x :
142 std::numeric_limits<float>::quiet_NaN();
143 rightIntercept = rightVelocity.y - rightGradient * rightVelocity.x;
146 Vector2 BezierInterpolation(
const std::size_t beginIndex,
const std::size_t endIndex,
float t)
const
148 static const float BINOMIAL_COEFFICIENTS[4] = {1, 3, 3, 1};
149 Vector2 p0 = points[beginIndex];
150 Vector2 p3 = points[endIndex];
151 Vector2 p1 = p0 + tangents[beginIndex];
152 Vector2 p2 = p3 - tangents[endIndex];
153 Vector2 interpPoints[4]{p0, p1, p2, p3};
155 float tComponent = 1;
156 float oneMinusT = 1 - t;
157 float oneMinusTComponent = oneMinusT * oneMinusT * oneMinusT;
158 Vector2 result{0, 0};
159 for(
int pointIndex = 0; pointIndex < 4; ++pointIndex)
161 result += BINOMIAL_COEFFICIENTS[pointIndex] *
164 interpPoints[pointIndex];
166 oneMinusTComponent /= (1 - t);
172 std::vector<Vector2> points{};
173 std::vector<Vector2> tangents{};
174 float epsilon = 0.0f;
176 float leftGradient = 0.0f;
177 float leftIntercept = 0.0f;
178 float rightGradient = 0.0f;
179 float rightIntercept = 0.0f;
184 #endif // GRAIL_BEZIER_SPLINE_H