diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f554cefc90ba0805e1d236dbe400cd2e68d832b..cc0b82429e984288cdc3506bc9ebb2dbf4aa12be 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,11 +23,20 @@ project(intersection)
 add_executable(
 	tests
 	tests/unit_tests/split_triangle_tests.cpp
-	src/debug_utilities/mostly_equal.cpp
 	tests/unit_tests/simple_triangle_tests.cpp
 	tests/unit_tests/point_in_triangle_tests.cpp
-	src/utilities/intersections.cpp
 	tests/union_tests.cpp
+	tests/unit_tests/orientation_tests.cpp
+	tests/unit_tests/contourize_tests.cpp
+	tests/unit_tests/intersection_tests/intersections_tests.cpp
+	tests/edge_union_cases.cpp
+	tests/unit_tests/orientation_tests.cpp
+	tests/union_neighbours_tests.cpp
+	tests/quad_tree_tests.cpp
+	tests/unit_tests/interpolate_z_tests.cpp
+	tests/unit_tests/convex_triangulation_tests.cpp
+	src/debug_utilities/mostly_equal.cpp
+	src/utilities/intersections.cpp
 	src/shapes/triangle.cpp
 	src/shapes/triangle_edges.cpp
 	src/utilities/contourize.cpp
@@ -36,20 +45,14 @@ add_executable(
 	src/shapes/point.cpp
 	src/union.cpp
 	src/utilities/pointList.cpp
-	tests/unit_tests/orientation_tests.cpp
-	tests/unit_tests/intersections_tests.cpp
 	src/data_structures/box.cpp
-	tests/edge_union_cases.cpp
-	tests/unit_tests/convex_triangulation_tests.cpp
 	src/utilities/convex_triangulation.cpp
-	tests/unit_tests/contourize_tests.cpp
 	src/debug_utilities/print_triangles.cpp
 	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
+	src/data_structures/quad_tree.cpp
+	src/data_structures/box_edges.cpp
 )
 
 include_directories(include)
diff --git a/include/box.h b/include/box.h
index b98bb511953535af356e25697a94bed14678c6a6..371cc139a966e53108ba2b48ec784d55fb7e64be 100644
--- a/include/box.h
+++ b/include/box.h
@@ -1,10 +1,23 @@
 #pragma once
+#include <point.h>
+#include "box_edges.h"
 
 struct Triangle;
-struct Point;
+#define BOX_NB_POINTS 4
 
+// left -> +x
+// up -> +y
 struct Box {
-    float minX, maxX, minY, maxY;
-    bool isIn(const Triangle &t) const;
-    bool isIn(const Point &p) const;
+    Point topLeft;
+    Point bottomRight;
+    Point points [BOX_NB_POINTS];
+    BoxEdges edges;
+    Box(Point topLeft, Point bottomRight);
+    bool intersects(const Triangle &t) const;
+    bool intersects(const Point &p) const;
+
+    Box firstQuadrant() const;
+    Box secondQuadrant() const;
+    Box thirdQuadrant() const;
+    Box fourthQuadrant() const;
 };
\ No newline at end of file
diff --git a/include/box_edges.h b/include/box_edges.h
new file mode 100644
index 0000000000000000000000000000000000000000..86ce251b15bfc92d83a0b9c1c9949aea301c9b36
--- /dev/null
+++ b/include/box_edges.h
@@ -0,0 +1,9 @@
+#pragma once
+#include <edge.h>
+struct Box;
+
+struct BoxEdges {
+    static const int size = 4;
+    Edge e [4];
+    BoxEdges(const Point p[size]);
+};
\ No newline at end of file
diff --git a/include/convex_triangulation.h b/include/convex_triangulation.h
index e38679e92ad7c842349ccb5f44a97e56a77e99ac..366b9e8c9c183f169166dafe795e2666292577de 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 triangleId);
+std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int triangleId, std::shared_ptr<std::vector<int>> neighbours);
diff --git a/include/quad_tree.h b/include/quad_tree.h
index 08f33d98c4e377547476c42305d0816084efcf16..072ceff1cf3ea3726d2b99ef12796b3c9614ab67 100644
--- a/include/quad_tree.h
+++ b/include/quad_tree.h
@@ -3,22 +3,30 @@
 #include <memory>
 #include <vector>
 #include "box.h"
+#include <set>
 
 const int POINT_NOT_IN_QUADTREE = -1;
+const int QUADTREE_MAX_DEPTH = 5;
 
 #define QUADTREE_NODE_MAX_SHAPE 4
 
-class QuadTree {
+class QuadTree
+{
     Box b;
-    std::vector<Triangle> triangles; 
+    int level;
+    std::vector<Triangle> triangles;
 
     std::vector<QuadTree> children;
+    QuadTree(Box b, int level);
+    void collectUniqueTriangleFragments(const Triangle &t, std::set<int> &seen, std::vector<Triangle> &result) const;
+    void split();
+    void addNonIntersectingTriangle(const Triangle &t);
 
-    public:
-        QuadTree(Box b);
-        void addTriangle(Triangle triangle);
-        std::vector<Triangle> visibleSurface() const;
-        // returns triangle id
-        int pointIntersection(Point p) const;
-
+    std::vector<Triangle> visibleSurface(std::set<int> &seen) const;
+public:
+    QuadTree(Box b);
+    void addTriangle(const Triangle &triangle);
+    std::vector<Triangle> visibleSurface() const;
+    // returns triangle id
+    int pointIntersection(const Point &p) const;
 };
\ No newline at end of file
diff --git a/include/triangle.h b/include/triangle.h
index 7240edf340d93f395bdfb63f001253ba36e76b2e..848e0f4398602372c0a1b4a46eb2df1d37765ea8 100644
--- a/include/triangle.h
+++ b/include/triangle.h
@@ -2,16 +2,21 @@
 #include "point.h"
 #include "print_triangle.h"
 #include <vector>
+#include <memory>
+
+// note : Triangle equality is only specified for tests
 
 // points specified in counterclockwise or collinear (line / point) order
 struct Triangle
 {
     Point points[3];
-    int id;
-    std::vector<int> neighbours;
+    int mainTriangleId;
+    int fragmentId;
+    std::shared_ptr<std::vector<int>> neighbours;
 
 
-    Triangle(const Point &p1, const Point &p2, const Point &p3, int id = 0, const std::vector<int> neighbours = {});
+    Triangle(const Point &p1, const Point &p2, const Point &p3, int mainTriangleId = 0, const std::vector<int> neighbours = {});
+    Triangle(const Point &p1, const Point &p2, const Point &p3, int mainTriangleId, std::shared_ptr<std::vector<int>> neighbours);
     bool pointInTriangle(const Point &p) const;
     Point nextPoint(int pointIndex) const;
     bool operator==(const Triangle &other) const;
diff --git a/include/triangle_fragment_id_assigner.h b/include/triangle_fragment_id_assigner.h
new file mode 100644
index 0000000000000000000000000000000000000000..faf50a4429168a492fe60f80795dbcb712448bd2
--- /dev/null
+++ b/include/triangle_fragment_id_assigner.h
@@ -0,0 +1,22 @@
+#pragma once
+
+class TriangleFragmentIdAssigner {
+   public:
+        static TriangleFragmentIdAssigner& getInstance()
+        {
+            static TriangleFragmentIdAssigner instance; 
+            return instance;
+        }
+        int generateUniqueId() {
+            currentInd++;
+            return currentInd;
+        };
+    private:
+        int currentInd = 0;
+        TriangleFragmentIdAssigner() {}       
+
+    public:
+        TriangleFragmentIdAssigner(TriangleFragmentIdAssigner const&) = delete;
+        void operator=(TriangleFragmentIdAssigner const&) = delete;
+
+};
\ No newline at end of file
diff --git a/src/data_structures/box.cpp b/src/data_structures/box.cpp
index 327ad7b6e1b72c4ea6938e36016b86dcd2861eaf..aa2dfb49bfa18ff6f74e6c841308eefb69c375d0 100644
--- a/src/data_structures/box.cpp
+++ b/src/data_structures/box.cpp
@@ -2,20 +2,47 @@
 #include <triangle.h>
 #include <constants.h>
 
-bool Box::isIn(const Triangle &t) const {
+Box::Box(Point topLeft, Point bottomRight) : 
+topLeft{topLeft},
+ bottomRight{bottomRight},
+  points{bottomRight, {topLeft.x, bottomRight.y}, topLeft, {bottomRight.x, topLeft.y}},
+  edges{{points}} {}
+
+
+bool Box::intersects(const Triangle &t) const {
     for (int i = 0; i < NB_TRIANGLE_SIDES; i++) {
         float x = t.points[i].x;
         float y = t.points[i].y;
-        if (x > minX && x < maxX && y > minY && y < maxY) {
+        if (intersects({x,y})) {
             return true;
         }
     }
-    return false;
-}
 
-bool Box::isIn(const Point &p) const {
-    if (p.x > minX && p.x < maxX && p.y > minY && p.y < maxY) {
-        return true;
+    for (int i = 0; i < BOX_NB_POINTS; i++) {
+        if (t.pointInTriangle(points[i])) {
+            return true;
+        }
     }
     return false;
+}
+
+bool Box::intersects(const Point &p) const {
+    return p.x <= topLeft.x && p.y <= topLeft.y && bottomRight.x <= p.x && bottomRight.y <= p.y; 
+}
+
+
+Box Box::firstQuadrant() const {
+    return Box({topLeft.x / 2, topLeft.y}, {bottomRight.x, topLeft.y / 2});
+}
+
+Box Box::secondQuadrant() const {
+    return Box(topLeft, {topLeft.x / 2, topLeft.y / 2});
+}
+
+Box Box::thirdQuadrant() const {
+    return Box({topLeft.x, topLeft.y / 2}, {topLeft.x/2,bottomRight.y});
+}
+
+Box Box::fourthQuadrant() const {
+    return Box({topLeft.x / 2, topLeft.y / 2}, bottomRight);
 }
\ No newline at end of file
diff --git a/src/data_structures/box_edges.cpp b/src/data_structures/box_edges.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47f5c85efe7c298d351cce526c8c1ccac589e354
--- /dev/null
+++ b/src/data_structures/box_edges.cpp
@@ -0,0 +1,8 @@
+#include <box_edges.h>
+#include <box.h>
+
+BoxEdges::BoxEdges(const Point p [size]) {
+    for (int i = 0; i < size; i++) {
+        e[i] = {p[i], p[(i + 1) % size]};
+    }
+}
\ No newline at end of file
diff --git a/src/data_structures/quad_tree.cpp b/src/data_structures/quad_tree.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7d6d320155e41eca6012fe7f6f7f5b29ccd8c44a
--- /dev/null
+++ b/src/data_structures/quad_tree.cpp
@@ -0,0 +1,152 @@
+#include <quad_tree.h>
+#include <union.h>
+#include <iterator>
+#include <set>
+
+QuadTree::QuadTree(Box b) : b{b}, level{0} {}
+
+QuadTree::QuadTree(Box b, int level = 0) : b{b}, level{level} {}
+
+void QuadTree::collectUniqueTriangleFragments(const Triangle &t, std::set<int> &seen, std::vector<Triangle> &result) const {
+    if (seen.count(t.fragmentId) > 0) {
+        return;
+    }
+
+    result.push_back(t);
+    seen.insert(t.fragmentId);
+}
+
+std::vector<Triangle> QuadTree::visibleSurface() const {
+    std::set<int> seen;
+    return visibleSurface(seen);
+}
+
+std::vector<Triangle> QuadTree::visibleSurface(std::set<int> & seen) const
+{
+    std::vector<Triangle> result;
+
+    for (const Triangle &t : triangles) {
+        collectUniqueTriangleFragments(t, seen, result);
+    }
+    for (const QuadTree &c : children)
+    {
+        std::vector<Triangle> childResult = c.visibleSurface(seen);
+        result.insert(result.end(), childResult.begin(), childResult.end());
+    }
+
+    return result;
+}
+
+void QuadTree::split()
+{
+    const int nextLevel = level + 1;
+    children = {
+        QuadTree(b.firstQuadrant(), nextLevel),
+        QuadTree(b.secondQuadrant(), nextLevel),
+        QuadTree(b.thirdQuadrant(), nextLevel),
+        QuadTree(b.fourthQuadrant(), nextLevel)};
+}
+
+void QuadTree::addTriangle(const Triangle &triangle)
+{
+    if (!b.intersects(triangle))
+    {
+        return;
+    }
+
+    if (triangles.empty())
+    {
+        triangles.push_back(triangle);
+        return;
+    }
+
+    if (!children.empty())
+    {
+        for (QuadTree &child : children)
+        {
+            child.addTriangle(triangle);
+        }
+        return;
+    }
+
+    std::vector<Triangle> currentTriangleFragments{triangle};
+
+    // triangles that are not the current triangle and that have already been unioned
+    std::vector<Triangle> otherTriangleFragments;
+    for (const auto &otherTriangle : triangles)
+    {
+        for (const auto &fragment : currentTriangleFragments)
+        {
+            auto newTriangles = unionize(triangle, otherTriangle);
+            std::vector<Triangle> bottoms;
+            if (newTriangles.size() > 1)
+            {
+                bottoms = {newTriangles.begin(), newTriangles.begin() + newTriangles.size() - 2};
+            }
+            const Triangle &top = newTriangles.back();
+            otherTriangleFragments.push_back(top);
+            if (top.mainTriangleId == triangle.mainTriangleId)
+            {
+                otherTriangleFragments.insert(otherTriangleFragments.begin(), bottoms.begin(), bottoms.end());
+            }
+            else
+            {
+                currentTriangleFragments.insert(currentTriangleFragments.begin(), bottoms.begin(), bottoms.end());
+            }
+        }
+    }
+
+    // split
+    if (level >= QUADTREE_MAX_DEPTH) {
+        triangles.insert(triangles.end(), currentTriangleFragments.begin(), currentTriangleFragments.end());
+        triangles.insert(triangles.end(), otherTriangleFragments.begin(), otherTriangleFragments.end());
+        return;
+    }
+    split();
+    for (QuadTree &q : children)
+    {
+        for (const Triangle &t : otherTriangleFragments)
+        {
+            q.addNonIntersectingTriangle(t);
+        }
+        for (const Triangle &t : currentTriangleFragments)
+        {
+            q.addNonIntersectingTriangle(t);
+        }
+    }
+
+    triangles.clear();
+}
+
+int QuadTree::pointIntersection(const Point &p) const
+{
+    if (b.intersects(p))
+    {
+        for (const Triangle &triangle : triangles)
+        {
+            if (triangle.pointInTriangle(p))
+            {
+                return triangle.mainTriangleId;
+            }
+        }
+
+        for (const QuadTree &child : children)
+        {
+            int id = child.pointIntersection(p);
+            if (id != POINT_NOT_IN_QUADTREE)
+            {
+                return id;
+            }
+        }
+    }
+
+    return POINT_NOT_IN_QUADTREE;
+}
+
+void QuadTree::addNonIntersectingTriangle(const Triangle &t)
+{
+    if (b.intersects(t))
+    {
+        triangles.push_back(t);
+    }
+}
\ No newline at end of file
diff --git a/src/debug_utilities/mostly_equal.cpp b/src/debug_utilities/mostly_equal.cpp
index 72574fc171137279bcd850330edc6fc8cdf7262e..a28493d976f1cc2f09109b6c8aab4fde493ac3a1 100644
--- a/src/debug_utilities/mostly_equal.cpp
+++ b/src/debug_utilities/mostly_equal.cpp
@@ -19,5 +19,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]) &&
-		id == other.id;
+		mainTriangleId == other.mainTriangleId;
 }
\ No newline at end of file
diff --git a/src/debug_utilities/print_triangles.cpp b/src/debug_utilities/print_triangles.cpp
index 108d7524e2401d46fd1b4d18c8a9adf45debfe59..e91b9b695f4cb4f12b5d399ccc69df0e1fdad387 100644
--- a/src/debug_utilities/print_triangles.cpp
+++ b/src/debug_utilities/print_triangles.cpp
@@ -3,7 +3,7 @@
 #include <point.h>
 
 std::ostream &operator<<(std::ostream &os, const Triangle &t) {
-	return os << "Triangle" << "(" << t.points[0] << ", " << t.points[1] << ", " << t.points[2] << ", " << t.id << ")";
+	return os << "Triangle" << "(" << t.points[0] << ", " << t.points[1] << ", " << t.points[2] << ", " << t.mainTriangleId << ")";
 }
 /*
 std::ostream &operator<<(std::ostream &os, const std::vector<Triangle> &triangles) {
diff --git a/src/shapes/triangle.cpp b/src/shapes/triangle.cpp
index 53d346d3747a81af8c645045a48d3fdc55371fe1..3cd04ac24c41d26415986e63c02ada90cbe358a2 100644
--- a/src/shapes/triangle.cpp
+++ b/src/shapes/triangle.cpp
@@ -1,22 +1,30 @@
 #include "triangle.h"
 #include "triangle_edges.h"
 #include "edge.h"
+#include <triangle_fragment_id_assigner.h>
 
-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} {}
+Triangle::Triangle(const Point &p1, const Point &p2, const Point &p3, int mainTriangleId, std::shared_ptr<std::vector<int>> neighbours) : 
+points{p1, p2, p3}, mainTriangleId{mainTriangleId}, fragmentId{TriangleFragmentIdAssigner::getInstance().generateUniqueId()}, neighbours{neighbours} {}
 
-bool Triangle::pointInTriangle(const Point &p) const {
+Triangle::Triangle(const Point &p1, const Point &p2, const Point &p3, int mainTriangleId, const std::vector<int> neighbours) : 
+points{p1, p2, p3}, mainTriangleId{mainTriangleId}, fragmentId{TriangleFragmentIdAssigner::getInstance().generateUniqueId()}, neighbours{make_shared<std::vector<int>>(neighbours)} {}
+
+bool Triangle::pointInTriangle(const Point &p) const
+{
     // all tests must be positive
     auto edges = TriangleEdges(*this);
 
-    for (int i = 0; i < NB_TRIANGLE_SIDES; i++) {
-        if (edges.edges[i].positiveSide(p)) {
+    for (int i = 0; i < NB_TRIANGLE_SIDES; i++)
+    {
+        if (edges.edges[i].positiveSide(p))
+        {
             return false;
         }
     }
     return true;
 }
 
-
-int nextPoint(int pointIndex)  {
+int nextPoint(int pointIndex)
+{
     return (pointIndex + 1) % 3;
 }
diff --git a/src/union.cpp b/src/union.cpp
index 2ab8724a0e377a171c37403194c18baf49d60307..0c3952b1fee9c1e3129f78f3751b6374b670569e 100644
--- a/src/union.cpp
+++ b/src/union.cpp
@@ -35,7 +35,7 @@ std::vector<Triangle> unionizeTopAndBottom(const Triangle &top, const Triangle &
         // add these to result
         if (!shapes[0].empty())
         {
-            std::vector<Triangle> relvTriangles = convexTriangulation(shapes[0], bot.id);
+            std::vector<Triangle> relvTriangles = convexTriangulation(shapes[0], bot.mainTriangleId, bot.neighbours);
             result.insert(result.end(), relvTriangles.begin(), relvTriangles.end());
         }
         // future relevant triangles
@@ -48,7 +48,11 @@ std::vector<Triangle> unionizeTopAndBottom(const Triangle &top, const Triangle &
 
 std::vector<Triangle> unionize(const Triangle &t1, const Triangle &t2)
 {
-	if (std::find(t1.neighbours.begin(), t1.neighbours.end(), t2.id) != t1.neighbours.end()) {
+    if (t1.mainTriangleId == t2.mainTriangleId) {
+        return {t1, t2};
+    }
+
+	if (std::find(t1.neighbours->begin(), t1.neighbours->end(), t2.mainTriangleId) != t1.neighbours->end()) {
 		return {t1, t2};
 	}
     if (intersections(t1, t2).empty())
diff --git a/src/utilities/convex_triangulation.cpp b/src/utilities/convex_triangulation.cpp
index 0ff1a483c63531e6edffad392f6dded216f1a98d..498ddd88f0daedf3081083bbe12122c7adbaefc4 100644
--- a/src/utilities/convex_triangulation.cpp
+++ b/src/utilities/convex_triangulation.cpp
@@ -9,13 +9,13 @@ void appendResults(std::vector<Triangle> &results, const Triangle &t) {
 	results.push_back(t);
 }
 
-std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int triangleId) {
+std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int triangleId, std::shared_ptr<std::vector<int>> neighbours) {
 	const int size = points.size();
 	if (size < 3) {
 		return std::vector<Triangle>{};
 	}
 
-	const Triangle t1 = Triangle(points[0], points[1], points[2], triangleId);
+	const Triangle t1 = Triangle(points[0], points[1], points[2], triangleId, neighbours);
 	std::vector<Triangle> results;
 
 	appendResults(results, t1);
@@ -23,7 +23,7 @@ std::vector<Triangle> convexTriangulation(const std::vector<Point> &points, int
 	
 	Point first = points[0];
 	for (int i = size - 1; i >= 3; i--) {
-		const Triangle t = Triangle(first, points[2], points[i], triangleId);
+		const Triangle t = Triangle(first, points[2], points[i], triangleId, neighbours);
 		appendResults(results, t);
 		
 		first = points[i];
diff --git a/tests/quad_tree_tests.cpp b/tests/quad_tree_tests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63ae5431214287db2beb614c7ed2c257fb9953a7
--- /dev/null
+++ b/tests/quad_tree_tests.cpp
@@ -0,0 +1,97 @@
+#include <gtest/gtest.h>
+#include <quad_tree.h>
+
+TEST(QuadTreeTests, SimplePointQueryTest) {
+    QuadTree q({{10,10}, {0,0}});
+
+    Triangle t({0,0}, {5,0}, {2,3}, 42);
+    q.addTriangle(t);
+
+
+    Point p{1,1};
+    int id = q.pointIntersection(p);
+
+    EXPECT_EQ(id, t.mainTriangleId);
+}
+
+TEST (QuadTreeTests, NotInQueryPointTest) {
+
+    QuadTree q({{10,10}, {0,0}});
+    Triangle t({0,0}, {5,0}, {2,3});
+    Point p{9,9};
+    int id = q.pointIntersection(p);
+    EXPECT_EQ(id, POINT_NOT_IN_QUADTREE);
+}
+
+TEST (QuadTreeTests, OverlapTest) {
+
+    QuadTree q({{10,10}, {0,0}});
+    Triangle t1({0, 0, 0}, {5, 0, 0}, {2, 3, 0}, 1);
+    Triangle t2({3, 1, 1}, {6, 1, 1}, {4, 3, 1}, 2);
+
+    q.addTriangle(t1);
+    q.addTriangle(t2);
+
+    Point p{1,1};
+    int id = q.pointIntersection(p);
+    EXPECT_EQ(id, t1.mainTriangleId);
+}
+
+TEST (QuadTreeTests, NonOverlappingTest) {
+
+    QuadTree q({{10,10}, {0,0}});
+    Triangle t1({0, 0, 0}, {5, 0, 0}, {2, 3, 0}, 1);
+    Triangle t2{{6, 0, 1}, {10, 0, 1}, {7, 5, 1}, 2};
+
+    q.addTriangle(t1);
+    q.addTriangle(t2);
+}
+
+TEST (QuadTreeTests, VisibleSurfaceTestNonOverlapping) {
+
+    QuadTree q({{10,10}, {0,0}});
+    Triangle t1({0, 0, 0}, {5, 0, 0}, {2, 3, 0}, 1);
+    Triangle t2{{6, 0, 1}, {10, 0, 1}, {7, 5, 1}, 2};
+
+    q.addTriangle(t1);
+    q.addTriangle(t2);
+
+    auto surface = q.visibleSurface();
+
+    std::vector<Triangle> expected_surface {{{6,0,1}, {10, 0, 1}, {7, 5, 1}, 2}, {{0,0,0}, {5,0,0},{2,3,0}, 1}};
+
+    EXPECT_EQ(surface, expected_surface);
+}
+
+TEST (QuadTreeTests, NoVisibleSurfaceTest) {
+    QuadTree q({{1,1}, {0,0}});
+    auto surface = q.visibleSurface();
+    EXPECT_EQ(surface, std::vector<Triangle>{});
+}
+
+TEST (QuadTreeTests, FiveTrianglesTest) {
+
+    QuadTree q({{1,1}, {0,0}});
+
+    Triangle t1{{0,0,0}, {0,0,0}, {0,0,0}, 1};
+    Triangle t2{{0,0,0}, {0,0,0}, {0,0,0}, 1};
+    Triangle t3{{0,0,0}, {0,0,0}, {0,0,0}, 1};
+    Triangle t4{{0,0,0}, {0,0,0}, {0,0,0}, 1};
+}
+
+TEST (QuadTreeTests, DegenerateTrianglesTest) {
+    QuadTree q({{1,1}, {0,0}});
+    Triangle t1{{0,0,0}, {0,0,0}, {0,0,0}, 1};
+    Triangle t2{{0.2, 0.1, 1}, {0.2, 0.1, 1}, {0.3, 0.2, 1}, 2};
+    Triangle t3{{1,0,0}, {1,0,0}, {0,0,0}, 3};
+
+    q.addTriangle(t3);
+    q.addTriangle(t2);
+    q.addTriangle(t1);
+
+    auto surface = q.visibleSurface();
+
+    std::vector<Triangle> expected_surface {t1, t3, t2};
+
+    EXPECT_EQ(surface, expected_surface);
+}
\ No newline at end of file
diff --git a/tests/unit_tests/convex_triangulation_tests.cpp b/tests/unit_tests/convex_triangulation_tests.cpp
index 5fa45e1408ca2fc77b8998f2c95c142c12d639c2..c5b80a4367ce460d79eb4882f8e7978ced8c407e 100644
--- a/tests/unit_tests/convex_triangulation_tests.cpp
+++ b/tests/unit_tests/convex_triangulation_tests.cpp
@@ -14,7 +14,7 @@ TEST(ConvexTriangulationTests, Simple) {
 		p1, p2, p3, p4, p5
 	};	
 
-	auto results = convexTriangulation(points, 2);
+	auto results = convexTriangulation(points, 2, std::make_shared<std::vector<int>>());
 
 	std::vector<Triangle> expected_result {
 		Triangle(p1, p2, p3, 2),
@@ -33,7 +33,7 @@ TEST(ConvexTriangulationTests, TrivialTriangle) {
 		{1.5, 2}
 	};
 
-	auto results = convexTriangulation(points, 1);
+	auto results = convexTriangulation(points, 1, std::make_shared<std::vector<int>>());
 	Triangle expected_triangle = Triangle({0,0}, {2,0}, {1.5, 2}, 1);
 
 	EXPECT_EQ(results.size(), 1);
diff --git a/tests/unit_tests/intersections_tests.cpp b/tests/unit_tests/intersection_tests/intersections_tests.cpp
similarity index 100%
rename from tests/unit_tests/intersections_tests.cpp
rename to tests/unit_tests/intersection_tests/intersections_tests.cpp