| New file |
| | |
| | | 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<ArdNoFlyZone> 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<Vertex> 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<Vertex> 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; |
| | | } |
| | | } |