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<Vertex> 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<Vertex> 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<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);
|
}
|
|
/**
|
* 将 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;
|
}
|
|
|
}
|