142 lines
3.7 KiB
C++
142 lines
3.7 KiB
C++
#ifndef AIRPORT_SPATIAL_QUADTREE_H
|
||
#define AIRPORT_SPATIAL_QUADTREE_H
|
||
|
||
#include <vector>
|
||
#include <memory>
|
||
#include "types/VehicleData.h"
|
||
|
||
// 定义矩形区域
|
||
struct Bounds {
|
||
double x; // 左上角x坐标
|
||
double y; // 左上角y坐标
|
||
double width; // 宽度
|
||
double height; // 高度
|
||
|
||
bool contains(const Vector2D& point) const {
|
||
return point.x >= x && point.x <= (x + width) &&
|
||
point.y >= y && point.y <= (y + height);
|
||
}
|
||
|
||
bool intersects(const Bounds& other) const {
|
||
return !(other.x > (x + width) ||
|
||
(other.x + other.width) < x ||
|
||
other.y > (y + height) ||
|
||
(other.y + other.height) < y);
|
||
}
|
||
};
|
||
|
||
template<typename T>
|
||
class QuadTree {
|
||
public:
|
||
explicit QuadTree(const Bounds& bounds, int capacity = 4)
|
||
: bounds_(bounds), capacity_(capacity) {}
|
||
|
||
void insert(const T& item) {
|
||
if (!bounds_.contains(getPosition(item))) {
|
||
return;
|
||
}
|
||
|
||
if (items_.size() < capacity_ && !divided_) {
|
||
items_.push_back(item);
|
||
return;
|
||
}
|
||
|
||
if (!divided_) {
|
||
subdivide();
|
||
}
|
||
|
||
northwest_->insert(item);
|
||
northeast_->insert(item);
|
||
southwest_->insert(item);
|
||
southeast_->insert(item);
|
||
}
|
||
|
||
std::vector<T> queryRange(const Bounds& range) const {
|
||
std::vector<T> found;
|
||
if (!bounds_.intersects(range)) {
|
||
return found;
|
||
}
|
||
|
||
for (const auto& item : items_) {
|
||
if (range.contains(getPosition(item))) {
|
||
found.push_back(item);
|
||
}
|
||
}
|
||
|
||
if (divided_) {
|
||
auto nw = northwest_->queryRange(range);
|
||
auto ne = northeast_->queryRange(range);
|
||
auto sw = southwest_->queryRange(range);
|
||
auto se = southeast_->queryRange(range);
|
||
|
||
found.insert(found.end(), nw.begin(), nw.end());
|
||
found.insert(found.end(), ne.begin(), ne.end());
|
||
found.insert(found.end(), sw.begin(), sw.end());
|
||
found.insert(found.end(), se.begin(), se.end());
|
||
}
|
||
|
||
return found;
|
||
}
|
||
|
||
std::vector<T> queryNearby(const Vector2D& point, double radius) const {
|
||
Bounds range{
|
||
point.x - radius,
|
||
point.y - radius,
|
||
radius * 2,
|
||
radius * 2
|
||
};
|
||
return queryRange(range);
|
||
}
|
||
|
||
void clear() {
|
||
items_.clear();
|
||
divided_ = false;
|
||
northwest_.reset();
|
||
northeast_.reset();
|
||
southwest_.reset();
|
||
southeast_.reset();
|
||
}
|
||
|
||
private:
|
||
Bounds bounds_;
|
||
int capacity_;
|
||
std::vector<T> items_;
|
||
bool divided_ = false;
|
||
|
||
std::unique_ptr<QuadTree> northwest_;
|
||
std::unique_ptr<QuadTree> northeast_;
|
||
std::unique_ptr<QuadTree> southwest_;
|
||
std::unique_ptr<QuadTree> southeast_;
|
||
|
||
void subdivide() {
|
||
double x = bounds_.x;
|
||
double y = bounds_.y;
|
||
double w = bounds_.width / 2;
|
||
double h = bounds_.height / 2;
|
||
|
||
Bounds nw{x, y, w, h};
|
||
northwest_ = std::make_unique<QuadTree>(nw, capacity_);
|
||
|
||
Bounds ne{x + w, y, w, h};
|
||
northeast_ = std::make_unique<QuadTree>(ne, capacity_);
|
||
|
||
Bounds sw{x, y + h, w, h};
|
||
southwest_ = std::make_unique<QuadTree>(sw, capacity_);
|
||
|
||
Bounds se{x + w, y + h, w, h};
|
||
southeast_ = std::make_unique<QuadTree>(se, capacity_);
|
||
|
||
divided_ = true;
|
||
}
|
||
|
||
// 获取对象的位置
|
||
static Vector2D getPosition(const T& item) {
|
||
if constexpr (std::is_same_v<T, VehicleData>) {
|
||
return item.position;
|
||
} else {
|
||
return item.getPosition(); // 对于其他类型,假设有getPosition方法
|
||
}
|
||
}
|
||
};
|
||
|
||
#endif // AIRPORT_SPATIAL_QUADTREE_H
|