diff --git a/src/modules/math/BezierCurve.cpp b/src/modules/math/BezierCurve.cpp index 2ed776157..f120e5705 100644 --- a/src/modules/math/BezierCurve.cpp +++ b/src/modules/math/BezierCurve.cpp @@ -22,7 +22,7 @@ #include "BezierCurve.h" #include "common/Exception.h" -#include +#include using namespace std; @@ -87,6 +87,21 @@ BezierCurve::BezierCurve(const vector &pts) { } + +BezierCurve BezierCurve::getDerivative() const +{ + if (getDegree() < 1) + throw Exception("Cannot derive a curve of degree < 1."); + // actually we can, it just doesn't make any sense. + + vector forward_differences(controlPoints.size()-1); + float degree = float(getDegree()); + for (size_t i = 0; i < forward_differences.size(); ++i) + forward_differences[i] = (controlPoints[i+1] - controlPoints[i]) * degree; + + return BezierCurve(forward_differences); +} + const Vector &BezierCurve::getControlPoint(int i) const { if (i < 0) @@ -120,6 +135,29 @@ void BezierCurve::insertControlPoint(const Vector &point, int pos) controlPoints.insert(controlPoints.begin() + pos, point); } +void BezierCurve::translate(const Vector &t) +{ + for (size_t i = 0; i < controlPoints.size(); ++i) + controlPoints[i] += t; +} + +void BezierCurve::rotate(double phi, const Vector ¢er) +{ + float c = cos(phi), s = sin(phi); + for (size_t i = 0; i < controlPoints.size(); ++i) + { + Vector v = controlPoints[i] - center; + controlPoints[i].x = c * v.x - s * v.y + center.x; + controlPoints[i].y = s * v.x + c * v.y + center.y; + } +} + +void BezierCurve::scale(double s, const Vector ¢er) +{ + for (size_t i = 0; i < controlPoints.size(); ++i) + controlPoints[i] = (controlPoints[i] - center) * s + center; +} + Vector BezierCurve::eval(double t) const { if (t < 0 || t > 1) diff --git a/src/modules/math/BezierCurve.h b/src/modules/math/BezierCurve.h index 6a2f0bd76..15f61c061 100644 --- a/src/modules/math/BezierCurve.h +++ b/src/modules/math/BezierCurve.h @@ -48,6 +48,11 @@ public: return controlPoints.size() - 1; } + /** + * @returns First derivative of the curve. + */ + BezierCurve getDerivative() const; + /** * @returns i'th control point. **/ @@ -68,6 +73,26 @@ public: **/ void insertControlPoint(const Vector &point, int pos = -1); + /** + * Move the curve. + * @param t Translation vector. + */ + void translate(const Vector &t); + + /** + * Rotate the curve. + * @param phi Rotation angle (radians). + * @param center Rotation center. + */ + void rotate(double phi, const Vector ¢er); + + /** + * Scale the curve. + * @param s Scale factor. + * @param center Scale center. + */ + void scale(double phi, const Vector ¢er); + /** * Evaluates the curve at time t. * @param t Curve parameter, must satisfy 0 <= t <= 1. diff --git a/src/modules/math/wrap_BezierCurve.cpp b/src/modules/math/wrap_BezierCurve.cpp index 957a41780..b6f470f55 100644 --- a/src/modules/math/wrap_BezierCurve.cpp +++ b/src/modules/math/wrap_BezierCurve.cpp @@ -40,6 +40,14 @@ int w_BezierCurve_getDegree(lua_State *L) return 1; } +int w_BezierCurve_getDerivative(lua_State *L) +{ + BezierCurve *curve = luax_checkbeziercurve(L, 1); + BezierCurve *deriv = new BezierCurve(curve->getDerivative()); + luax_newtype(L, "BezierCurve", MATH_BEZIER_CURVE_T, (void *)deriv); + return 1; +} + int w_BezierCurve_getControlPoint(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); @@ -106,6 +114,35 @@ int w_BezierCurve_insertControlPoint(lua_State *L) return 0; } +int w_BezierCurve_move(lua_State *L) +{ + BezierCurve *curve = luax_checkbeziercurve(L, 1); + double dx = luaL_checknumber(L, 2); + double dy = luaL_checknumber(L, 3); + curve->translate(Vector(dx,dy)); + return 0; +} + +int w_BezierCurve_rotate(lua_State *L) +{ + BezierCurve *curve = luax_checkbeziercurve(L, 1); + double phi = luaL_checknumber(L, 2); + double ox = luaL_optnumber(L, 3, 0); + double oy = luaL_optnumber(L, 4, 0); + curve->rotate(phi, Vector(ox,oy)); + return 0; +} + +int w_BezierCurve_scale(lua_State *L) +{ + BezierCurve *curve = luax_checkbeziercurve(L, 1); + double s = luaL_checknumber(L, 2); + double ox = luaL_optnumber(L, 3, 0); + double oy = luaL_optnumber(L, 4, 0); + curve->scale(s, Vector(ox,oy)); + return 0; +} + int w_BezierCurve_eval(lua_State *L) { BezierCurve *curve = luax_checkbeziercurve(L, 1); @@ -148,9 +185,13 @@ int w_BezierCurve_render(lua_State *L) static const luaL_Reg functions[] = { {"getDegree", w_BezierCurve_getDegree}, + {"getDerivative", w_BezierCurve_getDerivative}, {"getControlPoint", w_BezierCurve_getControlPoint}, {"setControlPoint", w_BezierCurve_setControlPoint}, {"insertControlPoint", w_BezierCurve_insertControlPoint}, + {"move", w_BezierCurve_move}, + {"rotate", w_BezierCurve_rotate}, + {"scale", w_BezierCurve_scale}, {"eval", w_BezierCurve_eval}, {"render", w_BezierCurve_render}, { 0, 0 } diff --git a/src/modules/math/wrap_BezierCurve.h b/src/modules/math/wrap_BezierCurve.h index e5347311f..a0b4ecf58 100644 --- a/src/modules/math/wrap_BezierCurve.h +++ b/src/modules/math/wrap_BezierCurve.h @@ -32,9 +32,13 @@ namespace math BezierCurve *luax_checkbeziercurve(lua_State *L, int idx); int w_BezierCurve_getDegree(lua_State *L); +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_move(lua_State *L); +int w_BezierCurve_rotate(lua_State *L); +int w_BezierCurve_scale(lua_State *L); int w_BezierCurve_eval(lua_State *L); int w_BezierCurve_render(lua_State *L); extern "C" int luaopen_beziercurve(lua_State *L);