1 #ifndef GRAIL_BEZIER_SPLINE_H
2 #define GRAIL_BEZIER_SPLINE_H
5 #include "../../libs/vector2/vector2.h"
13 template <
typename ContextType>
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}
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)),
56 virtual float Sample(
float argument)
const override final
58 if(argument <= points.front().x)
60 return points.front().y;
62 else if(argument > points.back().x)
64 return points.back().y;
67 for(std::size_t i = 1; i < points.size(); ++i)
69 if(argument == points[i].x)
74 if(argument > points[i - 1].x && argument < points[i].x)
82 float middle = (begin + end) / 2.0f;
83 result = BezierInterpolation(i - 1, i, middle);
85 if(result.x < argument)
94 while(end - begin > epsilon);
111 const std::vector<Vector2>&
GetPoints()
const {
return points; }
122 const std::vector<Vector2>&
GetTangents()
const {
return tangents; }
124 virtual EvaluatorType GetEvaluatorType() const override final {
return EvaluatorType::CURVE_BEZIER; }
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;
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;
144 Vector2 BezierInterpolation(
const std::size_t beginIndex,
const std::size_t endIndex,
float t)
const
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};
153 float tComponent = 1;
154 float oneMinusT = 1 - t;
155 float oneMinusTComponent = oneMinusT * oneMinusT * oneMinusT;
156 Vector2 result{0, 0};
157 for(
int pointIndex = 0; pointIndex < 4; ++pointIndex)
159 result += BINOMIAL_COEFFICIENTS[pointIndex] *
162 interpPoints[pointIndex];
164 oneMinusTComponent /= (1 - t);
170 std::vector<Vector2> points{};
171 std::vector<Vector2> tangents{};
172 float epsilon = 0.0f;
174 float leftGradient = 0.0f;
175 float leftIntercept = 0.0f;
176 float rightGradient = 0.0f;
177 float rightIntercept = 0.0f;
182 #endif // GRAIL_BEZIER_SPLINE_H