QDAirPortTestSystemBackend/src/detector/CollisionDetector.cpp
2026-02-04 10:22:05 +08:00

512 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "CollisionDetector.h"
#include "config/SystemConfig.h"
#include "utils/Logger.h"
#include <algorithm>
#include <cmath>
#include <unordered_set>
CollisionDetector::CollisionDetector(const AirportBounds& bounds, const ControllableVehicles& controllableVehicles)
: airportBounds_(bounds),
vehicleTree_(bounds.getAirportBounds(), 8), // 使用机场总边界初始化四叉树
controllableVehicles_(&controllableVehicles) {
// 记录初始化信息
const auto& airportBounds = bounds.getAirportBounds();
}
void CollisionDetector::updateTraffic(const std::vector<Aircraft>& aircraft,
const std::vector<Vehicle>& vehicles) {
Logger::debug("更新交通数据: 航空器数量=", aircraft.size(),
", 车辆数量=", vehicles.size());
// 更新航空器数据
aircraftData_ = aircraft;
// 更新车辆四叉树
vehicleTree_.clear();
size_t validVehicles = 0;
for (const auto& vehicle : vehicles) {
// 首先检查车辆是否在机场边界内
if (!airportBounds_.isPointInBounds(vehicle.position)) {
Logger::error("车辆在机场边界外: id=", vehicle.id, ", position=(",
vehicle.position.x, ",", vehicle.position.y, ")");
continue; // 跳过边界外的车辆
}
// 根据运行时注册表设置车辆类型
Vehicle updatedVehicle = vehicle;
bool controllable = controllableVehicles_ && controllableVehicles_->isControllable(vehicle.vehicleNo);
updatedVehicle.type = controllable ? MovingObjectType::UNMANNED : MovingObjectType::SPECIAL;
updatedVehicle.isControllable = controllable;
// 插入四叉树
try {
vehicleTree_.insert(updatedVehicle);
++validVehicles;
} catch (const std::exception& e) {
Logger::error("无法插入车辆到四叉树: id=", updatedVehicle.id,
", error=", e.what());
}
}
// 记录更新后的状态
auto bounds = vehicleTree_.getBounds();
Logger::debug("四叉树边界: min=(", bounds.x, ",", bounds.y, "), max=(",
bounds.x + bounds.width, ",", bounds.y + bounds.height, ")");
auto allVehicles = vehicleTree_.queryRange(bounds);
Logger::debug("交通数据更新完成: 有效车辆数量=", validVehicles,
", 四叉树中的车辆数量=", allVehicles.size());
}
std::vector<CollisionRisk> CollisionDetector::detectCollisions() {
std::vector<CollisionRisk> risks;
// 获取配置参数
const auto& predictionConfig =
SystemConfig::instance().collision_detection.prediction;
// 获取所有车辆
auto allVehicles = vehicleTree_.queryRange(vehicleTree_.getBounds());
// 前端注册表内的受管车辆WUREN + TEQIN
std::vector<Vehicle> managedVehicles;
managedVehicles.reserve(allVehicles.size());
for (const auto& vehicle : allVehicles) {
if (controllableVehicles_) {
if (controllableVehicles_->isManagedVehicle(vehicle.vehicleNo)) {
managedVehicles.push_back(vehicle);
}
} else {
// 兼容:若未提供注册表,则仅按可控标记处理
if (vehicle.isControllable) {
managedVehicles.push_back(vehicle);
}
}
}
// 记录当前检测到的冲突对
std::unordered_set<std::pair<std::string, std::string>, CollisionPairHash>
currentCollisions;
// 检测受管车辆与航空器的碰撞
for (const auto& aircraft : aircraftData_) {
for (const auto& vehicle : managedVehicles) {
// 获取冲突记录键
auto collisionKey = getCollisionKey(aircraft.id, vehicle.id);
// 获取区域配置
const auto& areaConfig = getCollisionParams(aircraft.position);
double safeDistance = areaConfig.getThresholds(aircraft.type, vehicle.type).warning;
// 检查是否存在未解除的冲突记录
auto it = collisionRecords_.find(collisionKey);
bool hasUnresolvedConflict =
(it != collisionRecords_.end() && !it->second.resolved);
if (hasUnresolvedConflict) {
Logger::debug("存在未解除的冲突记录: obj1=", aircraft.id,
", obj2=", vehicle.id, ", maxLevel=",
static_cast<int>(it->second.maxLevel),
", collisionPoint=(", it->second.collisionPoint.x,
",", it->second.collisionPoint.y, ")");
}
// 检测碰撞
auto collisionResult =
checkCollision(aircraft, vehicle, predictionConfig.time_window);
// 计算相对运动
MovementVector av(aircraft.speed, aircraft.heading);
MovementVector vv(vehicle.speed, vehicle.heading);
double vx = av.vx - vv.vx;
double vy = av.vy - vv.vy;
double relativeSpeed = std::sqrt(vx * vx + vy * vy);
// 评估风险等级
auto [level, zoneType] =
evaluateRisk(collisionResult, aircraft.position, aircraft.type,
vehicle.type);
if (level != RiskLevel::NONE) {
// 记录或更新冲突信息
auto& record = collisionRecords_[collisionKey];
if (!record.resolved) {
// 更新已存在的冲突记录
record.maxLevel = std::max(record.maxLevel, level);
record.collisionPoint =
collisionResult.collisionPoint; // 更新冲突点
Logger::debug("更新冲突记录: obj1=", aircraft.id,
", obj2=", vehicle.id, ", maxLevel=",
static_cast<int>(record.maxLevel),
", collisionPoint=(", record.collisionPoint.x,
",", record.collisionPoint.y, ")");
} else {
// 创建新的冲突记录
record = { collisionResult
.collisionPoint, // 使用当前检测到的冲突点
std::chrono::system_clock::now()
.time_since_epoch()
.count(),
level, false };
Logger::debug("创建新的冲突记录: obj1=", aircraft.id,
", obj2=", vehicle.id,
", level=", static_cast<int>(level),
", collisionPoint=(",
collisionResult.collisionPoint.x, ",",
collisionResult.collisionPoint.y, ")");
}
// 添加到当前冲突集合
currentCollisions.insert(collisionKey);
// 添加到风险列表
risks.push_back({ aircraft.id,
vehicle.id,
level,
collisionResult.distance,
collisionResult.minDistance,
relativeSpeed,
{vx, vy},
zoneType,
collisionResult.timeToCollision,
collisionResult.collisionPoint });
Logger::debug(
"检测到碰撞风险: obj1=", aircraft.id, ", obj2=", vehicle.id,
", minDistance=", collisionResult.minDistance, "m",
", timeToCollision=", collisionResult.timeToCollision, "s",
", level=", static_cast<int>(level));
} else if (hasUnresolvedConflict) {
// 检查是否满足解除条件
if (checkCollisionResolved(aircraft, vehicle, it->second,
safeDistance)) {
it->second.resolved = true;
Logger::debug("冲突已解除: obj1=", aircraft.id,
", obj2=", vehicle.id);
} else {
// 虽然当前没有检测到风险,但由于未满足解除条件,继续保持原有风险等级
currentCollisions.insert(collisionKey);
risks.push_back({ aircraft.id,
vehicle.id,
it->second.maxLevel,
collisionResult.distance,
collisionResult.minDistance,
relativeSpeed,
{vx, vy},
zoneType,
collisionResult.timeToCollision,
it->second.collisionPoint });
Logger::debug(
"保持原有风险等级: obj1=", aircraft.id,
", obj2=", vehicle.id,
", maxLevel=", static_cast<int>(it->second.maxLevel),
", minDistance=", collisionResult.minDistance, "m",
", timeToCollision=", collisionResult.timeToCollision,
"s");
}
}
}
}
// 清理已解除的冲突记录
for (auto it = collisionRecords_.begin(); it != collisionRecords_.end();) {
if (it->second.resolved) {
it = collisionRecords_.erase(it);
} else {
++it;
}
}
return risks;
}
bool CollisionDetector::checkCollisionResolved(const MovingObject& obj1,
const MovingObject& obj2,
const CollisionRecord& record,
double safeDistance) const {
// 计算航空器与冲突点的距离
double dist1 =
std::sqrt(std::pow(obj1.position.x - record.collisionPoint.x, 2) +
std::pow(obj1.position.y - record.collisionPoint.y, 2));
double dist2 =
std::sqrt(std::pow(obj2.position.x - record.collisionPoint.x, 2) +
std::pow(obj2.position.y - record.collisionPoint.y, 2));
// 计算冲突点相对于航空器的位置向量与航空器航向的夹角
double dx =
record.collisionPoint.x - obj1.position.x; // 冲突点相对于航空器的向量
double dy = record.collisionPoint.y - obj1.position.y;
double pointAngle =
std::atan2(dy, dx) * 180.0 / M_PI; // 冲突点相对于航空器的角度
double angleDiff =
normalizeAngle(pointAngle - (90.0 - obj1.heading)); // 修正航向角
Logger::debug("检查冲突解除条件: 航空器位置=(", obj1.position.x, ",",
obj1.position.y, "), 冲突点=(", record.collisionPoint.x, ",",
record.collisionPoint.y, "), 航向=", obj1.heading,
", 冲突点角度=", pointAngle, ", 角度差=", angleDiff,
", 距离=", dist1);
// 判断航空器是否已经通过交叉点
if (angleDiff > 90 && angleDiff < 270) {
// 航空器已经通过交叉点,只要航空器离开冲突点的距离大于安全距离就可以解除
Logger::debug("航空器已通过交叉点,航空器距离=", dist1,
"m, 安全距离=", safeDistance, "m");
return dist1 >= safeDistance;
} else {
// 航空器还未通过交叉点,需要两者都在安全距离外且预计不会碰撞
auto collisionResult =
checkCollision(obj1, obj2, 30.0); // 使用30秒的预测窗口
bool willCollide = collisionResult.willCollide;
bool bothOutside = (dist1 >= safeDistance && dist2 >= safeDistance);
Logger::debug("航空器未通过交叉点,航空器距离=", dist1,
"m, 无人车距离=", dist2, "m, 安全距离=", safeDistance,
"m, 预测碰撞=", willCollide ? "" : "");
return !willCollide && bothOutside;
}
}
// 统一的风险评估函数
std::pair<RiskLevel, WarningZoneType> CollisionDetector::evaluateRisk(
const CollisionResult& collisionResult, const Vector2D& position,
MovingObjectType type1, MovingObjectType type2) const {
// 取区域配置
const auto& areaConfig = getCollisionParams(position);
auto thresholds = areaConfig.getThresholds(type1, type2);
RiskLevel level = RiskLevel::NONE;
WarningZoneType zoneType = WarningZoneType::NONE;
// 如果预测到碰撞,根据当前距离判断风险等级
if (collisionResult.willCollide) {
// 当前距离小于警报距离 -> 危险等级
if (collisionResult.distance <= thresholds.critical) {
level = RiskLevel::CRITICAL;
zoneType = WarningZoneType::DANGER;
}
// 当前距离在预警范围内 -> 预警等级
else if (collisionResult.distance <= thresholds.warning) {
level = RiskLevel::WARNING;
zoneType = WarningZoneType::WARNING;
}
}
// 修改日志,添加物体类型信息
Logger::debug("风险评估: 物体1类型=", static_cast<int>(type1),
", 物体2类型=", static_cast<int>(type2),
", 当前距离=", collisionResult.distance,
"m, 预测最小距离=", collisionResult.minDistance,
"m, 预警阈值=", thresholds.warning,
"m, 警报阈值=", thresholds.critical,
"m, 预测碰撞=", collisionResult.willCollide ? "" : "",
", 风险等级=", static_cast<int>(level),
", 区域类型=", static_cast<int>(zoneType));
return { level, zoneType };
}
// 统一的碰撞检测函数
CollisionResult CollisionDetector::checkCollision(const MovingObject& obj1,
const MovingObject& obj2,
double timeWindow) const {
// 添加物体信息日志
Logger::debug("检查碰撞: obj1[", obj1.id, "]=(", obj1.position.x, ",",
obj1.position.y, "), obj2[", obj2.id, "]=(", obj2.position.x,
",", obj2.position.y, ")");
// 获取区域配置
const auto& areaConfig = getCollisionParams(obj1.position);
// 获取各自的碰撞半径和警告半径
double radius1 = areaConfig.collision_radius.getRadius(obj1.type);
double radius2 = areaConfig.collision_radius.getRadius(obj2.type);
double warning_radius1 =
areaConfig.warning_zone_radius.getRadius(obj1.type);
double warning_radius2 =
areaConfig.warning_zone_radius.getRadius(obj2.type);
// 计算当前距离
double dx = obj2.position.x - obj1.position.x;
double dy = obj2.position.y - obj1.position.y;
double current_distance = std::sqrt(dx * dx + dy * dy);
// 高度阈值过滤:飞机高于阈值时,不参与地面二维碰撞判断
if (areaConfig.height_threshold > 0.0) {
if (obj1.isAircraft()) {
const auto& ac = static_cast<const Aircraft&>(obj1);
if (std::isfinite(ac.altitude) && ac.altitude > areaConfig.height_threshold) {
CollisionResult result;
result.willCollide = false;
result.minDistance = current_distance;
result.distance = current_distance;
result.timeToMinDistance = 0.0;
return result;
}
}
if (obj2.isAircraft()) {
const auto& ac = static_cast<const Aircraft&>(obj2);
if (std::isfinite(ac.altitude) && ac.altitude > areaConfig.height_threshold) {
CollisionResult result;
result.willCollide = false;
result.minDistance = current_distance;
result.distance = current_distance;
result.timeToMinDistance = 0.0;
return result;
}
}
}
// 如果是静止的无人车,使用基础速度
double speed1_calc = obj1.speed;
double speed2_calc = obj2.speed;
if (obj1.type == MovingObjectType::UNMANNED && speed1_calc < 0.1) {
speed1_calc = SystemConfig::instance()
.collision_detection.prediction
.min_unmanned_speed; // 使用配置的最低速度
}
if (obj2.type == MovingObjectType::UNMANNED && speed2_calc < 0.1) {
speed2_calc = SystemConfig::instance()
.collision_detection.prediction
.min_unmanned_speed; // 使用配置的最低速度
}
// 计算速度分量
double vx1 =
speed1_calc * std::cos((90.0 - obj1.heading) * M_PI / 180.0); // x 方向
double vy1 =
speed1_calc * std::sin((90.0 - obj1.heading) * M_PI / 180.0); // y 方向
double vx2 = speed2_calc * std::cos((90.0 - obj2.heading) * M_PI / 180.0);
double vy2 = speed2_calc * std::sin((90.0 - obj2.heading) * M_PI / 180.0);
// 如果当前距离大于警告区域,直接返回不会碰撞
if (current_distance > (warning_radius1 + warning_radius2)) {
CollisionResult result;
result.willCollide = false;
result.minDistance = current_distance;
result.distance = current_distance;
return result;
}
// 否则进行碰撞检测
return predictCircleBasedCollision(obj1.position, radius1, speed1_calc,
obj1.heading, obj2.position, radius2,
speed2_calc, obj2.heading, timeWindow);
}
CollisionResult CollisionDetector::predictCircleBasedCollision(
const Vector2D& pos1, double radius1, double speed1, double heading1,
const Vector2D& pos2, double radius2, double speed2, double heading2,
double timeWindow) const {
CollisionResult result;
const double safe_distance = radius1 + radius2;
const double dx = pos2.x - pos1.x;
const double dy = pos2.y - pos1.y;
const double current_distance = std::sqrt(dx * dx + dy * dy);
result.distance = current_distance;
result.minDistance = current_distance;
result.timeToMinDistance = 0.0;
// 碰撞类型仅用于标记,不影响连续时间的圆形碰撞求解
if (speed1 < 0.1 && speed2 < 0.1) {
result.type = CollisionType::STATIC;
} else {
double angle_diff = getAngleDifference(heading1, heading2);
if (angle_diff > 150.0) {
result.type = CollisionType::HEAD_ON;
} else if (angle_diff > 15.0 && angle_diff < 165.0) {
result.type = CollisionType::CROSSING;
} else {
result.type = CollisionType::PARALLEL;
}
}
// 当前已经重叠
if (current_distance <= safe_distance) {
result.willCollide = true;
result.timeToCollision = 0.0;
result.minDistance = current_distance;
result.timeToMinDistance = 0.0;
result.collisionPoint = { (pos1.x + pos2.x) / 2.0,
(pos1.y + pos2.y) / 2.0 };
result.object1State = CollisionObjectState(pos1, speed1, heading1);
result.object2State = CollisionObjectState(pos2, speed2, heading2);
return result;
}
// 速度分量航向正北0度顺时针增加x=东y=北)
const double h1 = heading1 * M_PI / 180.0;
const double h2 = heading2 * M_PI / 180.0;
const Vector2D v1{ speed1 * std::sin(h1), speed1 * std::cos(h1) };
const Vector2D v2{ speed2 * std::sin(h2), speed2 * std::cos(h2) };
const Vector2D r0{ dx, dy };
const Vector2D v{ v2.x - v1.x, v2.y - v1.y };
const double a = v.x * v.x + v.y * v.y;
const double rv = r0.x * v.x + r0.y * v.y;
// 相对速度近似为0距离不会变化
if (a < 1e-9) {
result.object1State = CollisionObjectState(pos1, speed1, heading1);
result.object2State = CollisionObjectState(pos2, speed2, heading2);
return result;
}
// 计算时间窗口内的最小距离
double t_min = -rv / a;
if (t_min < 0.0) t_min = 0.0;
if (t_min > timeWindow) t_min = timeWindow;
const Vector2D r_min{ r0.x + v.x * t_min, r0.y + v.y * t_min };
const double d_min = std::sqrt(r_min.x * r_min.x + r_min.y * r_min.y);
result.minDistance = d_min;
result.timeToMinDistance = t_min;
result.object1State = CollisionObjectState({ pos1.x + v1.x * t_min, pos1.y + v1.y * t_min }, speed1, heading1);
result.object2State = CollisionObjectState({ pos2.x + v2.x * t_min, pos2.y + v2.y * t_min }, speed2, heading2);
// 计算首次进入安全距离的时间(连续时间解析解)
// |r0 + v t|^2 = safe^2 => a t^2 + 2(rv) t + (|r0|^2 - safe^2)=0
const double b = 2.0 * rv;
const double c = (r0.x * r0.x + r0.y * r0.y) - safe_distance * safe_distance;
const double disc = b * b - 4.0 * a * c;
if (disc < 0.0) {
return result;
}
const double sqrt_disc = std::sqrt(disc);
const double inv_2a = 1.0 / (2.0 * a);
double t_hit = (-b - sqrt_disc) * inv_2a;
double t_exit = (-b + sqrt_disc) * inv_2a;
if (t_exit < 0.0) {
return result;
}
if (t_hit < 0.0) {
t_hit = 0.0;
}
if (t_hit > timeWindow) {
return result;
}
result.willCollide = true;
result.timeToCollision = t_hit;
result.timeToMinDistance = std::min(result.timeToMinDistance, t_hit);
result.minDistance = std::min(result.minDistance, safe_distance);
const Vector2D p1_hit{ pos1.x + v1.x * t_hit, pos1.y + v1.y * t_hit };
const Vector2D p2_hit{ pos2.x + v2.x * t_hit, pos2.y + v2.y * t_hit };
result.collisionPoint = { (p1_hit.x + p2_hit.x) / 2.0,
(p1_hit.y + p2_hit.y) / 2.0 };
result.object1State = CollisionObjectState(p1_hit, speed1, heading1);
result.object2State = CollisionObjectState(p2_hit, speed2, heading2);
return result;
}