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.Vertex; import java.util.List; public class NoFlyZoneUtils { /** * 判断点是否在禁飞区集合中 * * @param point 目标点 * @param zones 禁飞区集合 * @return true: 点在任意禁飞区内 */ public static boolean isInNoFlyZones(Vertex point, List zones) { if (point == null || zones == null || zones.isEmpty()) { return false; } for (ArdNoFlyZone zone : zones) { // 1️⃣ 先快速判断外接矩形 if (zone.getArdNoFlyBox() != null && !isInBox(point, zone.getArdNoFlyBox())) { continue; // 点不在外接矩形内,跳过 } // 2️⃣ 多边形判断 List vertices = zone.getVertices(); if (vertices != null && !vertices.isEmpty()) { if (isPointInPolygon(point, vertices)) { return true; } } } return false; } /** * 判断点是否在矩形框内 */ private static boolean isInBox(Vertex point, ArdNoFlyBox box) { return point.x >= box.getMinx() && point.x <= box.getMaxx() && point.y >= box.getMiny() && point.y <= box.getMaxy(); } /** * 射线法判断点是否在多边形内 */ private static boolean isPointInPolygon(Vertex point, List vertices) { if (point == null || vertices == null || vertices.size() < 3) { return false; } int count = 0; int n = vertices.size(); double epsilon = 1e-9; for (int i = 0; i < n; i++) { Vertex v1 = vertices.get(i); Vertex v2 = vertices.get((i + 1) % n); // 点就是顶点 if (v1.IsSame(point)) { return true; } 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 (Math.abs(minY - maxY) < epsilon) { if (Math.abs(point.y - minY) < epsilon && point.x >= minX && point.x <= maxX) { return true; } else { continue; } } // 点不在纵向范围 if (point.y < minY || point.y > maxY) { continue; } double xIntersect = v1.x + (point.y - v1.y) * (v2.x - v1.x) / (v2.y - v1.y); if (Math.abs(xIntersect - point.x) < epsilon) { return true; // 点在边界 } if (xIntersect > point.x) { count++; } if (Math.abs(point.y - minY) < epsilon) { count--; } } return count % 2 != 0; } }