Added spatial extent math to CubicSpline.

This commit is contained in:
Kyzentun
2015-01-01 16:09:36 -07:00
parent 84e758c6c7
commit f9ba1cc415
2 changed files with 87 additions and 35 deletions
+83 -35
View File
@@ -128,6 +128,23 @@ void SplineSolutionCache::solve_diagonals_looped(vector<float>& diagonals)
SplineSolutionCache solution_cache; SplineSolutionCache solution_cache;
// loop_space_difference exists to handle numbers that exist in a finite
// looped space, instead of the flat infinite space.
// To put it more concretely, loop_space_difference exists to allow a spline
// to control rotation with wrapping behavior at 0.0 and 2pi, instead of
// suddenly jerking from 2pi to 0.0. -Kyz
float loop_space_difference(float a, float b, float spatial_extent);
float loop_space_difference(float a, float b, float spatial_extent)
{
float const plus_diff= a - (b + spatial_extent);
float const minus_diff= a - (b - spatial_extent);
if(abs(plus_diff) < abs(minus_diff))
{
return plus_diff;
}
return minus_diff;
}
void CubicSpline::solve_looped() void CubicSpline::solve_looped()
{ {
if(check_minimum_size()) { return; } if(check_minimum_size()) { return; }
@@ -135,9 +152,11 @@ void CubicSpline::solve_looped()
vector<float> results(m_points.size()); vector<float> results(m_points.size());
vector<float> diagonals(m_points.size()); vector<float> diagonals(m_points.size());
solution_cache.solve_diagonals_looped(diagonals); solution_cache.solve_diagonals_looped(diagonals);
results[0]= 3 * (m_points[1].a - m_points[last-1].a); results[0]= 3 * loop_space_difference(
m_points[1].a, m_points[last-1].a, m_spatial_extent);
prep_inner(last, results); prep_inner(last, results);
results[last-1]= 3 * (m_points[0].a - m_points[last-2].a); results[last-1]= 3 * loop_space_difference(
m_points[0].a, m_points[last-2].a, m_spatial_extent);
// The steps to solve the system of equations look like this: // The steps to solve the system of equations look like this:
// | 4 1 0 0 1 | -> | 4 0 0 0 1 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 | // | 4 1 0 0 1 | -> | 4 0 0 0 1 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 |
@@ -193,7 +212,8 @@ void CubicSpline::solve_straight()
solution_cache.solve_diagonals_straight(diagonals); solution_cache.solve_diagonals_straight(diagonals);
results[0]= 3 * (m_points[1].a - m_points[0].a); results[0]= 3 * (m_points[1].a - m_points[0].a);
prep_inner(last, results); prep_inner(last, results);
results[last-1]= 3 * (m_points[last-1].a - m_points[last-2].a); results[last-1]= 3 * loop_space_difference(
m_points[last-1].a, m_points[last-2].a, m_spatial_extent);
// The system of equations to be solved looks like this: // The system of equations to be solved looks like this:
// | 2 1 0 0 | = | results[0] | // | 2 1 0 0 | = | results[0] |
@@ -224,10 +244,12 @@ bool CubicSpline::check_minimum_size()
} }
if(last == 2) if(last == 2)
{ {
m_points[0].b= m_points[1].a - m_points[0].a; m_points[0].b= loop_space_difference(
m_points[1].a, m_points[0].a, m_spatial_extent);
m_points[0].c= m_points[0].d= 0.0f; m_points[0].c= m_points[0].d= 0.0f;
// These will be used in the looping case. // These will be used in the looping case.
m_points[1].b= m_points[0].a - m_points[1].a; m_points[1].b= loop_space_difference(
m_points[0].a, m_points[1].a, m_spatial_extent);
m_points[1].c= m_points[1].d= 0.0f; m_points[1].c= m_points[1].d= 0.0f;
return true; return true;
} }
@@ -245,7 +267,8 @@ void CubicSpline::prep_inner(size_t last, vector<float>& results)
{ {
for(size_t i= 1; i < last - 1; ++i) for(size_t i= 1; i < last - 1; ++i)
{ {
results[i]= 3 * (m_points[i+1].a - m_points[i-1].a); results[i]= 3 * loop_space_difference(
m_points[i+1].a, m_points[i-1].a, m_spatial_extent);
} }
} }
@@ -261,7 +284,8 @@ void CubicSpline::set_results(size_t last, vector<float>& diagonals, vector<floa
for(size_t i= 0; i < last; ++i) for(size_t i= 0; i < last; ++i)
{ {
size_t next= (i+1) % last; size_t next= (i+1) % last;
float diff= m_points[next].a - m_points[i].a; float diff= loop_space_difference(
m_points[next].a, m_points[i].a, m_spatial_extent);
m_points[i].b= results[i]; m_points[i].b= results[i];
m_points[i].c= (3 * diff) - (2 * results[i]) - results[next]; m_points[i].c= (3 * diff) - (2 * results[i]) - results[next];
m_points[i].d= (2 * -diff) + results[i] + results[next]; m_points[i].d= (2 * -diff) + results[i] + results[next];
@@ -432,6 +456,7 @@ void CubicSplineN::set_coefficients(size_t i, vector<float> const& b,
{ {
m_splines[n].set_coefficients(i, b[n], c[n], d[n]); m_splines[n].set_coefficients(i, b[n], c[n], d[n]);
} }
m_dirty= true;
} }
void CubicSplineN::get_coefficients(size_t i, vector<float>& b, void CubicSplineN::get_coefficients(size_t i, vector<float>& b,
@@ -446,6 +471,21 @@ void CubicSplineN::get_coefficients(size_t i, vector<float>& b,
} }
} }
void CubicSplineN::set_spatial_extent(size_t i, float extent)
{
ASSERT_M(i < m_splines.size(), "CubicSplineN: index of spline to set extent"
" of is out of range.");
m_splines[i].m_spatial_extent= extent;
m_dirty= true;
}
float CubicSplineN::get_spatial_extent(size_t i)
{
ASSERT_M(i < m_splines.size(), "CubicSplineN: index of spline to get extent"
" of is out of range.");
return m_splines[i].m_spatial_extent;
}
void CubicSplineN::resize(size_t s) void CubicSplineN::resize(size_t s)
{ {
for(spline_cont_t::iterator spline= m_splines.begin(); for(spline_cont_t::iterator spline= m_splines.begin();
@@ -485,6 +525,24 @@ size_t CubicSplineN::dimension() const
struct LunaCubicSplineN : Luna<CubicSplineN> struct LunaCubicSplineN : Luna<CubicSplineN>
{ {
static size_t dimension_index(T* p, lua_State* L, int s)
{
size_t i= static_cast<size_t>(IArg(s)-1);
if(i >= p->dimension())
{
luaL_error(L, "Spline dimension index out of range.");
}
return i;
}
static size_t point_index(T* p, lua_State* L, int s)
{
size_t i= static_cast<size_t>(IArg(s)-1);
if(i >= p->size())
{
luaL_error(L, "Spline point index out of range.");
}
return i;
}
static int solve(T* p, lua_State* L) static int solve(T* p, lua_State* L)
{ {
p->solve(); p->solve();
@@ -543,16 +601,8 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
} }
static int set_point(T* p, lua_State* L) static int set_point(T* p, lua_State* L)
{ {
int i= IArg(1)-1; size_t i= point_index(p, L, 1);
if(i < 0) set_point_from_stack(p, L, i, 2);
{
luaL_error(L, "Cannot set spline point at index less than 1.");
}
if(static_cast<size_t>(i) >= p->size())
{
luaL_error(L, "Cannot set spline point at index greater than size.");
}
set_point_from_stack(p, L, static_cast<size_t>(i), 2);
COMMON_RETURN_SELF; COMMON_RETURN_SELF;
} }
static void set_coefficients_from_stack(T* p, lua_State* L, size_t i, int s) static void set_coefficients_from_stack(T* p, lua_State* L, size_t i, int s)
@@ -569,29 +619,13 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
} }
static int set_coefficients(T* p, lua_State* L) static int set_coefficients(T* p, lua_State* L)
{ {
int i= IArg(1)-1; size_t i= point_index(p, L, 1);
if(i < 0)
{
luaL_error(L, "Cannot set spline coefficients at index less than 1.");
}
if(static_cast<size_t>(i) >= p->size())
{
luaL_error(L, "Cannot set spline coefficients at index greater than size.");
}
set_coefficients_from_stack(p, L, i, 2); set_coefficients_from_stack(p, L, i, 2);
COMMON_RETURN_SELF; COMMON_RETURN_SELF;
} }
static int get_coefficients(T* p, lua_State* L) static int get_coefficients(T* p, lua_State* L)
{ {
int i= IArg(1)-1; size_t i= point_index(p, L, 1);
if(i < 0)
{
luaL_error(L, "Cannot get spline coefficients at index less than 1.");
}
if(static_cast<size_t>(i) >= p->size())
{
luaL_error(L, "Cannot get spline coefficients at index greater than size.");
}
size_t limit= p->dimension(); size_t limit= p->dimension();
vector<vector<float> > coeff(3); vector<vector<float> > coeff(3);
coeff[0].resize(limit); coeff[0].resize(limit);
@@ -611,6 +645,18 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
} }
return 1; return 1;
} }
static int set_spatial_extent(T* p, lua_State* L)
{
size_t i= dimension_index(p, L, 1);
p->set_spatial_extent(i, FArg(2));
COMMON_RETURN_SELF;
}
static int get_spatial_extent(T* p, lua_State* L)
{
size_t i= dimension_index(p, L, 1);
lua_pushnumber(L, p->get_spatial_extent(i));
return 1;
}
static int resize(T* p, lua_State* L) static int resize(T* p, lua_State* L)
{ {
int siz= IArg(1); int siz= IArg(1);
@@ -669,6 +715,8 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
ADD_METHOD(set_point); ADD_METHOD(set_point);
ADD_METHOD(set_coefficients); ADD_METHOD(set_coefficients);
ADD_METHOD(get_coefficients); ADD_METHOD(get_coefficients);
ADD_METHOD(set_spatial_extent);
ADD_METHOD(get_spatial_extent);
ADD_METHOD(resize); ADD_METHOD(resize);
ADD_METHOD(size); ADD_METHOD(size);
ADD_METHOD(redimension); ADD_METHOD(redimension);
+4
View File
@@ -7,6 +7,7 @@ struct lua_State;
struct CubicSpline struct CubicSpline
{ {
CubicSpline() :m_spatial_extent(0.0f) {}
void solve_looped(); void solve_looped();
void solve_straight(); void solve_straight();
float evaluate(float t, bool loop) const; float evaluate(float t, bool loop) const;
@@ -17,6 +18,7 @@ struct CubicSpline
void resize(size_t s); void resize(size_t s);
size_t size() const; size_t size() const;
bool empty() const; bool empty() const;
float m_spatial_extent;
private: private:
bool check_minimum_size(); bool check_minimum_size();
void prep_inner(size_t last, vector<float>& results); void prep_inner(size_t last, vector<float>& results);
@@ -42,6 +44,8 @@ struct CubicSplineN
vector<float> const& c, vector<float> const& d); vector<float> const& c, vector<float> const& d);
void get_coefficients(size_t i, vector<float>& b, void get_coefficients(size_t i, vector<float>& b,
vector<float>& c, vector<float>& d); vector<float>& c, vector<float>& d);
void set_spatial_extent(size_t i, float extent);
float get_spatial_extent(size_t i);
void resize(size_t s); void resize(size_t s);
size_t size() const; size_t size() const;
void redimension(size_t d); void redimension(size_t d);