27#ifndef EASY3D_CORE_SPLINE_CURVE_FITTING_H
28#define EASY3D_CORE_SPLINE_CURVE_FITTING_H
64 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
123 Point<N, T>
eval_f(T u)
const;
130 Point<N, T>
eval_df(T u)
const;
158 void assert_splines()
const;
161 void set_nodal_vector();
164 void set_node_to_uniform();
167 void set_node_to_open_uniform();
178 Point<N, T> eval(T u,
179 const std::vector<Point<N, T>> &point,
181 const std::vector<T> &node,
191 Point<N, T> eval_rec(T u,
192 std::vector<Point<N, T>> p_in,
194 std::vector<T> node_in)
const;
202 std::vector<Point<N, T>> _point;
203 std::vector<Point<N, T>> _vec;
204 std::vector<T> _node;
208 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
210 _node_type(node_type),
214 _node(_k + _point.size()) {
220 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
223 _vec.resize(_point.size() - 1);
224 for (
int i = 0; i < (int) _vec.size(); ++i)
225 _vec[i] = _point[i + 1] - _point[i];
229 for (
int i = 0; i < (int) _vec.size(); ++i)
230 _vec[i] /= _node[_k + i] - _node[i + 1];
235 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
243 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
252 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
254 u = std::max(std::min(u, (T) 1), (T) 0);
255 return eval(u, _point, _k, _node);
260 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
262 u = std::max(std::min(u, (T) 1), (T) 0);
263 return eval(u, _vec, (_k - 1), _node, 1) * (T) (_k - 1);
268 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
272 std::vector<T> lengths(steps, 0);
273 std::vector<T> parameters(steps, 0);
274 Point<N, T> prev_point;
275 for (std::size_t i = 0; i < steps; ++i) {
276 const T u =
static_cast<T
>(i) /
static_cast<T
>(steps - 1);
278 const Point<N, T> pos =
eval_f(u);
280 lengths[i] = lengths[i - 1] +
distance(pos, prev_point);
283 T total_length = lengths.back();
287 auto find_closest_less_or_equal = [](
const std::vector<T> &sorted_values, T value,
288 std::size_t start) -> std::size_t {
289 assert(value >= sorted_values.front() && value <= sorted_values.back());
290 std::size_t index = start;
291 while (sorted_values[index] < value)
293 while (sorted_values[index] > value)
298 std::vector<T> U(steps);
299 for (std::size_t i = 0; i < steps; ++i) {
300 T u =
static_cast<T
>(i) /
static_cast<T
>(steps - 1);
301 T
length = total_length * u;
302 std::size_t left_index = find_closest_less_or_equal(lengths,
length, i);
303 std::size_t right_index = (lengths[left_index] ==
length) ? left_index : left_index + 1;
304 if (lengths[left_index] == lengths[right_index])
305 u = parameters[left_index];
307 T left_u = parameters[left_index];
308 T right_u = parameters[right_index];
309 T w = (
length - lengths[left_index]) / (lengths[right_index] - lengths[left_index]);
310 u = (1.0f - w) * left_u + w * right_u;
319 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
320 void SplineCurveFitting<Point, N, T>::assert_splines()
const {
322 assert((
int) _point.size() >= _k);
323 assert(_node.size() == (_k + _point.size()));
324 assert(_point.size() == (_vec.size() + 1));
329 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
330 void SplineCurveFitting<Point, N, T>::set_nodal_vector() {
331 if (_node_type == eOPEN_UNIFORM)
332 set_node_to_open_uniform();
333 else if (_node_type == eUNIFORM)
334 set_node_to_uniform();
339 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
340 void SplineCurveFitting<Point, N, T>::set_node_to_uniform() {
341 const std::size_t n = _point.size() - 1;
342 _node.resize(_k + n + 1);
344 T step = (T) 1 / (T) (n - _k + 2);
345 for (std::size_t i = 0; i < _node.size(); ++i) {
346 _node[i] = ((T) i) * step - step * (T) (_k - 1);
352 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
353 void SplineCurveFitting<Point, N, T>::set_node_to_open_uniform() {
354 _node.resize(_k + _point.size());
357 for (
int i = 0; i < (int) _node.size(); ++i) {
360 else if (i >= ((
int) _point.size() + 1))
363 _node[i] = (T) acc / (T) (_point.size() + 1 - _k);
371 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
372 Point<N, T> SplineCurveFitting<Point, N, T>::eval(T u,
373 const std::vector<Point<N, T>> &point,
375 const std::vector<T> &node,
378 assert((
int) point.size() >= k);
383 while (u > node[dec + k + off])
387 std::vector<Point<N, T>> p_rec(k, Point<N, T>());
388 for (
int i = dec, j = 0; i < (dec + k); ++i, ++j)
391 std::vector<T> node_rec(k + k - 2, (T) 0);
392 for (
int i = (dec + 1), j = 0; i < (dec + k + k - 1); ++i, ++j)
393 node_rec[j] = node[i + off];
395 return eval_rec(u, p_rec, k, node_rec);
400 template <
template <
size_t,
class>
class Point,
size_t N,
typename T>
401 Point<N, T> SplineCurveFitting<Point, N, T>::eval_rec(T u,
402 std::vector<Point<N, T>> p_in,
404 std::vector<T> node_in)
const {
405 if (p_in.size() == 1)
409 std::vector<Point<N, T>> p_out(k - 1, Point<N, T>());
410 for (
int i = 0; i < (k - 1); ++i) {
411 const T n0 = node_in[i + k - 1];
412 const T n1 = node_in[i];
413 const T f0 = (n0 - u) / (n0 - n1);
414 const T f1 = (u - n1) / (n0 - n1);
416 p_out[i] = p_in[i] * f0 + p_in[i + 1] * f1;
419 std::vector<T> node_out(node_in.size() - 2);
420 for (
int i = 1, j = 0; i < ((int) node_in.size() - 1); ++i, ++j)
421 node_out[j] = node_in[i];
423 return eval_rec(u, p_out, (k - 1), node_out);
SplineCurveFitting(int k=2, Node_e node_type=eOPEN_UNIFORM)
Constructor.
Definition spline_curve_fitting.h:209
void set_ctrl_points(const std::vector< Point< N, T > > &points)
Sets the positions of the spline control points.
Definition spline_curve_fitting.h:221
void get_ctrl_points(std::vector< Point< N, T > > &points) const
Gets the control points of the spline.
Definition spline_curve_fitting.h:236
Point< N, T > eval_df(T u) const
Evaluates speed of the spline.
Definition spline_curve_fitting.h:261
Point< N, T > eval_f(T u) const
Evaluates position of the spline.
Definition spline_curve_fitting.h:253
Node_e
The nodal vector (or knot vector) type.
Definition spline_curve_fitting.h:83
@ eOPEN_UNIFORM
Open uniform nodal vector.
Definition spline_curve_fitting.h:85
@ eUNIFORM
Uniform nodal vector.
Definition spline_curve_fitting.h:84
void set_node_type(Node_e type)
Sets the nodal vector type.
Definition spline_curve_fitting.h:244
int get_order() const
Gets the order of the spline.
Definition spline_curve_fitting.h:136
std::vector< T > get_equally_spaced_parameters(std::size_t steps) const
Gets parameters such that evaluation of the curve positions using these parameters results in equally...
Definition spline_curve_fitting.h:269
Definition collider.cpp:182
T distance(const Vec< N, T > &v1, const Vec< N, T > &v2)
Computes the distance between two vectors/points.
Definition vec.h:295
T length(const Vec< N, T > &v)
Computes the length/magnitude of a vector.
Definition vec.h:289