You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
4.1 KiB
C++
167 lines
4.1 KiB
C++
#pragma once
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
using namespace std;
|
|
struct PointT {
|
|
double x, y;
|
|
};
|
|
|
|
struct LineSegment {
|
|
PointT start, end;
|
|
};
|
|
|
|
class QuadTreeNode {
|
|
public:
|
|
QuadTreeNode(double x, double y, double width, double height, int capacity)
|
|
: boundary{ x, y, width, height }, capacity(capacity), divided(false) {}
|
|
|
|
bool insert(const LineSegment& segment) {
|
|
if (!intersects(segment, boundary)) {
|
|
return false;
|
|
}
|
|
|
|
if (segments.size() < capacity) {
|
|
segments.push_back(segment);
|
|
return true;
|
|
}
|
|
|
|
if (!divided) {
|
|
subdivide();
|
|
}
|
|
|
|
if (northeast->insert(segment)) return true;
|
|
if (northwest->insert(segment)) return true;
|
|
if (southeast->insert(segment)) return true;
|
|
if (southwest->insert(segment)) return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool hasIntersection(const LineSegment& querySegment) {
|
|
if (!intersects(querySegment, boundary)) {
|
|
return false;
|
|
}
|
|
|
|
for (const auto& segment : segments) {
|
|
if (segmentsIntersect(querySegment, segment)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (divided) {
|
|
if (northeast->hasIntersection(querySegment)) return true;
|
|
if (northwest->hasIntersection(querySegment)) return true;
|
|
if (southeast->hasIntersection(querySegment)) return true;
|
|
if (southwest->hasIntersection(querySegment)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
struct Boundary {
|
|
double x, y, width, height;
|
|
} boundary;
|
|
|
|
int capacity;
|
|
std::vector<LineSegment> segments;
|
|
bool divided;
|
|
QuadTreeNode* northeast;
|
|
QuadTreeNode* northwest;
|
|
QuadTreeNode* southeast;
|
|
QuadTreeNode* southwest;
|
|
|
|
void subdivide() {
|
|
double x = boundary.x;
|
|
double y = boundary.y;
|
|
double w = boundary.width / 2;
|
|
double h = boundary.height / 2;
|
|
|
|
northeast = new QuadTreeNode(x + w, y, w, h, capacity);
|
|
northwest = new QuadTreeNode(x, y, w, h, capacity);
|
|
southeast = new QuadTreeNode(x + w, y + h, w, h, capacity);
|
|
southwest = new QuadTreeNode(x, y + h, w, h, capacity);
|
|
divided = true;
|
|
}
|
|
|
|
bool intersects(const LineSegment& segment, const Boundary& boundary) {
|
|
double minX = segment.start.x;
|
|
double maxX = segment.end.x;
|
|
if (maxX < minX) {
|
|
minX = segment.end.x;
|
|
maxX = segment.start.x;
|
|
}
|
|
double minY = segment.start.y;
|
|
double maxY = segment.end.y;
|
|
if (maxY < minY)
|
|
{
|
|
minY = segment.end.y;
|
|
maxY = segment.start.y;
|
|
}
|
|
|
|
return !(minX > boundary.x + boundary.width || maxX < boundary.x ||
|
|
minY > boundary.y + boundary.height || maxY < boundary.y);
|
|
}
|
|
|
|
bool segmentsIntersect(const LineSegment& seg1, const LineSegment& seg2) {
|
|
auto orientation = [](const PointT& p, const PointT& q, const PointT& r) {
|
|
double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
if ((std::abs)(val) < 1.0E-5) return 0; // collinear
|
|
return (val > 0.0) ? 1 : 2; // clock or counterclock wise
|
|
};
|
|
|
|
auto onSegment = [](const PointT& p, const PointT& q, const PointT& r) {
|
|
return q.x <= (std::max)(p.x, r.x) && q.x >= (std::min)(p.x, r.x) &&
|
|
q.y <= (std::max)(p.y, r.y) && q.y >= (std::min)(p.y, r.y);
|
|
};
|
|
|
|
PointT p1 = seg1.start, q1 = seg1.end;
|
|
PointT p2 = seg2.start, q2 = seg2.end;
|
|
|
|
int o1 = orientation(p1, q1, p2);
|
|
int o2 = orientation(p1, q1, q2);
|
|
int o3 = orientation(p2, q2, p1);
|
|
int o4 = orientation(p2, q2, q1);
|
|
|
|
if (o1 != o2 && o3 != o4)
|
|
return true;
|
|
|
|
if (o1 == 0 && onSegment(p1, p2, q1)) return true;
|
|
if (o2 == 0 && onSegment(p1, q2, q1)) return true;
|
|
if (o3 == 0 && onSegment(p2, p1, q2)) return true;
|
|
if (o4 == 0 && onSegment(p2, q1, q2)) return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class CQuadTree
|
|
{
|
|
public:
|
|
CQuadTree(double x, double y, double width, double height, int capacity)
|
|
: root(new QuadTreeNode(x, y, width, height, capacity)) {}
|
|
|
|
void insert(const LineSegment& segment) {
|
|
root->insert(segment);
|
|
}
|
|
|
|
//void remove(const LineSegment& segment) {
|
|
// root->remove(segment);
|
|
//}
|
|
|
|
bool hasIntersection(const LineSegment& querySegment) {
|
|
return root->hasIntersection(querySegment);
|
|
}
|
|
|
|
private:
|
|
QuadTreeNode* root;
|
|
};
|
|
|
|
//bool operator==(const LineSegment& lhs, const LineSegment& rhs) {
|
|
// return lhs.start.x == rhs.start.x && lhs.start.y == rhs.start.y &&
|
|
// lhs.end.x == rhs.end.x && lhs.end.y == rhs.end.y;
|
|
//}
|
|
|
|
|