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