Fixed bug in spline evaluate. Added create_spline and spline:destroy to allow creation of splines not owned by actors. Added polygonal mode to splines.
This commit is contained in:
+166
-84
@@ -1,6 +1,7 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "CubicSpline.h"
|
#include "CubicSpline.h"
|
||||||
#include "RageLog.h"
|
#include "RageLog.h"
|
||||||
|
#include "RageUtil.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
using std::list;
|
using std::list;
|
||||||
|
|
||||||
@@ -136,9 +137,26 @@ SplineSolutionCache solution_cache;
|
|||||||
float loop_space_difference(float a, float b, float spatial_extent);
|
float loop_space_difference(float a, float b, float spatial_extent);
|
||||||
float loop_space_difference(float a, float b, float spatial_extent)
|
float loop_space_difference(float a, float b, float spatial_extent)
|
||||||
{
|
{
|
||||||
|
float const norm_diff= a - b;
|
||||||
|
if(spatial_extent == 0.0f) { return norm_diff; }
|
||||||
float const plus_diff= a - (b + spatial_extent);
|
float const plus_diff= a - (b + spatial_extent);
|
||||||
float const minus_diff= a - (b - spatial_extent);
|
float const minus_diff= a - (b - spatial_extent);
|
||||||
if(abs(plus_diff) < abs(minus_diff))
|
float const abs_norm_diff= abs(norm_diff);
|
||||||
|
float const abs_plus_diff= abs(plus_diff);
|
||||||
|
float const abs_minus_diff= abs(minus_diff);
|
||||||
|
if(abs_norm_diff < abs_plus_diff)
|
||||||
|
{
|
||||||
|
if(abs_norm_diff < abs_minus_diff)
|
||||||
|
{
|
||||||
|
return norm_diff;
|
||||||
|
}
|
||||||
|
if(abs_plus_diff < abs_minus_diff)
|
||||||
|
{
|
||||||
|
return plus_diff;
|
||||||
|
}
|
||||||
|
return minus_diff;
|
||||||
|
}
|
||||||
|
if(abs_plus_diff < abs_minus_diff)
|
||||||
{
|
{
|
||||||
return plus_diff;
|
return plus_diff;
|
||||||
}
|
}
|
||||||
@@ -234,6 +252,19 @@ void CubicSpline::solve_straight()
|
|||||||
set_results(last, diagonals, results);
|
set_results(last, diagonals, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CubicSpline::solve_polygonal()
|
||||||
|
{
|
||||||
|
if(check_minimum_size()) { return; }
|
||||||
|
size_t last= m_points.size() - 1;
|
||||||
|
for(size_t i= 0; i < last; ++i)
|
||||||
|
{
|
||||||
|
m_points[i].b= loop_space_difference(
|
||||||
|
m_points[i+1].a, m_points[i].a, m_spatial_extent);
|
||||||
|
}
|
||||||
|
m_points[last].b= loop_space_difference(
|
||||||
|
m_points[0].a, m_points[last].a, m_spatial_extent);
|
||||||
|
}
|
||||||
|
|
||||||
bool CubicSpline::check_minimum_size()
|
bool CubicSpline::check_minimum_size()
|
||||||
{
|
{
|
||||||
size_t last= m_points.size();
|
size_t last= m_points.size();
|
||||||
@@ -255,7 +286,7 @@ bool CubicSpline::check_minimum_size()
|
|||||||
}
|
}
|
||||||
float a= m_points[0].a;
|
float a= m_points[0].a;
|
||||||
bool all_points_identical= true;
|
bool all_points_identical= true;
|
||||||
for(size_t i= 1; i < m_points.size(); ++i)
|
for(size_t i= 0; i < m_points.size(); ++i)
|
||||||
{
|
{
|
||||||
m_points[i].b= m_points[i].c= m_points[i].d= 0.0f;
|
m_points[i].b= m_points[i].c= m_points[i].d= 0.0f;
|
||||||
if(m_points[i].a != a) { all_points_identical= false; }
|
if(m_points[i].a != a) { all_points_identical= false; }
|
||||||
@@ -298,33 +329,46 @@ void CubicSpline::set_results(size_t last, vector<float>& diagonals, vector<floa
|
|||||||
// Solving is now complete.
|
// Solving is now complete.
|
||||||
}
|
}
|
||||||
|
|
||||||
float CubicSpline::evaluate(float t, bool loop) const
|
void CubicSpline::p_and_tfrac_from_t(float t, bool loop, size_t& p, float& tfrac) const
|
||||||
{
|
{
|
||||||
if(m_points.empty())
|
|
||||||
{
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
int flort= static_cast<int>(t);
|
|
||||||
if(loop)
|
if(loop)
|
||||||
{
|
{
|
||||||
float max_t= m_points.size();
|
float max_t= static_cast<float>(m_points.size());
|
||||||
while(t >= max_t) { t-= max_t; }
|
while(t >= max_t) { t-= max_t; }
|
||||||
while(t < 0.0f) { t+= max_t; }
|
while(t < 0.0f) { t+= max_t; }
|
||||||
flort= static_cast<int>(t);
|
p= static_cast<size_t>(t);
|
||||||
|
tfrac= t - static_cast<float>(p);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(flort <= 0)
|
int flort= static_cast<int>(t);
|
||||||
|
if(flort < 0)
|
||||||
{
|
{
|
||||||
return m_points[0].a;
|
p= 0;
|
||||||
|
tfrac= 0;
|
||||||
}
|
}
|
||||||
else if(static_cast<size_t>(flort) >= m_points.size() - 1)
|
else if(static_cast<size_t>(flort) >= m_points.size() - 1)
|
||||||
{
|
{
|
||||||
return m_points[m_points.size() - 1].a;
|
p= m_points.size() - 1;
|
||||||
|
tfrac= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p= static_cast<size_t>(flort);
|
||||||
|
tfrac= t - static_cast<float>(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t p= min(static_cast<size_t>(flort), m_points.size()-1);
|
}
|
||||||
float tfrac= t - static_cast<float>(flort);
|
|
||||||
|
#define RETURN_IF_EMPTY if(m_points.empty()) { return 0.0f; }
|
||||||
|
#define DECLARE_P_AND_TFRAC \
|
||||||
|
size_t p= 0; float tfrac= 0.0f; \
|
||||||
|
p_and_tfrac_from_t(t, loop, p, tfrac);
|
||||||
|
|
||||||
|
float CubicSpline::evaluate(float t, bool loop) const
|
||||||
|
{
|
||||||
|
RETURN_IF_EMPTY;
|
||||||
|
DECLARE_P_AND_TFRAC;
|
||||||
float tsq= tfrac * tfrac;
|
float tsq= tfrac * tfrac;
|
||||||
float tcub= tsq * tfrac;
|
float tcub= tsq * tfrac;
|
||||||
return m_points[p].a + (m_points[p].b * tfrac) +
|
return m_points[p].a + (m_points[p].b * tfrac) +
|
||||||
@@ -333,32 +377,30 @@ float CubicSpline::evaluate(float t, bool loop) const
|
|||||||
|
|
||||||
float CubicSpline::evaluate_derivative(float t, bool loop) const
|
float CubicSpline::evaluate_derivative(float t, bool loop) const
|
||||||
{
|
{
|
||||||
if(m_points.empty())
|
RETURN_IF_EMPTY;
|
||||||
{
|
DECLARE_P_AND_TFRAC;
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
int flort= static_cast<int>(t);
|
|
||||||
if(loop)
|
|
||||||
{
|
|
||||||
float max_t= m_points.size();
|
|
||||||
while(t >= max_t) { t-= max_t; }
|
|
||||||
while(t < 0.0f) { t+= max_t; }
|
|
||||||
flort= static_cast<int>(t);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(static_cast<size_t>(flort) >= m_points.size() - 1)
|
|
||||||
{
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size_t p= min(static_cast<size_t>(flort), m_points.size()-1);
|
|
||||||
float tfrac= t - static_cast<float>(flort);
|
|
||||||
float tsq= tfrac * tfrac;
|
float tsq= tfrac * tfrac;
|
||||||
return m_points[p].b + (2.0f * m_points[p].c * tfrac) +
|
return m_points[p].b + (2.0f * m_points[p].c * tfrac) +
|
||||||
(3.0f * m_points[p].d * tsq);
|
(3.0f * m_points[p].d * tsq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float CubicSpline::evaluate_second_derivative(float t, bool loop) const
|
||||||
|
{
|
||||||
|
RETURN_IF_EMPTY;
|
||||||
|
DECLARE_P_AND_TFRAC;
|
||||||
|
return (2.0f * m_points[p].c) + (6.0f * m_points[p].d * tfrac);
|
||||||
|
}
|
||||||
|
|
||||||
|
float CubicSpline::evaluate_third_derivative(float t, bool loop) const
|
||||||
|
{
|
||||||
|
RETURN_IF_EMPTY;
|
||||||
|
DECLARE_P_AND_TFRAC;
|
||||||
|
return 6.0f * m_points[p].d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RETURN_IF_EMPTY
|
||||||
|
#undef DECLARE_P_AND_TFRAC
|
||||||
|
|
||||||
void CubicSpline::set_point(size_t i, float v)
|
void CubicSpline::set_point(size_t i, float v)
|
||||||
{
|
{
|
||||||
ASSERT_M(i < m_points.size(), "CubicSpline::set_point requires the index to be less than the number of points.");
|
ASSERT_M(i < m_points.size(), "CubicSpline::set_point requires the index to be less than the number of points.");
|
||||||
@@ -399,42 +441,47 @@ bool CubicSpline::empty() const
|
|||||||
void CubicSplineN::solve()
|
void CubicSplineN::solve()
|
||||||
{
|
{
|
||||||
if(!m_dirty) { return; }
|
if(!m_dirty) { return; }
|
||||||
if(loop)
|
#define SOLVE_LOOP(solvent) \
|
||||||
{
|
for(spline_cont_t::iterator spline= m_splines.begin(); \
|
||||||
for(spline_cont_t::iterator spline= m_splines.begin();
|
spline != m_splines.end(); ++spline) \
|
||||||
spline != m_splines.end(); ++spline)
|
{ \
|
||||||
{
|
spline->solvent(); \
|
||||||
spline->solve_looped();
|
|
||||||
}
|
}
|
||||||
|
if(polygonal)
|
||||||
|
{
|
||||||
|
SOLVE_LOOP(solve_polygonal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(spline_cont_t::iterator spline= m_splines.begin();
|
if(loop)
|
||||||
spline != m_splines.end(); ++spline)
|
|
||||||
{
|
{
|
||||||
spline->solve_straight();
|
SOLVE_LOOP(solve_looped);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SOLVE_LOOP(solve_straight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef SOLVE_LOOP
|
||||||
m_dirty= false;
|
m_dirty= false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicSplineN::evaluate(float t, vector<float>& v) const
|
#define CSN_EVAL_SOMETHING(something) \
|
||||||
{
|
void CubicSplineN::something(float t, vector<float>& v) const \
|
||||||
for(spline_cont_t::const_iterator spline= m_splines.begin();
|
{ \
|
||||||
spline != m_splines.end(); ++spline)
|
for(spline_cont_t::const_iterator spline= m_splines.begin(); \
|
||||||
{
|
spline != m_splines.end(); ++spline) \
|
||||||
v.push_back(spline->evaluate(t, loop));
|
{ \
|
||||||
}
|
v.push_back(spline->something(t, loop)); \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
void CubicSplineN::evaluate_derivative(float t, vector<float>& v) const
|
CSN_EVAL_SOMETHING(evaluate);
|
||||||
{
|
CSN_EVAL_SOMETHING(evaluate_derivative);
|
||||||
for(spline_cont_t::const_iterator spline= m_splines.begin();
|
CSN_EVAL_SOMETHING(evaluate_second_derivative);
|
||||||
spline != m_splines.end(); ++spline)
|
CSN_EVAL_SOMETHING(evaluate_third_derivative);
|
||||||
{
|
|
||||||
v.push_back(spline->evaluate_derivative(t, loop));
|
#undef CSN_EVAL_SOMETHING
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CubicSplineN::set_point(size_t i, vector<float> const& v)
|
void CubicSplineN::set_point(size_t i, vector<float> const& v)
|
||||||
{
|
{
|
||||||
@@ -548,30 +595,25 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
|
|||||||
p->solve();
|
p->solve();
|
||||||
COMMON_RETURN_SELF;
|
COMMON_RETURN_SELF;
|
||||||
}
|
}
|
||||||
static int evaluate(T* p, lua_State* L)
|
#define LCSN_EVAL_SOMETHING(something) \
|
||||||
{
|
static int something(T* p, lua_State* L) \
|
||||||
vector<float> pos;
|
{ \
|
||||||
p->evaluate(FArg(1), pos);
|
vector<float> pos; \
|
||||||
lua_createtable(L, pos.size(), 0);
|
p->something(FArg(1), pos); \
|
||||||
for(size_t i= 0; i < pos.size(); ++i)
|
lua_createtable(L, pos.size(), 0); \
|
||||||
{
|
for(size_t i= 0; i < pos.size(); ++i) \
|
||||||
lua_pushnumber(L, pos[i]);
|
{ \
|
||||||
lua_rawseti(L, -2, i+1);
|
lua_pushnumber(L, pos[i]); \
|
||||||
}
|
lua_rawseti(L, -2, i+1); \
|
||||||
return 1;
|
} \
|
||||||
}
|
return 1; \
|
||||||
static int evaluate_derivative(T* p, lua_State* L)
|
|
||||||
{
|
|
||||||
vector<float> pos;
|
|
||||||
p->evaluate_derivative(FArg(1), pos);
|
|
||||||
lua_createtable(L, pos.size(), 0);
|
|
||||||
for(size_t i= 0; i < pos.size(); ++i)
|
|
||||||
{
|
|
||||||
lua_pushnumber(L, pos[i]);
|
|
||||||
lua_rawseti(L, -2, i+1);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
LCSN_EVAL_SOMETHING(evaluate);
|
||||||
|
LCSN_EVAL_SOMETHING(evaluate_derivative);
|
||||||
|
LCSN_EVAL_SOMETHING(evaluate_second_derivative);
|
||||||
|
LCSN_EVAL_SOMETHING(evaluate_third_derivative);
|
||||||
|
#undef LCSN_EVAL_SOMETHING
|
||||||
|
|
||||||
static void get_element_table_from_stack(T* p, lua_State* L, int s,
|
static void get_element_table_from_stack(T* p, lua_State* L, int s,
|
||||||
size_t limit, vector<float>& ret)
|
size_t limit, vector<float>& ret)
|
||||||
{
|
{
|
||||||
@@ -657,6 +699,11 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
|
|||||||
lua_pushnumber(L, p->get_spatial_extent(i));
|
lua_pushnumber(L, p->get_spatial_extent(i));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
static int get_max_t(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushnumber(L, p->size() - 1 + p->loop);
|
||||||
|
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);
|
||||||
@@ -707,16 +754,39 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
|
|||||||
lua_pushboolean(L, p->loop);
|
lua_pushboolean(L, p->loop);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
static int set_polygonal(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
p->polygonal= lua_toboolean(L, 1);
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
|
static int get_polygonal(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushboolean(L, p->polygonal);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
static int destroy(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
if(p->m_owned_by_actor)
|
||||||
|
{
|
||||||
|
luaL_error(L, "This spline cannot be destroyed because it is "
|
||||||
|
"owned by an actor that relies on it existing.");
|
||||||
|
}
|
||||||
|
SAFE_DELETE(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
LunaCubicSplineN()
|
LunaCubicSplineN()
|
||||||
{
|
{
|
||||||
ADD_METHOD(solve);
|
ADD_METHOD(solve);
|
||||||
ADD_METHOD(evaluate);
|
ADD_METHOD(evaluate);
|
||||||
ADD_METHOD(evaluate_derivative);
|
ADD_METHOD(evaluate_derivative);
|
||||||
|
ADD_METHOD(evaluate_second_derivative);
|
||||||
|
ADD_METHOD(evaluate_third_derivative);
|
||||||
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(set_spatial_extent);
|
||||||
ADD_METHOD(get_spatial_extent);
|
ADD_METHOD(get_spatial_extent);
|
||||||
|
ADD_METHOD(get_max_t);
|
||||||
ADD_METHOD(resize);
|
ADD_METHOD(resize);
|
||||||
ADD_METHOD(size);
|
ADD_METHOD(size);
|
||||||
ADD_METHOD(redimension);
|
ADD_METHOD(redimension);
|
||||||
@@ -724,9 +794,21 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
|
|||||||
ADD_METHOD(empty);
|
ADD_METHOD(empty);
|
||||||
ADD_METHOD(set_loop);
|
ADD_METHOD(set_loop);
|
||||||
ADD_METHOD(get_loop);
|
ADD_METHOD(get_loop);
|
||||||
|
ADD_METHOD(set_polygonal);
|
||||||
|
ADD_METHOD(get_polygonal);
|
||||||
|
ADD_METHOD(destroy);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LUA_REGISTER_CLASS(CubicSplineN)
|
LUA_REGISTER_CLASS(CubicSplineN);
|
||||||
|
|
||||||
|
int LuaFunc_create_spline(lua_State* L);
|
||||||
|
int LuaFunc_create_spline(lua_State* L)
|
||||||
|
{
|
||||||
|
CubicSplineN* spline= new CubicSplineN;
|
||||||
|
spline->PushSelf(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
LUAFUNC_REGISTER_COMMON(create_spline);
|
||||||
|
|
||||||
// Side note: Actually written between 2014/12/26 and 2014/12/28
|
// Side note: Actually written between 2014/12/26 and 2014/12/28
|
||||||
/*
|
/*
|
||||||
|
|||||||
+8
-1
@@ -10,8 +10,12 @@ struct CubicSpline
|
|||||||
CubicSpline() :m_spatial_extent(0.0f) {}
|
CubicSpline() :m_spatial_extent(0.0f) {}
|
||||||
void solve_looped();
|
void solve_looped();
|
||||||
void solve_straight();
|
void solve_straight();
|
||||||
|
void solve_polygonal();
|
||||||
|
void p_and_tfrac_from_t(float t, bool loop, size_t& p, float& tfrac) const;
|
||||||
float evaluate(float t, bool loop) const;
|
float evaluate(float t, bool loop) const;
|
||||||
float evaluate_derivative(float t, bool loop) const;
|
float evaluate_derivative(float t, bool loop) const;
|
||||||
|
float evaluate_second_derivative(float t, bool loop) const;
|
||||||
|
float evaluate_third_derivative(float t, bool loop) const;
|
||||||
void set_point(size_t i, float v);
|
void set_point(size_t i, float v);
|
||||||
void set_coefficients(size_t i, float b, float c, float d);
|
void set_coefficients(size_t i, float b, float c, float d);
|
||||||
void get_coefficients(size_t i, float& b, float& c, float& d);
|
void get_coefficients(size_t i, float& b, float& c, float& d);
|
||||||
@@ -34,11 +38,13 @@ private:
|
|||||||
struct CubicSplineN
|
struct CubicSplineN
|
||||||
{
|
{
|
||||||
CubicSplineN()
|
CubicSplineN()
|
||||||
:m_owned_by_actor(false), m_dirty(true)
|
:loop(false), polygonal(false), m_owned_by_actor(false), m_dirty(true)
|
||||||
{}
|
{}
|
||||||
void solve();
|
void solve();
|
||||||
void evaluate(float t, vector<float>& v) const;
|
void evaluate(float t, vector<float>& v) const;
|
||||||
void evaluate_derivative(float t, vector<float>& v) const;
|
void evaluate_derivative(float t, vector<float>& v) const;
|
||||||
|
void evaluate_second_derivative(float t, vector<float>& v) const;
|
||||||
|
void evaluate_third_derivative(float t, vector<float>& v) const;
|
||||||
void set_point(size_t i, vector<float> const& v);
|
void set_point(size_t i, vector<float> const& v);
|
||||||
void set_coefficients(size_t i, vector<float> const& b,
|
void set_coefficients(size_t i, vector<float> const& b,
|
||||||
vector<float> const& c, vector<float> const& d);
|
vector<float> const& c, vector<float> const& d);
|
||||||
@@ -53,6 +59,7 @@ struct CubicSplineN
|
|||||||
bool empty() const;
|
bool empty() const;
|
||||||
typedef vector<CubicSpline> spline_cont_t;
|
typedef vector<CubicSpline> spline_cont_t;
|
||||||
bool loop;
|
bool loop;
|
||||||
|
bool polygonal;
|
||||||
bool m_owned_by_actor;
|
bool m_owned_by_actor;
|
||||||
|
|
||||||
void PushSelf(lua_State* L);
|
void PushSelf(lua_State* L);
|
||||||
|
|||||||
Reference in New Issue
Block a user