diff --git a/.gitignore b/.gitignore
index c795b054e5ade51b7031abab1581a5b7e2d2f5ba..6d7270f82d1cd707caf4df63c42211684a949cd5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
-build
\ No newline at end of file
+build
+.vscode/c_cpp_properties.json
+.vscode/launch.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ecd91b8772dfb3ee49e097ed65f106647b0f8b32..751c960c22fd50a8ce6e1f7ed60d08ebf9575288 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,9 +20,14 @@ project(intersection)
 
 add_executable(
 	tests
-	tests/simple_triangle_tests.cpp
+	tests/unit_tests/simple_triangle_tests.cpp
+	src/intersections/intersections.cpp
+	src/shapes/triangle.cpp
+	src/shapes/triangle_edges.cpp
 )
 
+include_directories(src)
+
 target_link_libraries(
 	tests
   GTest::gtest_main
diff --git a/src/contourize/contourize.cpp b/src/contourize/contourize.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1b70df007d586493d6950b5600e67d4af331435c
--- /dev/null
+++ b/src/contourize/contourize.cpp
@@ -0,0 +1,23 @@
+#include <shapes/triangle.h>
+#include <shapes/edge.h>
+#include <shapes/triangle_edges.h>
+#include <vector>
+
+bool positiveSide(Edge e, Point p) {
+    float h = e.p1.y - e.p2.y;
+    float g = e.p1.x - e.p2.x; 
+    return -h * (p.x - e.p1.x) + g * (p.y - e.p1.y) >= 0;
+}
+
+bool pointInTriangle(Point p, Triangle t) {
+    // all tests must be positive
+    auto edges = TriangleEdges(t);
+
+    return positiveSide(edges.e1, p) &&
+    positiveSide(edges.e2, p) &&
+    positiveSide(edges.e3, p);
+}
+
+void contourize(Triangle t1, Triangle t2, std::vector<Point> newIntersections) {
+
+}
\ No newline at end of file
diff --git a/src/intersections/intersections.cpp b/src/intersections/intersections.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c6b1ec18d7c668d106df70f6f12b16a74f804f24
--- /dev/null
+++ b/src/intersections/intersections.cpp
@@ -0,0 +1,81 @@
+#include "intersections.h"
+#include <shapes/edge.h>
+#include <shapes/triangle_edges.h>
+#include <shapes/point.h>
+#include <optional>
+
+
+
+std::optional<float> getB(std::optional<float> slope, Point p) {
+    if (!slope.has_value()) {
+        return {};
+    }
+
+    return p.y - slope.value() * p.x;
+}
+
+std::optional<float> getSlope(Edge e) {
+    if (e.p2.x - e.p1.x == 0) {
+        return {};
+    }
+    return (e.p2.y - e.p1.y) / (e.p2.x - e.p1.x) ;
+}
+
+bool withinEdge(Edge e, Point p) {
+    float minX = std::min(e.p1.x, e.p2.x);
+    float maxX = std::max(e.p1.x, e.p2.x);
+
+    float minY = std::min(e.p1.y, e.p2.y);
+    float maxY = std::max(e.p1.y, e.p2.y);
+
+    return minX <= p.x && p.x <= maxX && minY <= p.y && p.y <= maxY; 
+}
+
+
+void intersection(Edge e1, Edge e2, std::vector<Point> &results) {
+    auto slope1 = getSlope(e1);
+    auto slope2 = getSlope(e2);
+
+    auto b1 = getB(slope1, e1.p1);
+    auto b2 = getB(slope2, e2.p1);
+
+
+    // ignore overlapping case
+    if (!slope1.has_value() && !slope2.has_value()) {
+        return;
+    }
+
+    if (!slope1.has_value()) {
+        results.push_back(Point{e1.p1.x, slope2.value() * e1.p1.x + b2.value()});
+        return;
+    }
+
+    if (!slope2.has_value()) {
+        results.push_back(Point{e2.p1.x, slope1.value() * e2.p1.x + b1.value()});
+        return;
+    }
+    float candX = (b2.value() - b1.value()) / (slope1.value() - slope2.value());
+    auto candPoint = Point{ candX, slope1.value() * candX + b1.value()};
+
+    if (withinEdge(e1, candPoint) && withinEdge(e2, candPoint)) {
+        results.push_back(candPoint);
+    }
+}
+void intersections(Edge e1, TriangleEdges te, std::vector<Point> &results) {
+   intersection(e1, te.e1, results);
+   intersection(e1, te.e2, results);
+   intersection(e1, te.e3, results); 
+}
+std::vector<Point> intersections(Triangle t1, Triangle t2) {
+    TriangleEdges t1Edges = TriangleEdges(t1);
+
+    TriangleEdges t2Edges = TriangleEdges(t2);
+    std::vector<Point> results;
+
+    intersections(t1Edges.e1, t2Edges, results);
+    intersections(t1Edges.e2, t2Edges, results);
+    intersections(t1Edges.e3, t2Edges, results);
+
+    return results;
+}
+
diff --git a/src/intersections/intersections.h b/src/intersections/intersections.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca089a03a1e43d3277efffe481da7c664e926cc7
--- /dev/null
+++ b/src/intersections/intersections.h
@@ -0,0 +1,10 @@
+#pragma once
+#include <vector>
+#include "../shapes/point.h"
+#include "../shapes/triangle.h"
+
+struct TrigTrigInterResults {
+    std::vector<Point> results;
+};
+
+std::vector<Point> intersections(Triangle t1, Triangle t2);
\ No newline at end of file
diff --git a/src/shapes/edge.h b/src/shapes/edge.h
new file mode 100644
index 0000000000000000000000000000000000000000..22c0da354b30742275c217ccc5a5bb0dba79120f
--- /dev/null
+++ b/src/shapes/edge.h
@@ -0,0 +1,6 @@
+#pragma once
+#include "point.h"
+
+struct Edge {
+	Point p1, p2;
+};
\ No newline at end of file
diff --git a/src/shapes/point.h b/src/shapes/point.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e55134aa3248dd257aa408de3a145b583cb3756
--- /dev/null
+++ b/src/shapes/point.h
@@ -0,0 +1,5 @@
+#pragma once
+
+struct Point {
+	float x, y;
+};
\ No newline at end of file
diff --git a/src/shapes/triangle.cpp b/src/shapes/triangle.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f46643a92a4af6f222a5ca29d641f0308b3ac9b
--- /dev/null
+++ b/src/shapes/triangle.cpp
@@ -0,0 +1,7 @@
+#include "triangle.h"
+
+bool Triangle::neighbours(Triangle &other) {
+    return false;
+}
+
+Triangle::Triangle(Point p1, Point p2, Point p3, int depth) : p1{p1}, p2{p2}, p3{p3}, depth{depth} {}
\ No newline at end of file
diff --git a/src/shapes/triangle.h b/src/shapes/triangle.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d1d2984b80342bbc5b10d6f9222812296a3a3e3
--- /dev/null
+++ b/src/shapes/triangle.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "point.h"
+
+// points specified clockwise
+struct Triangle {
+	Point p1, p2, p3;
+	int depth;
+	bool neighbours(Triangle &other);
+	Triangle(Point p1, Point p2, Point p3, int depth);
+};
diff --git a/src/shapes/triangle_edges.cpp b/src/shapes/triangle_edges.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c5b5614a1529515315308c167dc6d3a9079e5711
--- /dev/null
+++ b/src/shapes/triangle_edges.cpp
@@ -0,0 +1,5 @@
+#include "triangle_edges.h"
+#include "triangle.h"
+
+TriangleEdges::TriangleEdges(const Triangle &t) : e1{Edge{t.p1, t.p2}}, e2{Edge{t.p2, t.p3}}, e3{Edge{t.p3, t.p1}}{
+}
\ No newline at end of file
diff --git a/src/shapes/triangle_edges.h b/src/shapes/triangle_edges.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0afc10effe9ff2a3bd89b0583059c00515fcc89
--- /dev/null
+++ b/src/shapes/triangle_edges.h
@@ -0,0 +1,6 @@
+#include "edge.h"
+struct Triangle;
+struct TriangleEdges {
+    Edge e1, e2, e3;
+    TriangleEdges(const Triangle &t);
+};
diff --git a/src/static_vector/static_vector.h b/src/static_vector/static_vector.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7386090766f159cd4c8fd55c9403a2b7ec9fb7e
--- /dev/null
+++ b/src/static_vector/static_vector.h
@@ -0,0 +1,7 @@
+
+template<class T>
+class StaticVector{
+
+    int maxSize;
+
+};
\ No newline at end of file
diff --git a/src/triangle.h b/src/triangle.h
deleted file mode 100644
index 8f479759cca3933d4192894d9c8365e60ec8a003..0000000000000000000000000000000000000000
--- a/src/triangle.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-struct Point {
-	float x, y;
-};
-
-struct Edge {
-	Point p1, p2;
-};
-
-struct Triangle {
-	Point p1, p2, p3;
-	int depth;
-	// neighbours
-};
diff --git a/src/triangulation/triangulation.h b/src/triangulation/triangulation.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f70f09beec2219624baeca92e2cd7deaa104fb4
--- /dev/null
+++ b/src/triangulation/triangulation.h
@@ -0,0 +1 @@
+#pragma once
diff --git a/src/union.cpp b/src/union.cpp
index bf21feb181117b8f9b12c901f9c8802d69e48794..a90877f1ee7432ea334a44b2317db447906971aa 100644
--- a/src/union.cpp
+++ b/src/union.cpp
@@ -1,26 +1,32 @@
-#include "triangle.h"
+#include "shapes/triangle.h"
 #include <vector>
 #include <optional>
+#include <intersections/intersections.h>
 
-std::optional<Point> intersection(Edge e1, Edge e2) {
+std::vector<Point> contourize(std::vector<Point> points) {
 
 }
 
-std::vector<Point> intersections(Triangle t1, Triangle t2) {
-
-}
-
-std::vector<Triangle> triangulate() {
-}
-
 std::vector<Triangle> unionize(Triangle t1, Triangle t2) {
 
+	// if neighbours, do nothing
+	if (t1.neighbours(t2)) {
+		return std::vector{t1, t2};
+	}
+
 	// at most 3? if infinite -> consider no intersections
 	std::vector<Point> newIntersections = intersections(t1, t2);
 
 	if (newIntersections.empty()) {
 		// either completely envelops each other, no intersections	
+		return std::vector{t1, t2};
 	}
 
-	return triangulate();
+	std::vector<Point> contour = contourize();
+
+	return triangulate(contour);
 }
+
+void unionize(Triangle soup) {
+
+}
\ No newline at end of file
diff --git a/src/union.h b/src/union.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/simple_triangle_tests.cpp b/tests/simple_triangle_tests.cpp
deleted file mode 100644
index 99f95a03f5d918e282703fc75f94a3fad1273240..0000000000000000000000000000000000000000
--- a/tests/simple_triangle_tests.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "gtest/gtest.h"
-
-TEST (TriangleIntersectionTests, TriangleIntersection) {
-
-}
\ No newline at end of file
diff --git a/tests/unit_tests/simple_triangle_tests.cpp b/tests/unit_tests/simple_triangle_tests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bb4603ea6f86ef1d700414344dd79badbf6896b5
--- /dev/null
+++ b/tests/unit_tests/simple_triangle_tests.cpp
@@ -0,0 +1,14 @@
+#include "gtest/gtest.h"
+#include "../../src/shapes/triangle.h"
+#include "../../src/intersections/intersections.h"
+
+TEST (TriangleIntersectionTests, TriangleIntersection) {
+    auto t1 = Triangle(Point(0,0), Point(2,3), Point(5,0), 0);
+    auto t2 = Triangle(Point(3,1), Point(4,3), Point(6,1), 0);
+
+    std::vector<Point> results = intersections(t1, t2);
+
+    EXPECT_TRUE(results.size() == 2) << "Actual size: " << results.size();
+
+}
+