diff --git a/.gitignore b/.gitignore index cafd3c2..d1e21fc 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,19 @@ /Test_Geometry2D.vcxproj /Test_Geometry2D.sln build + +#CMake generated files and directories +/ALL_BUILD.vcxproj +/ALL_BUILD.vcxproj.filters +/ALL_BUILD.vcxproj.user +/CMakeCache.txt +/Test_Geometry2D.vcxproj.user +/ZERO_CHECK.vcxproj +/ZERO_CHECK.vcxproj.filters +/ZERO_CHECK.vcxproj.user +/cmake_install.cmake +/olcUTIL_Geometry2D.sln + +CMakeFiles/ +TEST_Geometry2D.dir/ +bin/ \ No newline at end of file diff --git a/TEST_Geometry2D.cpp b/TEST_Geometry2D.cpp index fbdb6ee..91efc87 100644 --- a/TEST_Geometry2D.cpp +++ b/TEST_Geometry2D.cpp @@ -86,6 +86,11 @@ class Test_Geometry2D : public olc::PixelGameEngine olc::vf2d points[2]; // origin, direction }; + struct Polygon + { + std::vector points; // vertices + }; + // Create desired shapes using a sequence of points static auto make_internal(const Point& p) { return p.points[0]; } static auto make_internal(const Line& p) { return line{ p.points[0], p.points[1] }; } @@ -93,9 +98,10 @@ class Test_Geometry2D : public olc::PixelGameEngine static auto make_internal(const Circle& p) { return circle{ p.points[0], (p.points[1]-p.points[0]).mag() }; } static auto make_internal(const Triangle& p) { return triangle{ p.points[0], p.points[1], p.points[2] }; } static auto make_internal(const Ray& p) { return ray{ p.points[0], (p.points[1]-p.points[0]).norm() }; } + static auto make_internal(const Polygon& p) { return polygon{ p.points }; } // The clever bit (and a bit new to me - jx9) - using ShapeWrap = std::variant; + using ShapeWrap = std::variant; @@ -216,6 +222,17 @@ class Test_Geometry2D : public olc::PixelGameEngine DrawLine(t.origin, t.origin+t.direction * 1000.0f, col, 0xF0F0F0F0); } + void draw_internal(const Polygon& x, const olc::Pixel col) + { + const auto t = make_internal(x); + + for(uint32_t i = 0; i < t.pos.size(); ++i) + { + uint32_t next = (i + 1) % t.pos.size(); + DrawLine(t.pos[i], t.pos[next], col); + } + } + void DrawShape(const ShapeWrap& shape, const olc::Pixel col = olc::WHITE) { std::visit([&](const auto& x) @@ -238,14 +255,18 @@ class Test_Geometry2D : public olc::PixelGameEngine vecShapes.push_back({ Line{ { { 80.0f, 10.0f }, {10.0f, 20.0f} } } }); vecShapes.push_back({ Rect{ { { 80.0f, 10.0f }, {110.0f, 60.0f} } } }); + vecShapes.push_back({ Rect{ { { 80.0f, 10.0f }, {200.0f, 150.0f} } }}); vecShapes.push_back({ Circle{ { { 130.0f, 20.0f }, {170.0f, 20.0f} } } }); vecShapes.push_back({ Circle{ { { 330.0f, 300.0f }, {420.0f, 300.0f} } } }); vecShapes.push_back({ Circle{ { { 330.0f, 300.0f }, {400.0f, 300.0f} } } }); - vecShapes.push_back({ Triangle{{ {50.0f, 100.0f}, {10.0f, 150.0f}, {90.0f, 150.0f}} }}); + vecShapes.push_back({ Triangle{{ {50.0f, 100.0f}, {90.0f, 150.0f}, {10.0f, 150.0f}} }}); vecShapes.push_back({ Triangle{{ {350.0f, 200.0f}, {500.0f, 150.0f}, {450.0f, 400.0f}} }}); + vecShapes.push_back({create_regular_convex_polygon(5, 50, {150, 150})}); + vecShapes.push_back({create_regular_convex_polygon(8, 80, {300, 150})}); + return true; } @@ -430,6 +451,20 @@ class Test_Geometry2D : public olc::PixelGameEngine return true; } + + Polygon create_regular_convex_polygon(uint32_t point_count, float scale = 1, const olc::vf2d& translation = {}) + { + Polygon polygon; + float angle = olc::utils::geom2d::pi * 2 / (float)point_count; + + for(uint32_t i = 0; i < point_count; ++i) + { + olc::vf2d point = olc::vf2d{std::cos(angle * i), std::sin(angle * i)} * scale + translation; + polygon.points.push_back(point); + } + + return polygon; + } }; int main() diff --git a/olcUTIL_Geometry2D.h b/olcUTIL_Geometry2D.h index 7e3be8a..6481e0f 100644 --- a/olcUTIL_Geometry2D.h +++ b/olcUTIL_Geometry2D.h @@ -540,6 +540,48 @@ namespace olc::utils::geom2d return filtered_points; } + + template + bool overlaps(const std::vector>& a, const std::vector>& b) + { + for(uint32_t i = 0; i < a.size(); ++i) + { + uint32_t next = (i + 1) % a.size(); + olc::v_2d edge = a[next] - a[i]; + olc::v_2d normal = -edge.perp(); + T minProj = std::numeric_limits::max(); + + for(uint32_t j = 0; j < b.size(); ++j) + { + T proj = normal.dot(b[j] - a[i]); + minProj = std::min(minProj, proj); + } + + if(minProj >= 0) + return false; + } + + return true; + } + + template + bool contains(const std::vector>& a, const std::vector>& b) + { + for(uint32_t i = 0; i < a.size(); ++i) + { + uint32_t next = (i + 1) % a.size(); + olc::v_2d edge = a[next] - a[i]; + olc::v_2d normal = -edge.perp(); + + for(uint32_t j = 0; j < b.size(); ++j) + { + if(normal.dot(b[j] - a[i]) > 0) + return false; + } + } + + return true; + } }; //https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c @@ -2492,4 +2534,355 @@ namespace olc::utils::geom2d return internal::filter_duplicate_points(intersections); } + + + // ================================================================================================================ + // POLYGON ======================================================================================================== + + // overlaps(poly,poly) + // Checks if polygon overlaps polygon + template + inline constexpr bool overlaps(const polygon& poly1, const polygon& poly2) + { + return internal::overlaps(poly1.pos, poly2.pos) && internal::overlaps(poly2.pos, poly1.pos); + } + + // overlaps(poly,p) + // Checks if polygon overlaps point + template + inline constexpr bool overlaps(const polygon& poly, const v_2d& p) + { + return contains(poly, p); + } + + // overlaps(poly,l) + // Checks if polygon overlaps line segment + template + inline constexpr bool overlaps(const polygon& poly, const line& l) + { + std::vector> lineVerts{l.start, l.end}; + return internal::overlaps(poly.pos, lineVerts) && internal::overlaps(lineVerts, poly.pos); + } + + // overlaps(poly,r) + // Checks if polygon overlaps rect + template + inline constexpr bool overlaps(const polygon& poly, const rect& r) + { + std::vector> rectVerts{r.pos, {r.pos.x + r.size.x, r.pos.y}, r.pos + r.size, {r.pos.x, r.pos.y + r.size.y}}; + return internal::overlaps(poly.pos, rectVerts) && internal::overlaps(rectVerts, poly.pos); + } + + // overlaps(poly,c) + // Checks if polygon overlaps circle + template + inline constexpr bool overlaps(const polygon& poly, const circle& c) + { + T maxProj = std::numeric_limits::lowest(); + olc::v_2d start, edge; + + for(uint32_t i = 0; i < poly.pos.size(); ++i) + { + uint32_t next = (i + 1) % poly.pos.size(); + olc::v_2d e = poly.pos[next] - poly.pos[i]; + olc::v_2d normal = -e.perp(); + T proj = normal.dot(c.pos - poly.pos[i]); + + if(proj > maxProj) + { + maxProj = proj; + start = poly.pos[i]; + edge = e; + } + } + + if(maxProj <= 0) + return true; + + T t = std::clamp(edge.dot(c.pos - start) / edge.mag2(), T(0), T(1)); + olc::v_2d closest = start + edge * t; + olc::v_2d separation = c.pos - closest; + + return separation.mag2() < c.radius * c.radius; + } + + // overlaps(poly,t) + // Checks if polygon overlaps triangle + template + inline constexpr bool overlaps(const polygon& poly, const triangle& t) + { + std::vector> triVerts{t.pos.begin(), t.pos.end()}; + return internal::overlaps(poly.pos, triVerts) && internal::overlaps(triVerts, poly.pos); + } + + // overlaps(p,poly) + // Checks if point overlaps polygon + template + inline constexpr bool overlaps(const v_2d& p, const polygon& poly) + { + return contains(poly, p); + } + + // overlaps(l,poly) + // Checks if line segment overlaps polygon + template + inline constexpr bool overlaps(const line& l, const polygon& poly) + { + return overlaps(poly, l); + } + + // overlaps(r,poly) + // Checks if rect overlaps polygon + template + inline constexpr bool overlaps(const rect& r, const polygon& poly) + { + return overlaps(poly, r); + } + + // overlaps(c,poly) + // Checks if circle overlaps polygon + template + inline constexpr bool overlaps(const circle& c, const polygon& poly) + { + return overlaps(poly, c); + } + + // overlaps(t,poly) + // Checks if triangle overlaps polygon + template + inline constexpr bool overlaps(const triangle& t, const polygon& poly) + { + return overlaps(poly, t); + } + + // contains(poly,poly) + // Checks if polygon contains polygon + template + inline constexpr bool contains(const polygon& poly1, const polygon& poly2) + { + return internal::contains(poly1.pos, poly2.pos); + } + + // contains(poly,p) + // Checks if polygon contains point + template + inline constexpr bool contains(const polygon& poly, const v_2d& p) + { + std::vector> point{p}; + return internal::contains(poly.pos, point); + } + + // contains(poly,l) + // Checks if polygon contains line segment + template + inline constexpr bool contains(const polygon& poly, const line& l) + { + std::vector> lineVerts{l.start, l.end}; + return internal::contains(poly.pos, lineVerts); + } + + // contains(poly,r) + // Checks if polygon contains rect + template + inline constexpr bool contains(const polygon& poly, const rect& r) + { + std::vector> rectVerts{r.pos, {r.pos.x + r.size.x, r.pos.y}, r.pos + r.size, {r.pos.x, r.pos.y + r.size.y}}; + return internal::contains(poly.pos, rectVerts); + } + + // contains(poly,c) + // Checks if polygon contains circle + template + inline constexpr bool contains(const polygon& poly, const circle& c) + { + for(uint32_t i = 0; i < poly.pos.size(); ++i) + { + uint32_t next = (i + 1) % poly.pos.size(); + olc::v_2d edge = poly.pos[next] - poly.pos[i]; + olc::v_2d normal = -edge.perp(); + olc::v_2d diff = c.pos - poly.pos[i]; + T proj = normal.dot(diff); + + if(proj > 0) + return false; + + T t = edge.dot(diff) / edge.mag2(); + olc::v_2d closest = poly.pos[i] + edge * t; + olc::v_2d separation = c.pos - closest; + + if(separation.mag2() < c.radius * c.radius) + return false; + } + + return true; + } + + // contains(poly,t) + // Checks if polygon contains triangle + template + inline constexpr bool contains(const polygon& poly, const triangle& t) + { + std::vector> triVerts{t.pos.begin(), t.pos.end()}; + return internal::contains(poly.pos, triVerts); + } + + // contains(p,poly) + // Checks if point contains polygon + template + inline constexpr bool contains(const v_2d& p, const polygon& poly) + { + return false; + } + + // contains(l,poly) + // Checks if line segment contains polygon + template + inline constexpr bool contains(const line& l, const polygon& poly) + { + return false; + } + + // contains(r,poly) + // Checks if rect contains polygon + template + inline constexpr bool contains(const rect& r, const polygon& poly) + { + std::vector> rectVerts{r.pos, {r.pos.x + r.size.x, r.pos.y}, r.pos + r.size, {r.pos.x, r.pos.y + r.size.y}}; + return internal::contains(rectVerts, poly.pos); + } + + // contains(c,poly) + // Checks if circle contains polygon + template + inline constexpr bool contains(const circle& c, const polygon& poly) + { + for(uint32_t i = 0; i < poly.pos.size(); ++i) + { + if((poly.pos[i] - c.pos).mag2() > c.radius * c.radius) + return false; + } + + return true; + } + + // contains(t,poly) + // Checks if triangle contains polygon + template + inline constexpr bool contains(const triangle& t, const polygon& poly) + { + std::vector> triVerts{t.pos.begin(), t.pos.end()}; + return internal::contains(triVerts, poly.pos); + } + + // intersects(poly,poly) + // Get intersection points where polygon intersects with polygon + template + inline std::vector> intersects(const polygon& poly1, const polygon& poly2) + { + return {}; + } + + // intersects(poly,p) + // Get intersection points where polygon intersects with point + template + inline std::vector> intersects(const polygon& poly, const v_2d& p) + { + return {}; + } + + // intersects(poly,l) + // Get intersection points where polygon intersects with line segment + template + inline std::vector> intersects(const polygon& poly, const line& l) + { + return {}; + } + + // intersects(poly,r) + // Get intersection points where polygon intersects with rect + template + inline std::vector> intersects(const polygon& poly, const rect& r) + { + return {}; + } + + // intersects(poly,c) + // Get intersection points where polygon intersects with circle + template + inline std::vector> intersects(const polygon& poly, const circle& c) + { + return {}; + } + + // intersects(poly,t) + // Get intersection points where polygon intersects with triangle + template + inline std::vector> intersects(const polygon& poly, const triangle& t) + { + return {}; + } + + // intersects(p,poly) + // Get intersection points where point intersects with polygon + template + inline std::vector> intersects(const v_2d& p, const polygon& poly) + { + return {}; + } + + // intersects(l,poly) + // Get intersection points where line segment intersects with polygon + template + inline std::vector> intersects(const line& l, const polygon& poly) + { + return {}; + } + + // intersects(r,poly) + // Get intersection points where rect intersects with polygon + template + inline std::vector> intersects(const rect& r, const polygon& poly) + { + return {}; + } + + // intersects(c,poly) + // Get intersection points where circle intersects with polygon + template + inline std::vector> intersects(const circle& c, const polygon& poly) + { + return {}; + } + + // intersects(t,poly) + // Get intersection points where triangle intersects with polygon + template + inline std::vector> intersects(const triangle& t, const polygon& poly) + { + return {}; + } + + // intersects(q,poly) + // Get intersection points where ray intersects with polygon + template + inline std::vector> intersects(const ray& q, const polygon& poly) + { + return {}; + } + + // reflect(q,poly) + // Optionally returns a ray reflected off a polygon if collision occurs + template + inline std::optional> reflect(const ray& q, const polygon& poly) + { + return {}; + } + + // closest(poly,p) + // Returns closest point on polygon to point + template + inline olc::v_2d closest(const polygon& poly, const olc::v_2d& p) + { + return {}; + } }