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;
|
}
|
|
}
|