From 1d2de0f2873c66bf7a9567eb7f2b4bee7330ff6c Mon Sep 17 00:00:00 2001
From: liusuyi <1951119284@qq.com>
Date: Fri, 12 Dec 2025 15:16:12 +0800
Subject: [PATCH] 优化禁飞区距离算法

---
 ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java |   89 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 88 insertions(+), 1 deletions(-)

diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java b/ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java
index ea09a5a..26fc38f 100644
--- a/ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/utils/NoFlyZoneUtils.java
@@ -15,6 +15,78 @@
 
 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 = pointToSegmentDistanceHaversine(point, a, b);
+            minDistance = Math.min(minDistance, dist);
+        }
+
+        return minDistance;
+    }
+
+    /**
+     * 计算点到线段的距离(米)使用Haversine公式
+     */
+    public static double pointToSegmentDistanceHaversine(Vertex p, Vertex a, Vertex b) {
+        // 将经纬度换算成以 p 点为参考的局部平面米坐标
+        double[] pa = latLonToXY(a, p.y, p.x);
+        double[] pb = latLonToXY(b, p.y, p.x);
+        double[] pp = latLonToXY(p, p.y, p.x);
+
+        double dx = pb[0] - pa[0];
+        double dy = pb[1] - pa[1];
+
+        double t = ((pp[0] - pa[0]) * dx + (pp[1] - pa[1]) * dy) / (dx * dx + dy * dy);
+
+        double nearestX, nearestY;
+        if (t < 0) {
+            nearestX = pa[0];
+            nearestY = pa[1];
+        } else if (t > 1) {
+            nearestX = pb[0];
+            nearestY = pb[1];
+        } else {
+            nearestX = pa[0] + t * dx;
+            nearestY = pa[1] + t * dy;
+        }
+
+        double distX = pp[0] - nearestX;
+        double distY = pp[1] - nearestY;
+
+        return Math.sqrt(distX * distX + distY * distY);
+    }
+
+    /**
+     * 将经纬度转换为局部平面坐标(米)
+     * originLat、originLon 是参考点,经纬度转换到以参考点为原点的平面坐标
+     */
+    public static double[] latLonToXY(Vertex point, double originLat, double originLon) {
+        double R = 6371000; // 地球半径,单位米
+        double dLat = Math.toRadians(point.y - originLat);
+        double dLon = Math.toRadians(point.x - originLon);
+        double x = R * dLon * Math.cos(Math.toRadians(originLat));
+        double y = R * dLat;
+        return new double[]{x, y};
+    }
+
+
+
     /**
      * 判断点是否在多边形内(射线法)
      */
@@ -76,6 +148,18 @@
     private static boolean onSegment(Vertex p1, Vertex p2, Vertex q) {
         return q.x <= Math.max(p1.x, p2.x) && q.x >= Math.min(p1.x, p2.x)
                 && q.y <= Math.max(p1.y, p2.y) && q.y >= Math.min(p1.y, p2.y);
+    }
+
+
+    /**
+     * 判断点是否在矩形内
+     */
+    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();
     }
 
 
@@ -166,5 +250,8 @@
         return vertexes;
     }
 
-
+    public static double degDistanceToMeter(double deg, double lat) {
+        // 1° ≈ 111320 米,但是经度和纬度不一样,这里用纬度做修正
+        return deg * 111320.0 * Math.cos(Math.toRadians(lat));
+    }
 }

--
Gitblit v1.9.3