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; } }