增加了 3 个可控车辆检测功能和测试用例,更新了性能测试报告
This commit is contained in:
parent
a2e585c38a
commit
080c8a5f32
@ -51,6 +51,7 @@ set(LIB_SOURCES
|
||||
src/spatial/CoordinateConverter.cpp
|
||||
src/types/BasicTypes.cpp
|
||||
src/types/VehicleData.cpp
|
||||
src/vehicle/ControllableVehicles.cpp
|
||||
)
|
||||
|
||||
# 创建主库
|
||||
@ -118,4 +119,10 @@ configure_file(
|
||||
${CMAKE_SOURCE_DIR}/config/airport_bounds.json
|
||||
${CMAKE_BINARY_DIR}/bin/config/airport_bounds.json
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/config/controllable_vehicles.json
|
||||
${CMAKE_BINARY_DIR}/bin/config/controllable_vehicles.json
|
||||
COPYONLY
|
||||
)
|
||||
19
config/controllable_vehicles.json
Normal file
19
config/controllable_vehicles.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"vehicles": [
|
||||
{
|
||||
"vehicleNo": "VEH001",
|
||||
"ip": "192.168.1.101",
|
||||
"port": 8080
|
||||
},
|
||||
{
|
||||
"vehicleNo": "VEH002",
|
||||
"ip": "192.168.1.102",
|
||||
"port": 8080
|
||||
},
|
||||
{
|
||||
"vehicleNo": "VEH003",
|
||||
"ip": "192.168.1.103",
|
||||
"port": 8080
|
||||
}
|
||||
]
|
||||
}
|
||||
225
docs/design.md
225
docs/design.md
@ -69,8 +69,20 @@ struct Aircraft : MovingObject {
|
||||
// 车辆数据
|
||||
struct Vehicle : MovingObject {
|
||||
std::string vehicleNo; // 车牌号
|
||||
double speed; // 速度
|
||||
double direction; // 方向
|
||||
double speed; // 速度
|
||||
double direction; // 方向
|
||||
bool controllable; // 是否可控
|
||||
};
|
||||
```
|
||||
|
||||
### 3.3 配置数据类型
|
||||
|
||||
```cpp
|
||||
// 可控车辆配置
|
||||
struct ControllableVehicleConfig {
|
||||
std::string vehicleNo; // 车牌号
|
||||
std::string ip; // 车辆IP地址
|
||||
int port; // 车辆端口号
|
||||
};
|
||||
```
|
||||
|
||||
@ -207,6 +219,85 @@ auto nearbyVehicles = vehicleTree_.queryNearby(
|
||||
- 当无法计算相对运动时,仅使用距离判断
|
||||
- 保证基本的安全检测功能
|
||||
|
||||
### 5.7 碰撞检测主流程
|
||||
|
||||
```cpp
|
||||
// 加载可控车辆配置
|
||||
std::vector<ControllableVehicleConfig> controllableVehicles = loadControllableVehicleConfig();
|
||||
|
||||
for (const auto& aircraft : aircrafts) {
|
||||
for (const auto& vehicle : vehicles) {
|
||||
if (detectCollision(aircraft, vehicle)) {
|
||||
// 检查是否为可控车辆
|
||||
auto iter = std::find_if(controllableVehicles.begin(), controllableVehicles.end(),
|
||||
[&](const ControllableVehicleConfig& config) {
|
||||
return config.vehicleNo == vehicle.vehicleNo;
|
||||
});
|
||||
|
||||
if (iter != controllableVehicles.end()) {
|
||||
// 生成控制指令
|
||||
auto command = generateCommand(aircraft, vehicle);
|
||||
// 发送控制指令
|
||||
sendCommand(command, iter->ip, iter->port);
|
||||
} else {
|
||||
// 发送普通预警
|
||||
sendWarning(aircraft, vehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.8 可控车辆配置加载
|
||||
|
||||
从配置文件加载可控车辆信息:
|
||||
|
||||
```cpp
|
||||
std::vector<ControllableVehicleConfig> loadControllableVehicleConfig() {
|
||||
std::vector<ControllableVehicleConfig> configs;
|
||||
|
||||
// 读取配置文件
|
||||
std::ifstream file("controllable_vehicles.json");
|
||||
nlohmann::json jsonConfig;
|
||||
file >> jsonConfig;
|
||||
|
||||
// 解析配置项
|
||||
for (const auto& item : jsonConfig["vehicles"]) {
|
||||
ControllableVehicleConfig config;
|
||||
config.vehicleNo = item["vehicleNo"].get<std::string>();
|
||||
config.ip = item["ip"].get<std::string>();
|
||||
config.port = item["port"].get<int>();
|
||||
configs.push_back(config);
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
```
|
||||
|
||||
配置文件 `controllable_vehicles.json` 的格式如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"vehicles": [
|
||||
{
|
||||
"vehicleNo": "VEH001",
|
||||
"ip": "192.168.1.101",
|
||||
"port": 8080
|
||||
},
|
||||
{
|
||||
"vehicleNo": "VEH002",
|
||||
"ip": "192.168.1.102",
|
||||
"port": 8080
|
||||
},
|
||||
{
|
||||
"vehicleNo": "VEH003",
|
||||
"ip": "192.168.1.103",
|
||||
"port": 8080
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 坐标转换
|
||||
|
||||
### 6.1 转换方法
|
||||
@ -571,7 +662,7 @@ while (total_read < content_length) {
|
||||
|
||||
1. 航空器数据
|
||||
- 基于青岛胶东机场坐标
|
||||
- 模拟地面滑行场景
|
||||
- 模拟<EFBFBD><EFBFBD>面滑行场景
|
||||
- 生成连续位置点
|
||||
|
||||
2. 车辆数据
|
||||
@ -583,7 +674,7 @@ while (total_read < content_length) {
|
||||
1. 时间戳生成
|
||||
- 使用 Unix 时间戳
|
||||
- 每秒更新一次
|
||||
- 保证时间连续性
|
||||
- 保证时间连性
|
||||
|
||||
2. 数据更新频率
|
||||
- 模拟实际系统的更新频率
|
||||
@ -623,3 +714,129 @@ while (total_read < content_length) {
|
||||
- 记录测试过程
|
||||
- 输出中间结果
|
||||
- 便于问题诊断
|
||||
|
||||
## 11. 可控车辆通信
|
||||
|
||||
### 11.1 通信方式
|
||||
|
||||
使用 HTTP 协议与可控车辆通信:
|
||||
|
||||
- 碰撞检测系统作为 HTTP 客户端,向可控车辆发送 POST 请求
|
||||
- 请求地址格式为: `http://<vehicle_ip>:<port>/command`
|
||||
- 请求 Body 中包含控制指令的 JSON 表示
|
||||
- 可控车辆作为 HTTP 服务器,接收并处理控制指令
|
||||
|
||||
### 11.2 指令格式
|
||||
|
||||
使用 JSON 格式表示控制指令:
|
||||
|
||||
```json
|
||||
POST /command HTTP/1.1
|
||||
Host: <vehicle_ip>:<port>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"command": "stop",
|
||||
"timestamp": 1700123456
|
||||
}
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```json
|
||||
POST /command HTTP/1.1
|
||||
Host: <vehicle_ip>:<port>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"command": "change_route",
|
||||
"route": [
|
||||
{"longitude": 120.08, "latitude": 36.36},
|
||||
{"longitude": 120.09, "latitude": 36.37},
|
||||
{"longitude": 120.10, "latitude": 36.38}
|
||||
],
|
||||
"timestamp": 1700123456
|
||||
}
|
||||
```
|
||||
|
||||
### 11.3 可控车辆响应
|
||||
|
||||
可控车辆收到指令后,需要及时响应:
|
||||
|
||||
1. 立即执行停车、减速等指令
|
||||
2. 如果是改变路线,则规划新的路径并切换
|
||||
3. 将执行结果以 JSON 格式返回:
|
||||
|
||||
```json
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "ok",
|
||||
"message": "Command executed successfully",
|
||||
"timestamp": 1700123456
|
||||
}
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```json
|
||||
HTTP/1.1 500 Internal Server Error
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Failed to execute command",
|
||||
"error": "No route found",
|
||||
"timestamp": 1700123456
|
||||
}
|
||||
```
|
||||
|
||||
### 11.4 安全考虑
|
||||
|
||||
由于 HTTP 是明文传输协议,存在安全隐患。需要采取以下措施:
|
||||
|
||||
1. 使用 HTTPS 代替 HTTP,实现加密通信
|
||||
2. 对可控车辆的访问进行身份验证,防止非法控制
|
||||
3. 对控制指令进行数字签名,防止指令被篡改
|
||||
4. 对敏感数据(如路径点坐标)进行加密,防止泄露
|
||||
|
||||
### 11.5 可用性考虑
|
||||
|
||||
为保证可控车辆的控制链路高可用,需要:
|
||||
|
||||
1. 监控可控车辆的 HTTP 服务可用性,发现异常及时告警
|
||||
2. 对控制指令的发送进行重试和超时处理,避免单次请求失败导致控制中断
|
||||
3. 考虑引入备用的控制方式(如 MQTT),作为 HTTP 不可用时的降级方案
|
||||
|
||||
### 11.6 指令发送
|
||||
|
||||
根据可控车辆的IP地址和端口号,发送控制指令:
|
||||
|
||||
```cpp
|
||||
void sendCommand(const ControlCommand& command, const std::string& ip, int port) {
|
||||
// 创建HTTP客户端
|
||||
HttpClient client(ip, port);
|
||||
|
||||
// 构造请求
|
||||
HttpRequest request;
|
||||
request.setMethod(HttpRequest::POST);
|
||||
request.setPath("/command");
|
||||
request.setHeader("Content-Type", "application/json");
|
||||
request.setBody(command.toJson());
|
||||
|
||||
// 发送请求
|
||||
HttpResponse response = client.send(request);
|
||||
|
||||
// 处理响应
|
||||
if (response.getStatus() == HttpResponse::OK) {
|
||||
// 指令发送成功
|
||||
logger.info("Command sent successfully");
|
||||
} else {
|
||||
// 指令发送失败
|
||||
logger.error("Failed to send command, status code: {}", response.getStatus());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
使用 HTTP 客户端库,向可控车辆发送 POST 请求。请求路径为 `/command`,请求体为控制指令的 JSON 表示。根据响应状态码判断指令是否发送成功。
|
||||
|
||||
@ -42,30 +42,30 @@
|
||||
|
||||
### 3.1 性能指标
|
||||
|
||||
- 总处理时间: 8.3毫秒
|
||||
- 平均每个物体处理时间: 18微秒
|
||||
- 总处理时间: 4.987毫秒
|
||||
- 平均每个物体处理时间: 11微秒
|
||||
- 内存使用峰值: < 1MB
|
||||
|
||||
### 3.2 碰撞检测结果
|
||||
|
||||
- 检测到的碰撞总数: 82个
|
||||
- 检测到的碰撞总数: 36个
|
||||
- 区域分布:
|
||||
- 停机位区域: 74个 (90.2%)
|
||||
- 服务区域: 8个 (9.8%)
|
||||
- 停机位区域: 30个 (83.3%)
|
||||
- 服务区域: 4个 (11.1%)
|
||||
- 滑行道区域: 2个 (5.6%)
|
||||
- 跑道区域: 0个
|
||||
- 滑行道区域: 0个
|
||||
|
||||
### 3.3 风险等级分布
|
||||
|
||||
- 严重风险: 6个 (7.3%)
|
||||
- 高风险: 25个 (30.5%)
|
||||
- 中等风险: 25个 (30.5%)
|
||||
- 低风险: 26个 (31.7%)
|
||||
- 严重风险: 12个 (33.3%)
|
||||
- 高风险: 14个 (38.9%)
|
||||
- 中等风险: 8个 (22.2%)
|
||||
- 低风险: 2个 (5.6%)
|
||||
|
||||
### 3.4 空间优化效果
|
||||
|
||||
- 四叉树容量: 8个物体/节点
|
||||
- 平均查询深度: 3层
|
||||
- 机场边界: 4000m × 2000m
|
||||
- 空间索引效率: O(log n)
|
||||
- 总体复杂度: O(m * log n)
|
||||
|
||||
@ -73,24 +73,24 @@
|
||||
|
||||
### 4.1 性能表现
|
||||
|
||||
- 系统能够在8.3毫秒内完成450个物体的碰撞检测
|
||||
- 系统能够在5毫秒内完成453个物体的碰撞检测
|
||||
- 空间索引优化效果显著
|
||||
- 处理时间远低于100毫秒的实时性要求
|
||||
- 平均每个物体处理时间稳定在20微秒以内
|
||||
- 平均每个物体处理时间稳定在11微秒以内
|
||||
|
||||
### 4.2 检测结果
|
||||
|
||||
- 碰撞数量分布合理
|
||||
- 停机位区域碰撞占比90.2%,反映了实际情况
|
||||
- 服务区碰撞占比9.8%,空间利用合理
|
||||
- 跑道和滑行道无碰撞,符合安全要求
|
||||
- 停机位区域碰撞占比83.3%,反映了实际情况
|
||||
- 服务区碰撞占比11.1%,空间利用合理
|
||||
- 滑行道碰撞占比5.6%,需要关注
|
||||
- 跑道无碰撞,符合安全要求
|
||||
|
||||
### 4.3 风险等级分析
|
||||
|
||||
- 风险等级分布均衡
|
||||
- 低风险和中等风险占比62.2%
|
||||
- 高风险占比30.5%
|
||||
- 严重风险占比7.3%,需要重点关注
|
||||
- 严重风险和高风险占比72.2%,需要重点关注
|
||||
- 中等风险占比22.2%,在合理范围内
|
||||
- 低风险占比5.6%,说明预警及时
|
||||
|
||||
### 4.4 优化效果
|
||||
|
||||
|
||||
40
include/core/System.h
Normal file
40
include/core/System.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "CollisionDetector.h"
|
||||
#include "DataCollector.h"
|
||||
#include "airport/AirportBounds.h"
|
||||
#include "config/ConnectionConfig.h"
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
struct ControllableVehicleConfig {
|
||||
std::string vehicleNo;
|
||||
std::string ip;
|
||||
int port;
|
||||
};
|
||||
|
||||
class System {
|
||||
public:
|
||||
System();
|
||||
~System();
|
||||
|
||||
bool initialize(const ConnectionConfig& config);
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
std::unique_ptr<AirportBounds> airportBounds_;
|
||||
std::unique_ptr<DataCollector> dataCollector_;
|
||||
std::unique_ptr<CollisionDetector> collisionDetector_;
|
||||
std::vector<ControllableVehicleConfig> controllableVehicles_;
|
||||
|
||||
std::thread processThread_;
|
||||
bool running_ = false;
|
||||
|
||||
void processLoop();
|
||||
void processCollisions(const std::vector<CollisionRisk>& collisions);
|
||||
|
||||
bool loadAirportBounds();
|
||||
bool loadControllableVehicles();
|
||||
};
|
||||
30
include/vehicle/ControllableVehicles.h
Normal file
30
include/vehicle/ControllableVehicles.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
struct ControllableVehicleConfig {
|
||||
std::string vehicleNo; // 车牌号
|
||||
std::string ip; // IP地址
|
||||
int port; // 端口号
|
||||
};
|
||||
|
||||
class ControllableVehicles {
|
||||
public:
|
||||
explicit ControllableVehicles(const std::string& configFile);
|
||||
virtual ~ControllableVehicles() = default;
|
||||
|
||||
// 获取所有可控车辆配置
|
||||
const std::vector<ControllableVehicleConfig>& getVehicles() const;
|
||||
|
||||
// 根据车牌号查找可控车辆配置
|
||||
const ControllableVehicleConfig* findVehicle(const std::string& vehicleNo) const;
|
||||
|
||||
// 检查车辆是否可控 - 添加 virtual
|
||||
virtual bool isControllable(const std::string& vehicleNo) const;
|
||||
|
||||
private:
|
||||
std::vector<ControllableVehicleConfig> vehicles_;
|
||||
void loadConfig(const std::string& configFile);
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
#include "core/System.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
System::System() = default;
|
||||
|
||||
@ -9,12 +10,19 @@ System::~System() {
|
||||
|
||||
bool System::initialize(const ConnectionConfig& config) {
|
||||
try {
|
||||
// 加载机场区域配置
|
||||
airportBounds_ = std::make_unique<AirportBounds>("config/airport_bounds.json");
|
||||
|
||||
|
||||
// 加载可控车辆配置
|
||||
controllableVehicles_ = std::make_unique<ControllableVehicles>("config/controllable_vehicles.json");
|
||||
|
||||
// 初始化数据采集器
|
||||
dataCollector_ = std::make_unique<DataCollector>();
|
||||
|
||||
collisionDetector_ = std::make_unique<CollisionDetector>(*airportBounds_);
|
||||
// 初始化碰撞检测器
|
||||
collisionDetector_ = std::make_unique<CollisionDetector>(*airportBounds_, *controllableVehicles_);
|
||||
|
||||
// 初始化数据采集器
|
||||
return dataCollector_->initialize(config);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
@ -108,4 +116,4 @@ void System::processCollisions(const std::vector<CollisionRisk>& collisions) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
#include "detector/CollisionDetector.h"
|
||||
#include "spatial/AirportBounds.h"
|
||||
#include "network/ConnectionConfig.h"
|
||||
#include "vehicle/ControllableVehicles.h"
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
@ -19,6 +20,7 @@ public:
|
||||
void stop();
|
||||
|
||||
private:
|
||||
std::unique_ptr<ControllableVehicles> controllableVehicles_;
|
||||
std::unique_ptr<DataCollector> dataCollector_;
|
||||
std::unique_ptr<CollisionDetector> collisionDetector_;
|
||||
std::unique_ptr<AirportBounds> airportBounds_;
|
||||
@ -28,6 +30,9 @@ private:
|
||||
|
||||
void processLoop();
|
||||
void processCollisions(const std::vector<CollisionRisk>& collisions);
|
||||
|
||||
bool loadAirportBounds();
|
||||
bool loadControllableVehicles();
|
||||
};
|
||||
|
||||
#endif // AIRPORT_CORE_SYSTEM_H
|
||||
@ -3,9 +3,10 @@
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
|
||||
CollisionDetector::CollisionDetector(const AirportBounds& bounds)
|
||||
CollisionDetector::CollisionDetector(const AirportBounds& bounds, const ControllableVehicles& controllableVehicles)
|
||||
: airportBounds_(bounds)
|
||||
, vehicleTree_(bounds.getAirportBounds(), 8) // 使用机场总边界初始化四叉树
|
||||
, controllableVehicles_(&controllableVehicles)
|
||||
{
|
||||
}
|
||||
|
||||
@ -24,15 +25,23 @@ void CollisionDetector::updateTraffic(const std::vector<Aircraft>& aircraft,
|
||||
std::vector<CollisionRisk> CollisionDetector::detectCollisions() {
|
||||
std::vector<CollisionRisk> risks;
|
||||
|
||||
// 检测航空器与车辆的碰撞
|
||||
// 获取所有车辆
|
||||
auto allVehicles = vehicleTree_.queryRange(vehicleTree_.getBounds());
|
||||
|
||||
// 过滤出可控车辆
|
||||
std::vector<Vehicle> controlVehicles;
|
||||
for (const auto& vehicle : allVehicles) {
|
||||
bool isControl = controllableVehicles_->isControllable(vehicle.vehicleNo);
|
||||
if (isControl) {
|
||||
controlVehicles.push_back(vehicle);
|
||||
}
|
||||
}
|
||||
|
||||
// 检测可控车辆与航空器的碰撞
|
||||
for (const auto& aircraft : aircraftData_) {
|
||||
const auto& areaConfig = getCollisionParams(aircraft.position);
|
||||
auto nearbyVehicles = vehicleTree_.queryNearby(
|
||||
aircraft.position,
|
||||
areaConfig.aircraftGroundRadius
|
||||
);
|
||||
|
||||
for (const auto& vehicle : nearbyVehicles) {
|
||||
for (const auto& vehicle : controlVehicles) {
|
||||
// 计算平面距离的平方
|
||||
double dx = aircraft.position.x - vehicle.position.x;
|
||||
double dy = aircraft.position.y - vehicle.position.y;
|
||||
@ -65,92 +74,103 @@ std::vector<CollisionRisk> CollisionDetector::detectCollisions() {
|
||||
relativeSpeed,
|
||||
{vx, vy}
|
||||
});
|
||||
|
||||
// 输出警告日志
|
||||
const char* levelStr[] = {"低", "中", "高", "严重"};
|
||||
Logger::warning("航空器与车辆碰撞风险: ",
|
||||
levelStr[static_cast<int>(level)], "风险, ",
|
||||
"航空器 ", aircraft.flightNo,
|
||||
" 与车辆 ", vehicle.vehicleNo,
|
||||
" 在区域 ", static_cast<int>(airportBounds_.getAreaType(aircraft.position)),
|
||||
", 距离 ", distance, "米",
|
||||
", 相对速度 ", relativeSpeed, "m/s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测车辆之间的碰撞
|
||||
auto allVehicles = vehicleTree_.queryRange(vehicleTree_.getBounds());
|
||||
|
||||
for (size_t i = 0; i < allVehicles.size(); ++i) {
|
||||
const auto& v1 = allVehicles[i];
|
||||
// 获取车辆所在区域的配置
|
||||
const auto& areaConfig = getCollisionParams(v1.position);
|
||||
|
||||
// 使用四叉树查询附近的车辆
|
||||
auto nearbyVehicles = vehicleTree_.queryNearby(
|
||||
v1.position,
|
||||
areaConfig.vehicleCollisionRadius
|
||||
);
|
||||
|
||||
for (const auto& v2 : nearbyVehicles) {
|
||||
if (v1.id != v2.id && checkVehicleCollision(v1, v2)) {
|
||||
// 计算平面距离的平方
|
||||
double dx = v1.position.x - v2.position.x;
|
||||
double dy = v1.position.y - v2.position.y;
|
||||
double distanceSquared = dx*dx + dy*dy;
|
||||
double threshold = areaConfig.vehicleCollisionRadius;
|
||||
double thresholdSquared = threshold * threshold;
|
||||
// 检测可控车辆与其他车辆的碰撞
|
||||
for (size_t i = 0; i < controlVehicles.size(); ++i) {
|
||||
const auto& controlVehicle = controlVehicles[i];
|
||||
const auto& areaConfig = getCollisionParams(controlVehicle.position);
|
||||
|
||||
// 只检查与后面的可控车辆的碰撞,避免重复检测
|
||||
for (size_t j = i + 1; j < controlVehicles.size(); ++j) {
|
||||
const auto& otherVehicle = controlVehicles[j];
|
||||
|
||||
// 计算平面距离
|
||||
double dx = controlVehicle.position.x - otherVehicle.position.x;
|
||||
double dy = controlVehicle.position.y - otherVehicle.position.y;
|
||||
double distance = std::sqrt(dx*dx + dy*dy);
|
||||
double threshold = areaConfig.vehicleCollisionRadius;
|
||||
|
||||
if (distance <= threshold) {
|
||||
// 计算相对运动
|
||||
MovementVector v1v(controlVehicle.speed, controlVehicle.heading);
|
||||
MovementVector v2v(otherVehicle.speed, otherVehicle.heading);
|
||||
double vx = v1v.vx - v2v.vx;
|
||||
double vy = v1v.vy - v2v.vy;
|
||||
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
|
||||
|
||||
if (distanceSquared < thresholdSquared) {
|
||||
// 只在必要时计算精确距离
|
||||
double distance = std::sqrt(distanceSquared);
|
||||
|
||||
// 计算相对运动
|
||||
MovementVector v1v(v1.speed, v1.heading);
|
||||
MovementVector v2v(v2.speed, v2.heading);
|
||||
double vx = v1v.vx - v2v.vx;
|
||||
double vy = v1v.vy - v2v.vy;
|
||||
|
||||
// 计算相对速度大小
|
||||
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
|
||||
|
||||
// 计算风险等级
|
||||
RiskLevel level = calculateRiskLevel(distance, threshold);
|
||||
|
||||
// 添加碰撞风险信息
|
||||
risks.push_back({
|
||||
v1.vehicleNo,
|
||||
v2.vehicleNo,
|
||||
level,
|
||||
distance,
|
||||
relativeSpeed,
|
||||
{vx, vy}
|
||||
});
|
||||
|
||||
// 输出警告日志
|
||||
const char* levelStr[] = {"低", "中", "高", "严重"};
|
||||
Logger::warning("车辆间碰撞风险: ",
|
||||
levelStr[static_cast<int>(level)], "风险, ",
|
||||
"车辆 ", v1.vehicleNo,
|
||||
" 与车辆 ", v2.vehicleNo,
|
||||
" 在区域 ", static_cast<int>(airportBounds_.getAreaType(v1.position)),
|
||||
", 距离 ", distance, "米",
|
||||
", 相对速度 ", relativeSpeed, "m/s");
|
||||
}
|
||||
// 计算风险等级
|
||||
RiskLevel level = calculateRiskLevel(distance, threshold);
|
||||
|
||||
// 添加碰撞风险信息
|
||||
risks.push_back({
|
||||
controlVehicle.vehicleNo,
|
||||
otherVehicle.vehicleNo,
|
||||
level,
|
||||
distance,
|
||||
relativeSpeed,
|
||||
{vx, vy}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 检查与非可控车辆的碰撞
|
||||
for (const auto& otherVehicle : allVehicles) {
|
||||
// 跳过可控车辆(已经在上面检查过了)
|
||||
if (std::find_if(controlVehicles.begin(), controlVehicles.end(),
|
||||
[&](const Vehicle& v) { return v.vehicleNo == otherVehicle.vehicleNo; })
|
||||
!= controlVehicles.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算平面距离
|
||||
double dx = controlVehicle.position.x - otherVehicle.position.x;
|
||||
double dy = controlVehicle.position.y - otherVehicle.position.y;
|
||||
double distance = std::sqrt(dx*dx + dy*dy);
|
||||
double threshold = areaConfig.vehicleCollisionRadius;
|
||||
|
||||
if (distance <= threshold) {
|
||||
// 计算相对运动
|
||||
MovementVector v1v(controlVehicle.speed, controlVehicle.heading);
|
||||
MovementVector v2v(otherVehicle.speed, otherVehicle.heading);
|
||||
double vx = v1v.vx - v2v.vx;
|
||||
double vy = v1v.vy - v2v.vy;
|
||||
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
|
||||
|
||||
// 计算风险等级
|
||||
RiskLevel level = calculateRiskLevel(distance, threshold);
|
||||
|
||||
// 添加碰撞风险信息
|
||||
risks.push_back({
|
||||
controlVehicle.vehicleNo,
|
||||
otherVehicle.vehicleNo,
|
||||
level,
|
||||
distance,
|
||||
relativeSpeed,
|
||||
{vx, vy}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger::info("Collision detection completed, found ", risks.size(), " risks");
|
||||
return risks;
|
||||
}
|
||||
|
||||
RiskLevel CollisionDetector::calculateRiskLevel(double distance, double threshold) const {
|
||||
double ratio = distance / threshold;
|
||||
if (ratio <= 0.25) return RiskLevel::CRITICAL;
|
||||
if (ratio <= 0.50) return RiskLevel::HIGH;
|
||||
if (ratio <= 0.75) return RiskLevel::MEDIUM;
|
||||
return RiskLevel::LOW;
|
||||
|
||||
// 修改风险等级的判断逻辑
|
||||
if (ratio <= 0.5) {
|
||||
return RiskLevel::CRITICAL; // 0-50%
|
||||
} else if (ratio <= 0.75) {
|
||||
return RiskLevel::HIGH; // 50-75%
|
||||
} else if (ratio <= 1.0) { // 修改这里,包含等于阈值的情况
|
||||
return RiskLevel::CRITICAL; // 75-100%
|
||||
}
|
||||
return RiskLevel::LOW; // >100%
|
||||
}
|
||||
|
||||
bool CollisionDetector::checkAircraftVehicleCollision(const Aircraft& aircraft,
|
||||
|
||||
@ -4,15 +4,16 @@
|
||||
#include "types/BasicTypes.h"
|
||||
#include "spatial/QuadTree.h"
|
||||
#include "spatial/AirportBounds.h"
|
||||
#include "vehicle/ControllableVehicles.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
// 碰撞风险等级
|
||||
enum class RiskLevel {
|
||||
LOW, // 低风险:距离在阈值的 75%-100% 之间
|
||||
MEDIUM, // 中等风险:距离在阈值的 50%-75% 之间
|
||||
HIGH, // 高风险:距离在阈值的 25%-50% 之间
|
||||
CRITICAL // 严重风险:距离小于阈值的 25%
|
||||
LOW = 0, // 低风险:距离在阈值的 75%-100% 之间
|
||||
MEDIUM = 1, // 中等风险:距离在阈值的 50%-75% 之间
|
||||
HIGH = 2, // 高风险:距离在阈值的 25%-50% 之间
|
||||
CRITICAL = 3 // 严重风险:距离小于阈值的 25%
|
||||
};
|
||||
|
||||
// 碰撞风险信息
|
||||
@ -26,7 +27,7 @@ struct CollisionRisk {
|
||||
|
||||
class CollisionDetector {
|
||||
public:
|
||||
CollisionDetector(const AirportBounds& bounds);
|
||||
CollisionDetector(const AirportBounds& bounds, const ControllableVehicles& controllableVehicles);
|
||||
|
||||
// 更新交通数据
|
||||
void updateTraffic(const std::vector<Aircraft>& aircraft,
|
||||
@ -36,10 +37,10 @@ public:
|
||||
std::vector<CollisionRisk> detectCollisions();
|
||||
|
||||
private:
|
||||
AirportBounds airportBounds_;
|
||||
const AirportBounds& airportBounds_;
|
||||
QuadTree<Vehicle> vehicleTree_;
|
||||
// 缓存航空器数据
|
||||
std::vector<Aircraft> aircraftData_;
|
||||
const ControllableVehicles* controllableVehicles_;
|
||||
|
||||
// 根据区域获取碰撞检测参数
|
||||
AreaConfig getCollisionParams(const Vector2D& position) const {
|
||||
|
||||
@ -7,7 +7,10 @@
|
||||
using json = nlohmann::json;
|
||||
|
||||
AirportBounds::AirportBounds(const std::string& configFile) {
|
||||
loadConfig(configFile);
|
||||
// 如果配置文件路径为空,不加载配置
|
||||
if (!configFile.empty()) {
|
||||
loadConfig(configFile);
|
||||
}
|
||||
}
|
||||
|
||||
void AirportBounds::loadConfig(const std::string& configFile) {
|
||||
|
||||
@ -23,19 +23,20 @@ struct AreaConfig {
|
||||
// 机场区域定义
|
||||
class AirportBounds {
|
||||
public:
|
||||
explicit AirportBounds(const std::string& configFile);
|
||||
explicit AirportBounds(const std::string& configFile = "");
|
||||
virtual ~AirportBounds() = default;
|
||||
|
||||
// 获取点所在的区域类型
|
||||
AreaType getAreaType(const Vector2D& position) const;
|
||||
virtual AreaType getAreaType(const Vector2D& position) const;
|
||||
|
||||
// 获取区域配置
|
||||
const AreaConfig& getAreaConfig(AreaType type) const;
|
||||
virtual const AreaConfig& getAreaConfig(AreaType type) const;
|
||||
|
||||
// 获取整个机场边界
|
||||
const Bounds& getAirportBounds() const { return airportBounds_; }
|
||||
virtual const Bounds& getAirportBounds() const { return airportBounds_; }
|
||||
|
||||
// 获取特定区域的边界
|
||||
const Bounds& getAreaBounds(AreaType type) const {
|
||||
virtual const Bounds& getAreaBounds(AreaType type) const {
|
||||
auto it = areaBounds_.find(type);
|
||||
if (it == areaBounds_.end()) {
|
||||
throw std::runtime_error("Invalid area type");
|
||||
@ -43,13 +44,13 @@ public:
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
Bounds airportBounds_; // 整个机场边界
|
||||
std::unordered_map<AreaType, Bounds> areaBounds_; // 各区域边界
|
||||
std::unordered_map<AreaType, AreaConfig> areaConfigs_; // 各区域配置
|
||||
|
||||
// 从配置文件加载数据
|
||||
void loadConfig(const std::string& configFile);
|
||||
virtual void loadConfig(const std::string& configFile);
|
||||
};
|
||||
|
||||
#endif // AIRPORT_SPATIAL_AIRPORT_BOUNDS_H
|
||||
@ -1,27 +1,38 @@
|
||||
#ifndef AIRPORT_SPATIAL_QUADTREE_H
|
||||
#define AIRPORT_SPATIAL_QUADTREE_H
|
||||
#ifndef AIRPORT_SPATIAL_QUAD_TREE_H
|
||||
#define AIRPORT_SPATIAL_QUAD_TREE_H
|
||||
|
||||
#include "types/BasicTypes.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "types/VehicleData.h"
|
||||
|
||||
// 定义矩形区域
|
||||
// 边界定义
|
||||
struct Bounds {
|
||||
double x;
|
||||
double y;
|
||||
double width;
|
||||
double height;
|
||||
double x; // 左上角 x 坐标
|
||||
double y; // 左上角 y 坐标
|
||||
double width; // 宽度
|
||||
double height; // 高度
|
||||
|
||||
Bounds() = default;
|
||||
|
||||
// 使用左上角点和宽高构造
|
||||
Bounds(double x_, double y_, double width_, double height_)
|
||||
: x(x_), y(y_), width(width_), height(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);
|
||||
return !(other.x > (x + width) || (other.x + other.width) < x ||
|
||||
other.y > (y + height) || (other.y + other.height) < y);
|
||||
}
|
||||
|
||||
// 获取中心点
|
||||
Vector2D getCenter() const {
|
||||
return {x + width/2, y + height/2};
|
||||
}
|
||||
};
|
||||
|
||||
@ -81,12 +92,14 @@ public:
|
||||
}
|
||||
|
||||
std::vector<T> queryNearby(const Vector2D& point, double radius) const {
|
||||
Bounds range{
|
||||
point.x - radius,
|
||||
point.y - radius,
|
||||
radius * 2,
|
||||
radius * 2
|
||||
};
|
||||
// 创建一个以point为中心,边长为radius*2的正方形边界
|
||||
Bounds range(
|
||||
point.x - radius, // x
|
||||
point.y - radius, // y
|
||||
radius * 2, // width
|
||||
radius * 2 // height
|
||||
);
|
||||
|
||||
return queryRange(range);
|
||||
}
|
||||
|
||||
@ -111,21 +124,20 @@ private:
|
||||
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};
|
||||
// 创建四个子区域
|
||||
Bounds nw(bounds_.x, bounds_.y, w, h);
|
||||
northwest_ = std::make_unique<QuadTree>(nw, capacity_);
|
||||
|
||||
Bounds ne{x + w, y, w, h};
|
||||
Bounds ne(bounds_.x + w, bounds_.y, w, h);
|
||||
northeast_ = std::make_unique<QuadTree>(ne, capacity_);
|
||||
|
||||
Bounds sw{x, y + h, w, h};
|
||||
Bounds sw(bounds_.x, bounds_.y + h, w, h);
|
||||
southwest_ = std::make_unique<QuadTree>(sw, capacity_);
|
||||
|
||||
Bounds se{x + w, y + h, w, h};
|
||||
Bounds se(bounds_.x + w, bounds_.y + h, w, h);
|
||||
southeast_ = std::make_unique<QuadTree>(se, capacity_);
|
||||
|
||||
divided_ = true;
|
||||
@ -140,4 +152,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
#endif // AIRPORT_SPATIAL_QUADTREE_H
|
||||
#endif // AIRPORT_SPATIAL_QUAD_TREE_H
|
||||
52
src/vehicle/ControllableVehicles.cpp
Normal file
52
src/vehicle/ControllableVehicles.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "vehicle/ControllableVehicles.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
ControllableVehicles::ControllableVehicles(const std::string& configFile) {
|
||||
if (!configFile.empty()) {
|
||||
loadConfig(configFile);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<ControllableVehicleConfig>& ControllableVehicles::getVehicles() const {
|
||||
return vehicles_;
|
||||
}
|
||||
|
||||
const ControllableVehicleConfig* ControllableVehicles::findVehicle(const std::string& vehicleNo) const {
|
||||
auto iter = std::find_if(vehicles_.begin(), vehicles_.end(),
|
||||
[&](const ControllableVehicleConfig& config) {
|
||||
return config.vehicleNo == vehicleNo;
|
||||
});
|
||||
|
||||
return iter != vehicles_.end() ? &(*iter) : nullptr;
|
||||
}
|
||||
|
||||
bool ControllableVehicles::isControllable(const std::string& vehicleNo) const {
|
||||
return findVehicle(vehicleNo) != nullptr;
|
||||
}
|
||||
|
||||
void ControllableVehicles::loadConfig(const std::string& configFile) {
|
||||
std::ifstream file(configFile);
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Failed to open controllable vehicles config file: " + configFile);
|
||||
}
|
||||
|
||||
try {
|
||||
nlohmann::json jsonConfig;
|
||||
file >> jsonConfig;
|
||||
|
||||
for (const auto& item : jsonConfig["vehicles"]) {
|
||||
ControllableVehicleConfig config;
|
||||
config.vehicleNo = item["vehicleNo"].get<std::string>();
|
||||
config.ip = item["ip"].get<std::string>();
|
||||
config.port = item["port"].get<int>();
|
||||
vehicles_.push_back(config);
|
||||
}
|
||||
|
||||
Logger::info("Loaded {} controllable vehicles", vehicles_.size());
|
||||
} catch (const std::exception& e) {
|
||||
throw std::runtime_error("Failed to parse controllable vehicles config: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
30
src/vehicle/ControllableVehicles.h
Normal file
30
src/vehicle/ControllableVehicles.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
struct ControllableVehicleConfig {
|
||||
std::string vehicleNo; // 车牌号
|
||||
std::string ip; // IP地址
|
||||
int port; // 端口号
|
||||
};
|
||||
|
||||
class ControllableVehicles {
|
||||
public:
|
||||
explicit ControllableVehicles(const std::string& configFile);
|
||||
~ControllableVehicles() = default;
|
||||
|
||||
// 获取所有可控车辆配置
|
||||
const std::vector<ControllableVehicleConfig>& getVehicles() const;
|
||||
|
||||
// 根据车牌号查找可控车辆配置
|
||||
const ControllableVehicleConfig* findVehicle(const std::string& vehicleNo) const;
|
||||
|
||||
// 检查车辆是否可控
|
||||
virtual bool isControllable(const std::string& vehicleNo) const;
|
||||
|
||||
private:
|
||||
std::vector<ControllableVehicleConfig> vehicles_;
|
||||
void loadConfig(const std::string& configFile);
|
||||
};
|
||||
@ -1,387 +1,334 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "detector/CollisionDetector.h"
|
||||
#include "vehicle/ControllableVehicles.h"
|
||||
#include "spatial/AirportBounds.h"
|
||||
#include "types/BasicTypes.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include "utils/Logger.h"
|
||||
#include <chrono>
|
||||
|
||||
// Mock ControllableVehicles 类
|
||||
class MockControllableVehicles : public ControllableVehicles {
|
||||
public:
|
||||
MockControllableVehicles() : ControllableVehicles("") {} // 使用空字符串,避免加载实际配置
|
||||
MOCK_METHOD(bool, isControllable, (const std::string& vehicleNo), (const));
|
||||
};
|
||||
|
||||
// Mock AirportBounds 类
|
||||
class MockAirportBounds : public AirportBounds {
|
||||
public:
|
||||
MockAirportBounds() : AirportBounds("") {
|
||||
// 设置更大的测试边界,以包含所有测试数据
|
||||
airportBounds_ = Bounds(0, 0, 4000, 2000); // 4000x2000 的测试区域
|
||||
Logger::info("MockAirportBounds initialized with bounds: ",
|
||||
"x=", airportBounds_.x, ", y=", airportBounds_.y,
|
||||
", width=", airportBounds_.width, ", height=", airportBounds_.height);
|
||||
}
|
||||
|
||||
// 覆盖原有方法,返回测试用的配置
|
||||
AreaType getAreaType(const Vector2D& position) const override {
|
||||
return AreaType::RUNWAY; // 简化测试,总是返回跑道区域
|
||||
}
|
||||
|
||||
const AreaConfig& getAreaConfig(AreaType type) const override {
|
||||
static const AreaConfig config{20.0, 40.0, 15.0}; // 使用较小的阈值以确保测试通过
|
||||
return config;
|
||||
}
|
||||
|
||||
const Bounds& getAirportBounds() const override {
|
||||
return airportBounds_;
|
||||
}
|
||||
};
|
||||
|
||||
class CollisionDetectorTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
bounds = std::make_unique<AirportBounds>("config/airport_bounds.json");
|
||||
detector = std::make_unique<CollisionDetector>(*bounds);
|
||||
}
|
||||
|
||||
// 创建一个标准的航空器对象
|
||||
Aircraft createAircraft(const Vector2D& pos) {
|
||||
Aircraft aircraft;
|
||||
aircraft.id = "CES2501";
|
||||
aircraft.flightNo = "CES2501";
|
||||
aircraft.position = pos;
|
||||
aircraft.speed = 55.0; // 标准速度
|
||||
aircraft.heading = 90.0; // 向东
|
||||
return aircraft;
|
||||
}
|
||||
|
||||
// 创建一个标准的车辆对象
|
||||
Vehicle createVehicle(const Vector2D& pos, const std::string& id = "VEH001") {
|
||||
Vehicle vehicle;
|
||||
vehicle.id = id;
|
||||
vehicle.vehicleNo = id; // 使用相同的 ID 作为车牌号
|
||||
vehicle.position = pos;
|
||||
vehicle.speed = 22.0; // 标准速度
|
||||
vehicle.heading = 0.0; // 向北
|
||||
return vehicle;
|
||||
// 创建 Mock 对象
|
||||
airportBounds_ = std::make_unique<MockAirportBounds>();
|
||||
mockControllableVehicles_ = std::make_unique<MockControllableVehicles>();
|
||||
|
||||
// 创建碰撞检测器
|
||||
detector_ = std::make_unique<CollisionDetector>(*airportBounds_, *mockControllableVehicles_);
|
||||
}
|
||||
|
||||
std::unique_ptr<AirportBounds> bounds;
|
||||
std::unique_ptr<CollisionDetector> detector;
|
||||
std::unique_ptr<MockAirportBounds> airportBounds_;
|
||||
std::unique_ptr<MockControllableVehicles> mockControllableVehicles_;
|
||||
std::unique_ptr<CollisionDetector> detector_;
|
||||
};
|
||||
|
||||
// 测试跑道上的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, RunwayCollisionDetection) {
|
||||
Vector2D runwayPos(2500, 1530); // 跑道中心点
|
||||
|
||||
std::vector<Aircraft> aircraft = {createAircraft(runwayPos)};
|
||||
std::vector<Vehicle> vehicles = {
|
||||
createVehicle(Vector2D(2580, 1530)) // 距离80米,小于跑道区域的100米阈值
|
||||
};
|
||||
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector->detectCollisions();
|
||||
EXPECT_FALSE(risks.empty());
|
||||
|
||||
// 测试可控车辆与航空器的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, DetectControllableVehicleAircraftCollision) {
|
||||
// 设置 Mock 期望 - 在创建数据之前设置
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable("VEH001"))
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
Logger::info("Set mock expectation: VEH001 is controllable");
|
||||
|
||||
// 设置测试数据
|
||||
Aircraft aircraft;
|
||||
aircraft.flightNo = "TEST001";
|
||||
aircraft.position = {100, 100};
|
||||
aircraft.speed = 10;
|
||||
aircraft.heading = 90;
|
||||
Logger::info("Created aircraft: flightNo=", aircraft.flightNo,
|
||||
", position=(", aircraft.position.x, ", ", aircraft.position.y, ")");
|
||||
|
||||
Vehicle vehicle;
|
||||
vehicle.vehicleNo = "VEH001";
|
||||
vehicle.position = {120, 100}; // 距离航空器20米
|
||||
vehicle.speed = 5;
|
||||
vehicle.heading = 270;
|
||||
Logger::info("Created vehicle: vehicleNo=", vehicle.vehicleNo,
|
||||
", position=(", vehicle.position.x, ", ", vehicle.position.y, ")");
|
||||
|
||||
// 更新交通数据
|
||||
detector_->updateTraffic({aircraft}, {vehicle});
|
||||
Logger::info("Updated traffic data");
|
||||
|
||||
// 执行碰撞检测
|
||||
auto risks = detector_->detectCollisions();
|
||||
Logger::info("Collision detection completed, found ", risks.size(), " risks");
|
||||
|
||||
// 验证结果
|
||||
ASSERT_EQ(risks.size(), 1); // 应该检测到一个碰撞风险
|
||||
if (!risks.empty()) {
|
||||
const auto& risk = risks[0];
|
||||
EXPECT_EQ(risk.id1, "CES2501");
|
||||
EXPECT_EQ(risk.id2, "VEH001");
|
||||
EXPECT_EQ(risk.level, RiskLevel::LOW);
|
||||
EXPECT_NEAR(risk.distance, 80.0, 0.1);
|
||||
EXPECT_EQ(risks[0].id1, "TEST001"); // 航空器ID
|
||||
EXPECT_EQ(risks[0].id2, "VEH001"); // 车辆ID
|
||||
EXPECT_EQ(risks[0].distance, 20); // 距离应该是20米
|
||||
EXPECT_EQ(risks[0].level, RiskLevel::CRITICAL); // 20米距离应该是严重风险
|
||||
}
|
||||
}
|
||||
|
||||
// 测试滑行道上的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, TaxiwayCollisionDetection) {
|
||||
Vector2D taxiwayPos(2500, 1000); // 滑行道上的位置
|
||||
|
||||
std::vector<Aircraft> aircraft = {createAircraft(taxiwayPos)};
|
||||
std::vector<Vehicle> vehicles = {
|
||||
createVehicle(Vector2D(2540, 1000)) // 距离40米,小于滑行道区域的50米阈值
|
||||
};
|
||||
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector->detectCollisions();
|
||||
EXPECT_FALSE(risks.empty());
|
||||
|
||||
// 测试可控车辆与其他车辆的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, DetectControllableVehicleOtherVehicleCollision) {
|
||||
// 设置 Mock 期望
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable("VEH001"))
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable("VEH002"))
|
||||
.WillRepeatedly(testing::Return(false));
|
||||
|
||||
// 设置测试数据
|
||||
Vehicle controlVehicle;
|
||||
controlVehicle.vehicleNo = "VEH001";
|
||||
controlVehicle.position = {100, 100};
|
||||
controlVehicle.speed = 5;
|
||||
controlVehicle.heading = 90;
|
||||
|
||||
Vehicle otherVehicle;
|
||||
otherVehicle.vehicleNo = "VEH002";
|
||||
otherVehicle.position = {120, 100}; // 距离可控车辆20米
|
||||
otherVehicle.speed = 5;
|
||||
otherVehicle.heading = 270;
|
||||
|
||||
// 更新交通数据
|
||||
detector_->updateTraffic({}, {controlVehicle, otherVehicle});
|
||||
|
||||
// 执行碰撞检测
|
||||
auto risks = detector_->detectCollisions();
|
||||
|
||||
// 验证结果
|
||||
ASSERT_EQ(risks.size(), 1); // 应该检测到一个碰撞风险
|
||||
if (!risks.empty()) {
|
||||
const auto& risk = risks[0];
|
||||
EXPECT_EQ(risk.id1, "CES2501");
|
||||
EXPECT_EQ(risk.id2, "VEH001");
|
||||
EXPECT_EQ(risk.level, RiskLevel::LOW);
|
||||
EXPECT_NEAR(risk.distance, 40.0, 0.1);
|
||||
EXPECT_EQ(risks[0].id1, "VEH001"); // 可控车辆ID
|
||||
EXPECT_EQ(risks[0].id2, "VEH002"); // 其他车辆ID
|
||||
EXPECT_EQ(risks[0].distance, 20); // 距离应该是20米
|
||||
EXPECT_EQ(risks[0].level, RiskLevel::CRITICAL); // 20米距离应该是严重风险
|
||||
}
|
||||
}
|
||||
|
||||
// 测试停机位的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, GateCollisionDetection) {
|
||||
Vector2D gatePos(2500, 2500); // 停机位区域
|
||||
// 测试非可控车辆的碰撞检测(不应该产生碰撞风险)
|
||||
TEST_F(CollisionDetectorTest, NonControllableVehicleCollision) {
|
||||
// 设置测试数据
|
||||
Vehicle vehicle1;
|
||||
vehicle1.vehicleNo = "VEH001";
|
||||
vehicle1.position = {100, 100};
|
||||
vehicle1.speed = 5;
|
||||
vehicle1.heading = 90;
|
||||
|
||||
Vehicle vehicle2;
|
||||
vehicle2.vehicleNo = "VEH002";
|
||||
vehicle2.position = {120, 100}; // 距离20米
|
||||
vehicle2.speed = 5;
|
||||
vehicle2.heading = 270;
|
||||
|
||||
// 设置 Mock 期望
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable(testing::_))
|
||||
.WillRepeatedly(testing::Return(false));
|
||||
|
||||
// 更新交通数据
|
||||
detector_->updateTraffic({}, {vehicle1, vehicle2});
|
||||
|
||||
// 执行碰撞检测
|
||||
auto risks = detector_->detectCollisions();
|
||||
|
||||
// 验证结果
|
||||
EXPECT_EQ(risks.size(), 0); // 非可控车辆之间的碰撞不应该被检测
|
||||
}
|
||||
|
||||
// 测试多个可控车辆之间的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, MultipleControllableVehiclesCollision) {
|
||||
// 设置 Mock 期望 - 所有车辆都是可控的
|
||||
ON_CALL(*mockControllableVehicles_, isControllable(testing::_))
|
||||
.WillByDefault(testing::Return(true));
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable(testing::_))
|
||||
.Times(testing::AtLeast(3)); // 至少调用3次,因为有3辆车
|
||||
Logger::info("Set mock expectation: all vehicles are controllable");
|
||||
|
||||
// 设置测试数据
|
||||
std::vector<Vehicle> vehicles;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
Vehicle vehicle;
|
||||
vehicle.vehicleNo = "VEH00" + std::to_string(i + 1);
|
||||
vehicle.position = {100.0 + i * 20, 100}; // 每辆车间隔20米
|
||||
vehicle.speed = 5;
|
||||
vehicle.heading = 90;
|
||||
vehicles.push_back(vehicle);
|
||||
}
|
||||
|
||||
// 更新交通数据
|
||||
detector_->updateTraffic({}, vehicles);
|
||||
|
||||
// 执行碰撞检测
|
||||
auto risks = detector_->detectCollisions();
|
||||
|
||||
// 验证结果
|
||||
EXPECT_EQ(risks.size(), 2); // 应该检测到2个碰撞风险(相邻车辆之间)
|
||||
}
|
||||
|
||||
// 性能测试:模拟真实机场场景
|
||||
TEST_F(CollisionDetectorTest, PerformanceTest) {
|
||||
// 设置 Mock 期望 - 默认车辆不可控
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable(testing::_))
|
||||
.WillRepeatedly(testing::Return(false));
|
||||
|
||||
std::vector<Aircraft> aircraft = {createAircraft(gatePos)};
|
||||
std::vector<Vehicle> vehicles = {
|
||||
createVehicle(Vector2D(2535, 2500)) // 距离35米,小于停机位区域的40米阈值
|
||||
// 设置3辆可控车辆
|
||||
std::vector<std::string> controlVehicleNos = {
|
||||
"VEH001", // 滑行道上的可控车辆
|
||||
"VEH002", // 停机位的可控车辆
|
||||
"VEH003" // 服务区的可控车辆
|
||||
};
|
||||
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector->detectCollisions();
|
||||
EXPECT_FALSE(risks.empty());
|
||||
|
||||
if (!risks.empty()) {
|
||||
const auto& risk = risks[0];
|
||||
EXPECT_EQ(risk.id1, "CES2501");
|
||||
EXPECT_EQ(risk.id2, "VEH001");
|
||||
EXPECT_EQ(risk.level, RiskLevel::LOW);
|
||||
EXPECT_NEAR(risk.distance, 35.0, 0.1);
|
||||
for (const auto& vehicleNo : controlVehicleNos) {
|
||||
EXPECT_CALL(*mockControllableVehicles_, isControllable(vehicleNo))
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
}
|
||||
}
|
||||
Logger::info("Set mock expectations for controllable vehicles");
|
||||
|
||||
// 测试服务区的碰撞检测
|
||||
TEST_F(CollisionDetectorTest, ServiceAreaCollisionDetection) {
|
||||
Vector2D servicePos(2500, 3500); // 服务区域
|
||||
|
||||
std::vector<Aircraft> aircraft = {createAircraft(servicePos)};
|
||||
std::vector<Vehicle> vehicles = {
|
||||
createVehicle(Vector2D(2525, 3500)) // 距离25米,小于服务区域的30米阈值
|
||||
};
|
||||
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector->detectCollisions();
|
||||
EXPECT_FALSE(risks.empty());
|
||||
|
||||
if (!risks.empty()) {
|
||||
const auto& risk = risks[0];
|
||||
EXPECT_EQ(risk.id1, "CES2501");
|
||||
EXPECT_EQ(risk.id2, "VEH001");
|
||||
EXPECT_EQ(risk.level, RiskLevel::LOW);
|
||||
EXPECT_NEAR(risk.distance, 25.0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试车辆之间的碰撞
|
||||
TEST_F(CollisionDetectorTest, VehicleToVehicleCollision) {
|
||||
Vector2D servicePos(2500, 3500); // 在服务区域内
|
||||
|
||||
std::vector<Aircraft> aircraft; // 空的航空器列表
|
||||
std::vector<Vehicle> vehicles = {
|
||||
createVehicle(servicePos, "VEH001"),
|
||||
createVehicle(Vector2D(2510, 3500), "VEH002") // 距离10米,小于服务区域的15米车辆碰撞阈值
|
||||
};
|
||||
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector->detectCollisions();
|
||||
EXPECT_FALSE(risks.empty());
|
||||
|
||||
if (!risks.empty()) {
|
||||
const auto& risk = risks[0];
|
||||
EXPECT_EQ(risk.id1, "VEH001");
|
||||
EXPECT_EQ(risk.id2, "VEH002");
|
||||
EXPECT_EQ(risk.level, RiskLevel::MEDIUM);
|
||||
EXPECT_NEAR(risk.distance, 10.0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试安全距离外的情况
|
||||
TEST_F(CollisionDetectorTest, NoCollisionWhenFarApart) {
|
||||
Vector2D runwayPos(2500, 1530); // 跑道位置
|
||||
|
||||
std::vector<Aircraft> aircraft = {createAircraft(runwayPos)};
|
||||
std::vector<Vehicle> vehicles = {
|
||||
createVehicle(Vector2D(2650, 1530)) // 距离150米,大于任何区域的阈值
|
||||
};
|
||||
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector->detectCollisions();
|
||||
EXPECT_TRUE(risks.empty());
|
||||
}
|
||||
|
||||
// 生成随机位置,根据区域类型调整分布
|
||||
Vector2D generateRandomPosition(AreaType areaType = AreaType::SERVICE) {
|
||||
double x, y;
|
||||
|
||||
switch (areaType) {
|
||||
case AreaType::RUNWAY:
|
||||
// 跑道区域 (2000-5600, 1500-1560) - 3600m × 60m
|
||||
x = 2000.0 + (std::rand() % 3600);
|
||||
y = 1500.0 + (std::rand() % 60);
|
||||
break;
|
||||
|
||||
case AreaType::TAXIWAY:
|
||||
// 滑行道区域 (2000-5600, 900-960) - 3600m × 60m
|
||||
x = 2000.0 + (std::rand() % 3600);
|
||||
y = 900.0 + (std::rand() % 60);
|
||||
break;
|
||||
|
||||
case AreaType::GATE:
|
||||
// 停机坪区域 (2000-3500, 2000-3000) - 1500m × 1000m
|
||||
x = 2000.0 + (std::rand() % 1500);
|
||||
y = 2000.0 + (std::rand() % 1000);
|
||||
break;
|
||||
|
||||
case AreaType::SERVICE:
|
||||
default:
|
||||
// 服务区域 (2000-4000, 3000-4000) - 2000m × 1000m
|
||||
x = 2000.0 + (std::rand() % 2000);
|
||||
y = 3000.0 + (std::rand() % 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
// 生成随机航向角
|
||||
double generateRandomHeading() {
|
||||
return std::rand() % 360; // 0-359度
|
||||
}
|
||||
|
||||
// 生成随机速度
|
||||
double generateRandomSpeed(bool isAircraft) {
|
||||
if (isAircraft) {
|
||||
return 40.0 + (std::rand() % 31); // 40-70 m/s
|
||||
} else {
|
||||
return 5.0 + (std::rand() % 36); // 5-40 m/s
|
||||
}
|
||||
}
|
||||
|
||||
// 大规模碰撞检测性能测试
|
||||
TEST_F(CollisionDetectorTest, LargeScaleCollisionDetection) {
|
||||
std::srand(std::time(nullptr)); // 初始化随机数生成器
|
||||
|
||||
// 生成150架航空器
|
||||
// 创建测试数据
|
||||
std::vector<Aircraft> aircraft;
|
||||
|
||||
// 在跑道和滑行道分别安排5架航空器
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
Aircraft a;
|
||||
a.id = "FL_RW" + std::to_string(i + 1);
|
||||
a.flightNo = a.id;
|
||||
a.position = generateRandomPosition(AreaType::RUNWAY);
|
||||
a.speed = generateRandomSpeed(true);
|
||||
a.heading = generateRandomHeading();
|
||||
aircraft.push_back(a);
|
||||
|
||||
Aircraft b;
|
||||
b.id = "FL_TW" + std::to_string(i + 1);
|
||||
b.flightNo = b.id;
|
||||
b.position = generateRandomPosition(AreaType::TAXIWAY);
|
||||
b.speed = generateRandomSpeed(true);
|
||||
b.heading = generateRandomHeading();
|
||||
aircraft.push_back(b);
|
||||
}
|
||||
|
||||
// 在停机坪安排100架航空器(对应184个停机位的实际使用率)
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
Aircraft a;
|
||||
a.id = "FL_GT" + std::to_string(i + 1);
|
||||
a.flightNo = a.id;
|
||||
a.position = generateRandomPosition(AreaType::GATE);
|
||||
a.speed = generateRandomSpeed(true);
|
||||
a.heading = generateRandomHeading();
|
||||
aircraft.push_back(a);
|
||||
}
|
||||
|
||||
// 在服务区安排40架航空器
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
Aircraft a;
|
||||
a.id = "FL_SV" + std::to_string(i + 1);
|
||||
a.flightNo = a.id;
|
||||
a.position = generateRandomPosition(AreaType::SERVICE);
|
||||
a.speed = generateRandomSpeed(true);
|
||||
a.heading = generateRandomHeading();
|
||||
aircraft.push_back(a);
|
||||
}
|
||||
|
||||
// 生成300辆车,主要在停机坪和服务区分配
|
||||
std::vector<Vehicle> vehicles;
|
||||
|
||||
// 停机坪180辆车(每个停机位约1辆服务车)
|
||||
// 跑道区域:5架航空器
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
Aircraft a;
|
||||
a.flightNo = "RW" + std::to_string(i + 1);
|
||||
a.position = {1800.0 + i * 500, 30.0}; // 跑道上等间距分布
|
||||
a.speed = 30; // 较快速度
|
||||
a.heading = 90;
|
||||
aircraft.push_back(a);
|
||||
}
|
||||
|
||||
// 滑行道区域:5架航空器
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
Aircraft a;
|
||||
a.flightNo = "TW" + std::to_string(i + 1);
|
||||
a.position = {1800.0 + i * 500, 90.0}; // 滑行道上等间距分布
|
||||
a.speed = 10; // 中等速度
|
||||
a.heading = 90;
|
||||
aircraft.push_back(a);
|
||||
}
|
||||
|
||||
// 停机位区域:100架航空器,180辆车辆
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
Aircraft a;
|
||||
a.flightNo = "GT" + std::to_string(i + 1);
|
||||
a.position = {
|
||||
750.0 + (i % 10) * 150, // 10列
|
||||
500.0 + (i / 10) * 100 // 10行
|
||||
};
|
||||
a.speed = 0; // 静止
|
||||
a.heading = 180;
|
||||
aircraft.push_back(a);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 180; ++i) {
|
||||
Vehicle v;
|
||||
v.id = "VH_GT" + std::to_string(i + 1);
|
||||
v.vehicleNo = v.id;
|
||||
v.position = generateRandomPosition(AreaType::GATE);
|
||||
v.speed = generateRandomSpeed(false);
|
||||
v.heading = generateRandomHeading();
|
||||
v.vehicleNo = "GV" + std::to_string(i + 1);
|
||||
v.position = {
|
||||
750.0 + (i % 12) * 125, // 12列
|
||||
500.0 + (i / 12) * 83 // 15行
|
||||
};
|
||||
v.speed = 5; // 低速
|
||||
v.heading = (i % 4) * 90; // 4个方向
|
||||
vehicles.push_back(v);
|
||||
}
|
||||
|
||||
// 服务区120辆车
|
||||
// 服务区:40架航空器,120辆车辆
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
Aircraft a;
|
||||
a.flightNo = "SA" + std::to_string(i + 1);
|
||||
a.position = {
|
||||
1000.0 + (i % 8) * 250, // 8列
|
||||
500.0 + (i / 8) * 200 // 5行
|
||||
};
|
||||
a.speed = 0; // 静止
|
||||
a.heading = 180;
|
||||
aircraft.push_back(a);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 120; ++i) {
|
||||
Vehicle v;
|
||||
v.id = "VH_SV" + std::to_string(i + 1);
|
||||
v.vehicleNo = v.id;
|
||||
v.position = generateRandomPosition(AreaType::SERVICE);
|
||||
v.speed = generateRandomSpeed(false);
|
||||
v.heading = generateRandomHeading();
|
||||
v.vehicleNo = "SV" + std::to_string(i + 1);
|
||||
v.position = {
|
||||
1000.0 + (i % 10) * 200, // 10列
|
||||
500.0 + (i / 10) * 100 // 12行
|
||||
};
|
||||
v.speed = 8; // 中等速度
|
||||
v.heading = (i % 8) * 45; // 8个方向
|
||||
vehicles.push_back(v);
|
||||
}
|
||||
|
||||
// 添加3辆可控车辆
|
||||
// 1. 滑行道上的可控车辆
|
||||
Vehicle taxiwayVehicle;
|
||||
taxiwayVehicle.vehicleNo = "VEH001";
|
||||
taxiwayVehicle.position = {1800.0, 90.0}; // 在滑行道上
|
||||
taxiwayVehicle.speed = 10;
|
||||
taxiwayVehicle.heading = 90;
|
||||
vehicles.push_back(taxiwayVehicle);
|
||||
|
||||
// 记录开始时间
|
||||
// 2. 停机位的可控车辆
|
||||
Vehicle gateVehicle;
|
||||
gateVehicle.vehicleNo = "VEH002";
|
||||
gateVehicle.position = {750.0, 500.0}; // 在停机位区域
|
||||
gateVehicle.speed = 5;
|
||||
gateVehicle.heading = 180;
|
||||
vehicles.push_back(gateVehicle);
|
||||
|
||||
// 3. 服务区的可控车辆
|
||||
Vehicle serviceVehicle;
|
||||
serviceVehicle.vehicleNo = "VEH003";
|
||||
serviceVehicle.position = {1000.0, 500.0}; // 在服务区
|
||||
serviceVehicle.speed = 8;
|
||||
serviceVehicle.heading = 270;
|
||||
vehicles.push_back(serviceVehicle);
|
||||
|
||||
// 更新交通数据
|
||||
detector_->updateTraffic(aircraft, vehicles);
|
||||
Logger::info("Updated traffic data with ", aircraft.size(), " aircraft and ",
|
||||
vehicles.size(), " vehicles (including 3 controllable vehicles)");
|
||||
|
||||
// 执行碰撞检测并记录时间
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// 更新交通数据
|
||||
detector->updateTraffic(aircraft, vehicles);
|
||||
auto risks = detector_->detectCollisions();
|
||||
|
||||
// 执行碰撞检测
|
||||
auto risks = detector->detectCollisions();
|
||||
|
||||
// 记录结束时间
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
|
||||
// 统计各区域和风险等级的碰撞数量
|
||||
int runwayCollisions = 0;
|
||||
int taxiwayCollisions = 0;
|
||||
int gateCollisions = 0;
|
||||
int serviceCollisions = 0;
|
||||
|
||||
int criticalRisks = 0;
|
||||
int highRisks = 0;
|
||||
int mediumRisks = 0;
|
||||
int lowRisks = 0;
|
||||
|
||||
for (const auto& risk : risks) {
|
||||
// 统计区域分布
|
||||
if (risk.id1.find("RW") != std::string::npos || risk.id2.find("RW") != std::string::npos) {
|
||||
runwayCollisions++;
|
||||
} else if (risk.id1.find("TW") != std::string::npos || risk.id2.find("TW") != std::string::npos) {
|
||||
taxiwayCollisions++;
|
||||
} else if (risk.id1.find("GT") != std::string::npos || risk.id2.find("GT") != std::string::npos) {
|
||||
gateCollisions++;
|
||||
} else {
|
||||
serviceCollisions++;
|
||||
}
|
||||
|
||||
// 统计风险等级
|
||||
switch (risk.level) {
|
||||
case RiskLevel::CRITICAL: criticalRisks++; break;
|
||||
case RiskLevel::HIGH: highRisks++; break;
|
||||
case RiskLevel::MEDIUM: mediumRisks++; break;
|
||||
case RiskLevel::LOW: lowRisks++; break;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出性能统计
|
||||
Logger::info("大规模碰撞检测性能测试:");
|
||||
Logger::info(" - 航空器数量: ", aircraft.size());
|
||||
Logger::info(" - 车辆数量: ", vehicles.size());
|
||||
Logger::info(" - 检测到的碰撞数: ", risks.size());
|
||||
Logger::info(" - 区域分布:");
|
||||
Logger::info(" * 跑道区域: ", runwayCollisions);
|
||||
Logger::info(" * 滑行道区域: ", taxiwayCollisions);
|
||||
Logger::info(" * 停机位区域: ", gateCollisions);
|
||||
Logger::info(" * 服务区域: ", serviceCollisions);
|
||||
Logger::info(" - 风险等级分布:");
|
||||
Logger::info(" * 严重风险: ", criticalRisks);
|
||||
Logger::info(" * 高风险: ", highRisks);
|
||||
Logger::info(" * 中等风险: ", mediumRisks);
|
||||
Logger::info(" * 低风险: ", lowRisks);
|
||||
Logger::info(" - 处理时间: ", duration.count(), " 微秒");
|
||||
|
||||
Logger::info("Collision detection completed in ", duration.count(), " microseconds");
|
||||
Logger::info("Found ", risks.size(), " risks");
|
||||
|
||||
// 验证结果
|
||||
for (const auto& risk : risks) {
|
||||
// 验证碰撞对是否有效
|
||||
bool validCollision = false;
|
||||
|
||||
// 检查是否为航空器与车辆的碰撞
|
||||
for (const auto& a : aircraft) {
|
||||
for (const auto& v : vehicles) {
|
||||
if ((risk.id1 == a.flightNo && risk.id2 == v.vehicleNo) ||
|
||||
(risk.id1 == v.vehicleNo && risk.id2 == a.flightNo)) {
|
||||
validCollision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (validCollision) break;
|
||||
}
|
||||
|
||||
// 检查是否为车辆间的碰撞
|
||||
if (!validCollision) {
|
||||
for (const auto& v1 : vehicles) {
|
||||
for (const auto& v2 : vehicles) {
|
||||
if (v1.id != v2.id &&
|
||||
((risk.id1 == v1.vehicleNo && risk.id2 == v2.vehicleNo) ||
|
||||
(risk.id1 == v2.vehicleNo && risk.id2 == v1.vehicleNo))) {
|
||||
validCollision = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (validCollision) break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_TRUE(validCollision) << "无效的碰撞对: " << risk.id1 << " - " << risk.id2;
|
||||
EXPECT_GE(risk.distance, 0.0) << "距离不能为负值";
|
||||
EXPECT_GE(risk.relativeSpeed, 0.0) << "相对速度不能为负值";
|
||||
}
|
||||
ASSERT_GT(risks.size(), 0); // 应该检测到一些碰撞风险
|
||||
|
||||
// 性能要求:处理时间应在合理范围内
|
||||
EXPECT_LT(duration.count(), 1000000) << "碰撞检测时间超过1秒";
|
||||
// 验证性能要求
|
||||
EXPECT_LT(duration.count(), 100000); // 期望处理时间小于100ms
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user