Browse Source

Merged in muddmaker/love-render-curve-segment (pull request #39)

Add BezierCurve:renderSegment
vrld 10 years ago
parent
commit
f7cb16be87

+ 2 - 1
changes.txt

@@ -28,6 +28,7 @@ Released: N/A
   * Added Text objects and love.graphics.newText.
   * Added BMFont bitmap font file support to love.graphics.newFont and love.font.
   * Added love.window.maximize.
+  * Added BezierCurve:renderSegment and BezierCurve:removePoint.
 
   * Removed love.filesystem.exists (use love.filesystem.isFile or love.filesystem.isDirectory instead.)
   * Removed the "wu" and "wd" constants for love.mousepressed (replaced by love.wheelmoved.)
@@ -315,7 +316,7 @@ LOVE 0.9.0 [Baby Inspector]
   * Added love.window.getIcon.
   * Added t.window.icon to love.conf.
   * Added love.mousefocus and love.window.hasMouseFocus.
-  * Added custom hardware cursors via love.mouse.newCursor. 
+  * Added custom hardware cursors via love.mouse.newCursor.
   * Added love.mouse.setX/setY.
   * Added Joystick objects.
   * Added love.joystick.getJoystick.

+ 48 - 13
src/modules/math/BezierCurve.cpp

@@ -104,35 +104,46 @@ BezierCurve BezierCurve::getDerivative() const
 
 const Vector &BezierCurve::getControlPoint(int i) const
 {
-	if (i < 0)
+	while (i < 0)
 		i += controlPoints.size();
 
-	if (i < 0 || (size_t) i >= controlPoints.size())
-		throw Exception("Invalid control point index");
+	while ((size_t) i >= controlPoints.size())
+		i -= controlPoints.size();
 
 	return controlPoints[i];
 }
 
 void BezierCurve::setControlPoint(int i, const Vector &point)
 {
-	if (i < 0)
+	while (i < 0)
 		i += controlPoints.size();
 
-	if (i < 0 || (size_t) i >= controlPoints.size())
-		throw Exception("Invalid control point index");
+	while ((size_t) i >= controlPoints.size())
+		i -= controlPoints.size();
 
 	controlPoints[i] = point;
 }
 
-void BezierCurve::insertControlPoint(const Vector &point, int pos)
+void BezierCurve::insertControlPoint(const Vector &point, int i)
 {
-	if (pos < 0)
-		pos += controlPoints.size() + 1;
+	while (i < 0)
+		i += controlPoints.size();
 
-	if (pos < 0 ||(size_t)  pos > controlPoints.size())
-		throw Exception("Invalid control point index");
+	while ((size_t)  i > controlPoints.size())
+		i -= controlPoints.size();
 
-	controlPoints.insert(controlPoints.begin() + pos, point);
+	controlPoints.insert(controlPoints.begin() + i, point);
+}
+
+void BezierCurve::removeControlPoint(int i)
+{
+	while (i < 0)
+		i += controlPoints.size();
+
+	while ((size_t) i >= controlPoints.size())
+		i -= controlPoints.size();
+
+	controlPoints.erase(controlPoints.begin() + i);
 }
 
 void BezierCurve::translate(const Vector &t)
@@ -170,7 +181,7 @@ Vector BezierCurve::evaluate(double t) const
 	for (size_t step = 1; step < controlPoints.size(); ++step)
 		for (size_t i = 0; i < controlPoints.size() - step; ++i)
 			points[i] = points[i] * (1-t) + points[i+1] * t;
-	
+
 	return points[0];
 }
 
@@ -183,6 +194,30 @@ vector<Vector> BezierCurve::render(int accuracy) const
 	return vertices;
 }
 
+vector<Vector> BezierCurve::renderSegment(double start, double end, size_t accuracy) const
+{
+	if (controlPoints.size() < 2)
+		throw Exception("Invalid Bezier curve: Not enough control points.");
+	vector<Vector> vertices(controlPoints);
+	subdivide(vertices, accuracy);
+	if (start == end)
+	{
+		vertices.clear();
+	}
+	else if (start < end)
+	{
+		size_t start_idx = size_t(start * vertices.size());
+		size_t end_idx = size_t(end * vertices.size() + 0.5);
+		return std::vector<Vector>(vertices.begin() + start_idx, vertices.begin() + end_idx);
+	}
+	else if (end > start)
+	{
+		size_t start_idx = size_t(end * vertices.size() + 0.5);
+		size_t end_idx = size_t(start * vertices.size());
+		return std::vector<Vector>(vertices.begin() + start_idx, vertices.begin() + end_idx);
+	}
+	return vertices;
+}
 
 } // namespace math
 } // namespace love

+ 15 - 0
src/modules/math/BezierCurve.h

@@ -73,6 +73,12 @@ public:
 	 **/
 	void insertControlPoint(const Vector &point, int pos = -1);
 
+	/**
+	 * Remove the i'th control point from the curve.
+	 * @param i Control point to remove
+	 **/
+	void removeControlPoint(int i);
+
 	/**
 	 * @returns Number of control points.
 	 **/
@@ -114,6 +120,15 @@ public:
 	 **/
 	std::vector<Vector> render(int accuracy = 4) const;
 
+	/**
+	 * Renders a segment of the curve by subdivision.
+	 * @param start The starting point (between 0 and 1) on the curve.
+	 * @param end The ending point on the curve.
+	 * @param accuracy The 'fineness' of the curve.
+	 * @returns A polygon chain that approximates the segment along the curve
+	 **/
+	std::vector<Vector> renderSegment(double start, double end, size_t accuracy = 4) const;
+
 private:
 	std::vector<Vector> controlPoints;
 };

+ 36 - 0
src/modules/math/wrap_BezierCurve.cpp

@@ -94,6 +94,18 @@ int w_BezierCurve_insertControlPoint(lua_State *L)
 	return 0;
 }
 
+int w_BezierCurve_removeControlPoint(lua_State *L)
+{
+	BezierCurve *curve = luax_checkbeziercurve(L, 1);
+	int idx = luaL_checkint(L, 2);
+	
+	if (idx > 0) // 1-indexing
+		idx--;
+	
+	luax_catchexcept(L, [&](){ curve->removeControlPoint(idx); });
+	return 0;
+}
+	
 int w_BezierCurve_getControlPointCount(lua_State *L)
 {
 	BezierCurve *curve = luax_checkbeziercurve(L, 1);
@@ -165,6 +177,28 @@ int w_BezierCurve_render(lua_State *L)
 	return 1;
 }
 
+int w_BezierCurve_renderSegment(lua_State *L)
+{
+	BezierCurve *curve = luax_checkbeziercurve(L, 1);
+	double start = luaL_checknumber(L, 2);
+	double end = luaL_checknumber(L, 3);
+	int accuracy = luaL_optinteger(L, 4, 5);
+	
+	std::vector<Vector> points;
+	luax_catchexcept(L, [&](){ points = curve->renderSegment(start, end, accuracy); });
+	
+	lua_createtable(L, points.size()*2, 0);
+	for (size_t i = 0; i < points.size(); ++i)
+	{
+		lua_pushnumber(L, points[i].x);
+		lua_rawseti(L, -2, 2*i+1);
+		lua_pushnumber(L, points[i].y);
+		lua_rawseti(L, -2, 2*i+2);
+	}
+	
+	return 1;
+}
+	
 static const luaL_Reg functions[] =
 {
 	{"getDegree", w_BezierCurve_getDegree},
@@ -172,12 +206,14 @@ static const luaL_Reg functions[] =
 	{"getControlPoint", w_BezierCurve_getControlPoint},
 	{"setControlPoint", w_BezierCurve_setControlPoint},
 	{"insertControlPoint", w_BezierCurve_insertControlPoint},
+	{"removeControlPoint", w_BezierCurve_removeControlPoint},
 	{"getControlPointCount", w_BezierCurve_getControlPointCount},
 	{"translate", w_BezierCurve_translate},
 	{"rotate", w_BezierCurve_rotate},
 	{"scale", w_BezierCurve_scale},
 	{"evaluate", w_BezierCurve_evaluate},
 	{"render", w_BezierCurve_render},
+	{"renderSegment", w_BezierCurve_renderSegment},
 	{ 0, 0 }
 };
 

+ 2 - 0
src/modules/math/wrap_BezierCurve.h

@@ -36,12 +36,14 @@ int w_BezierCurve_getDerivative(lua_State *L);
 int w_BezierCurve_getControlPoint(lua_State *L);
 int w_BezierCurve_setControlPoint(lua_State *L);
 int w_BezierCurve_insertControlPoint(lua_State *L);
+int w_BezierCurve_removeControlPoint(lua_State *L);
 int w_BezierCurve_getControlPointCount(lua_State *L);
 int w_BezierCurve_translate(lua_State *L);
 int w_BezierCurve_rotate(lua_State *L);
 int w_BezierCurve_scale(lua_State *L);
 int w_BezierCurve_evaluate(lua_State *L);
 int w_BezierCurve_render(lua_State *L);
+int w_BezierCurve_renderSegment(lua_State *L);
 extern "C" int luaopen_beziercurve(lua_State *L);
 
 } // math