Add Intersection test between ConvexHull2s, based on Separate Axis Theorem

This commit is contained in:
Erik Broberg
2016-06-10 15:03:51 -04:00
parent 2c89f36cbe
commit ff3ac1b368
5 changed files with 183 additions and 5 deletions

View File

@@ -32,6 +32,46 @@ namespace {
}
namespace openspace {
AABB1::AABB1() : min(1e35), max(-1e35) { }
AABB1::AABB1(float min, float max) : min(min), max(max) { }
void AABB1::expand(float p) {
min = glm::min(min, p);
max = glm::max(max, p);
}
float AABB1::center() const {
return 0.5f * (min + max);
}
float AABB1::size() const {
return max - min;
}
bool AABB1::contains(float p) const {
return (min <= p) && (p <= max);
}
bool AABB1::contains(const AABB1& o) const {
return (min <= o.min) && (o.max <= max);
}
bool AABB1::intersects(const AABB1& o) const {
return (min <= o.max) && (o.min <= max);
}
AABBSpatialRelation AABB1::relationTo(const AABB1& o) const {
if (intersects(o)) {
if (contains(o)) return AABBSpatialRelation::Containing;
if (o.contains(*this)) return AABBSpatialRelation::Contained;
return AABBSpatialRelation::Intersecting;
}
return AABBSpatialRelation::None;
}
AABB2::AABB2() : min(1e35), max(-1e35) { }

View File

@@ -43,6 +43,22 @@ namespace openspace {
Containing
};
struct AABB1 {
AABB1();
AABB1(float min, float max);
void expand(float p);
float center() const;
float size() const;
bool contains(float p) const;
bool contains(const AABB1& o) const;
bool intersects(const AABB1& o) const;
AABBSpatialRelation relationTo(const AABB1& o) const;
float min;
float max;
};
struct AABB2 {
AABB2();

View File

@@ -97,6 +97,49 @@ namespace openspace {
return hull;
}
bool ConvexHull2::intersects(const ConvexHull2& other) const {
// uses Separating Axis Theorem
// ref: http://stackoverflow.com/questions/753140/how-do-i-determine-if-two-convex-polygons-intersect
return this->hasPerpendicularLineWhereProjectedPointsOverlap(other) ||
other.hasPerpendicularLineWhereProjectedPointsOverlap(*this);
}
bool ConvexHull2::hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const {
for (size_t i = 1; i < _points.size(); i++) {
glm::vec2 dividingAxis = _points[i] - _points[i - 1];
// project all points onto the vector perpendicular to the dividing axis
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
const AABB1& myBounds = projectedRegion(projAxis);
const AABB1& otherBounds = other.projectedRegion(projAxis);
if (!myBounds.intersects(otherBounds)) {
return false;
}
}
// test line defined by last-to-first point
glm::vec2 dividingAxis = _points[0] - _points.back();
glm::vec2 projAxis(glm::normalize(glm::vec2(-dividingAxis.y, dividingAxis.x)));
const AABB1& myBounds = projectedRegion(projAxis);
const AABB1& otherBounds = other.projectedRegion(projAxis);
if (!myBounds.intersects(otherBounds)) {
return false;
}
return true;
}
AABB1 ConvexHull2::projectedRegion(glm::vec2 direction) const {
AABB1 projectedRegion;
for (size_t i = 0; i < _points.size(); i++) {
projectedRegion.expand(glm::dot(_points[i], direction));
}
return projectedRegion;
}
Point2 ConvexHull2::oneBelowTop(std::stack<Point2>& S) {
Point2 p = S.top();
S.pop();
@@ -106,7 +149,7 @@ namespace openspace {
}
void ConvexHull2::swap(Point2& p1, Point2& p2) {
Point2& temp = p1;
Point2 temp = p1;
p1 = p2;
p2 = temp;
}

View File

@@ -25,6 +25,9 @@
#ifndef __CONVEX_HULL_H__
#define __CONVEX_HULL_H__
#include <modules/globebrowsing/geometry/aabb.h>
#include <vector>
#include <stack>
@@ -48,13 +51,18 @@ namespace openspace {
public:
ConvexHull2();
static ConvexHull2 grahamScan_NOT_THREAD_SAFE(std::vector<Point2>& points, int yMinIndex = -1);
const std::vector<Point2> points() const;
bool intersects(const ConvexHull2& o) const;
AABB1 projectedRegion(glm::vec2 direction) const;
private:
bool hasPerpendicularLineWhereProjectedPointsOverlap(const ConvexHull2& other) const;
static int compare(const void *vp1, const void *vp2);
static Point2 oneBelowTop(std::stack<Point2>&);

View File

@@ -37,16 +37,87 @@ class ConvexHull2Test : public testing::Test {};
TEST_F(ConvexHull2Test, basic) {
// points
// 2 x
// 1 x
// 0 x x
// -1 0 1
std::vector<Point2> points = {
{ -1.0, 0.0 },
{ 1.0, 0.0 },
{ 0.0, 2.0 },
{ 0.0, 1.0 } };
{ 0.0, 1.0 }
};
EXPECT_EQ(4, points.size()) << "Should have 4 points";
// Convex hull
// 2 x
// 1 / \
// 0 x ___ x
// -1 0 1
ConvexHull2 hull = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points);
EXPECT_EQ(3, hull.points().size()) << "Should have 3 points";
EXPECT_EQ(4, points.size()) << "Should have 4 points";
}
TEST_F(ConvexHull2Test, intersection) {
std::vector<Point2> points1 = {
{ -1.0, 0.0 },
{ 1.0, 0.0 },
{ 0.0, 2.0 },
{ 0.0, 1.0 }
};
ConvexHull2 hull1 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points1);
std::vector<Point2> points2 = {
{ 0.0, 0.0 },
{ 2.0, 0.0 },
{ 1.0, 2.0 },
{ 1.0, 1.0 }
};
ConvexHull2 hull2 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points2);
// Convex hull
// 3
// 2 x x
// 1 / /\ \
// 0 x _x__x__x
// -1 0 1 2 3
EXPECT_TRUE(hull1.intersects(hull2)) << "They should intersect";
}
TEST_F(ConvexHull2Test, non_intersection) {
std::vector<Point2> points1 = {
{ -2.0, 0.0 },
{ 2.0, 0.0 },
{ 0.0, 2.0 },
};
ConvexHull2 hull1 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points1);
std::vector<Point2> points2 = {
{ 1.0, 2.0 },
{ 3.0, 0.0 },
{ 5.0, 2.0 }
};
ConvexHull2 hull2 = ConvexHull2::grahamScan_NOT_THREAD_SAFE(points2);
// Convex hull
// 3
// 2 x x-----------x
// 1 _-' '-_'-_ _-'
// 0 x___________x x
// -2 -1 0 1 2 3 4 5
EXPECT_FALSE(hull1.intersects(hull2)) << "They should not intersect";
}