cgv
Loading...
Searching...
No Matches
bezier_tube.h
1#pragma once
2
3#include "bezier.h"
4#include "distance.h"
5#include "oriented_box.h"
6
7namespace cgv {
8namespace math {
9
10template<typename T>
12 fvec<T, 3> pos = T(0);
13 T rad = T(0);
14};
15
16template<typename T>
18public:
19 using vec_type = fvec<T, 3>;
22
23 // the start node
24 node_type n0;
25 // the middle node
26 node_type n1;
27 // the end node
28 node_type n2;
29
30 template<typename ParamT = float>
31 node_type evaluate(ParamT t) const {
32 node_type n;
33 n.pos = interpolate_quadratic_bezier(n0.pos, n1.pos, n2.pos, t);
34 n.rad = interpolate_quadratic_bezier(n0.rad, n1.rad, n2.rad, t);
35 return n;
36 }
37
38 template<typename ParamT = float>
39 node_type derivative(ParamT t) const {
40 node_type n;
41 n.pos = interpolate_linear(point_type(2) * (n1.pos - n0.pos), point_type(2) * (n2.pos - n1.pos), t);
42 n.rad = interpolate_linear(point_type(2) * (n1.rad - n0.rad), point_type(2) * (n2.rad - n1.rad), t);
43 return n;
44 }
45
46 template<typename ParamT = float>
47 std::vector<node_type> sample(size_t num_segments) const {
48 std::vector<node_type> points;
49 points.reserve(num_segments + 1);
50 sample_steps_transform<ParamT>(std::back_inserter(points), [this](ParamT t) { return evaluate(t); }, num_segments);
51 return points;
52 }
53
54 std::pair<vec_type, vec_type> axis_aligned_bounding_box() const {
56 curve.p0 = n0.pos - n0.rad;
57 curve.p1 = n1.pos - n1.rad;
58 curve.p2 = n2.pos - n2.rad;
59
60 auto box_min = curve.axis_aligned_bounding_box();
61
62 curve.p0 = n0.pos + n0.rad;
63 curve.p1 = n1.pos + n1.rad;
64 curve.p2 = n2.pos + n2.rad;
65 auto box_max = curve.axis_aligned_bounding_box();
66
67 return { min(box_min.first, box_max.first), max(box_min.second, box_max.second) };
68 }
69
70 oriented_box3<T> oriented_bounding_box() const {
71 const fvec<T, 4> corners[4] = {
72 { T(-0.5), T(-0.5), T(-0.5), T(1.0) },
73 { T(+0.5), T(-0.5), T(-0.5), T(1.0) },
74 { T(-0.5), T(+0.5), T(-0.5), T(1.0) },
75 { T(-0.5), T(-0.5), T(+0.5), T(1.0) }
76 };
77
78 cgv::mat4 M = calculate_transformation_matrix();
79
80 vec_type p000 = vec_type(M * corners[0]);
81 vec_type p100 = vec_type(M * corners[1]);
82 vec_type p010 = vec_type(M * corners[2]);
83 vec_type p001 = vec_type(M * corners[3]);
84
85 vec_type dx = p100 - p000;
86 vec_type dy = p010 - p000;
87 vec_type dz = p001 - p000;
88
89 T lx = length(dx);
90 T ly = length(dy);
91 T lz = length(dz);
92
93 fmat<T, 3, 3> R({ dx / lx, dy / ly, dz / lz });
94
96 box.center = M.col(3);
97 box.extent = cgv::vec3(lx, ly, lz);
98 box.rotation = cgv::quat(R);
99 return box;
100 }
101
102 std::pair<T, T> signed_distance(const vec_type& pos) const {
103 quadratic_bezier_curve<vec_type> curve = { n0.pos, n1.pos, n2.pos };
104 std::pair<T, T> res = point_quadratic_bezier_distance(pos, n0.pos, n1.pos, n2.pos);
105
106 T rc[3];
107 control_points_to_poly_coeffs(n0.rad, n1.rad, n2.rad, rc);
108 T radius = eval_poly_d0(res.second, rc);
109
110 res.first -= radius;
111 return res;
112 }
113
114 matrix_type calculate_transformation_matrix() const {
115 vec_type x, y, z;
116
117 T xl, yl;
118 bool xq = false;
119 bool yq = false;
120 {
121 x = n2.pos - n0.pos;
122 xl = length(x);
123
124 if(xl < T(0.0001)) {
125 y = n1.pos - n0.pos;
126 yl = length(y);
127
128 if(yl < T(0.0001)) {
129 x = vec_type(T(1), T(0), T(0));
130 y = vec_type(T(0), T(1), T(0));
131 z = vec_type(T(0), T(0), T(1));
132
133 xl = T(1); xq = true;
134 yl = T(1); yq = true;
135 } else {
136 x = normalize(ortho(x));
137 xl = T(1); xq = true;
138
139 z = cross(x, y);
140 }
141 } else {
142 y = project_to_plane(n1.pos - n0.pos, x);
143 yl = length(y);
144
145 if(yl < T(0.0001)) {
146 y = normalize(ortho(x));
147 yl = T(1); yq = true;
148 }
149
150 z = cross(x, y);
151 }
152 }
153
154 vec_type xd = x / xl;
155 vec_type yd = y / yl;
156 vec_type zd = normalize(z);
157
158 T xm, xp, ym, yp, zm;
159 {
160 T xyl = dot(n1.pos - n0.pos, xd);
161
162 T cx[3];
163 control_points_to_poly_coeffs(T(0), xyl, xl, cx);
164
165 T cy[3];
166 control_points_to_poly_coeffs(T(0), yl, T(0), cy);
167
168 T rc[3];
169 control_points_to_poly_coeffs(n0.rad, n1.rad, n2.rad, rc);
170
171 T c_xm[3];
172 c_xm[0] = cx[0] - rc[0]; c_xm[1] = cx[1] - rc[1]; c_xm[2] = cx[2] - rc[2];
173
174 T c_xp[3];
175 c_xp[0] = cx[0] + rc[0]; c_xp[1] = cx[1] + rc[1]; c_xp[2] = cx[2] + rc[2];
176
177 xm = std::min(-n0.rad, std::min(xl - n2.rad, eval_poly_d0(saturate(-c_xm[1] / c_xm[2] * T(0.5)), c_xm)));
178 xp = std::max(+n0.rad, std::max(xl + n2.rad, eval_poly_d0(saturate(-c_xp[1] / c_xp[2] * T(0.5)), c_xp)));
179
180 T c_ym[3];
181 c_ym[0] = cy[0] - rc[0]; c_ym[1] = cy[1] - rc[1]; c_ym[2] = cy[2] - rc[2];
182
183 T c_yp[3];
184 c_yp[0] = cy[0] + rc[0]; c_yp[1] = cy[1] + rc[1]; c_yp[2] = cy[2] + rc[2];
185
186 ym = std::min(-n0.rad, std::min(-n2.rad, eval_poly_d0(saturate(-c_ym[1] / c_ym[2] * T(0.5)), c_ym)));
187 yp = std::max(+n0.rad, std::max(+n2.rad, eval_poly_d0(saturate(-c_yp[1] / c_yp[2] * T(0.5)), c_yp)));
188
189 zm = std::max(n0.rad, std::max(n2.rad, eval_poly_d0(saturate(-rc[1] / rc[2] * T(0.5)), rc)));
190
191 if(xq) { xm = -zm; xp = zm; }
192 if(yq) { ym = -zm; yp = zm; }
193 }
194
195 vec_type center = n0.pos + 0.5f * (xd * (xm + xp) + yd * (ym + yp));
196
197 return {
198 { (xp - xm) * xd, T(0) },
199 { (yp - ym) * yd, T(0) },
200 { T(2) * zm * zd, T(0) },
201 { center, T(1) }
202 };
203 }
204
205private:
206 // TODO: Ideally, this function is provided in the math namespace to allow reuse.
207 vec_type project_to_plane(vec_type vec, vec_type n) const {
208 return vec - n * dot(vec, n) / dot(n, n);
209 }
210
211 void control_points_to_poly_coeffs(T p0, T h, T p1, T o_c[3]) const {
212 o_c[0] = p0;
213 o_c[1] = T(-2) * p0 + T(2) * h;
214 o_c[2] = p0 + p1 - T(2) * h;
215 }
216
217 T eval_poly_d0(T x, T c[3]) const {
218 return x * (x * c[2] + c[1]) + c[0];
219 }
220};
221
222} // namespace math
223} // namespace cgv
matrix of fixed size dimensions
Definition fmat.h:23
fvec< T, N > & col(unsigned j)
reference a column of the matrix as a vector
Definition fmat.h:209
A vector with zero based index.
Definition fvec.h:27
PointT p2
the end control point
Definition bezier.h:49
PointT p0
the start control point
Definition bezier.h:45
PointT p1
the middle control point
Definition bezier.h:47
A column vector class.
Definition vec.h:28
the cgv namespace
Definition print.h:11
cgv::math::quaternion< float > quat
declare type of quaternion
Definition quaternion.h:370
cgv::math::fvec< float, 3 > vec3
declare type of 3d single precision floating point vectors
Definition fvec.h:670