|
|
@@ -0,0 +1,205 @@
|
|
|
+package com.aoyang.tms.util;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description: 判断一个地理坐标是否在一个以多边形的顶点组成的地理围栏里
|
|
|
+ * @Author guoyong
|
|
|
+ * @Date 2022/4/23 13:48
|
|
|
+ * @Version 1.0
|
|
|
+ */
|
|
|
+
|
|
|
+import java.awt.geom.Point2D;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+public class RegionUtil {
|
|
|
+
|
|
|
+ private static double EARTH_RADIUS = 6378137;
|
|
|
+ //private static double EARTH_SEA = 1.852;海里
|
|
|
+
|
|
|
+ private static double rad(double d) {
|
|
|
+ return d * Math.PI / 180.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断是否在多边形区域内
|
|
|
+ *
|
|
|
+ * @param pointLon 要判断的点的横坐标 经度
|
|
|
+ * @param pointLat 要判断的点的纵坐标 维度
|
|
|
+ * @param lon 区域各顶点的横坐标数组
|
|
|
+ * @param lat 区域各顶点的纵坐标数组
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isInPolygon(double pointLon, double pointLat, Double[] lon,
|
|
|
+ Double[] lat) {
|
|
|
+ // 将要判断的横纵坐标组成一个点
|
|
|
+ Point2D.Double point = new Point2D.Double(pointLon, pointLat);
|
|
|
+ // 将区域各顶点的横纵坐标放到一个点集合里面
|
|
|
+ List<Point2D.Double> pointList = new ArrayList<Point2D.Double>();
|
|
|
+ double polygonPoint_x = 0.0, polygonPoint_y = 0.0;
|
|
|
+ for (int i = 0; i < lon.length; i++) {
|
|
|
+ polygonPoint_x = lon[i];
|
|
|
+ polygonPoint_y = lat[i];
|
|
|
+ Point2D.Double polygonPoint = new Point2D.Double(polygonPoint_x, polygonPoint_y);
|
|
|
+ pointList.add(polygonPoint);
|
|
|
+ }
|
|
|
+ return check(point, pointList);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param point 要判断的点的横纵坐标
|
|
|
+ * @param polygon 组成的顶点坐标集合
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static boolean check(Point2D.Double point, List<Point2D.Double> polygon) {
|
|
|
+ java.awt.geom.GeneralPath peneralPath = new java.awt.geom.GeneralPath();
|
|
|
+
|
|
|
+ Point2D.Double first = polygon.get(0);
|
|
|
+ // 通过移动到指定坐标(以双精度指定),将一个点添加到路径中
|
|
|
+ peneralPath.moveTo(first.x, first.y);
|
|
|
+ polygon.remove(0);
|
|
|
+ for (Point2D.Double d : polygon) {
|
|
|
+ // 通过绘制一条从当前坐标到新指定坐标(以双精度指定)的直线,将一个点添加到路径中。
|
|
|
+ peneralPath.lineTo(d.x, d.y);
|
|
|
+ }
|
|
|
+ // 将几何多边形封闭
|
|
|
+ peneralPath.lineTo(first.x, first.y);
|
|
|
+ peneralPath.closePath();
|
|
|
+ // 测试指定的 Point2D 是否在 Shape 的边界内。
|
|
|
+ return peneralPath.contains(point);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 返回一个点是否在一个多边形区域内, 如果点位于多边形的顶点或边上,不算做点在多边形内,返回false
|
|
|
+ *
|
|
|
+ * @param point
|
|
|
+ * @param polygon
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean checkWithJdkGeneralPath(Point2D.Double point, List<Point2D.Double> polygon) {
|
|
|
+ java.awt.geom.GeneralPath p = new java.awt.geom.GeneralPath();
|
|
|
+ Point2D.Double first = polygon.get(0);
|
|
|
+ p.moveTo(first.x, first.y);
|
|
|
+ polygon.remove(0);
|
|
|
+ for (Point2D.Double d : polygon) {
|
|
|
+ p.lineTo(d.x, d.y);
|
|
|
+ }
|
|
|
+ p.lineTo(first.x, first.y);
|
|
|
+ p.closePath();
|
|
|
+ return p.contains(point);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断点是否在多边形内,如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
|
|
|
+ *
|
|
|
+ * @param point 检测点
|
|
|
+ * @param pts 多边形的顶点
|
|
|
+ * @return 点在多边形内返回true, 否则返回false
|
|
|
+ */
|
|
|
+ public static boolean IsPtInPoly(Point2D.Double point, List<Point2D.Double> pts) {
|
|
|
+
|
|
|
+ int N = pts.size();
|
|
|
+ boolean boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
|
|
|
+ int intersectCount = 0;//cross points count of x
|
|
|
+ double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
|
|
|
+ Point2D.Double p1, p2;//neighbour bound vertices
|
|
|
+ Point2D.Double p = point; //当前点
|
|
|
+
|
|
|
+ p1 = pts.get(0);//left vertex
|
|
|
+ for (int i = 1; i <= N; ++i) {//check all rays
|
|
|
+ if (p.equals(p1)) {
|
|
|
+ return boundOrVertex;//p is an vertex
|
|
|
+ }
|
|
|
+
|
|
|
+ p2 = pts.get(i % N);//right vertex
|
|
|
+ if (p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)) {//ray is outside of our interests
|
|
|
+ p1 = p2;
|
|
|
+ continue;//next ray left point
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)) {//ray is crossing over by the algorithm (common part of)
|
|
|
+ if (p.y <= Math.max(p1.y, p2.y)) {//x is before of ray
|
|
|
+ if (p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)) {//overlies on a horizontal ray
|
|
|
+ return boundOrVertex;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p1.y == p2.y) {//ray is vertical
|
|
|
+ if (p1.y == p.y) {//overlies on a vertical ray
|
|
|
+ return boundOrVertex;
|
|
|
+ } else {//before ray
|
|
|
+ ++intersectCount;
|
|
|
+ }
|
|
|
+ } else {//cross point on the left side
|
|
|
+ double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y
|
|
|
+ if (Math.abs(p.y - xinters) < precision) {//overlies on a ray
|
|
|
+ return boundOrVertex;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p.y < xinters) {//before ray
|
|
|
+ ++intersectCount;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {//special case when ray is crossing through the vertex
|
|
|
+ if (p.x == p2.x && p.y <= p2.y) {//p crossing over p2
|
|
|
+ Point2D.Double p3 = pts.get((i + 1) % N); //next vertex
|
|
|
+ if (p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)) {//p.x lies between p1.x & p3.x
|
|
|
+ ++intersectCount;
|
|
|
+ } else {
|
|
|
+ intersectCount += 2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ p1 = p2;//next ray left point
|
|
|
+ }
|
|
|
+
|
|
|
+ if (intersectCount % 2 == 0) {//偶数在多边形外
|
|
|
+ return false;
|
|
|
+ } else { //奇数在多边形内
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过经纬度获取距离(单位:米)
|
|
|
+ *
|
|
|
+ * @param lat1 纬度1
|
|
|
+ * @param lng1 经度1
|
|
|
+ * @param lat2 纬度2
|
|
|
+ * @param lng2 经度2
|
|
|
+ * @return 距离
|
|
|
+ */
|
|
|
+ public static double getDistance(double lat1, double lng1, double lat2,
|
|
|
+ double lng2) {
|
|
|
+ double radLat1 = rad(lat1);
|
|
|
+ double radLat2 = rad(lat2);
|
|
|
+ double a = radLat1 - radLat2;
|
|
|
+ double b = rad(lng1) - rad(lng2);
|
|
|
+ double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
|
|
|
+ Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
|
|
|
+ s = s * EARTH_RADIUS;
|
|
|
+ s = Math.round(s * 10000d) / 10000d;
|
|
|
+ //double len=s/EARTH_SEA;
|
|
|
+ //s = s / 1000;
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param lat1 纬度
|
|
|
+ * @param lat2 纬度
|
|
|
+ * @param lng1 经度
|
|
|
+ * @param lng2 经度
|
|
|
+ * @param radius 判断一个点是否在圆形区域内,比较坐标点与圆心的距离是否小于半径
|
|
|
+ */
|
|
|
+ public static boolean isInCircle(double lng1, double lat1, double lng2, double lat2, double radius) {
|
|
|
+ double distance = getDistance(lat1, lng1, lat2, lng2);
|
|
|
+ if (distance > radius) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ //System.err.println("经度:"+lng1+"维度:"+lat1+"经度:"+lng2+"维度:"+lat2+"距离:"+distance);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|