Skip to content
Snippets Groups Projects
Commit 8b8700c5 authored by Brandon Lai-Cheong's avatar Brandon Lai-Cheong
Browse files

added edge union cases

parent 7e16b5d0
No related branches found
No related tags found
No related merge requests found
Showing
with 113 additions and 114 deletions
...@@ -26,8 +26,6 @@ add_executable( ...@@ -26,8 +26,6 @@ add_executable(
src/debug_utilities/mostly_equal.cpp src/debug_utilities/mostly_equal.cpp
tests/unit_tests/simple_triangle_tests.cpp tests/unit_tests/simple_triangle_tests.cpp
tests/unit_tests/point_in_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 src/utilities/intersections.cpp
tests/union_tests.cpp tests/union_tests.cpp
src/shapes/triangle.cpp src/shapes/triangle.cpp
...@@ -37,13 +35,10 @@ add_executable( ...@@ -37,13 +35,10 @@ add_executable(
src/utilities/orientation.cpp src/utilities/orientation.cpp
src/shapes/point.cpp src/shapes/point.cpp
src/union.cpp src/union.cpp
src/utilities/triangulation.cpp
src/utilities/pointList.cpp src/utilities/pointList.cpp
tests/unit_tests/orientation_tests.cpp tests/unit_tests/orientation_tests.cpp
tests/unit_tests/intersections_tests.cpp tests/unit_tests/intersections_tests.cpp
src/data_structures/box.cpp src/data_structures/box.cpp
src/data_structures/quad_tree.cpp
tests/quad_tree_tests.cpp
tests/edge_union_cases.cpp tests/edge_union_cases.cpp
tests/unit_tests/convex_triangulation_tests.cpp tests/unit_tests/convex_triangulation_tests.cpp
src/utilities/convex_triangulation.cpp src/utilities/convex_triangulation.cpp
...@@ -53,6 +48,9 @@ add_executable( ...@@ -53,6 +48,9 @@ add_executable(
src/utilities/split_triangle.cpp src/utilities/split_triangle.cpp
tests/unit_tests/orientation_tests.cpp tests/unit_tests/orientation_tests.cpp
tests/union_neighbours_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) include_directories(include)
......
#pragma once #pragma once
#include <vector> #include <vector>
#include <string>
#include <exception>
struct Triangle; struct Triangle;
struct Point; struct Point;
class ContourizeException : public std::exception {
virtual const char *what() const throw();
};
// creates a contour from a list of points // creates a contour from a list of points
std::vector<Point> contourize(const std::vector<Point> &points); std::vector<Point> contourize(const std::vector<Point> &points);
\ No newline at end of file
...@@ -5,4 +5,4 @@ ...@@ -5,4 +5,4 @@
#include <vector> #include <vector>
// Requires a convex shape // 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);
#pragma once
#include <vector>
struct Point;
float interpolateZ(const std::vector<Point> &shape, const Point &p);
\ No newline at end of file
#pragma once #pragma once
struct Triangle;
struct Point; struct Point;
enum Orientation { enum Orientation {
Clockwise, Collinear, Counterclockwise Clockwise, Collinear, Counterclockwise
}; };
Orientation orientation(const Point &p1, const Point &p2, const Point &p3); Orientation orientation(const Point &p1, const Point &p2, const Point &p3);
\ No newline at end of file
Orientation orientation(const Triangle &t);
\ No newline at end of file
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
struct Point { struct Point {
float x, y, z; float x, y, z;
bool operator==(const Point &other) const; 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); std::ostream &operator<<(std::ostream &os, Point const &p);
#pragma once
struct Triangle;
void shiftZ(Triangle &t, float z) ;
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include "print_triangle.h" #include "print_triangle.h"
#include <vector> #include <vector>
// points specified counterclockwise // points specified in counterclockwise or collinear (line / point) order
struct Triangle struct Triangle
{ {
Point points[3]; Point points[3];
......
#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
#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
...@@ -17,6 +17,5 @@ bool Triangle::operator==(const Triangle &other) const { ...@@ -17,6 +17,5 @@ bool Triangle::operator==(const Triangle &other) const {
return mostlyEqual(points[0], other.points[0]) && return mostlyEqual(points[0], other.points[0]) &&
mostlyEqual(points[1], other.points[1]) && mostlyEqual(points[1], other.points[1]) &&
mostlyEqual(points[2], other.points[2]) && mostlyEqual(points[2], other.points[2]) &&
depth == other.depth &&
id == other.id; id == other.id;
} }
\ No newline at end of file
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
std::ostream &operator<<(std::ostream &os, const Triangle &t) { std::ostream &operator<<(std::ostream &os, const Triangle &t) {
return os << "Triangle: " << t.id return os << "Triangle: " << t.id
<< ", " << "Depth: " << t.depth
<< " {" << t.points[0] << ", " << t.points[1] << ", " << t.points[2] << "}"; << " {" << t.points[0] << ", " << t.points[1] << ", " << t.points[2] << "}";
} }
/* /*
......
#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
...@@ -9,3 +9,17 @@ bool Point::operator==(const Point &other) const { ...@@ -9,3 +9,17 @@ bool Point::operator==(const Point &other) const {
std::ostream &operator<<(std::ostream &os, Point const &p) { std::ostream &operator<<(std::ostream &os, Point const &p) {
return os << "(" << p.x << "," << p.y << "," << p.z << ")"; 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
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include "triangle_edges.h" #include "triangle_edges.h"
#include "edge.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 { bool Triangle::pointInTriangle(const Point &p) const {
// all tests must be positive // all tests must be positive
......
...@@ -6,13 +6,12 @@ ...@@ -6,13 +6,12 @@
#include <triangle_edges.h> #include <triangle_edges.h>
#include <intersections.h> #include <intersections.h>
#include <split_triangle.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> unionizeTopAndBottom(const Triangle &top, const Triangle &bot)
{ {
std::vector<Triangle> result; std::vector<Triangle> result;
std::list<Point> intr;
TriangleEdges topEdges = TriangleEdges(top); TriangleEdges topEdges = TriangleEdges(top);
// keep track of relevant triangles // keep track of relevant triangles
...@@ -21,13 +20,16 @@ std::vector<Triangle> unionizeTopAndBottom(const Triangle &top, const Triangle & ...@@ -21,13 +20,16 @@ std::vector<Triangle> unionizeTopAndBottom(const Triangle &top, const Triangle &
for (int i = 0; i < NB_TRIANGLE_SIDES; i++) for (int i = 0; i < NB_TRIANGLE_SIDES; i++)
{ {
const Edge &e = topEdges.edges[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); auto shapes = splitShape(relv, e);
// split triangle if exists // split triangle if exists
// currently relevant triangles // currently relevant triangles
// add these to result // add these to result
if (!shapes[0].empty()) 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()); result.insert(result.end(), relvTriangles.begin(), relvTriangles.end());
} }
// future relevant triangles // future relevant triangles
...@@ -47,7 +49,7 @@ std::vector<Triangle> unionize(const Triangle &t1, const Triangle &t2) ...@@ -47,7 +49,7 @@ std::vector<Triangle> unionize(const Triangle &t1, const Triangle &t2)
{ {
return {t1, t2}; return {t1, t2};
} }
if (t1.depth < t2.depth) if (t1.points[0].z < t2.points[0].z)
{ {
return unionizeTopAndBottom(t1, t2); return unionizeTopAndBottom(t1, t2);
} }
......
...@@ -3,12 +3,20 @@ ...@@ -3,12 +3,20 @@
#include <orientation.h> #include <orientation.h>
#include <list> #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) { bool isCounterClockwiseForAll(const Point &previous, const Point &candidate, const std::vector<Point> & points) {
for (const auto &point : points) { for (const auto &point : points) {
if (previous == point || candidate == point) { if (previous == point || candidate == point) {
continue; continue;
} }
auto o = orientation(previous, candidate, point); auto o = orientation(previous, candidate, point);
if (o == Collinear) {
continue;
}
if (o != Counterclockwise) { if (o != Counterclockwise) {
return false; return false;
} }
...@@ -21,19 +29,34 @@ std::vector<Point> contourize(const std::vector<Point> &points) { ...@@ -21,19 +29,34 @@ std::vector<Point> contourize(const std::vector<Point> &points) {
return points; return points;
} }
std::vector<Point> result; std::vector<Point> result;
Point previous = points[0]; Point previous = points[0];
result.push_back(previous); result.push_back(previous);
std::list<Point> candidates(points.begin() + 1, points.end()); std::list<Point> candidates(points.begin() + 1, points.end());
const int size = candidates.size();
// infinite loop detection
int seen = 0;
while (!candidates.empty()) { while (!candidates.empty()) {
// detect infinite loop
if (seen >= candidates.size()) {
throw ContourizeException();
}
if (isCounterClockwiseForAll(previous, candidates.front(), points)) { if (isCounterClockwiseForAll(previous, candidates.front(), points)) {
previous = candidates.front(); previous = candidates.front();
candidates.pop_front(); candidates.pop_front();
result.push_back(previous); result.push_back(previous);
seen = 0;
} else { } else {
candidates.push_back(candidates.front()); candidates.push_back(candidates.front());
candidates.pop_front(); candidates.pop_front();
seen++;
} }
} }
return result; return result;
......
#include <convex_triangulation.h> #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(); const int size = points.size();
if (size < 3) { if (size < 3) {
return std::vector<Triangle>{}; 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}; std::vector<Triangle> results = {t1};
Point first = points[0]; Point first = points[0];
for (int i = size - 1; i >= 3; i--) { 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]; first = points[i];
} }
return results; return results;
......
#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;
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <triangle.h> #include <triangle.h>
#include <constants.h> #include <constants.h>
#include <edge.h> #include <edge.h>
#include <interpolate_z.h>
std::optional<float> getB(std::optional<float> slope, Point p) std::optional<float> getB(std::optional<float> slope, Point p)
{ {
...@@ -138,7 +139,6 @@ std::optional<Point> intersection(const Edge &e1, const Edge &e2) ...@@ -138,7 +139,6 @@ std::optional<Point> intersection(const Edge &e1, const Edge &e2)
{ {
return {}; return {};
} }
return candPoint; return candPoint;
} }
void intersections(const Edge &e1, const TriangleEdges &te, std::vector<Point> &results) 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 ...@@ -172,6 +172,9 @@ std::vector<Point> intersections(const std::vector<Point> &points, const Edge &l
auto cand = intersectionFirstSide(line, es[i]); auto cand = intersectionFirstSide(line, es[i]);
if (cand.has_value()) if (cand.has_value())
{ {
// add depth information
float z = interpolateZ(points, cand.value());
cand.value().z = z;
result.push_back(cand.value()); result.push_back(cand.value());
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment