-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathb_spline_curve.hpp
99 lines (81 loc) · 3.2 KB
/
b_spline_curve.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#ifndef B_SPLINE_CURVE_HPP
#define B_SPLINE_CURVE_HPP
#include <array>
#include <iostream>
#include "utils.hpp"
template<size_t degree, size_t n_control_points, size_t n_points, size_t dimensions,
std::enable_if_t<std::greater<size_t>()(degree, 0), bool> = true,
std::enable_if_t<std::less<size_t>()(degree, n_control_points), bool> = true>
class BSplineCurve {
public:
constexpr explicit BSplineCurve (
const std::array<std::array<double, dimensions>, n_control_points>& control_points,
const std::array<int, n_control_points + degree + 1>& knots,
const std::array<int, n_control_points>& weights
) : control_points(control_points), knots(knots), weights(weights) {
const std::array<size_t, 2> domain = {
degree,
knots.size() - 1 - degree
};
const auto low = knots[domain[0]];
const auto high = knots[domain[1]];
auto homogeneous_coordinates = std::array<Point<dimensions+1>, n_control_points>();
for(size_t i = 0; i < n_control_points; i++) {
for(size_t j = 0; j < dimensions; j++) {
homogeneous_coordinates[i][j] = control_points[i][j] * weights[i];
}
homogeneous_coordinates[i][dimensions] = weights[i];
}
double t = 0;
const double delta = 1./(n_points - 1);
for(size_t i = 0; i < n_points; i++, t += delta) {
const double t_normalized = t * (high - low) + low;
points[i] = interpolate(t_normalized, domain, homogeneous_coordinates);
}
}
constexpr void print() const {
for (size_t i = 0; i < n_points; i++) {
for (size_t j = 0; j < dimensions; j++) {
std::cout << points[i][j] << ", ";
}
std::cout << '\n';
}
}
constexpr std::array<std::array<double, dimensions>, n_control_points> get_control_points() const {
return control_points;
}
private:
constexpr Point<dimensions> interpolate(const double& t,
const std::array<size_t, 2>& domain,
std::array<Point<dimensions+1>, n_control_points> homogeneous_coordinates
) {
size_t s = std::distance(
std::begin(knots),
std::find_if(std::begin(knots), std::end(knots), [&t](const auto& ele) { return t <= ele; })
);
s = std::max(domain[0], s);
s = std::min(domain[1]-1, s);
for(size_t l = 1; l <= degree + 1; l++) {
for(size_t i = s; i > s - degree - 1 + l; i--) {
const double alpha = (t - knots[i]) / (knots[i + degree + 1 - l] - knots[i]);
for(size_t j = 0; j < dimensions + 1; j++) {
if (i < homogeneous_coordinates.size()) {
homogeneous_coordinates[i][j] = (1 - alpha) * homogeneous_coordinates[i-1][j] + alpha * homogeneous_coordinates[i][j];
}
}
}
}
Point<dimensions> result;
for(size_t i = 0; i < dimensions; i++) {
result[i] = homogeneous_coordinates[s][i] / homogeneous_coordinates[s][dimensions];
}
return result;
}
const std::array<std::array<double, dimensions>, n_control_points> control_points;
const size_t order = degree + 1;
const size_t n_knots = n_control_points + degree + 1;
const std::array<int, n_control_points + degree + 1> knots;
const std::array<int, n_control_points> weights;
std::array<Point<dimensions>, n_points> points;
};
#endif // B_SPLINE_CURVE_HPP