cgv
Loading...
Searching...
No Matches
bezier.h
1#pragma once
2
3#include "fvec.h"
4#include "fmat.h"
5#include "interpolate.h"
6#include "parametric_curve.h"
7
8namespace cgv {
9namespace math {
10
11template<typename PointT>
12class bezier_curve : public parametric_curve<bezier_curve<PointT>> {
13public:
15 std::vector<PointT> points;
16
17 bezier_curve() {}
18 template<typename InputIt>
19 bezier_curve(InputIt first, InputIt last) : points(first, last) {}
20 bezier_curve(std::initializer_list<PointT> points) : points(points) {}
21
22 template<typename ParamT = float>
23 PointT evaluate(ParamT t) const {
24 // TODO: throw an exception
25 if(points.empty())
26 return {};
27
28 if(points.size() == 1)
29 return points.front();
30
31 size_t degree = points.size() - 1;
32 std::vector<PointT> d = points;
33
34 for(size_t i = 1; i <= degree; ++i) {
35 for(size_t j = degree; j > i - 1; --j)
36 d[j] = interpolate_linear(d[j - 1], d[j], t);
37 }
38
39 return d[degree];
40 }
41};
42
43template<typename PointT>
44class quadratic_bezier_curve : public parametric_curve<quadratic_bezier_curve<PointT>> {
45public:
47 PointT p0 = { 0 };
49 PointT p1 = { 0 };
51 PointT p2 = { 0 };
52
54 quadratic_bezier_curve(const PointT& p0, const PointT& p1, const PointT& p2) : p0(p0), p1(p1), p2(p2) {}
55
56 template<typename ParamT = float>
57 PointT evaluate(ParamT t) const {
58 return interpolate_quadratic_bezier(p0, p1, p2, t);
59 }
60
61 template<typename ParamT = float>
62 PointT derivative(ParamT t) const {
63 return interpolate_linear(PointT(2) * (p1 - p0), PointT(2) * (p2 - p1), t);
64 }
65
66 std::pair<PointT, PointT> axis_aligned_bounding_box() const {
67 PointT mi = per_component_min(p0, p2);
68 PointT ma = per_component_max(p0, p2);
69
70 if(is_outside_bounds(p1, mi, ma)) {
71 PointT t = clamp((p0 - p1) / (p0 - PointT(2) * p1 + p2), PointT(0), PointT(1));
72 PointT s = PointT(1) - t;
73 PointT q = s * s * p0 + PointT(2) * s * t * p1 + t * t * p2;
74 mi = per_component_min(mi, q);
75 ma = per_component_max(ma, q);
76 }
77
78 return { mi, ma };
79 }
80
81private:
82 template<typename T>
83 T per_component_min(const T& a, const T& b) const {
84 return std::min(a, b);
85 }
86
87 template<typename T, cgv::type::uint32_type N>
88 fvec<T, N> per_component_min(const fvec<T, N>& a, const fvec<T, N>& b) const {
89 return min(a, b);
90 }
91
92 template<typename T>
93 T per_component_max(const T& a, const T& b) const {
94 return std::max(a, b);
95 }
96
97 template<typename T, cgv::type::uint32_type N>
98 fvec<T, N> per_component_max(const fvec<T, N>& a, const fvec<T, N>& b) const {
99 return max(a, b);
100 }
101
102 template<typename T>
103 bool is_outside_bounds(const T& p, const T& min, const T& max) const {
104 return p < min || p > max;
105 }
106
107 template<typename T, cgv::type::uint32_type N>
108 bool is_outside_bounds(const fvec<T, N>& p, const fvec<T, N>& min, const fvec<T, N>& max) const {
109 for(cgv::type::uint32_type i = 0; i < N; ++i) {
110 if(p[i] < min[i] || p[i] > max[i])
111 return true;
112 }
113 return false;
114 }
115};
116
117template<typename PointT>
118class cubic_bezier_curve : public parametric_curve<cubic_bezier_curve<PointT>> {
119public:
121 PointT p0 = { 0 };
123 PointT p1 = { 0 };
125 PointT p2 = { 0 };
127 PointT p3 = { 0 };
128
130 cubic_bezier_curve(const PointT& p0, const PointT& p1, const PointT& p2, const PointT& p3) : p0(p0), p1(p1), p2(p2), p3(p3) {}
131
132 template<typename ParamT = float>
133 PointT evaluate(ParamT t) const {
134 return interpolate_cubic_bezier(p0, p1, p2, p3, t);
135 }
136
137 template<typename ParamT = float>
138 PointT derivative(ParamT t) const {
139 return interpolate_quadratic_bezier(PointT(3) * (p1 - p0), PointT(3) * (p2 - p1), PointT(3) * (p3 - p2), t);
140 }
141
142 std::pair<PointT, PointT> axis_aligned_bounding_box() const {
143 return compute_bounds(p0, p1, p2, p3);
144 }
145private:
146 // Altered from original version. (Copyright 2013 Inigo Quilez: https://iquilezles.org/articles/bezierbbox/ and https://www.shadertoy.com/view/MdKBWt)
147 template<typename T>
148 std::pair<T, T> compute_bounds(const T& p0, const T& p1, const T& p2, const T& p3) const {
149 T mi = std::min(p0, p3);
150 T ma = std::max(p0, p3);
151
152 T c = T(-1) * p0 + T(1) * p1;
153 T b = T(1) * p0 - T(2) * p1 + T(1) * p2;
154 T a = T(-1) * p0 + T(3) * p1 - T(3) * p2 + T(1) * p3;
155
156 T h = b * b - a * c;
157
158 if(h > T(0)) {
159 h = sqrt(h);
160 T t = (-b - h) / a;
161 if(t > T(0) && t < T(1)) {
162 T s = T(1) - t;
163 T q = s * s * s * p0 + T(3) * s * s * t * p1 + T(3) * s * t * t * p2 + t * t * t * p3;
164 mi = std::min(mi, q);
165 ma = std::max(ma, q);
166 }
167 t = (-b + h) / a;
168 if(t > T(0) && t < T(1)) {
169 T s = T(1) - t;
170 T q = s * s * s * p0 + T(3) * s * s * t * p1 + T(3) * s * t * t * p2 + t * t * t * p3;
171 mi = std::min(mi, q);
172 ma = std::max(ma, q);
173 }
174 }
175
176 return { mi, ma };
177 }
178
179 template<typename T, cgv::type::uint32_type N>
180 std::pair<fvec<T, N>, fvec<T, N>> compute_bounds(const fvec<T, N>& p0, const fvec<T, N>& p1, const fvec<T, N>& p2, const fvec<T, N>& p3) const {
181 std::pair<fvec<T, N>, fvec<T, N>> bounds;
182 for(cgv::type::uint32_type i = 0; i < N; ++i) {
183 std::pair<T, T> coord_bounds = compute_bounds(p0[i], p1[i], p2[i], p3[i]);
184 bounds.first[i] = coord_bounds.first;
185 bounds.second[i] = coord_bounds.second;
186 }
187 return bounds;
188 }
189};
190
191} // namespace math
192} // namespace cgv
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
std::vector< PointT > points
the control points
Definition bezier.h:15
PointT p3
the fourth control point
Definition bezier.h:127
PointT p1
the second control point
Definition bezier.h:123
PointT p2
the third control point
Definition bezier.h:125
PointT p0
the first control point
Definition bezier.h:121
CRTP base class for parametric curves.
PointT p2
the end control point
Definition bezier.h:51
PointT p0
the start control point
Definition bezier.h:47
PointT p1
the middle control point
Definition bezier.h:49
this header is dependency free
Definition print.h:11