mirror of
https://github.com/love2d/love.git
synced 2026-08-18 19:54:22 +02:00
Add BezierCurve:getSegment(t1, t2)
Returns a BezierCurve that corresponds to the curve-segment between t1 and t2 on the original curve.
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
#include "common/Exception.h"
|
#include "common/Exception.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -185,6 +186,44 @@ Vector BezierCurve::evaluate(double t) const
|
|||||||
return points[0];
|
return points[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BezierCurve* BezierCurve::getSegment(double t1, double t2) const
|
||||||
|
{
|
||||||
|
if (t1 < 0 || t2 > 1)
|
||||||
|
throw Exception("Invalid segment parameters: must be between 0 and 1");
|
||||||
|
if (t2 <= t1)
|
||||||
|
throw Exception("Invalid segment parameters: t1 must be smaller than t2");
|
||||||
|
|
||||||
|
// First, sudivide the curve at t2, then subdivide the "left"
|
||||||
|
// sub-curve at t1/t2. The "right" curve is the segment.
|
||||||
|
vector<Vector> points(controlPoints);
|
||||||
|
vector<Vector> left, right;
|
||||||
|
left.reserve(points.size());
|
||||||
|
right.reserve(points.size());
|
||||||
|
|
||||||
|
// first subdivision at t2 (take only the left curve)
|
||||||
|
for (size_t step = 1; step < points.size(); ++step)
|
||||||
|
{
|
||||||
|
left.push_back(points[0]);
|
||||||
|
for (size_t i = 0; i < points.size() - step; ++i)
|
||||||
|
points[i] += (points[i+1] - points[i]) * t2; // p_i <- (1-t2)*p_i + t2*p_{i+1}
|
||||||
|
}
|
||||||
|
left.push_back(points[0]);
|
||||||
|
|
||||||
|
// second subdivion at t1/t2 (take only the right curve)
|
||||||
|
double s = t1/t2;
|
||||||
|
for (size_t step = 1; step < left.size(); ++step)
|
||||||
|
{
|
||||||
|
right.push_back(left[left.size() - step]);
|
||||||
|
for (size_t i = 0; i < left.size() - step; ++i)
|
||||||
|
left[i] += (left[i+1] - left[i]) * s;
|
||||||
|
}
|
||||||
|
right.push_back(left[0]);
|
||||||
|
|
||||||
|
// control points for right curve were added in reversed order
|
||||||
|
std::reverse(right.begin(), right.end());
|
||||||
|
return new BezierCurve(right);
|
||||||
|
}
|
||||||
|
|
||||||
vector<Vector> BezierCurve::render(int accuracy) const
|
vector<Vector> BezierCurve::render(int accuracy) const
|
||||||
{
|
{
|
||||||
if (controlPoints.size() < 2)
|
if (controlPoints.size() < 2)
|
||||||
|
|||||||
@@ -113,6 +113,15 @@ public:
|
|||||||
**/
|
**/
|
||||||
Vector evaluate(double t) const;
|
Vector evaluate(double t) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get curve segment starting at t1 and ending at t2.
|
||||||
|
* The new curve will be parametrized from 0 <= t <= 1.
|
||||||
|
* @param t1 Start of the segment.
|
||||||
|
* @param t2 End of the segment.
|
||||||
|
* @returns Bezier curve covering the segment.
|
||||||
|
*/
|
||||||
|
BezierCurve* getSegment(double t1, double t2) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the curve by subdivision.
|
* Renders the curve by subdivision.
|
||||||
* @param accuracy The 'fineness' of the curve.
|
* @param accuracy The 'fineness' of the curve.
|
||||||
|
|||||||
@@ -157,6 +157,20 @@ int w_BezierCurve_evaluate(lua_State *L)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int w_BezierCurve_getSegment(lua_State *L)
|
||||||
|
{
|
||||||
|
BezierCurve *curve = luax_checkbeziercurve(L, 1);
|
||||||
|
double t1 = luaL_checknumber(L, 2);
|
||||||
|
double t2 = luaL_checknumber(L, 3);
|
||||||
|
|
||||||
|
BezierCurve *segment;
|
||||||
|
luax_catchexcept(L, [&](){ segment = curve->getSegment(t1, t2); });
|
||||||
|
luax_pushtype(L, MATH_BEZIER_CURVE_ID, segment);
|
||||||
|
segment->release();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int w_BezierCurve_render(lua_State *L)
|
int w_BezierCurve_render(lua_State *L)
|
||||||
{
|
{
|
||||||
BezierCurve *curve = luax_checkbeziercurve(L, 1);
|
BezierCurve *curve = luax_checkbeziercurve(L, 1);
|
||||||
@@ -212,6 +226,7 @@ static const luaL_Reg functions[] =
|
|||||||
{"rotate", w_BezierCurve_rotate},
|
{"rotate", w_BezierCurve_rotate},
|
||||||
{"scale", w_BezierCurve_scale},
|
{"scale", w_BezierCurve_scale},
|
||||||
{"evaluate", w_BezierCurve_evaluate},
|
{"evaluate", w_BezierCurve_evaluate},
|
||||||
|
{"getSegment", w_BezierCurve_getSegment},
|
||||||
{"render", w_BezierCurve_render},
|
{"render", w_BezierCurve_render},
|
||||||
{"renderSegment", w_BezierCurve_renderSegment},
|
{"renderSegment", w_BezierCurve_renderSegment},
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ int w_BezierCurve_translate(lua_State *L);
|
|||||||
int w_BezierCurve_rotate(lua_State *L);
|
int w_BezierCurve_rotate(lua_State *L);
|
||||||
int w_BezierCurve_scale(lua_State *L);
|
int w_BezierCurve_scale(lua_State *L);
|
||||||
int w_BezierCurve_evaluate(lua_State *L);
|
int w_BezierCurve_evaluate(lua_State *L);
|
||||||
|
int w_BezierCurve_getSegment(lua_State *L);
|
||||||
int w_BezierCurve_render(lua_State *L);
|
int w_BezierCurve_render(lua_State *L);
|
||||||
int w_BezierCurve_renderSegment(lua_State *L);
|
int w_BezierCurve_renderSegment(lua_State *L);
|
||||||
extern "C" int luaopen_beziercurve(lua_State *L);
|
extern "C" int luaopen_beziercurve(lua_State *L);
|
||||||
|
|||||||
Reference in New Issue
Block a user