|
@@ -0,0 +1,162 @@
|
|
|
+package com.fdkankan.scene.util;
|
|
|
+
|
|
|
+
|
|
|
+import com.fdkankan.scene.dto.GeoPoint;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description: 距离 范围 计算工具类
|
|
|
+ * @author Xiewj
|
|
|
+ * @date 2021/11/23
|
|
|
+ */
|
|
|
+public class CoordinateUtil {
|
|
|
+ /**
|
|
|
+ * 计算经纬度围成的实际面积(平方公里)
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static BigDecimal getArea(List<GeoPoint> ring){
|
|
|
+ double sJ = 6378137;
|
|
|
+ double Hq = 0.017453292519943295;
|
|
|
+ double c = sJ *Hq;
|
|
|
+ double d = 0;
|
|
|
+
|
|
|
+ if (3 > ring.size()) {
|
|
|
+ return new BigDecimal( 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < ring.size() - 1; i ++){
|
|
|
+ GeoPoint h = ring.get(i);
|
|
|
+ GeoPoint k = ring.get(i + 1);
|
|
|
+ double u = h.getLon() * c * Math.cos(h.getLat() * Hq);
|
|
|
+
|
|
|
+ double hhh = h.getLat() * c;
|
|
|
+ double v = k.getLon() * c * Math.cos(k.getLat() *Hq);
|
|
|
+ d = d + (u * k.getLat() * c - v * hhh);
|
|
|
+ }
|
|
|
+
|
|
|
+ GeoPoint g1 = ring.get(ring.size()-1);
|
|
|
+ GeoPoint point = ring.get(0);
|
|
|
+ double eee = g1.getLon() * c * Math.cos(g1.getLat() * Hq);
|
|
|
+ double g2 = g1.getLat() * c;
|
|
|
+
|
|
|
+ double k = point.getLon() * c * Math.cos(point.getLat() * Hq);
|
|
|
+ d += eee * point.getLat() * c - k * g2;
|
|
|
+ return new BigDecimal( 0.5*Math.abs(d));
|
|
|
+ }
|
|
|
+
|
|
|
+ // WGS84标准参考椭球中的地球长半径(单位:米)
|
|
|
+ private static final double EARTH_RADIUS_WGS84 = 6378137.0;
|
|
|
+ public static GeoPoint pointA = new GeoPoint();
|
|
|
+ public static GeoPoint pointB = new GeoPoint();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算两个坐标的距离(粗略计算,单位:米)
|
|
|
+ * 计算公式参照 google map 的距离计算
|
|
|
+ *
|
|
|
+ * @param gps1 坐标1
|
|
|
+ * @param gps2 坐标2
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static double distance(GeoPoint gps1, GeoPoint gps2) {
|
|
|
+
|
|
|
+ double radLat1 = Math.toRadians(gps1.getLat());
|
|
|
+ double radLat2 = Math.toRadians(gps2.getLat());
|
|
|
+
|
|
|
+ double a = radLat1 - radLat2;
|
|
|
+ double b = Math.toRadians(gps1.getLon()) - Math.toRadians(gps2.getLon());
|
|
|
+
|
|
|
+ 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)));
|
|
|
+
|
|
|
+ return Math.round(s * EARTH_RADIUS_WGS84);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static void distance(List<Object> pointList) {
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * @Title divide
|
|
|
+ * @Description 求平面上距离最近的两个点
|
|
|
+ * @author 滑技工厂
|
|
|
+ * @Date 2020/3/28
|
|
|
+ * @param [left, right, points]
|
|
|
+ * @return double
|
|
|
+ * @throws
|
|
|
+ */
|
|
|
+ public static double divide(int left, int right, GeoPoint[] points, Map<String, GeoPoint> res) {
|
|
|
+ // 当前最小两点距离,初始值设置为无穷大
|
|
|
+ double curMaxDis = 1e20;
|
|
|
+ // 如果只有一个点,则不存在最近两点距离,返回无穷大
|
|
|
+ if (left == right) {
|
|
|
+ return curMaxDis;
|
|
|
+ }
|
|
|
+ // 这里是判断是否为只有两个点,如果只有两个点的话那么直接求解。
|
|
|
+ if (left + 1 == right) {
|
|
|
+ res.put("pointA",points[left]);
|
|
|
+ res.put("pointB",points[right]);
|
|
|
+ return distance(points[left], points[right]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分治法:第一步:分区,并求取左右分区最小两点距离
|
|
|
+ // 通过右移运算除2,对区域进行合理的划分,使得左右两边保持大致相等个数点
|
|
|
+ int middle = (left + right) >> 1;
|
|
|
+ double leftMinDis = divide(left, middle, points,res);
|
|
|
+ double rightMinDis = divide(middle, right, points,res);
|
|
|
+
|
|
|
+ curMaxDis = (leftMinDis <= rightMinDis) ? leftMinDis : leftMinDis;
|
|
|
+
|
|
|
+ // 分治法:第二步:假设距离最近的两点分别在左右分区中
|
|
|
+ // 关键代码,距离最近的两个点,一个位于左边区域,一个位于右边区域,x轴搜索范围[middle-curMaxDis, middle+curMaxDis]
|
|
|
+ // 记录搜索区间内的点的索引,便于进一步计算最小距离
|
|
|
+ List<Integer> validPointIndex = new ArrayList<>();
|
|
|
+ for (int i = left; i <= right; i++) {
|
|
|
+ if (Math.abs(points[middle].getLat() - points[i].getLat()) <= curMaxDis) {
|
|
|
+ validPointIndex.add(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 基于索引,进一步计算区间内最小两点距离
|
|
|
+ for (int i = 0; i < validPointIndex.size() - 1; i++) {
|
|
|
+ for (int j = i + 1; j < validPointIndex.size(); j++) {
|
|
|
+ // 如果区间内的两点y轴距离大于curMinDis,则没必要计算了,因为,它们的距离肯定大于curMinDis,
|
|
|
+ if (Math.abs(points[validPointIndex.get(i)].getLon()
|
|
|
+ - points[validPointIndex.get(j)].getLon()) > curMaxDis) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ double tempDis = distance(points[validPointIndex.get(i)],
|
|
|
+ points[validPointIndex.get(j)]);
|
|
|
+
|
|
|
+ if (tempDis > curMaxDis){
|
|
|
+ curMaxDis=tempDis;
|
|
|
+ res.put("pointA",points[validPointIndex.get(i)]);
|
|
|
+ res.put("pointB",points[validPointIndex.get(j)]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return curMaxDis;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+// int i=500;
|
|
|
+// List<GeoPoint> ring = new ArrayList<>();
|
|
|
+//
|
|
|
+// for (int i1 = i; i1 > 0; i1--) {
|
|
|
+// double a = RandomUtil.randomDouble(113.0000001, 113.9999999);
|
|
|
+// double b = RandomUtil.randomDouble(22.0000001,22.9999999);
|
|
|
+// GeoPoint d=new GeoPoint(a,b);
|
|
|
+// ring.add(d);
|
|
|
+// }
|
|
|
+// JSONObject res=new JSONObject();
|
|
|
+// TimeInterval timer = DateUtil.timer();
|
|
|
+// System.out.println(divide(0, ring.size()-1, ring.toArray(new GeoPoint[0]),res));
|
|
|
+// System.out.println(res);
|
|
|
+// System.out.println("使用秒数"+timer.intervalMs());
|
|
|
+ }
|
|
|
+}
|