| ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java | ●●●●● patch | view | raw | blame | history | |
| ard-work/src/main/java/com/ard/work/component/websocket/handler/NoFlyDistanceManager.java | ●●●●● patch | view | raw | blame | history | |
| ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java | ●●●●● patch | view | raw | blame | history | |
| ard-work/src/main/java/com/ard/work/domain/dto/NoFlyDistanceDTO.java | ●●●●● patch | view | raw | blame | history | |
| ard-work/src/main/java/com/ard/work/domain/enums/MessageType.java | ●●●●● patch | view | raw | blame | history | |
| ard-work/src/main/java/com/ard/work/domain/message/NoFlyDistanceMessage.java | ●●●●● patch | view | raw | blame | history |
ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java
@@ -15,6 +15,72 @@ public class NoFlyZoneUtils { /** * 计算点到多边形的最近距离 */ public static double pointToPolygonDistance(Vertex point, List<Vertex> polygon) { // 如果在多边形内部,距离为 0 if (isPointInPolygon(point, polygon)) { return 0; } double minDistance = Double.MAX_VALUE; int n = polygon.size(); for (int i = 0; i < n; i++) { Vertex a = polygon.get(i); Vertex b = polygon.get((i + 1) % n); // 下一点,最后一条边连接第一个点 double dist = pointToSegmentDistance(point, a, b); minDistance = Math.min(minDistance, dist); } return minDistance; } /** * 计算点到线段的距离 */ public static double pointToSegmentDistance(Vertex p, Vertex a, Vertex b) { double x = p.x, y = p.y; double x1 = a.x, y1 = a.y; double x2 = b.x, y2 = b.y; double dx = x2 - x1; double dy = y2 - y1; if (dx == 0 && dy == 0) { // A 和 B 是同一个点 dx = x - x1; dy = y - y1; return Math.sqrt(dx * dx + dy * dy); } // 投影参数 t(0-1之间表示在线段内部) double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); if (t < 0) { // 最近点是 A dx = x - x1; dy = y - y1; } else if (t > 1) { // 最近点是 B dx = x - x2; dy = y - y2; } else { // 最近点在线段中间 double projX = x1 + t * dx; double projY = y1 + t * dy; dx = x - projX; dy = y - projY; } return Math.sqrt(dx * dx + dy * dy); } /** * 判断点是否在多边形内(射线法) */ @@ -80,6 +146,18 @@ /** * 判断点是否在矩形内 */ public static boolean isInsideBox(Vertex point, ArdNoFlyBox box) { if (point == null || box == null) return false; return point.x >= box.getMinx() && point.x <= box.getMaxx() && point.y >= box.getMiny() && point.y <= box.getMaxy(); } /** * 根据 GeoJSON(FeatureCollection)计算外接矩形 */ @SuppressWarnings("unchecked") ard-work/src/main/java/com/ard/work/component/websocket/handler/NoFlyDistanceManager.java
New file @@ -0,0 +1,76 @@ package com.ard.work.component.websocket.handler; import com.ard.data.noflyzone.domain.ArdNoFlyBox; import com.ard.data.noflyzone.domain.ArdNoFlyZone; import com.ard.data.noflyzone.domain.Vertex; import com.ard.data.noflyzone.service.IArdNoFlyZoneService; import com.ard.data.noflyzone.utils.NoFlyZoneUtils; import com.ard.work.domain.cache.UavTelemetryDataCache; import com.ard.work.domain.dto.NoFlyDistanceDTO; import com.ard.work.domain.dto.telemetry.TelemetryData; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; /** * 禁飞区距离管理器 * @author liuyaping * @date 2021/3/22 */ @Component public class NoFlyDistanceManager extends BaseSubscriptionManager<NoFlyDistanceDTO> { @Resource private IArdNoFlyZoneService ardNoFlyZoneService; @Override protected NoFlyDistanceDTO getData(String boxSn) { TelemetryData telemetryData = UavTelemetryDataCache.get(boxSn); if (telemetryData == null) return null; Vertex current = new Vertex(telemetryData.getLng(), telemetryData.getLat()); List<ArdNoFlyZone> zones = ardNoFlyZoneService.selectArdNoFlyZoneList(new ArdNoFlyZone()); if (zones.isEmpty()) return null; double minDistance = Double.MAX_VALUE; ArdNoFlyZone nearestZone = null; for (ArdNoFlyZone zone : zones) { ArdNoFlyBox box = zone.getArdNoFlyBox(); if (box == null) continue; // 包围盒快速排除 if (current.x < box.getMinx() || current.x > box.getMaxx() || current.y < box.getMiny() || current.y > box.getMaxy()) { continue; } List<Vertex> polygon = zone.getVertices(); if (polygon == null || polygon.size() < 3) continue; double distance = NoFlyZoneUtils.pointToPolygonDistance(current, polygon); if (distance < minDistance) { minDistance = distance; nearestZone = zone; } } if (nearestZone == null) return null; return NoFlyDistanceDTO.builder() .boxSn(boxSn) .zoneName(nearestZone.getName()) .distance(minDistance) .inNoFlyZone(minDistance == 0) .build(); } @Override protected String getMessageType() { return "noFlyZoneDistance"; } } ard-work/src/main/java/com/ard/work/component/websocket/handler/TyMessageHandler.java
@@ -42,6 +42,8 @@ @Resource private UavAllManager uavAllManager; @Resource private NoFlyDistanceManager noFlyDistanceManager; @Resource private TokenService tokenService; private final Map<Long, Long> lastDisconnectTime = new ConcurrentHashMap<>(); @@ -73,6 +75,9 @@ break; case CONTROLLER: handleControlMessage(payload, userId); break; case NO_FLY_DISTANCE: handleNoFlyDistanceMessage(payload, userId); break; case ALL: handleAllMessage(payload, userId); @@ -272,6 +277,37 @@ } } /** * 处理禁飞区距离 * * @param payload 消息负载,包含订阅信息 * @param userId 用户ID,用于标识用户 */ private void handleNoFlyDistanceMessage(String payload, Long userId) { // 解析接收到的JSON消息,将其转换为BaseMessage对象 BaseMessage<NoFlyDistanceMessage> baseMessage = JSON.parseObject(payload, new TypeReference<BaseMessage<NoFlyDistanceMessage>>() { }); // 获取消息的有效载荷部分 NoFlyDistanceMessage noFlyDistanceMessage = baseMessage.getPayload(); // 检查有效载荷是否存在 if (noFlyDistanceMessage != null) { // 获取无人机盒子的序列号 String boxSn = noFlyDistanceMessage.getBoxSn(); // 根据消息中的订阅标志,决定是订阅还是退订无人机状态 Boolean subscribe = noFlyDistanceMessage.getSubscribe(); if (subscribe) { // 执行订阅操作 noFlyDistanceManager.subscribe(boxSn, userId, 1); } else { // 执行退订操作 noFlyDistanceManager.unsubscribe(boxSn, userId); } } } @Override public void afterConnectionEstablished(WebSocketSession session) { String userIdStr = (String) session.getAttributes().get("userId"); ard-work/src/main/java/com/ard/work/domain/dto/NoFlyDistanceDTO.java
New file @@ -0,0 +1,18 @@ package com.ard.work.domain.dto; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class NoFlyDistanceDTO { private String boxSn; private String zoneName; private double distance; // 米 private boolean inNoFlyZone; // getters/setters } ard-work/src/main/java/com/ard/work/domain/enums/MessageType.java
@@ -7,6 +7,7 @@ TELEMETRY("telemetry"), SIGNAL("signal"), CONTROLLER("controller"), NO_FLY_DISTANCE("noFlyDistance"), ALL("all"); private final String type; ard-work/src/main/java/com/ard/work/domain/message/NoFlyDistanceMessage.java
New file @@ -0,0 +1,30 @@ package com.ard.work.domain.message; import com.ard.work.domain.dto.signal.SignalInfo; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; /** * Description: 禁飞距离消息 * Author: liusuyi * Date: 2025年03月10日11:49 **/ @Data @Builder @AllArgsConstructor @NoArgsConstructor public class NoFlyDistanceMessage { /** * 盒子编号 */ private String boxSn; /** * 是否订阅 */ private Boolean subscribe; }