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:
Kyzentun
2015-01-02 12:08:53 -07:00
parent f9ba1cc415
commit 6d9243335d
2 changed files with 174 additions and 85 deletions
+166 -84
View File
@@ -1,6 +1,7 @@
#include "global.h"
#include "CubicSpline.h"
#include "RageLog.h"
#include "RageUtil.h"
#include <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 const norm_diff= a - b;
if(spatial_extent == 0.0f) { return norm_diff; }
float const plus_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;
}
@@ -234,6 +252,19 @@ void CubicSpline::solve_straight()
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()
{
size_t last= m_points.size();
@@ -255,7 +286,7 @@ bool CubicSpline::check_minimum_size()
}
float a= m_points[0].a;
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;
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.
}
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)
{
float max_t= m_points.size();
float max_t= static_cast<float>(m_points.size());
while(t >= max_t) { 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
{
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)
{
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 tcub= tsq * 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
{
if(m_points.empty())
{
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);
RETURN_IF_EMPTY;
DECLARE_P_AND_TFRAC;
float tsq= tfrac * tfrac;
return m_points[p].b + (2.0f * m_points[p].c * tfrac) +
(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)
{
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()
{
if(!m_dirty) { return; }
if(loop)
#define SOLVE_LOOP(solvent) \
for(spline_cont_t::iterator spline= m_splines.begin(); \
spline != m_splines.end(); ++spline) \
{ \
spline->solvent(); \
}
if(polygonal)
{
for(spline_cont_t::iterator spline= m_splines.begin();
spline != m_splines.end(); ++spline)
{
spline->solve_looped();
}
SOLVE_LOOP(solve_polygonal);
}
else
{
for(spline_cont_t::iterator spline= m_splines.begin();
spline != m_splines.end(); ++spline)
if(loop)
{
spline->solve_straight();
SOLVE_LOOP(solve_looped);
}
else
{
SOLVE_LOOP(solve_straight);
}
}
#undef SOLVE_LOOP
m_dirty= false;
}
void CubicSplineN::evaluate(float t, vector<float>& v) const
{
for(spline_cont_t::const_iterator spline= m_splines.begin();
spline != m_splines.end(); ++spline)
{
v.push_back(spline->evaluate(t, loop));
}
#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) \
{ \
v.push_back(spline->something(t, loop)); \
} \
}
void CubicSplineN::evaluate_derivative(float t, vector<float>& v) const
{
for(spline_cont_t::const_iterator spline= m_splines.begin();
spline != m_splines.end(); ++spline)
{
v.push_back(spline->evaluate_derivative(t, loop));
}
}
CSN_EVAL_SOMETHING(evaluate);
CSN_EVAL_SOMETHING(evaluate_derivative);
CSN_EVAL_SOMETHING(evaluate_second_derivative);
CSN_EVAL_SOMETHING(evaluate_third_derivative);
#undef CSN_EVAL_SOMETHING
void CubicSplineN::set_point(size_t i, vector<float> const& v)
{
@@ -548,30 +595,25 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
p->solve();
COMMON_RETURN_SELF;
}
static int evaluate(T* p, lua_State* L)
{
vector<float> pos;
p->evaluate(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;
}
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;
#define LCSN_EVAL_SOMETHING(something) \
static int something(T* p, lua_State* L) \
{ \
vector<float> pos; \
p->something(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,
size_t limit, vector<float>& ret)
{
@@ -657,6 +699,11 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
lua_pushnumber(L, p->get_spatial_extent(i));
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)
{
int siz= IArg(1);
@@ -707,16 +754,39 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
lua_pushboolean(L, p->loop);
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()
{
ADD_METHOD(solve);
ADD_METHOD(evaluate);
ADD_METHOD(evaluate_derivative);
ADD_METHOD(evaluate_second_derivative);
ADD_METHOD(evaluate_third_derivative);
ADD_METHOD(set_point);
ADD_METHOD(set_coefficients);
ADD_METHOD(get_coefficients);
ADD_METHOD(set_spatial_extent);
ADD_METHOD(get_spatial_extent);
ADD_METHOD(get_max_t);
ADD_METHOD(resize);
ADD_METHOD(size);
ADD_METHOD(redimension);
@@ -724,9 +794,21 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
ADD_METHOD(empty);
ADD_METHOD(set_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
/*
+8 -1
View File
@@ -10,8 +10,12 @@ struct CubicSpline
CubicSpline() :m_spatial_extent(0.0f) {}
void solve_looped();
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_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_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
{
CubicSplineN()
:m_owned_by_actor(false), m_dirty(true)
:loop(false), polygonal(false), m_owned_by_actor(false), m_dirty(true)
{}
void solve();
void evaluate(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_coefficients(size_t i, vector<float> const& b,
vector<float> const& c, vector<float> const& d);
@@ -53,6 +59,7 @@ struct CubicSplineN
bool empty() const;
typedef vector<CubicSpline> spline_cont_t;
bool loop;
bool polygonal;
bool m_owned_by_actor;
void PushSelf(lua_State* L);