diff --git a/Line.h b/Line.h new file mode 100644 index 0000000..1727495 --- /dev/null +++ b/Line.h @@ -0,0 +1,40 @@ +#pragma once + +#include "Point.h" + +class Line +{ +private: + Point m_from, m_to, m_to_from_origin; + +public: + Line(Point from, Point to) : m_from(from), m_to(to), m_to_from_origin(to - from) {} + + Point from() const + { + return m_from; + } + + Point to() const + { + return m_to; + } + + // Return true if the given point is to the right of this line. + // False is also returned if the point is directly on the line. + bool is_point_right(Point other) + { + other -= from(); + + // Cross product greater than zero? + if (m_to_from_origin.x() * other.y() - m_to_from_origin.y() * other.x() > 0) + { + return true; + } + else + { + return false; + } + + } +}; \ No newline at end of file diff --git a/Makefile b/Makefile index 3d01542..a1ab1a7 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ CXXFLAGS = -Wall -O3 # If SFML is not installed in a standard path, you need to tell the dynamic linker where to find the SFML libraries first by specifying LD_LIBRARY_PATH: # export LD_LIBRARY_PATH=/lib && ./sfml-app -quickhull: main.o Timing.o Display.o +quickhull: main.o Quickhull.h Point.h Line.h Timing.o Display.o # link with sfml libs; -lsfml-network -lsfml-audio currently not needed - $(CXX) $(CXXFLAGS) -o quickhull main.o Timing.o Display.o -lsfml-system -lsfml-window -lsfml-graphics + $(CXX) $(CXXFLAGS) -o quickhull main.o Quickhull.h Point.h Line.h Timing.o Display.o -lsfml-system -lsfml-window -lsfml-graphics main.o: main.cpp Timing.h $(CXX) $(CXXFLAGS) -c main.cpp @@ -18,7 +18,5 @@ Display.o: Display.h Timing.o: Timing.h -Quickhull.o: Quickhull.h - clean : -rm *.o quickhull diff --git a/Point.h b/Point.h index 2f7ce72..90f464c 100644 --- a/Point.h +++ b/Point.h @@ -8,13 +8,41 @@ private: public: Point(float x, float y) : m_x(x), m_y(y) {} - float x() + Point() : m_x(0), m_y(0) {} + + float x() const { return m_x; } - float y() + float y() const { return m_y; } + + Point operator+(const Point &other) + { + return Point(x() + other.x(), y() + other.y()); + } + + Point operator-(const Point &other) + { + return Point(x() - other.x(), y() - other.y()); + } + + Point &operator+=(const Point &other) + { + m_x += other.x(); + m_y += other.y(); + + return *this; + } + + Point &operator-=(const Point &other) + { + m_x -= other.x(); + m_y -= other.y(); + + return *this; + } }; \ No newline at end of file diff --git a/Quickhull.cpp b/Quickhull.cpp deleted file mode 100644 index f92e5ca..0000000 --- a/Quickhull.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "Quickhull.h" - -void Quickhull::get_hull(std::vector &input, std::vector &output) -{ - // Get leftmost and rightmost point - // Add them to the output. - - // Create a line from leftmost to rightmost - - // Sort points between left and right of that line - - // Call get_hull_with_line with the left points, as well as with the right points, and the line -} - -void Quickhull::get_hull_with_line(std::vector &input, std::vector &output, Point, Point) -{ - // If the input vector is empty, we're done - - // Find the point which is furthest away from the line, add it to the output - - // Build a triangle with these 3 points - // Remove points inside this triangle - - // Recursively call get_hull_with_line for each side of the triangle -} diff --git a/Quickhull.h b/Quickhull.h index ea44b79..c458cb2 100644 --- a/Quickhull.h +++ b/Quickhull.h @@ -1,14 +1,70 @@ #pragma once -#include +#include +#include // For INT_MIN & INT_MAX #include "Point.h" +#include "Line.h" class Quickhull { public: - static void get_hull(std::vector &, std::vector &); + static void get_hull(std::list &input, std::list &output) + { + // Get leftmost and rightmost point + Point leftmost(INT_MAX, 0), rightmost(INT_MIN, 0); + + for (const Point &point : input) + { + if (point.x() < leftmost.x()) { + leftmost = point; + } else if (point.y() > rightmost.y()) { + rightmost = point; + } + } + // Add them to the output + output.emplace_back(leftmost); + output.emplace_back(rightmost); + + // Remove them from the input (as well as duplicates) + input.remove(leftmost); + input.remove(rightmost); + + // Create a line from leftmost to rightmost + Line line = Line(leftmost, rightmost); + + // Sort points between left and right of that line + std::list points_left, points_right; + + for (const Point &point : input) + { + if (line.is_point_right(point)) + { + points_right.emplace_back(point); + } + else + { + points_left.emplace_back(point); + } + + } + + // Call get_hull_with_line with the left points, as well as with the right points, and the line + get_hull_with_line(points_left, output, line); + get_hull_with_line(points_right, output, line); + } private: - static void get_hull_with_line(std::vector &, std::vector &, Point, Point); + static void get_hull_with_line(std::list &input, std::list &output, const Line &line) + { + // If the input vector is empty, we're done + if (input.empty()) return; + + // Find the point which is furthest away from the line, add it to the output + + // Build a triangle with these 3 points + // Remove points inside this triangle + + // Recursively call get_hull_with_line for each side of the triangle + } }; \ No newline at end of file