package com.ard.data.noflyzone.utils; import com.ard.data.noflyzone.domain.ArdNoFlyBox; import com.ard.data.noflyzone.domain.ArdNoFlyZone; import com.ard.data.noflyzone.domain.FeatureCollection; import com.ard.data.noflyzone.domain.Vertex; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.Polygon; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class NoFlyZoneUtils { /** * 判断点是否在多边形内(射线法) */ public static boolean isPointInPolygon(Vertex point, List polygon) { int n = polygon.size(); boolean inside = false; for (int i = 0, j = n - 1; i < n; j = i++) { Vertex vi = polygon.get(i); Vertex vj = polygon.get(j); boolean intersect = ((vi.y > point.y) != (vj.y > point.y)) && (point.x < (vj.x - vi.x) * (point.y - vi.y) / (vj.y - vi.y) + vi.x); if (intersect) inside = !inside; } return inside; } /** * 判断线段是否与多边形相交 */ public static boolean isLineIntersectPolygon(Vertex p1, Vertex p2, List polygon) { int n = polygon.size(); for (int i = 0; i < n; i++) { Vertex a = polygon.get(i); Vertex b = polygon.get((i + 1) % n); if (isSegmentsIntersect(p1, p2, a, b)) { return true; } } return false; } /** * 判断两条线段是否相交 */ private static boolean isSegmentsIntersect(Vertex p1, Vertex p2, Vertex p3, Vertex p4) { double d1 = cross(p3, p4, p1); double d2 = cross(p3, p4, p2); double d3 = cross(p1, p2, p3); double d4 = cross(p1, p2, p4); if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) { return true; } // 处理共线情况 if (d1 == 0 && onSegment(p3, p4, p1)) return true; if (d2 == 0 && onSegment(p3, p4, p2)) return true; if (d3 == 0 && onSegment(p1, p2, p3)) return true; if (d4 == 0 && onSegment(p1, p2, p4)) return true; return false; } private static double cross(Vertex p1, Vertex p2, Vertex p3) { return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y); } 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); } /** * 根据 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>> rings = (List>>) coords; for (List> ring : rings) { for (List 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>>> polygons = (List>>>) coords; for (List>> polygon : polygons) { for (List> ring : polygon) { for (List 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); } /** * 将 GeoJSON Polygon 的外环坐标转换成 Vertex 列表 */ public static List toVertexes(FeatureCollection featureCollection) { List 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>> coords = feature.getGeometry().getCoordinates(); if (coords != null && !coords.isEmpty()) { List> outerRing = coords.get(0); for (List point : outerRing) { if (point.size() >= 2) { vertexes.add(new Vertex(point.get(0), point.get(1))); } } } } return vertexes; } }