package com.ard.work.service.impl;
|
|
import com.ard.work.domain.cache.UavTelemetryDataCache;
|
import com.ard.work.domain.dto.telemetry.TelemetryData;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
|
/**
|
* 无人机位置变化判断服务
|
*
|
* @author 刘苏义
|
*/
|
@Slf4j
|
@Service
|
public class UavPositionChangeService {
|
|
// 位置变化阈值(米)
|
private static final double POSITION_CHANGE_THRESHOLD = 5.0;
|
|
// 无效坐标的默认值
|
private static final double INVALID_COORD = 0.0;
|
|
/**
|
* 判断是否需要触发区域检测
|
* @param telemetryData 当前遥测数据
|
* @return true-需要触发区域检测,false-不需要
|
*/
|
public boolean shouldTriggerRegionCheck(TelemetryData telemetryData) {
|
String boxSn = telemetryData.getBoxSn();
|
|
// 获取上次遥测数据
|
TelemetryData lastData = UavTelemetryDataCache.get(boxSn);
|
|
// 首次上报,需要检测
|
if (lastData == null) {
|
log.debug("无人机 {} 首次上报,触发区域检测", boxSn);
|
return true;
|
}
|
|
// 判断位置是否变化
|
return isPositionChanged(lastData, telemetryData);
|
}
|
|
/**
|
* 判断位置是否发生变化
|
*/
|
private boolean isPositionChanged(TelemetryData lastData, TelemetryData newData) {
|
double lastLng = lastData.getLng();
|
double lastLat = lastData.getLat();
|
double newLng = newData.getLng();
|
double newLat = newData.getLat();
|
|
// 坐标无效(为0),认为需要检测
|
if (lastLng == INVALID_COORD || lastLat == INVALID_COORD ||
|
newLng == INVALID_COORD || newLat == INVALID_COORD) {
|
log.debug("坐标无效,触发区域检测");
|
return true;
|
}
|
|
// 计算移动距离
|
double distance = calculateDistance(lastLat, lastLng, newLat, newLng);
|
|
boolean changed = distance > POSITION_CHANGE_THRESHOLD;
|
|
if (changed) {
|
log.debug("无人机 {} 移动了 {:.2f} 米,触发区域检测", newData.getBoxSn(), distance);
|
}
|
|
return changed;
|
}
|
|
/**
|
* 计算两点间距离(米)- Haversine公式
|
*/
|
private double calculateDistance(double lat1, double lng1, double lat2, double lng2) {
|
double earthRadius = 6371000; // 地球半径(米)
|
|
double dLat = Math.toRadians(lat2 - lat1);
|
double dLng = Math.toRadians(lng2 - lng1);
|
|
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
|
Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
|
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
return earthRadius * c;
|
}
|
}
|