Radium Engine  1.5.20
Loading...
Searching...
No Matches
Spline.hpp
1#pragma once
2
3#include <Core/Containers/VectorArray.hpp>
4#include <Core/Math/Math.hpp>
5#include <Core/RaCore.hpp>
6
7#include <algorithm>
8#include <vector>
9
10namespace Ra {
11namespace Core {
12namespace Geometry {
22template <uint D, uint K = 2>
23class Spline
24{
25 public:
26 enum Type {
27 UNIFORM,
29 };
30
31 using Vector = typename Eigen::Matrix<Scalar, D, 1>;
32
33 public:
38 explicit inline Spline( Type type = OPEN_UNIFORM );
39
41 inline void setCtrlPoints( const Core::VectorArray<Vector>& points );
42
44 inline const Core::VectorArray<Vector>& getCtrlPoints() const;
45
47 inline void setType( Type type );
48
51 inline Vector f( Scalar u ) const;
52
54 inline Vector df( Scalar u ) const;
55
56 private:
57 // -------------------------------------------------------------------------
59 // -------------------------------------------------------------------------
60
61 inline void assertSplines() const;
62
65 inline void setNodalVector();
66
68 inline void setNodeToUniform();
69
71 inline void setNodeToOpenUniform();
72
83 static inline Vector eval( Scalar u,
84 const Core::VectorArray<Vector>& points,
85 const std::vector<Scalar>& node,
86 uint k,
87 int off = 0 );
88
89 static inline Vector evalRec( Scalar u,
90 const Core::VectorArray<Vector>& points,
91 const std::vector<Scalar>& node,
92 uint k );
93
94 // -------------------------------------------------------------------------
96 // -------------------------------------------------------------------------
97
100 std::vector<Scalar> m_node;
101 Type m_type;
102};
103
104template <uint D, uint K>
105inline Spline<D, K>::Spline( typename Spline<D, K>::Type type ) : m_type( type ) {
106 static_assert( K >= 2, "Order must be at least two" );
107 m_points.resize( K, Vector::Zero() );
108 m_vecs.resize( K - 1, Vector::Zero() );
109 m_node.resize( K + K, 0.f );
110 assertSplines();
111}
112
113// -----------------------------------------------------------------------------
114
115template <uint D, uint K>
116inline void
117Spline<D, K>::setCtrlPoints( const Core::VectorArray<typename Spline<D, K>::Vector>& points ) {
118 m_points = points;
119 m_vecs.resize( points.size() - 1, Vector::Zero() );
120 for ( uint i = 0; i < m_vecs.size(); ++i ) {
121 m_vecs[i] = m_points[i + 1] - m_points[i];
122 }
123 setNodalVector();
124 assertSplines();
125
126 for ( uint i = 0; i < m_vecs.size(); ++i ) {
127 m_vecs[i] /= m_node[K + i] - m_node[i + 1];
128 }
129}
130
131// -----------------------------------------------------------------------------
132
133template <uint D, uint K>
135 return m_points;
136}
137
138// -----------------------------------------------------------------------------
139
141template <uint D, uint K>
142inline void Spline<D, K>::setType( Type type ) {
143 m_type = type;
144 setNodalVector();
145 assertSplines();
146}
147
148// -----------------------------------------------------------------------------
149
150template <uint D, uint K>
151inline typename Spline<D, K>::Vector Spline<D, K>::f( Scalar u ) const {
152 u = std::clamp( u, Scalar( 0 ), Scalar( 1 ) );
153 return eval( u, m_points, m_node, K );
154}
155
156// -----------------------------------------------------------------------------
157
158template <uint D, uint K>
159inline typename Spline<D, K>::Vector Spline<D, K>::df( Scalar u ) const {
160 u = std::clamp( u, Scalar( 0 ), Scalar( 1 ) );
161 return eval( u, m_vecs, m_node, K - 1, 1 ) * Scalar( K - 1 );
162}
163
164// -----------------------------------------------------------------------------
165
166template <uint D, uint K>
167inline void Spline<D, K>::assertSplines() const {
168 CORE_ASSERT( m_points.size() >= K, "Not enough points" );
169 CORE_ASSERT( m_node.size() == ( K + m_points.size() ), "Wrong nodal vector size" );
170 CORE_ASSERT( m_points.size() == ( m_vecs.size() + 1 ), "Wrong point / diffs size" );
171}
172
173// -----------------------------------------------------------------------------
174
175template <uint D, uint K>
176inline void Spline<D, K>::setNodalVector() {
177 switch ( m_type ) {
178 case OPEN_UNIFORM:
179 setNodeToOpenUniform();
180 break;
181 case UNIFORM:
182 setNodeToUniform();
183 break;
184 }
185}
186
187// -----------------------------------------------------------------------------
188
189template <uint D, uint K>
190inline void Spline<D, K>::setNodeToUniform() {
191 const uint n = m_points.size() - 1;
192 m_node.resize( K + n + 1 );
193
194 Scalar step = 1.f / Scalar( n - K + 2 );
195 for ( uint i = 0; i < m_node.size(); ++i ) {
196 m_node[i] = Scalar( i ) * step - step * (Scalar)( K - 1 );
197 }
198}
199
200// -----------------------------------------------------------------------------
201
202template <uint D, uint K>
203inline void Spline<D, K>::setNodeToOpenUniform() {
204 m_node.resize( K + m_points.size() );
205
206 uint acc = 1;
207 for ( uint i = 0; i < m_node.size(); ++i ) {
208 if ( i < K ) { m_node[i] = 0.f; }
209 else if ( i >= ( m_points.size() + 1 ) ) { m_node[i] = 1.f; }
210 else {
211 m_node[i] = Scalar( acc ) / Scalar( m_points.size() + 1 - K );
212 acc++;
213 }
214 }
215}
216
217// -----------------------------------------------------------------------------
218
219template <uint D, uint K>
220inline typename Spline<D, K>::Vector Spline<D, K>::eval( Scalar u,
221 const Core::VectorArray<Vector>& points,
222 const std::vector<Scalar>& node,
223 uint k,
224 int off ) {
225 CORE_ASSERT( k >= 2, "K must be at least 2" );
226 CORE_ASSERT( points.size() >= k, "Not enough points" );
227 uint dec = 0;
228 // TODO: better search with dichotomy ?
229 // TODO: check for overflow
230 while ( u > node[dec + k + off] ) {
231 dec++;
232 }
233
234 // TODO: use buffers in attributes for better performances ?
235 Core::VectorArray<Vector> pOut( k, Vector::Zero() );
236 for ( uint i = dec, j = 0; i < ( dec + k ); ++i, ++j ) {
237 pOut[j] = points[i];
238 }
239
240 std::vector<Scalar> nodeOut( k + k - 2, Scalar( 0 ) );
241 for ( uint i = ( dec + 1 ), j = 0; i < ( dec + k + k - 1 ); ++i, ++j ) {
242 nodeOut[j] = node[i + off];
243 }
244 return evalRec( u, pOut, nodeOut, k );
245}
246
247// -----------------------------------------------------------------------------
248
249template <uint D, uint K>
250inline typename Spline<D, K>::Vector Spline<D, K>::evalRec( Scalar u,
251 const Core::VectorArray<Vector>& points,
252 const std::vector<Scalar>& node,
253 uint k ) {
254 if ( points.size() == 1 ) { return points[0]; }
255
256 // TODO: use buffers in attributes for better performances ?
257 Core::VectorArray<Vector> pOut( k - 1, Vector::Zero() );
258
259 for ( uint i = 0; i < ( k - 1 ); ++i ) {
260 const Scalar n0 = node[i + k - 1];
261 const Scalar n1 = node[i];
262 const Scalar f0 = ( n0 - u ) / ( n0 - n1 );
263 const Scalar f1 = ( u - n1 ) / ( n0 - n1 );
264
265 pOut[i] = points[i] * f0 + points[i + 1] * f1;
266 }
267
268 std::vector<Scalar> nodeOut( node.size() - 2 );
269
270 for ( uint i = 1; i < node.size() - 1; ++i ) {
271 nodeOut[i - 1] = node[i];
272 }
273 return evalRec( u, pOut, nodeOut, k - 1 );
274}
275} // namespace Geometry
276} // namespace Core
277} // namespace Ra
Handling spline curves of arbitrary dimensions.
Definition Spline.hpp:24
@ OPEN_UNIFORM
Connected to the first and last control points.
Definition Spline.hpp:28
const Core::VectorArray< Vector > & getCtrlPoints() const
Get the control points of the spline.
Definition Spline.hpp:134
Vector f(Scalar u) const
Definition Spline.hpp:151
void setCtrlPoints(const Core::VectorArray< Vector > &points)
Set the position of the spline control points.
Definition Spline.hpp:117
Vector df(Scalar u) const
Evaluate speed of the spline.
Definition Spline.hpp:159
void setType(Type type)
The the nodal vector type.
Definition Spline.hpp:142
Spline(Type type=OPEN_UNIFORM)
Definition Spline.hpp:105
This class implements ContainerIntrospectionInterface for AlignedStdVector.
T dec(T... args)
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T resize(T... args)
T size(T... args)