From d454be70259cbf499ba8473ed8197a03d858a6eb Mon Sep 17 00:00:00 2001 From: vrld Date: Sun, 12 May 2013 13:00:08 +0200 Subject: [PATCH] Add love.math.isConvex() Checks whether a given polygon is convex or not. --- src/modules/math/MathModule.cpp | 28 ++++++++++++++++++++++++ src/modules/math/MathModule.h | 8 +++++++ src/modules/math/wrap_Math.cpp | 38 +++++++++++++++++++++++++++++++++ src/modules/math/wrap_Math.h | 1 + 4 files changed, 75 insertions(+) diff --git a/src/modules/math/MathModule.cpp b/src/modules/math/MathModule.cpp index 837195b0c..bab274d05 100644 --- a/src/modules/math/MathModule.cpp +++ b/src/modules/math/MathModule.cpp @@ -20,6 +20,7 @@ // LOVE #include "MathModule.h" +#include "common/Vector.h" // STL #include @@ -159,5 +160,32 @@ vector Math::triangulate(const vector &polygon) return triangles; } +bool Math::isConvex(const std::vector &polygon) +{ + if (polygon.size() < 3) + return false; + + // a polygon is convex if all corners turn in the same direction + // turning direction can be determined using the cross-product of + // the forward difference vectors + size_t i = polygon.size() - 2, j = polygon.size() - 1, k = 0; + Vector p(polygon[j].x - polygon[i].x, polygon[j].y - polygon[i].y); + Vector q(polygon[k].x - polygon[j].x, polygon[k].y - polygon[j].y); + float winding = p ^ q; + + while (k+1 < polygon.size()) + { + i = j; j = k; k++; + p.x = polygon[j].x - polygon[i].x; + p.y = polygon[j].y - polygon[i].y; + q.x = polygon[k].x - polygon[j].x; + q.y = polygon[k].y - polygon[j].y; + + if ((p^q) * winding < 0) + return false; + } + return true; +} + } // math } // love diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index cf40f285f..2a97a7783 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -108,6 +108,14 @@ public: **/ std::vector triangulate(const std::vector &polygon); + /** + * Checks whether a polygon is convex. + * + * @param polygon Polygon to test. + * @return True if the polygon is convex, false otherwise. + **/ + bool isConvex(const std::vector &polygon); + /** * Calculate Simplex noise for the specified coordinate(s). * diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index ae8d3826e..0af23edf2 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -148,6 +148,43 @@ int w_triangulate(lua_State *L) return 1; } +int w_isConvex(lua_State *L) +{ + std::vector vertices; + if (lua_istable(L, 1)) + { + size_t top = lua_objlen(L, 1); + vertices.reserve(top / 2); + for (size_t i = 1; i <= top; i += 2) + { + lua_rawgeti(L, 1, i); + lua_rawgeti(L, 1, i+1); + + vertex v; + v.x = luaL_checknumber(L, -2); + v.y = luaL_checknumber(L, -1); + vertices.push_back(v); + + lua_pop(L, 2); + } + } + else + { + size_t top = lua_gettop(L); + vertices.reserve(top / 2); + for (size_t i = 1; i <= top; i += 2) + { + vertex v; + v.x = luaL_checknumber(L, i); + v.y = luaL_checknumber(L, i+1); + vertices.push_back(v); + } + } + + lua_pushboolean(L, Math::instance.isConvex(vertices)); + return 1; +} + int w_noise(lua_State *L) { float w, x, y, z; @@ -192,6 +229,7 @@ static const luaL_Reg functions[] = { "randomnormal", w_randomnormal }, { "newRandomGenerator", w_newRandomGenerator }, { "triangulate", w_triangulate }, + { "isConvex", w_isConvex }, { "noise", w_noise }, { 0, 0 } }; diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index 3d312f110..369827e77 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -35,6 +35,7 @@ int w_random(lua_State *L); int w_randomnormal(lua_State *L); int w_newRandomGenerator(lua_State *L); int w_triangulate(lua_State *L); +int w_isConvex(lua_State *L); int w_noise(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);