From 36503d07775d54085464405cb8f35a30b29d8fe7 Mon Sep 17 00:00:00 2001
From: liusuyi <1951119284@qq.com>
Date: Fri, 17 Oct 2025 13:43:24 +0800
Subject: [PATCH] 优化禁飞区增加缓冲区
---
ard-system/src/main/java/com/ard/data/noflyzone/domain/Vertex.java | 30 +++++++
ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyBox.java | 15 +++
ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyZone.java | 24 ++++++
ard-system/src/main/java/com/ard/data/noflyzone/utils/GeoUtils.java | 171 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 240 insertions(+), 0 deletions(-)
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyBox.java b/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyBox.java
new file mode 100644
index 0000000..9d5ecf1
--- /dev/null
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyBox.java
@@ -0,0 +1,15 @@
+package com.ard.data.noflyzone.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ArdNoFlyBox {
+ private double minx;
+ private double miny;
+ private double maxx;
+ private double maxy;
+}
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyZone.java b/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyZone.java
index ea87870..477377e 100644
--- a/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyZone.java
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyZone.java
@@ -1,10 +1,13 @@
package com.ard.data.noflyzone.domain;
+import com.ard.data.noflyzone.utils.GeoUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.ard.common.annotation.Excel;
import com.ard.common.core.domain.BaseEntity;
+
+import java.util.List;
/**
* 禁飞区管理对象 ard_no_fly_zone
@@ -29,4 +32,25 @@
/** 数据json */
@Excel(name = "数据json")
private FeatureCollection geojson;
+
+ /** 禁飞区外接矩形 */
+ private ArdNoFlyBox ardNoFlyBox;
+
+ private List<Vertex> vertices;
+
+ // 懒加载 / 动态计算
+ public ArdNoFlyBox getArdNoFlyBox() {
+ if (ardNoFlyBox == null && geojson != null) {
+ ardNoFlyBox = GeoUtils.getArdNoFlyBox(geojson);
+ }
+ return ardNoFlyBox;
+ }
+
+ public List<Vertex> getVertices() {
+ if (vertices == null && geojson != null) {
+ vertices = GeoUtils.toVertexes(geojson);
+ }
+ return vertices;
+ }
+
}
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/domain/Vertex.java b/ard-system/src/main/java/com/ard/data/noflyzone/domain/Vertex.java
new file mode 100644
index 0000000..eae5166
--- /dev/null
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/domain/Vertex.java
@@ -0,0 +1,30 @@
+package com.ard.data.noflyzone.domain;
+
+public class Vertex {
+ public double x;
+ public double y;
+
+ public Vertex() {
+
+ }
+
+ public Vertex(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ // 判断这个点是不是和另外一个点重合(允许极小的误差,算作同一个点
+ public boolean IsSame(Vertex anotherV) {
+ double almostZero = 0.00000001;
+ if ((Math.abs(x - anotherV.x) < almostZero) && (Math.abs(y - anotherV.y) < almostZero)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // 直线距离
+ public double Distance(Vertex anotherV) {
+ return Math.sqrt(Math.pow(x - anotherV.x, 2) + Math.pow(y - anotherV.y, 2));
+ }
+}
\ No newline at end of file
diff --git a/ard-system/src/main/java/com/ard/data/noflyzone/utils/GeoUtils.java b/ard-system/src/main/java/com/ard/data/noflyzone/utils/GeoUtils.java
new file mode 100644
index 0000000..0c8e045
--- /dev/null
+++ b/ard-system/src/main/java/com/ard/data/noflyzone/utils/GeoUtils.java
@@ -0,0 +1,171 @@
+package com.ard.data.noflyzone.utils;
+
+import com.ard.data.noflyzone.domain.ArdNoFlyBox;
+import com.ard.data.noflyzone.domain.FeatureCollection;
+import com.ard.data.noflyzone.domain.Vertex;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 几何工具类
+ */
+public class GeoUtils {
+ /**
+ * 根据 GeoJSON(FeatureCollection)计算外接矩形
+ */
+ @SuppressWarnings("unchecked")
+ public static ArdNoFlyBox getArdNoFlyBox(FeatureCollection featureCollection) {
+ if (featureCollection == null || featureCollection.getFeatures() == null) {
+ return null;
+ }
+
+ double minx = Double.MAX_VALUE;
+ double miny = Double.MAX_VALUE;
+ double maxx = Double.MIN_VALUE;
+ double maxy = Double.MIN_VALUE;
+
+ for (FeatureCollection.Feature feature : featureCollection.getFeatures()) {
+ FeatureCollection.Geometry geometry = feature.getGeometry();
+ if (geometry == null || geometry.getCoordinates() == null) {
+ continue;
+ }
+
+ String type = geometry.getType();
+ Object coords = geometry.getCoordinates();
+
+ if ("Polygon".equalsIgnoreCase(type)) {
+ // Polygon: [[[lon, lat], [lon, lat], ...]]
+ List<List<List<Double>>> rings = (List<List<List<Double>>>) coords;
+ for (List<List<Double>> ring : rings) {
+ for (List<Double> point : ring) {
+ if (point.size() < 2) {
+ continue;
+ }
+ double x = point.get(0);
+ double y = point.get(1);
+ minx = Math.min(minx, x);
+ miny = Math.min(miny, y);
+ maxx = Math.max(maxx, x);
+ maxy = Math.max(maxy, y);
+ }
+ }
+ }
+ else if ("MultiPolygon".equalsIgnoreCase(type)) {
+ // MultiPolygon: [[[[lon, lat], ...]], ...]
+ List<List<List<List<Double>>>> polygons = (List<List<List<List<Double>>>>) coords;
+ for (List<List<List<Double>>> polygon : polygons) {
+ for (List<List<Double>> ring : polygon) {
+ for (List<Double> point : ring) {
+ if (point.size() < 2) {
+ continue;
+ }
+ double x = point.get(0);
+ double y = point.get(1);
+ minx = Math.min(minx, x);
+ miny = Math.min(miny, y);
+ maxx = Math.max(maxx, x);
+ maxy = Math.max(maxy, y);
+ }
+ }
+ }
+ }
+ }
+
+ return new ArdNoFlyBox(minx, miny, maxx, maxy);
+ }
+ /**
+ * 判断点是否在多边形内(包括边界)
+ * 射线法:从该点向右发射水平射线,计算交点个数
+ *
+ * @param vertex 点对象
+ * @param vertexes 多边形顶点列表(按顺序闭合)
+ * @return true 表示点在多边形内或在边上
+ */
+ public static boolean isVertexInPoly(Vertex vertex, List<Vertex> vertexes) {
+ if (vertex == null || vertexes == null || vertexes.size() < 3) {
+ return false; // 无效输入
+ }
+
+ int count = 0;
+ int n = vertexes.size();
+
+ for (int i = 0; i < n; i++) {
+ Vertex v1 = vertexes.get(i);
+ Vertex v2 = vertexes.get((i + 1) % n);
+
+ // 1. 点就是多边形的顶点
+ if (v1.IsSame(vertex)) {
+ return true;
+ }
+
+ // 2. 点在线段上
+ double minX = Math.min(v1.x, v2.x);
+ double maxX = Math.max(v1.x, v2.x);
+ double minY = Math.min(v1.y, v2.y);
+ double maxY = Math.max(v1.y, v2.y);
+
+ // 水平线段
+ if (minY == maxY) {
+ if (vertex.y == minY && vertex.x >= minX && vertex.x <= maxX) {
+ return true;
+ } else {
+ continue; // 不计入交点
+ }
+ }
+
+ // 点在线段纵向范围外
+ if (vertex.y < minY || vertex.y > maxY) {
+ continue;
+ }
+
+ // 计算射线交点的 X 坐标
+ double xIntersect = v1.x + (vertex.y - v1.y) * (v2.x - v1.x) / (v2.y - v1.y);
+
+ // 交点在点左侧,不计入
+ if (xIntersect < vertex.x) {
+ continue;
+ }
+
+ // 交点就在点上,认为在边界
+ if (xIntersect == vertex.x) {
+ return true;
+ }
+
+ // 避免射线穿过线段下端点重复计数
+ if (vertex.y == minY) {
+ continue;
+ }
+
+ // 其它情况,交点计数
+ count++;
+ }
+
+ // 奇数交点 → 点在多边形内
+ return count % 2 != 0;
+ }
+
+ /**
+ * 将 GeoJSON Polygon 的外环坐标转换成 Vertex 列表
+ */
+ public static List<Vertex> toVertexes(FeatureCollection featureCollection) {
+ List<Vertex> vertexes = new ArrayList<>();
+ if (featureCollection == null || featureCollection.getFeatures() == null || featureCollection.getFeatures().isEmpty()) {
+ return vertexes;
+ }
+ FeatureCollection.Feature feature = featureCollection.getFeatures().get(0);
+ if (feature.getGeometry() != null) {
+ List<List<List<Double>>> coords = feature.getGeometry().getCoordinates();
+ if (coords != null && !coords.isEmpty()) {
+ List<List<Double>> outerRing = coords.get(0);
+ for (List<Double> point : outerRing) {
+ if (point.size() >= 2) {
+ vertexes.add(new Vertex(point.get(0), point.get(1)));
+ }
+ }
+ }
+ }
+ return vertexes;
+ }
+
+}
--
Gitblit v1.9.3