Compare commits
No commits in common. "23fef77aaafe6965371917828cb01a9d352a2374" and "14e633d236806c559e289cf9c23453fe1be0c09a" have entirely different histories.
23fef77aaa
...
14e633d236
6
Makefile
6
Makefile
@ -1,5 +1,5 @@
|
|||||||
CXX = g++
|
CXX = g++
|
||||||
CXXFLAGS = -Wall -O3
|
CXXFLAGS = -Wall -O3 -g
|
||||||
SFMLFLAGS = -lsfml-system -lsfml-window -lsfml-graphics
|
SFMLFLAGS = -lsfml-system -lsfml-window -lsfml-graphics
|
||||||
|
|
||||||
# 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):
|
# 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):
|
||||||
@ -20,5 +20,5 @@ main.o: main.cpp
|
|||||||
|
|
||||||
Display.o: Display.h
|
Display.o: Display.h
|
||||||
|
|
||||||
clean:
|
clean :
|
||||||
-rm *.o quickhull
|
-rm *.o quickhull performance
|
||||||
|
120
Quickhull.h
120
Quickhull.h
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include "Triangle.h"
|
#include "Triangle.h"
|
||||||
#include "Utility.h" // For IsPointInRectangle
|
|
||||||
|
|
||||||
class Quickhull
|
class Quickhull
|
||||||
{
|
{
|
||||||
@ -20,56 +19,21 @@ public:
|
|||||||
// Get leftmost and rightmost point
|
// Get leftmost and rightmost point
|
||||||
Point leftmost(INFINITY, 0.0), rightmost(-INFINITY, 0.0);
|
Point leftmost(INFINITY, 0.0), rightmost(-INFINITY, 0.0);
|
||||||
|
|
||||||
if (akl)
|
for (const Point &point : input)
|
||||||
{
|
{
|
||||||
// Also get highest and lowest point
|
if (point.x() < leftmost.x()) {
|
||||||
Point lowest(0.0, -INFINITY), highest(0.0, INFINITY);
|
leftmost = point;
|
||||||
|
} else if (point.y() > rightmost.y()) {
|
||||||
for (const Point &point : input)
|
rightmost = point;
|
||||||
{
|
|
||||||
if (point.x() < leftmost.x()) {
|
|
||||||
leftmost = point;
|
|
||||||
} else if (point.x() > rightmost.x()) {
|
|
||||||
rightmost = point;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (point.y() < highest.y()) {
|
|
||||||
highest = point;
|
|
||||||
} else if (point.y() > lowest.y()) {
|
|
||||||
lowest = point;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Triangle t1(highest, rightmost, lowest);
|
|
||||||
Triangle t2(lowest, leftmost, highest);
|
|
||||||
|
|
||||||
// Remove all points in this rectangle
|
|
||||||
input.remove_if([highest, leftmost, lowest, rightmost](const Point &point)
|
|
||||||
{
|
|
||||||
return IsPointInRectangle(point, highest, leftmost, lowest, rightmost);
|
|
||||||
});
|
|
||||||
|
|
||||||
output.emplace_back(leftmost);
|
|
||||||
output.emplace_back(rightmost);
|
|
||||||
output.emplace_back(highest);
|
|
||||||
output.emplace_back(lowest);
|
|
||||||
} else {
|
|
||||||
for (const Point &point : input)
|
|
||||||
{
|
|
||||||
if (point.x() < leftmost.x()) {
|
|
||||||
leftmost = point;
|
|
||||||
} else if (point.x() > rightmost.x()) {
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
// 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
|
// Create a line from leftmost to rightmost
|
||||||
Line line = Line(leftmost, rightmost);
|
Line line = Line(leftmost, rightmost);
|
||||||
@ -149,38 +113,46 @@ private:
|
|||||||
// If the input vector is empty, we're done
|
// If the input vector is empty, we're done
|
||||||
if (input.empty()) return;
|
if (input.empty()) return;
|
||||||
|
|
||||||
// Find the points which are furthest away from the line
|
// Find the point which is furthest away from the line, add it to the output
|
||||||
|
Point furthest_point;
|
||||||
float furthest_distance = -1.0;
|
float furthest_distance = -1.0;
|
||||||
|
|
||||||
std::list<Point> furthest_points;
|
|
||||||
|
|
||||||
for (const Point &point : input)
|
for (const Point &point : input)
|
||||||
{
|
{
|
||||||
float this_distance = line.distance_squared_to(point);
|
float this_distance = line.distance_squared_to(point);
|
||||||
// It's possible for there to be multiple closests points (e.g. in the case)
|
|
||||||
// of a rectangle). We need to handle all these properly, so we make a list
|
|
||||||
// of all points at the furthest distance.
|
|
||||||
if (this_distance > furthest_distance)
|
if (this_distance > furthest_distance)
|
||||||
{
|
{
|
||||||
furthest_distance = this_distance;
|
furthest_distance = this_distance;
|
||||||
furthest_points.clear();
|
furthest_point = point;
|
||||||
furthest_points.emplace_back(point);
|
|
||||||
}
|
|
||||||
else if (this_distance == furthest_distance)
|
|
||||||
{
|
|
||||||
furthest_points.emplace_back(point);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const Point &point : furthest_points)
|
// TODO: e.g. in the case of a rectangle, it's possible for there to be
|
||||||
|
// multiple closest points (sometimes all at distance 0). How do we handle
|
||||||
|
// these properly? We definitely need to remove them all from input later;
|
||||||
|
// do we also need to handle them all further? This hotfix works, but seems
|
||||||
|
// like an unnecessarily big performance hit for that edge case.
|
||||||
|
// FIXME: This workaround also causes problems with extremely large numbers
|
||||||
|
// of randomly generated numbers, causing random lines within the data!
|
||||||
|
// Points inside the hull are added because of random lines.
|
||||||
|
for (const Point &point : input)
|
||||||
{
|
{
|
||||||
// All furthest points we found are part of the hull, so add them to the output
|
float this_distance = line.distance_squared_to(point);
|
||||||
// and remove them from the input.
|
// TODO: Both are required, otherwise only one side of the rectangle is
|
||||||
output.emplace_back(point);
|
// taken -- why?
|
||||||
input.remove(point);
|
if (this_distance == furthest_distance || line.distance_squared_to(point) == 0)
|
||||||
|
{
|
||||||
|
output.emplace_back(point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
input.remove_if([furthest_distance, line](Point point)
|
||||||
|
{
|
||||||
|
return furthest_distance == line.distance_squared_to(point);
|
||||||
|
});
|
||||||
|
// Hotfix end
|
||||||
|
|
||||||
Point furthest_point = furthest_points.front();
|
output.emplace_back(furthest_point);
|
||||||
|
input.remove(furthest_point);
|
||||||
|
|
||||||
// Build a triangle with these 3 points
|
// Build a triangle with these 3 points
|
||||||
|
|
||||||
@ -191,6 +163,7 @@ private:
|
|||||||
|
|
||||||
if (line.is_point_right(furthest_point))
|
if (line.is_point_right(furthest_point))
|
||||||
{
|
{
|
||||||
|
// TOOD: It's probably more efficient to set the fields?
|
||||||
new_line1 = Line(line.to(), furthest_point);
|
new_line1 = Line(line.to(), furthest_point);
|
||||||
new_line2 = Line(furthest_point, line.from());
|
new_line2 = Line(furthest_point, line.from());
|
||||||
}
|
}
|
||||||
@ -200,9 +173,12 @@ private:
|
|||||||
new_line2 = Line(furthest_point, line.to());
|
new_line2 = Line(furthest_point, line.to());
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't need to remove points inside the triangle created by those lines.
|
// TODO: Test if this improves performance
|
||||||
// That happens implicitly since they are not handled further due to the
|
//Triangle triangle(a, b, c);
|
||||||
// following step, which assigns each line its corresponding points to handle:
|
//input.remove_if([triangle](Point point)
|
||||||
|
//{
|
||||||
|
// return triangle.is_point_inside(point);
|
||||||
|
//});
|
||||||
|
|
||||||
// Get points right of new_line1 and 2
|
// Get points right of new_line1 and 2
|
||||||
std::list<Point> left_of_line1, left_of_line2;
|
std::list<Point> left_of_line1, left_of_line2;
|
||||||
@ -213,15 +189,15 @@ private:
|
|||||||
{
|
{
|
||||||
left_of_line1.emplace_back(point);
|
left_of_line1.emplace_back(point);
|
||||||
}
|
}
|
||||||
// TODO: Are there any possible edge cases where this 'else if' won't work,
|
// TODO: Can we do else if here, or could we then miss out on points?
|
||||||
// and we need an 'if' instead?
|
if (!new_line2.is_point_right(point))
|
||||||
else if (!new_line2.is_point_right(point))
|
|
||||||
{
|
{
|
||||||
left_of_line2.emplace_back(point);
|
left_of_line2.emplace_back(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively call get_hull_with_line for each side of the triangle
|
// Recursively call get_hull_with_line for each side of the triangle
|
||||||
|
// TODO: We can skip the original one
|
||||||
get_hull_with_line(left_of_line1, output, new_line1);
|
get_hull_with_line(left_of_line1, output, new_line1);
|
||||||
get_hull_with_line(left_of_line2, output, new_line2);
|
get_hull_with_line(left_of_line2, output, new_line2);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user