mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-22 04:49:12 -06:00
Add Intersection test between ConvexHull2s, based on Separate Axis Theorem
This commit is contained in:
@@ -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) { }
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>&);
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user