diff --git a/Line.h b/Line.h index b156d02..6038a82 100644 --- a/Line.h +++ b/Line.h @@ -1,5 +1,7 @@ #pragma once +#include // For abs, sqrt + #include "Point.h" class Line @@ -35,6 +37,14 @@ public: { return false; } - + } + + float distance_to(Point other) const + { + float a = from().y() - to().y(); + float b = to().x() - from().x(); + float c = from().x() * to().y() - to().x() * from().y(); + + return abs(a * other.x() + b * other.y() + c) / sqrt(a * a + b * b); } }; \ No newline at end of file diff --git a/Makefile b/Makefile index 109ae4d..6ea65ec 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -Wall -O3 +CXXFLAGS = -Wall -O3 -g # In case you installed SFML to a non-standard path, you'll need to tell the compiler where to find the SFML headers (.hpp files): # g++ -c main.cpp -I/include @@ -11,6 +11,9 @@ quickhull: main.o Quickhull.h Point.h Line.h Triangle.h Timing.o Display.o # link with sfml libs; -lsfml-network -lsfml-audio currently not needed $(CXX) $(CXXFLAGS) -o quickhull main.o Quickhull.h Point.h Line.h Triangle.h Timing.o Display.o -lsfml-system -lsfml-window -lsfml-graphics +performance: performance.cpp + $(CXX) $(CXXFLAGS) -o performance performance.cpp + main.o: main.cpp Timing.h $(CXX) $(CXXFLAGS) -c main.cpp @@ -19,4 +22,4 @@ Display.o: Display.h Timing.o: Timing.h clean : - -rm *.o quickhull + -rm *.o quickhull performance diff --git a/Point.h b/Point.h index 90f464c..92a2864 100644 --- a/Point.h +++ b/Point.h @@ -20,12 +20,12 @@ public: return m_y; } - Point operator+(const Point &other) + Point operator+(const Point &other) const { return Point(x() + other.x(), y() + other.y()); } - Point operator-(const Point &other) + Point operator-(const Point &other) const { return Point(x() - other.x(), y() - other.y()); } @@ -45,4 +45,9 @@ public: return *this; } + + bool operator==(const Point &other) const + { + return (x() == other.x() && y() == other.y()); + } }; \ No newline at end of file diff --git a/Quickhull.h b/Quickhull.h index a49ade5..0e392cb 100644 --- a/Quickhull.h +++ b/Quickhull.h @@ -13,7 +13,7 @@ public: static void get_hull(std::list &input, std::list &output) { // Get leftmost and rightmost point - Point leftmost(INT_MAX, 0), rightmost(INT_MIN, 0); + Point leftmost(INFINITY, 0.0), rightmost(-INFINITY, 0.0); for (const Point &point : input) { @@ -62,13 +62,26 @@ private: if (input.empty()) return; // Find the point which is furthest away from the line, add it to the output - Point furthest_point; // TODO + Point furthest_point; + float furthest_distance = 0.0; + + for (const Point &point : input) + { + float this_distance = line.distance_to(point); + if (this_distance > furthest_distance) + { + furthest_distance = this_distance; + furthest_point = point; + } + } output.emplace_back(furthest_point); + input.remove(furthest_point); // Build a triangle with these 3 points // The order with which we must pass the points depends on where the new furthest point is + // TODO: Is there a nicer way to do this? Point a, b, c; if (line.is_point_right(furthest_point)) { @@ -86,12 +99,19 @@ private: Triangle triangle(a, b, c); // Remove points inside this triangle + // TODO: I think we can actually skip this, and instead only + // pass points to the left (?) of the individual line to the + // new get_hull_with_line call. That way the ones inside are + // implicitly ignored. input.remove_if([triangle](Point point) { - return !triangle.is_point_inside(point); + return triangle.is_point_inside(point); }); // Recursively call get_hull_with_line for each side of the triangle - // TODO + // TODO: We can skip the original one + get_hull_with_line(input, output, triangle.l1()); + get_hull_with_line(input, output, triangle.l2()); + get_hull_with_line(input, output, triangle.l3()); } }; \ No newline at end of file diff --git a/Triangle.h b/Triangle.h index d271c1a..ffc7085 100644 --- a/Triangle.h +++ b/Triangle.h @@ -19,4 +19,19 @@ public: { return m_l1.is_point_right(other) && m_l2.is_point_right(other) && m_l3.is_point_right(other); } + + Line l1() + { + return m_l1; + } + + Line l2() + { + return m_l2; + } + + Line l3() + { + return m_l3; + } }; \ No newline at end of file diff --git a/performance.cpp b/performance.cpp new file mode 100644 index 0000000..4a7cdeb --- /dev/null +++ b/performance.cpp @@ -0,0 +1,22 @@ +#include "Quickhull.h" + +int main() +{ + std::list points = { + Point(-1, -1), + Point(-1, 1), + Point(1, -1), + Point(1, 1), + Point(0.5, 0) // Should not be in the hull + }; + std::list hull; + + Quickhull::get_hull(points, hull); + + for (const Point &point : hull) + { + std::cout << point.x() << ", " << point.y() << std::endl; + } + + return 0; +} \ No newline at end of file