diff --git a/CMakeLists.txt b/CMakeLists.txt index d1a3823c306c5e8f0f3a8fd4e5b01cae727e50b3..6d6c94bb5a6eb83392fa744f92844e47b0b5097e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,10 @@ add_executable( tests/unit_tests/simple_triangle_tests.cpp tests/unit_tests/contourize_tests.cpp tests/unit_tests/point_in_triangle_tests.cpp + tests/unit_tests/triangulation_tests.cpp + tests/unit_tests/ear_removal_tests.cpp src/utilities/intersections.cpp + tests/union_tests.cpp src/shapes/triangle.cpp src/shapes/triangle_edges.cpp src/utilities/contourize.cpp @@ -32,6 +35,7 @@ add_executable( src/shapes/point.cpp src/union.cpp src/utilities/triangulation.cpp + src/utilities/pointList.cpp ) include_directories(include) diff --git a/include/constants.h b/include/constants.h new file mode 100644 index 0000000000000000000000000000000000000000..0ec927ff5a50bdc477c466fd376435550bbc613d --- /dev/null +++ b/include/constants.h @@ -0,0 +1,3 @@ +#pragma once + +#define MAX_TRIANGLE_INTERSECTION_POINTS 12 \ No newline at end of file diff --git a/include/pointList.h b/include/pointList.h new file mode 100644 index 0000000000000000000000000000000000000000..746cfd080688bbb5dc5fa2d8e222dfd83f71c2b4 --- /dev/null +++ b/include/pointList.h @@ -0,0 +1,22 @@ +#pragma once +#include <constants.h> +#include <point.h> +#include <vector> + +struct PointNode { + int prevIndex; + int nextIndex; + Point p; + int next() const; +}; + +class PointList { + int size; + public: + PointNode points[MAX_TRIANGLE_INTERSECTION_POINTS]; + PointList(const std::vector<Point> &points); + bool empty() const; + int prev(const PointNode &p) const; + int next(const PointNode &p) const; + void remove(int index); +}; \ No newline at end of file diff --git a/include/triangle_edges.h b/include/triangle_edges.h index d0afc10effe9ff2a3bd89b0583059c00515fcc89..5dbdb74acb94bb1e1fce838496c0516eb873437c 100644 --- a/include/triangle_edges.h +++ b/include/triangle_edges.h @@ -1,3 +1,5 @@ +#pragma once + #include "edge.h" struct Triangle; struct TriangleEdges { diff --git a/include/triangulation.h b/include/triangulation.h index 299914a58d4cb7707fdf3057c9beda955796ca40..ef2134e9502f80c5e641b6322305daff62e23295 100644 --- a/include/triangulation.h +++ b/include/triangulation.h @@ -1,9 +1,12 @@ #pragma once #include <vector> +#include <optional> +#include <triangle.h> -struct Triangle; +class PointList; struct Point; +std::optional<Triangle> removeEar(int &index, PointList &pointList, const std::vector<Point> &allPoints); std::vector<Triangle> triangulate(std::vector<Point> points); diff --git a/src/utilities/pointList.cpp b/src/utilities/pointList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b6d92e78c35de20594389d08acb4a645ac0ff80 --- /dev/null +++ b/src/utilities/pointList.cpp @@ -0,0 +1,34 @@ +#include <pointList.h> + +bool PointList::empty() const { + return size == 0; +} + +int PointList::prev(const PointNode &p) const { + const int index = (p.prevIndex + size) % size; + return index; +} + +int PointList::next(const PointNode &p) const { + const int index = p.nextIndex % size; + return index; +} + +void PointList::remove(int i) { + if (size == 1) { + size--; + return; + } + const PointNode &p = points[i]; + int prevInd = prev(p); + int nextInd = next(p); + points[prevInd].nextIndex = nextInd; + points[nextInd].prevIndex = prevInd; + size--; +} + +PointList::PointList(const std::vector<Point> &points) : size {points.size()} { + for (int i = 0; i < points.size(); i++) { + this->points[i] = PointNode{i - 1, i + 1, points[i]}; + } +} \ No newline at end of file diff --git a/src/utilities/triangulation.cpp b/src/utilities/triangulation.cpp index 186976e81e96f0af04cf2fd739f880cbce09c51e..dca98614101a2b42c17b2af6c7fd6822a290e28a 100644 --- a/src/utilities/triangulation.cpp +++ b/src/utilities/triangulation.cpp @@ -2,19 +2,76 @@ #include <list> #include <point.h> #include <triangle.h> +#include <optional> +#include <pointList.h> + + + + +bool isAnEar(Triangle triangle, const std::vector<Point> &points) { + for (const Point &p: points) { + if (triangle.pointInTriangle(p)) { + return false; + } + } + return true; +} + +int mod(int a, int b) { + return (a + b) % b; +} + + + +std::optional<Triangle> removeEar(int &index, PointList &pointList, const std::vector<Point> &allPoints) { + PointNode &p = pointList.points[index]; + const int next = pointList.next(p); + const int prev = pointList.prev(p); + + const PointNode &nextNode = pointList.points[next]; + const PointNode &prevNode = pointList.points[prev]; /* -bool isAnEar(Point point, Triangle triangle, Point start[], Point end[]) { + Triangle candidate; + + if (index > next_index && next_index < previous_index) { + candidate = Triangle{points[index], points[next_index], points[previous_index], 0}; + } + + if (index < next_index) { + candidate = Triangle{points[index], points[next_index], points[previous_index], 0}; + + } + */ + + Triangle candidate = Triangle{p.p, nextNode.p, prevNode.p, 0}; + + if (isAnEar(candidate, allPoints)) { + + index = pointList.next(nextNode); + pointList.remove(index); + + return candidate; + } + index = prev; + return {}; } -*/ + + std::vector<Triangle> triangulate(std::vector<Point> points) { - //std::list<Point> polygon = std::list(points); std::vector<Triangle> result; - for (int i = 0; i < points.size(); i++) { + PointList polygon = PointList(points); + int i = 0; + while (!polygon.empty()) { + std::optional<Triangle> t = removeEar(i, polygon, points); + if (t.has_value()) { + result.push_back(t.value()); + } } + return result; diff --git a/tests/unit_tests/ear_removal_tests.cpp b/tests/unit_tests/ear_removal_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..478161db15c05b2c45bc5817f3f6cd56c6fcf929 --- /dev/null +++ b/tests/unit_tests/ear_removal_tests.cpp @@ -0,0 +1,22 @@ +#include <gtest/gtest.h> +#include <triangulation.h> +#include <vector> +#include <point.h> +#include <pointList.h> + +TEST(EarRemovalTests, SingleEarRemoval) { + std::vector<Point> polygon = { + {3,48}, {52, 8}, {99,50}, {138,25}, + {175, 77}, {131, 72}, {111, 113}, + {72, 43}, {26, 55}, {29, 100}}; + + PointList pointList = PointList(polygon); + int index = 0; + auto t = removeEar(index, pointList, polygon); + EXPECT_FALSE(t.has_value()); + EXPECT_TRUE(true); + + auto t2 = removeEar(index, pointList, polygon); + + auto t3 = removeEar(index, pointList, polygon); +} \ No newline at end of file diff --git a/tests/unit_tests/triangulation_tests.cpp b/tests/unit_tests/triangulation_tests.cpp index 6e74b3b7329c171123216467bd5d16bbcc7cbf12..0e48222c8618eb9f53730a286350aaa503977639 100644 --- a/tests/unit_tests/triangulation_tests.cpp +++ b/tests/unit_tests/triangulation_tests.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" #include <point.h> - +#include <triangulation.h> TEST(TriangulationTests, Page3Example) { std::vector<Point> polygon = { @@ -8,6 +8,6 @@ TEST(TriangulationTests, Page3Example) { {175, 77}, {131, 72}, {111, 113}, {72, 43}, {26, 55}, {29, 100}}; - - + auto t = triangulate(polygon); + EXPECT_TRUE(t.size() > 0); } \ No newline at end of file