liusuyi
2025-10-17 36503d07775d54085464405cb8f35a30b29d8fe7
优化禁飞区增加缓冲区
3 files added
1 files modified
240 ■■■■■ changed files
ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyBox.java 15 ●●●●● patch | view | raw | blame | history
ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyZone.java 24 ●●●●● patch | view | raw | blame | history
ard-system/src/main/java/com/ard/data/noflyzone/domain/Vertex.java 30 ●●●●● patch | view | raw | blame | history
ard-system/src/main/java/com/ard/data/noflyzone/utils/GeoUtils.java 171 ●●●●● patch | view | raw | blame | history
ard-system/src/main/java/com/ard/data/noflyzone/domain/ArdNoFlyBox.java
New file
@@ -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;
}
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;
    }
}
ard-system/src/main/java/com/ard/data/noflyzone/domain/Vertex.java
New file
@@ -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));
    }
}
ard-system/src/main/java/com/ard/data/noflyzone/utils/GeoUtils.java
New file
@@ -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;
    }
}