package org.yzh.commons.util; /** * 几何图形工具类 * @author yezhihao * https://gitee.com/yezhihao/jt808-server */ public class GeomUtils { /** 长半轴(赤道半径,单位米,WGS-84) */ public static final double A = 6378137; /** 弧度 */ public static final double RADIAN = Math.PI / 180.0; public static double[] calculatePoint(double lng1, double lat1, double lng2, double lat2, double distance) { double radLat1 = lat1 * RADIAN; double radLat2 = lat2 * RADIAN; double deltaLat = (lat2 - lat1) * RADIAN; double deltaLng = (lng2 - lng1) * RADIAN; double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); double d = A * c; double lat = lat1 + (distance / d) * (lat2 - lat1); double lng = lng1 + (distance / d) * (lng2 - lng1); return new double[]{lng, lat}; } /** 计算球面点到点距离(单位米) */ public static double distance(double lng1, double lat1, double lng2, double lat2) { double radLat1 = lat1 * RADIAN; double radLat2 = lat2 * RADIAN; double a = radLat1 - radLat2; double b = lng1 * RADIAN - lng2 * RADIAN; double distance = A * 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))); distance = Math.round(distance * 10000) / 10000D; return distance; } /** 计算平面点到点距离(单位米) */ public static double distance_(double x1, double y1, double x2, double y2) { double a = x1 - x2; double b = y1 - y2; double distance = Math.sqrt(Math.abs((a * a) + (b * b))); return distance * 100000; } /** 计算点到线距离(单位米) */ public static double distancePointToLine(double x1, double y1, double x2, double y2, double x0, double y0) { double a = distance_(x1, y1, x2, y2); double b = distance_(x1, y1, x0, y0); double c = distance_(x2, y2, x0, y0); if (c <= 0.001 || b <= 0.001) { return 0.0; } if (a <= 0.001) { return b; } double aa = a * a; double bb = b * b; double cc = c * c; if (cc >= aa + bb) { return b; } if (bb >= aa + cc) { return c; } double p = (a + b + c) / 2D; double s = Math.sqrt(p * (p - a) * (p - b) * (p - c)); return 2D * s / a; } /** 判断坐标是否在矩形内 */ public static boolean inside(double x, double y, double minX, double minY, double maxX, double maxY) { return (x >= minX && x <= maxX && y >= minY && y <= maxY); } /** 判断坐标是否在多边形内部 */ public static boolean inside(double x, double y, double[] points) { boolean oddNodes = false; double ret; for (int i = 0, j = points.length - 2; i < points.length; i += 2) { double x1 = points[i]; double y1 = points[i + 1]; double x2 = points[j]; double y2 = points[j + 1]; if ((y1 < y && y2 >= y) || (y2 < y && y1 >= y)) { ret = x1 + (y - y1) / (y2 - y1) * (x2 - x1); if (ret < x) oddNodes = !oddNodes; } j = i; } return oddNodes; } /** 计算三个坐标角度 */ public static double getDegree(double lng1, double lat1, double lng2, double lat2, double lng3, double lat3) { return getRadian(lng1, lat1, lng2, lat2, lng3, lat3) * (180 / Math.PI); } /** 计算三个坐标弧度 */ public static double getRadian(double lng1, double lat1, double lng2, double lat2, double lng3, double lat3) { double[] p1 = ball2xyz(lng1, lat1); double[] p2 = ball2xyz(lng2, lat2); double[] p3 = ball2xyz(lng3, lat3); double abx = p1[x] - p2[x]; double aby = p1[y] - p2[y]; double abz = p1[z] - p2[z]; double cbx = p3[x] - p2[x]; double cby = p3[y] - p2[y]; double cbz = p3[z] - p2[z]; double p1p2 = Math.sqrt(abx * abx + aby * aby + abz * abz); double p2p3 = Math.sqrt(cbx * cbx + cby * cby + cbz * cbz); double p = abx * cbx + aby * cby + abz * cbz; double a = Math.acos(p / (p1p2 * p2p3)); double c = abx * cby - cbx * aby; return (c > 0) ? a : -a; } private static final int x = 0; private static final int y = 1; private static final int z = 2; private static double[] ball2xyz(double lng, double lat) { lat = lat * RADIAN; lng = lng * RADIAN; double[] p = new double[3]; double t = Math.cos(lat) * 64; p[x] = Math.cos(lng) * t; p[y] = Math.sin(lng) * t; p[z] = Math.sin(lat) * 64; return p; } }