From 8b8700c5a4fee5af1b9e7ff68de93f213a1c61c6 Mon Sep 17 00:00:00 2001 From: Brandon Lai-Cheong <brandon.lai-cheong@uwaterloo.ca> Date: Wed, 27 Nov 2024 15:14:12 -0500 Subject: [PATCH] added edge union cases --- CMakeLists.txt | 8 +- include/contourize.h | 5 ++ include/convex_triangulation.h | 2 +- include/interpolate_z.h | 5 ++ include/orientation.h | 6 +- include/point.h | 3 + include/shift_triangle.h | 4 + include/triangle.h | 2 +- include/triangulation.h | 13 --- src/data_structures/quad_tree.cpp | 80 ------------------- src/debug_utilities/mostly_equal.cpp | 1 - src/debug_utilities/print_triangles.cpp | 1 - src/debug_utilities/shift_triangle.cpp | 9 +++ src/shapes/point.cpp | 14 ++++ src/shapes/triangle.cpp | 2 +- src/union.cpp | 10 ++- src/utilities/contourize.cpp | 25 +++++- src/utilities/convex_triangulation.cpp | 6 +- src/utilities/interpolate_z.cpp | 26 ++++++ src/utilities/intersections.cpp | 5 +- src/utilities/orientation.cpp | 6 ++ src/utilities/triangulation.cpp | 70 ---------------- tests/edge_union_cases.cpp | 74 ++++++++++++++--- tests/quad_tree_tests.cpp | 53 ------------ tests/union_neighbours_tests.cpp | 4 +- tests/union_tests.cpp | 69 ++++++++-------- tests/unit_tests/contourize_tests.cpp | 4 +- .../unit_tests/convex_triangulation_tests.cpp | 12 +-- tests/unit_tests/ear_removal_tests.cpp | 22 ----- tests/unit_tests/interpolate_z_tests.cpp | 26 ++++++ tests/unit_tests/orientation_tests.cpp | 4 + tests/unit_tests/split_triangle_tests.cpp | 22 ++++- tests/unit_tests/triangulation_tests.cpp | 13 --- 33 files changed, 282 insertions(+), 324 deletions(-) create mode 100644 include/interpolate_z.h create mode 100644 include/shift_triangle.h delete mode 100644 include/triangulation.h delete mode 100644 src/data_structures/quad_tree.cpp create mode 100644 src/debug_utilities/shift_triangle.cpp create mode 100644 src/utilities/interpolate_z.cpp delete mode 100644 src/utilities/triangulation.cpp delete mode 100644 tests/quad_tree_tests.cpp delete mode 100644 tests/unit_tests/ear_removal_tests.cpp create mode 100644 tests/unit_tests/interpolate_z_tests.cpp delete mode 100644 tests/unit_tests/triangulation_tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 61c608d..e6d36f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,8 +26,6 @@ add_executable( src/debug_utilities/mostly_equal.cpp tests/unit_tests/simple_triangle_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 @@ -37,13 +35,10 @@ add_executable( src/utilities/orientation.cpp src/shapes/point.cpp src/union.cpp - src/utilities/triangulation.cpp src/utilities/pointList.cpp tests/unit_tests/orientation_tests.cpp tests/unit_tests/intersections_tests.cpp src/data_structures/box.cpp - src/data_structures/quad_tree.cpp - tests/quad_tree_tests.cpp tests/edge_union_cases.cpp tests/unit_tests/convex_triangulation_tests.cpp src/utilities/convex_triangulation.cpp @@ -53,6 +48,9 @@ add_executable( src/utilities/split_triangle.cpp tests/unit_tests/orientation_tests.cpp tests/union_neighbours_tests.cpp + src/debug_utilities/shift_triangle.cpp + src/utilities/interpolate_z.cpp + tests/unit_tests/interpolate_z_tests.cpp ) include_directories(include) diff --git a/include/contourize.h b/include/contourize.h index cb605f7..4292e98 100644 --- a/include/contourize.h +++ b/include/contourize.h @@ -1,9 +1,14 @@ #pragma once #include <vector> +#include <string> +#include <exception> struct Triangle; struct Point; +class ContourizeException : public std::exception { + virtual const char *what() const throw(); +}; // creates a contour from a list of points std::vector<Point> contourize(const std::vector<Point> &points); \ No newline at end of file diff --git a/include/convex_triangulation.h b/include/convex_triangulation.h index 21c08ef..e38679e 100644 --- a/include/convex_triangulation.h +++ b/include/convex_triangulation.h @@ -5,4 +5,4 @@ #include <vector> // Requires a convex shape -std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int depth, int triangleId); +std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int triangleId); diff --git a/include/interpolate_z.h b/include/interpolate_z.h new file mode 100644 index 0000000..914b763 --- /dev/null +++ b/include/interpolate_z.h @@ -0,0 +1,5 @@ +#pragma once +#include <vector> +struct Point; + +float interpolateZ(const std::vector<Point> &shape, const Point &p); \ No newline at end of file diff --git a/include/orientation.h b/include/orientation.h index cc80bc6..dfaae1f 100644 --- a/include/orientation.h +++ b/include/orientation.h @@ -1,8 +1,10 @@ #pragma once - +struct Triangle; struct Point; enum Orientation { Clockwise, Collinear, Counterclockwise }; -Orientation orientation(const Point &p1, const Point &p2, const Point &p3); \ No newline at end of file +Orientation orientation(const Point &p1, const Point &p2, const Point &p3); + +Orientation orientation(const Triangle &t); \ No newline at end of file diff --git a/include/point.h b/include/point.h index 7b279aa..8376d86 100644 --- a/include/point.h +++ b/include/point.h @@ -4,6 +4,9 @@ struct Point { float x, y, z; bool operator==(const Point &other) const; + Point operator-(const Point &other) const; + Point operator+(const Point &other) const; + Point operator-() const; }; std::ostream &operator<<(std::ostream &os, Point const &p); diff --git a/include/shift_triangle.h b/include/shift_triangle.h new file mode 100644 index 0000000..dabd4cc --- /dev/null +++ b/include/shift_triangle.h @@ -0,0 +1,4 @@ +#pragma once +struct Triangle; + +void shiftZ(Triangle &t, float z) ; \ No newline at end of file diff --git a/include/triangle.h b/include/triangle.h index 52fd2d8..7240edf 100644 --- a/include/triangle.h +++ b/include/triangle.h @@ -3,7 +3,7 @@ #include "print_triangle.h" #include <vector> -// points specified counterclockwise +// points specified in counterclockwise or collinear (line / point) order struct Triangle { Point points[3]; diff --git a/include/triangulation.h b/include/triangulation.h deleted file mode 100644 index 39153ae..0000000 --- a/include/triangulation.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include <vector> -#include <optional> -#include <triangle.h> - -class PointList; -struct Point; - -std::optional<Triangle> removeEar(int &index, PointList &pointList, const std::vector<Point> &allPoints, int depth, int id); - -std::vector<Triangle> triangulate(std::vector<Point> points, int depth, int id); - -std::vector<Triangle> triangulate(Triangle t1, Triangle t2); \ No newline at end of file diff --git a/src/data_structures/quad_tree.cpp b/src/data_structures/quad_tree.cpp deleted file mode 100644 index c192453..0000000 --- a/src/data_structures/quad_tree.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include <quad_tree.h> -#include <union.h> - -QuadTree::QuadTree(Box b) : b{b} {} - -int QuadTree::pointIntersection(Point p) const -{ - int triangleId = POINT_NOT_IN_QUADTREE; - if (!b.isIn(p)) - { - return POINT_NOT_IN_QUADTREE; - } - if (triangles.size() > 0) - { - int depth = INT32_MAX; - for (const Triangle &t : triangles) - { - if (t.depth < depth && t.pointInTriangle(p)) - { - depth = t.depth; - triangleId = t.id; - } - } - return triangleId; - } - - for (const QuadTree &q : children) - { - int id = q.pointIntersection(p); - if (id != POINT_NOT_IN_QUADTREE) - { - triangleId = POINT_NOT_IN_QUADTREE; - } - } - return triangleId; -} - -void QuadTree::addTriangle(Triangle triangle) -{ - - if (!b.isIn(triangle)) - { - return; - } - - if (triangles.size() >= QUADTREE_NODE_MAX_SHAPE && children.empty()) - { - children = { - QuadTree(Box{b.minX, b.maxX / 2, b.minY, b.maxY}), - QuadTree(Box{b.maxX / 2, b.maxX, b.minY, b.maxY / 2}), - QuadTree(Box{b.maxX / 2, b.maxX, b.maxY / 2, b.maxY}), - QuadTree(Box{b.minX, b.maxX / 2, b.minY, b.maxY / 2})}; - - for (QuadTree &c : children) - { - - c.addTriangle(triangle); - for (const Triangle &t : triangles) - { - c.addTriangle(t); - } - } - triangles.clear(); - return; - } - - if (children.empty()) - { - triangles.push_back(triangle); - return; - } - - for (QuadTree &c : children) - { - for (const Triangle &t : triangles) - { - c.addTriangle(t); - } - } -} \ No newline at end of file diff --git a/src/debug_utilities/mostly_equal.cpp b/src/debug_utilities/mostly_equal.cpp index 63f9d12..98585a3 100644 --- a/src/debug_utilities/mostly_equal.cpp +++ b/src/debug_utilities/mostly_equal.cpp @@ -17,6 +17,5 @@ bool Triangle::operator==(const Triangle &other) const { return mostlyEqual(points[0], other.points[0]) && mostlyEqual(points[1], other.points[1]) && mostlyEqual(points[2], other.points[2]) && - depth == other.depth && id == other.id; } \ No newline at end of file diff --git a/src/debug_utilities/print_triangles.cpp b/src/debug_utilities/print_triangles.cpp index 4230de0..679c7f9 100644 --- a/src/debug_utilities/print_triangles.cpp +++ b/src/debug_utilities/print_triangles.cpp @@ -4,7 +4,6 @@ std::ostream &operator<<(std::ostream &os, const Triangle &t) { return os << "Triangle: " << t.id - << ", " << "Depth: " << t.depth << " {" << t.points[0] << ", " << t.points[1] << ", " << t.points[2] << "}"; } /* diff --git a/src/debug_utilities/shift_triangle.cpp b/src/debug_utilities/shift_triangle.cpp new file mode 100644 index 0000000..9f76e8b --- /dev/null +++ b/src/debug_utilities/shift_triangle.cpp @@ -0,0 +1,9 @@ +#include <shift_triangle.h> +#include <triangle.h> +#include <constants.h> + +void shiftZ(Triangle &t, float z) { + for (int i =0; i < NB_TRIANGLE_SIDES; i++) { + t.points[i].z += z; + } +} \ No newline at end of file diff --git a/src/shapes/point.cpp b/src/shapes/point.cpp index ce13d15..bd2de6a 100644 --- a/src/shapes/point.cpp +++ b/src/shapes/point.cpp @@ -9,3 +9,17 @@ bool Point::operator==(const Point &other) const { std::ostream &operator<<(std::ostream &os, Point const &p) { return os << "(" << p.x << "," << p.y << "," << p.z << ")"; } + +Point Point::operator-() const { + return {-x, -y,-z}; +} + + +Point Point::operator+(const Point &other) const { + return {x + other.x, y + other.y, z + other.z}; +} + + +Point Point::operator-(const Point &other) const { + return *this + (- other); +} \ No newline at end of file diff --git a/src/shapes/triangle.cpp b/src/shapes/triangle.cpp index 97aff7a..53d346d 100644 --- a/src/shapes/triangle.cpp +++ b/src/shapes/triangle.cpp @@ -2,7 +2,7 @@ #include "triangle_edges.h" #include "edge.h" -Triangle::Triangle(const Point &p1, const Point &p2, const Point &p3, int depth, int id, std::vector<int> neighbours) : points{p1,p2,p3}, depth{depth}, id{id}, neighbours{neighbours} {} +Triangle::Triangle(const Point &p1, const Point &p2, const Point &p3, int id, std::vector<int> neighbours) : points{p1,p2,p3}, id{id}, neighbours{neighbours} {} bool Triangle::pointInTriangle(const Point &p) const { // all tests must be positive diff --git a/src/union.cpp b/src/union.cpp index 48d60ba..523cf7a 100644 --- a/src/union.cpp +++ b/src/union.cpp @@ -6,13 +6,12 @@ #include <triangle_edges.h> #include <intersections.h> #include <split_triangle.h> -#include <triangulation.h> +#include <convex_triangulation.h> std::vector<Triangle> unionizeTopAndBottom(const Triangle &top, const Triangle &bot) { std::vector<Triangle> result; - std::list<Point> intr; TriangleEdges topEdges = TriangleEdges(top); // keep track of relevant triangles @@ -21,13 +20,16 @@ std::vector<Triangle> unionizeTopAndBottom(const Triangle &top, const Triangle & for (int i = 0; i < NB_TRIANGLE_SIDES; i++) { const Edge &e = topEdges.edges[i]; + + // index 0: On the "outside" of the edge + // index 1: On the "inside" of the edge auto shapes = splitShape(relv, e); // split triangle if exists // currently relevant triangles // add these to result if (!shapes[0].empty()) { - std::vector<Triangle> relvTriangles = triangulate(shapes[0], bot.depth, bot.id); + std::vector<Triangle> relvTriangles = convexTriangulation(shapes[0], bot.id); result.insert(result.end(), relvTriangles.begin(), relvTriangles.end()); } // future relevant triangles @@ -47,7 +49,7 @@ std::vector<Triangle> unionize(const Triangle &t1, const Triangle &t2) { return {t1, t2}; } - if (t1.depth < t2.depth) + if (t1.points[0].z < t2.points[0].z) { return unionizeTopAndBottom(t1, t2); } diff --git a/src/utilities/contourize.cpp b/src/utilities/contourize.cpp index 920b62a..9d5cfc3 100644 --- a/src/utilities/contourize.cpp +++ b/src/utilities/contourize.cpp @@ -3,12 +3,20 @@ #include <orientation.h> #include <list> +const char* ContourizeException::what() const throw() { + return "Infinite Loop detected"; +} + bool isCounterClockwiseForAll(const Point &previous, const Point &candidate, const std::vector<Point> & points) { for (const auto &point : points) { if (previous == point || candidate == point) { continue; } auto o = orientation(previous, candidate, point); + if (o == Collinear) { + continue; + } + if (o != Counterclockwise) { return false; } @@ -21,19 +29,34 @@ std::vector<Point> contourize(const std::vector<Point> &points) { return points; } + + std::vector<Point> result; Point previous = points[0]; result.push_back(previous); std::list<Point> candidates(points.begin() + 1, points.end()); + const int size = candidates.size(); + + // infinite loop detection + int seen = 0; + while (!candidates.empty()) { + // detect infinite loop + if (seen >= candidates.size()) { + throw ContourizeException(); + } + + if (isCounterClockwiseForAll(previous, candidates.front(), points)) { previous = candidates.front(); candidates.pop_front(); - result.push_back(previous); + result.push_back(previous); + seen = 0; } else { candidates.push_back(candidates.front()); candidates.pop_front(); + seen++; } } return result; diff --git a/src/utilities/convex_triangulation.cpp b/src/utilities/convex_triangulation.cpp index c9ba15d..5dd8ca9 100644 --- a/src/utilities/convex_triangulation.cpp +++ b/src/utilities/convex_triangulation.cpp @@ -1,18 +1,18 @@ #include <convex_triangulation.h> -std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int depth, int triangleId) { +std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int triangleId) { const int size = points.size(); if (size < 3) { return std::vector<Triangle>{}; } - const Triangle t1 = Triangle(points[0], points[1], points[2], depth, triangleId); + const Triangle t1 = Triangle(points[0], points[1], points[2], triangleId); std::vector<Triangle> results = {t1}; Point first = points[0]; for (int i = size - 1; i >= 3; i--) { - results.push_back(Triangle(first, points[2], points[i], depth, triangleId)); + results.push_back(Triangle(first, points[2], points[i], triangleId)); first = points[i]; } return results; diff --git a/src/utilities/interpolate_z.cpp b/src/utilities/interpolate_z.cpp new file mode 100644 index 0000000..b822762 --- /dev/null +++ b/src/utilities/interpolate_z.cpp @@ -0,0 +1,26 @@ +#include <interpolate_z.h> +#include <limits> +#include <point.h> +#include <cmath> + + +float interpolateZ(const std::vector<Point> &shape, const Point &p) { + // create direction vectors + const Point v1 = -(shape[0] - shape[1]); + const Point v2 = -(shape[0] - shape[2]); + + const Point &origin = shape[0]; + + float t = (p.y * v1.x - origin.y * v1.x - p.x * v1.y + origin.x * v1.y) / (v1.x * v2.y - v1.y * v2.x); + float s = (p.y - origin.y - t * v2.y) / v1.y; + + if (s == - std::numeric_limits<float>::infinity() || std::isnan(s)) { + s = 0; + } + + if (t == - std::numeric_limits<float>::infinity() || std::isnan(t)) { + t = 0; + } + + return origin.z + v1.z * s + v2.z * t; +} diff --git a/src/utilities/intersections.cpp b/src/utilities/intersections.cpp index 23551ee..660443f 100644 --- a/src/utilities/intersections.cpp +++ b/src/utilities/intersections.cpp @@ -4,6 +4,7 @@ #include <triangle.h> #include <constants.h> #include <edge.h> +#include <interpolate_z.h> std::optional<float> getB(std::optional<float> slope, Point p) { @@ -138,7 +139,6 @@ std::optional<Point> intersection(const Edge &e1, const Edge &e2) { return {}; } - return candPoint; } void intersections(const Edge &e1, const TriangleEdges &te, std::vector<Point> &results) @@ -172,6 +172,9 @@ std::vector<Point> intersections(const std::vector<Point> &points, const Edge &l auto cand = intersectionFirstSide(line, es[i]); if (cand.has_value()) { + // add depth information + float z = interpolateZ(points, cand.value()); + cand.value().z = z; result.push_back(cand.value()); } } diff --git a/src/utilities/orientation.cpp b/src/utilities/orientation.cpp index fcbfbf9..02bc8f2 100644 --- a/src/utilities/orientation.cpp +++ b/src/utilities/orientation.cpp @@ -1,5 +1,6 @@ #include "orientation.h" #include <point.h> +#include <triangle.h> float edgeValue(const Point &p1, const Point &p2) { return (p2.x - p1.x) * (p2.y + p1.y); @@ -12,4 +13,9 @@ Orientation orientation(const Point &p1, const Point &p2, const Point &p3) { } return (val > 0) ? Clockwise : Counterclockwise; +} + + +Orientation orientation(const Triangle &t) { + return orientation(t.points[0], t.points[1], t.points[2]); } \ No newline at end of file diff --git a/src/utilities/triangulation.cpp b/src/utilities/triangulation.cpp deleted file mode 100644 index 539517b..0000000 --- a/src/utilities/triangulation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "triangulation.h" -#include <list> -#include <point.h> -#include <triangle.h> -#include <optional> -#include <pointList.h> -#include <orientation.h> - - - - -bool isAnEar(Triangle triangle, const std::vector<Point> &points) { - for (const Point &p: points) { - if (triangle.pointInTriangle(p)) { - return false; - } - } - return true; -} - - -std::optional<Triangle> removeEar(int &index, PointList &pointList, const std::vector<Point> &allPoints,int depth, int id) { - PointNode &p = pointList.points[index]; - const int next = p.next(); - const int prev = p.prev(); - - - const PointNode &nextNode = pointList.points[next]; - const PointNode &prevNode = pointList.points[prev]; - - Triangle candidate = Triangle{p.p, nextNode.p, prevNode.p, depth, id}; - - if (orientation(p.p, nextNode.p, prevNode.p) == Counterclockwise && isAnEar(candidate, allPoints)) { - - pointList.remove(index); - index = next; - - return candidate; - } - index = next; - return {}; - -} - - - -std::vector<Triangle> triangulate(std::vector<Point> points, int depth, int id) { - std::vector<Triangle> result; - - PointList polygon = PointList(points); - int i = 0; - while (polygon.getSize() >= 4) { - - std::optional<Triangle> t = removeEar(i, polygon, points, depth, id); - if (t.has_value()) { - result.push_back(t.value()); - } - } - - const PointNode curr = polygon.points[i]; - const int next = curr.next(); - const int prev = curr.prev(); - - Triangle last {curr.p, polygon.points[next].p, polygon.points[prev].p, depth, id}; - result.push_back(last); - - - return result; - -} \ No newline at end of file diff --git a/tests/edge_union_cases.cpp b/tests/edge_union_cases.cpp index 30bf2e4..c118d48 100644 --- a/tests/edge_union_cases.cpp +++ b/tests/edge_union_cases.cpp @@ -1,21 +1,77 @@ #include <gtest/gtest.h> #include <union.h> #include <triangle.h> +#include <orientation.h> -TEST(UnionEdgeTests, TriangleVertexOnEdge) { - Triangle t1 = Triangle({}, {}, {}, 1, 1); - Triangle t2 = Triangle({}, {}, {}, 2, 2); +struct UnionParams +{ + Triangle t1; + Triangle t2; + std::vector<Triangle> expected; +}; + +std::ostream &operator<<(std::ostream &os, const UnionParams &u) { + os << u.t1 << "|" << u.t2; + return os; +} + +class InstantiateUnionEdgeTests : public testing::TestWithParam<UnionParams> +{ +}; + +TEST_P(InstantiateUnionEdgeTests, UnionTest) +{ + const Triangle &t1 = GetParam().t1; + const Triangle &t2 = GetParam().t2; + auto expected = GetParam().expected; + + ASSERT_NE(orientation(t1), Clockwise); + ASSERT_NE(orientation(t2), Clockwise); auto result = unionize(t1, t2); + EXPECT_EQ(result, expected); +} + +INSTANTIATE_TEST_SUITE_P(EdgeUnionTests, InstantiateUnionEdgeTests, testing::Values( + // Point on top of triangle + UnionParams{Triangle({0, 0, 4}, {5, 0, 4}, {2, 3, 4}, 1), Triangle({1, 1, 0}, {1, 1, 0}, {1, 1, 0}, 2), {Triangle({0, 0, 4}, {5, 0, 4}, {2, 3, 4}, 1), Triangle({1, 1, 0}, {1, 1, 0}, {1, 1, 0}, 2)}}, + // Point on edge of triangle + UnionParams{Triangle({0, 0, 6}, {5, 0, 6}, {2, 3, 6}, 1), Triangle({0, 2, 3}, {0, 2, 3}, {0, 2, 3}, 2), {Triangle({0, 0, 6}, {5, 0, 6}, {2, 3, 6}, 1), Triangle({0, 2, 3}, {0, 2, 3}, {0, 2, 3}, 2)}}, + // Point on vertex of triangle + UnionParams{Triangle({0, 0, 2}, {5,0,2}, {2,3,2}, 1), Triangle({0,0,0}, {0,0,0}, {0,0,0}, 2), {Triangle({0, 0, 2}, {5,0,2}, {2,3,2}, 1), Triangle({0,0,0}, {0,0,0}, {0,0,0}, 2)}} + )); + +TEST(UnionEdgeTests, TriangleVertexOnEdge) +{ + Triangle t1 = Triangle({}, {}, {}, 1); + Triangle t2 = Triangle({}, {}, {}, 2); + + auto result = unionize(t1, t2); } -TEST(UnionEdgeTests, TriangleEdgeLength0) { - Triangle t1 = Triangle({1,1}, {2,2}, {3,3}, 1, 1); - Triangle t2 = Triangle({}, {}, {}, 2, 2); +TEST(UnionEdgeTests, TriangleIsPoint) +{ + Triangle t1 = Triangle({1, 1, 2}, {2, 2, 2}, {3, 3, 2}, 1); + Triangle t2 = Triangle({2, 2, 1}, {2, 2, 1}, {2, 2, 1}, 2); + + auto results = unionize(t1, t2); + + std::vector<Triangle> expected = { + Triangle({1, 1, 2}, {2, 2, 2}, {3, 3, 2}, 1), + Triangle({2, 2, 1}, {2, 2, 1}, {2, 2, 1}, 2)}; + + EXPECT_EQ(results, expected); } -TEST(UnionEdgeTests, TriangleOnSide) { - Triangle t1 = Triangle({}, {}, {}, 1, 1); - Triangle t2 = Triangle({}, {}, {}, 2, 2); +TEST(UnionEdgeTests, TriangleOnSide) +{ + Triangle t1 = Triangle({0, 0, 1}, {0, 5, 1}, {2, 3, 1}, 1); + Triangle t2 = Triangle({0, 1}, {1, 1}, {0, 3}, 2); + + auto results = unionize(t1, t2); + + std::vector<Triangle> expected; + + EXPECT_EQ(results, expected); } diff --git a/tests/quad_tree_tests.cpp b/tests/quad_tree_tests.cpp deleted file mode 100644 index cbe8689..0000000 --- a/tests/quad_tree_tests.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include <gtest/gtest.h> -#include <quad_tree.h> - -/* -TEST (QuadTreeTest, OverlappingTriangles) { - - QuadTree q{Box{0, 10, 0, 10}}; - auto t1 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 1); - auto t2 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 2); - auto t3 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 3); - auto t4 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 4); - auto t5 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 5); - - q.addTriangle(t1); - q.addTriangle(t2); - q.addTriangle(t3); - q.addTriangle(t4); - q.addTriangle(t5); - EXPECT_EQ(q.pointIntersection(Point{1,1}), 1); - -} -*/ -TEST (QuadTreeTest, SingleInsertion) { - QuadTree q{Box{0, 10, 0, 10}}; - - auto t1 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 0); - - auto t2 = Triangle(Point{3,1}, Point{6,1}, Point{4,3}, 0); - - - q.addTriangle(t1); - q.addTriangle(t2); - - EXPECT_TRUE(true); -} - -TEST (QuadTreeTest, PointOnTriangleQueryTest) { - QuadTree q{Box{0, 10, 0, 10}}; - - auto t1 = Triangle(Point{0,0}, Point{5,0}, Point{2,3}, 1, 1); - - auto t2 = Triangle(Point{3,1}, Point{6,1}, Point{4,3}, 2, 2); - - - q.addTriangle(t1); - q.addTriangle(t2); - - EXPECT_EQ(q.pointIntersection(Point{1,1}), 1); - EXPECT_EQ(q.pointIntersection(Point{5,1.5}), 2); - EXPECT_EQ(q.pointIntersection(Point{3.5, 1.5}), 1); - EXPECT_EQ(q.pointIntersection(Point{-1,-1}), POINT_NOT_IN_QUADTREE); - -} diff --git a/tests/union_neighbours_tests.cpp b/tests/union_neighbours_tests.cpp index 0896426..e595e35 100644 --- a/tests/union_neighbours_tests.cpp +++ b/tests/union_neighbours_tests.cpp @@ -3,8 +3,8 @@ #include <union.h> TEST (UnionNeighbourTests, NeighbourTest) { - Triangle t1 = Triangle({}, {}, {}, 1, 1, {2}); - Triangle t2 = Triangle({}, {}, {}, 2, 2, {1}); + Triangle t1 = Triangle({}, {}, {}, 1, {2}); + Triangle t2 = Triangle({}, {}, {}, 2, {1}); auto results = unionize(t1, t2); std::vector<Triangle> expected ={t1, t2} ; diff --git a/tests/union_tests.cpp b/tests/union_tests.cpp index ace3d5b..900335a 100644 --- a/tests/union_tests.cpp +++ b/tests/union_tests.cpp @@ -2,6 +2,7 @@ #include <union.h> #include <triangle.h> #include <orientation.h> +#include <shift_triangle.h> TEST(UnionTrivialTests, NotTouching) { @@ -16,27 +17,27 @@ TEST(UnionTrivialTests, NotTouching) TEST(UnionTests, TwoIntersections) { - auto t1 = Triangle(Point{0, 0}, Point{5, 0}, Point{2, 3}, 0, 1); - auto t2 = Triangle(Point{3, 1}, Point{6, 1}, Point{4, 3}, 1, 2); + auto t1 = Triangle(Point{0, 0, 0}, Point{5, 0, 0}, Point{2, 3, 0}, 1); + auto t2 = Triangle(Point{3, 1, 1}, Point{6, 1, 1}, Point{4, 3, 1}, 2); auto ts = unionize(t1, t2); EXPECT_TRUE(ts.size() == 3); std::vector<Triangle> expected{ - Triangle({6,1}, {4,3}, {4,1}, 1, 2), - Triangle({4,3}, {3.33333,1.66667}, {4,1}, 1,2), - Triangle({0,0}, {5,0}, {2,3}, 0, 1)}; + Triangle({6,1,1}, {4,3,1}, {3.333333,1.66666,1}, 2), + Triangle({4,3,1}, {3.33333,1.66667,1}, {4,1,1},2), + Triangle({0,0}, {5,0}, {2,3}, 1)}; EXPECT_EQ(ts, expected); } // Edge Case -/* + TEST(UnionTests, SharesPointTest) { // Case 1 t1 covers t2 - Triangle bottom = Triangle({0, 5}, {3, 2}, {5, 3}, 1, 1); - Triangle top = Triangle({0.1, 7}, {5, 3}, {3.2, 9}, 2, 2); + Triangle top = Triangle({0, 5}, {3, 2}, {5, 3}, 1); + Triangle bottom = Triangle({0.1, 7, 5}, {5, 3,5}, {3.2, 9,5}, 2); auto results = unionize(bottom, top); std::vector<Triangle> expected_results_1; @@ -44,41 +45,41 @@ TEST(UnionTests, SharesPointTest) EXPECT_EQ(results, expected_results_1); // Case 2 t2 covers t1 - bottom.depth = 3; + shiftZ(top, 10); results = unionize(bottom, top); std::vector<Triangle> expected_results_2; EXPECT_EQ(results, expected_results_2); -}*/ +} TEST(UnionTests, FoldTriangleTest) { - Triangle top = Triangle({0, 5}, {3, 2}, {5, 3}, 1, 1); - Triangle bottom = Triangle({0.1, 9}, {2, 4}, {5,5}, 2, 2); + Triangle top = Triangle({0, 5}, {3, 2}, {5, 3}, 1); + Triangle bottom = Triangle({0.1, 9,1}, {2, 4,1}, {5,5,1}, 2); auto results = unionize(bottom, top); std::vector<Triangle> expected_results_1 = { - Triangle({0.1, 9}, {1.91038, 4.23585}, {5,5}, 2, 2), - Triangle({1.91038,4.23585}, {2.27273,4.09091}, {5, 5}, 2, 2), - Triangle({0,5}, {3,2}, {5,3}, 1, 1) + Triangle({0.1, 9,1}, {1.91038, 4.23585,1}, {5,5}, 2), + Triangle({1.91038,4.23585,1}, {2.27273,4.09091,1}, {5, 5}, 2), + Triangle({0,5}, {3,2}, {5,3}, 1) }; EXPECT_EQ(results, expected_results_1); - top.depth = 3; + shiftZ(top, 3); results = unionize(bottom, top); std::vector<Triangle> expected_results_2 = { - Triangle({0,5}, {2.6129, 2.3871}, {1.91038, 4.23585}, 3, 1), - Triangle({3,2}, {5, 3}, {2.6129, 2.3871}, 3, 1), - Triangle({5,3}, {2.27273, 4.09091}, {2.6129, 2.3871}, 3, 1), - Triangle({2.27273,4.09091}, {2, 4}, {2.6129, 2.3871}, 3, 1), - Triangle({0.1,9}, {2, 4}, {5, 5}, 2, 2) + Triangle({0,5}, {2.6129, 2.3871}, {1.91038, 4.23585}, 1), + Triangle({3,2}, {5, 3}, {2.6129, 2.3871}, 1), + Triangle({5,3}, {2.27273, 4.09091}, {2.6129, 2.3871}, 1), + Triangle({2.27273,4.09091}, {2, 4}, {2.6129, 2.3871}, 1), + Triangle({0.1,9}, {2, 4}, {5, 5}, 2) }; EXPECT_EQ(results, expected_results_2); @@ -106,8 +107,8 @@ TEST(UnionTests, IceCreamTest) TEST(UnionTests, StarTest) { - Triangle bottom = Triangle({0, 3}, {5, 3}, {2.5, 6}, 1, 1); - Triangle top = Triangle({0, 5}, {2, 0}, {5, 5}, 2, 2); + Triangle bottom = Triangle({0, 3}, {5, 3}, {2.5, 6}, 1); + Triangle top = Triangle({0, 5, 1}, {2, 0, 1}, {5, 5, 1}, 2); ASSERT_EQ(orientation(bottom.points[0], bottom.points[1], bottom.points[2]), Counterclockwise); ASSERT_EQ(orientation(top.points[0], top.points[1], top.points[2]), Counterclockwise); @@ -115,24 +116,28 @@ TEST(UnionTests, StarTest) auto results = unionize(bottom, top); std::vector<Triangle> expected_results_1 = { - Triangle({2,0}, {3.8, 3}, {0.8, 3}, 2, 2), - Triangle({5,5}, {3.33333, 5}, {4.30233, 3.83721}, 2, 2), - Triangle({0,5}, {0.540541, 3.64865}, {1.66667, 5}, 2, 2), - Triangle({0, 3}, {5, 3}, {2.5, 6}, 1, 1) + Triangle({2,0}, {3.8, 3}, {0.8, 3}, 2), + Triangle({5,5}, {3.33333, 5}, {4.30233, 3.83721}, 2), + Triangle({0,5}, {0.540541, 3.64865}, {1.66667, 5}, 2), + Triangle({0, 3}, {5, 3}, {2.5, 6}, 1) }; EXPECT_EQ(results, expected_results_1); - bottom.depth = 3; + shiftZ(bottom, 3); results = unionize(bottom, top); std::vector<Triangle> expected_results_2 = { - Triangle({0,3}, {0.8,3}, {0.540541,3.64865}, 3, 1), - Triangle({5,3}, {4.30233,3.83721}, {3.8,3}, 3, 1), - Triangle({2.5,6}, {1.66667,5}, {3.33333,5}, 3, 1), - Triangle({0,5}, {2,0}, {5,5}, 2, 2) + Triangle({0,3}, {0.8,3}, {0.540541,3.64865}, 1), + Triangle({5,3}, {4.30233,3.83721}, {3.8,3}, 1), + Triangle({2.5,6}, {1.66667,5}, {3.33333,5}, 1), + Triangle({0,5}, {2,0}, {5,5}, 2) }; EXPECT_EQ(results, expected_results_2); } + +TEST (UnionTests, DepthTest) { + +} \ No newline at end of file diff --git a/tests/unit_tests/contourize_tests.cpp b/tests/unit_tests/contourize_tests.cpp index c4c9d10..80f0f6a 100644 --- a/tests/unit_tests/contourize_tests.cpp +++ b/tests/unit_tests/contourize_tests.cpp @@ -4,11 +4,11 @@ #include <intersections.h> TEST(ContourizeTest, Simple) { - std::vector<Point> points{{6,1}, {4,3}, {4, 1}, {3.3333, 1.6666}}; + std::vector<Point> points{{0,0}, {0,5}, {2, 3}}; auto result = contourize(points); - std::vector<Point> expected{{4,1}, {3.3333,1.6666}, {4,3}, {6,1}}; + std::vector<Point> expected{{0,0}, {0,5}, {2, 3}}; EXPECT_EQ(result, expected); } diff --git a/tests/unit_tests/convex_triangulation_tests.cpp b/tests/unit_tests/convex_triangulation_tests.cpp index 21c77eb..5fa45e1 100644 --- a/tests/unit_tests/convex_triangulation_tests.cpp +++ b/tests/unit_tests/convex_triangulation_tests.cpp @@ -14,12 +14,12 @@ TEST(ConvexTriangulationTests, Simple) { p1, p2, p3, p4, p5 }; - auto results = convexTriangulation(points, 2, 2); + auto results = convexTriangulation(points, 2); std::vector<Triangle> expected_result { - Triangle(p1, p2, p3, 2, 2), - Triangle(p1, p3, p5, 2, 2), - Triangle(p5, p3, p4, 2, 2) + Triangle(p1, p2, p3, 2), + Triangle(p1, p3, p5, 2), + Triangle(p5, p3, p4, 2) }; EXPECT_EQ(results, expected_result); @@ -33,8 +33,8 @@ TEST(ConvexTriangulationTests, TrivialTriangle) { {1.5, 2} }; - auto results = convexTriangulation(points, 1, 1); - Triangle expected_triangle = Triangle({0,0}, {2,0}, {1.5, 2}, 1, 1); + auto results = convexTriangulation(points, 1); + Triangle expected_triangle = Triangle({0,0}, {2,0}, {1.5, 2}, 1); EXPECT_EQ(results.size(), 1); EXPECT_EQ(results[0], expected_triangle); diff --git a/tests/unit_tests/ear_removal_tests.cpp b/tests/unit_tests/ear_removal_tests.cpp deleted file mode 100644 index ed567b8..0000000 --- a/tests/unit_tests/ear_removal_tests.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#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, 0,0); - EXPECT_FALSE(t.has_value()); - EXPECT_TRUE(true); - - auto t2 = removeEar(index, pointList, polygon,0,0); - - auto t3 = removeEar(index, pointList, polygon,0,0); -} \ No newline at end of file diff --git a/tests/unit_tests/interpolate_z_tests.cpp b/tests/unit_tests/interpolate_z_tests.cpp new file mode 100644 index 0000000..c1fe2aa --- /dev/null +++ b/tests/unit_tests/interpolate_z_tests.cpp @@ -0,0 +1,26 @@ +#include <gtest/gtest.h> +#include <interpolate_z.h> +#include <point.h> + +struct InterpolateParams { + std::vector<Point> points; + float expected_z; +}; + +class InstantiateInterpolateZTests : public testing::TestWithParam<InterpolateParams>{ +}; + +TEST_P (InstantiateInterpolateZTests, Interpolate) { + + std::vector<Point> points = GetParam().points; + + float z = interpolateZ(points, {0,1,0}); + + EXPECT_EQ(z,GetParam().expected_z); +} + +INSTANTIATE_TEST_SUITE_P(Interpolation, InstantiateInterpolateZTests, testing::Values( + InterpolateParams{ + {{1,1,3}, {2,2,3}, {4,5,3}} + , 3}, + InterpolateParams{{{1,1,5}, {1,1,5}, {1,1,5}}, 5})); \ No newline at end of file diff --git a/tests/unit_tests/orientation_tests.cpp b/tests/unit_tests/orientation_tests.cpp index 8f91929..ec9d68d 100644 --- a/tests/unit_tests/orientation_tests.cpp +++ b/tests/unit_tests/orientation_tests.cpp @@ -12,6 +12,10 @@ TEST(OrientationTests, ExampleCounterClockwiseTest) EXPECT_EQ(orientation(Point{0, 0}, Point{4, 4}, Point{1, 2}), Counterclockwise); } +TEST (OrientationTests, Counterclockwise) { + EXPECT_EQ(orientation({0,0}, {5,0}, {2,3}), Counterclockwise); +} + TEST(OrientationTests, TestAll) { Point p1 = {3, 1}; diff --git a/tests/unit_tests/split_triangle_tests.cpp b/tests/unit_tests/split_triangle_tests.cpp index 8185284..65c1eb3 100644 --- a/tests/unit_tests/split_triangle_tests.cpp +++ b/tests/unit_tests/split_triangle_tests.cpp @@ -4,7 +4,7 @@ #include <edge.h> TEST(SplitTriangleTests, NormalCase) { - Triangle t = Triangle({0,0}, {5,0}, {2,3}, 1, 1); + Triangle t = Triangle({0,0}, {5,0}, {2,3}, 1); Edge e{{4,3}, {3,1}}; auto results = splitShape(std::vector<Point>{t.points[0], t.points[1], t.points[2]}, e); @@ -46,4 +46,24 @@ TEST (SplitTriangleTests, Quadric) { auto results = splitShape(p,e); EXPECT_TRUE(results[0].size() > 2); +} + +TEST(SplitTriangleTests, OnEdge1) { + std::vector<Point> t {{0,0}, {0,5}, {2,3}}; + Edge e = Edge{{1,1}, {0,1}}; + + auto results = splitShape(t, e); + + EXPECT_EQ(results[0].size(), 4); + EXPECT_EQ(results[1].size(), 3); +} + +TEST(SplitTriangleTests, OnEdge2) { + + std::vector<Point> t {{0,0}, {0,5}, {2,3}}; + Edge e {{1,1}, {0,3}}; + + auto results = splitShape(t,e); + + EXPECT_EQ(results[0].size(), 4); } \ No newline at end of file diff --git a/tests/unit_tests/triangulation_tests.cpp b/tests/unit_tests/triangulation_tests.cpp deleted file mode 100644 index 65493fb..0000000 --- a/tests/unit_tests/triangulation_tests.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "gtest/gtest.h" -#include <point.h> -#include <triangulation.h> - -TEST(TriangulationTests, Page3Example) { - std::vector<Point> polygon = { - {3,48}, {52, 8}, {99,50}, {138,25}, - {175, 77}, {131, 72}, {111, 113}, - {72, 43}, {26, 55}, {29, 100}}; - - auto t = triangulate(polygon, 0, 0); - EXPECT_TRUE(t.size() > 0); -} \ No newline at end of file -- GitLab