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