Lat / Long&由Lat / Longs组成的多边形的最近边缘?

时间:2015-10-15 18:52:51

标签: java coordinates

我有一个Lat / Long坐标列表,它代表一个多边形和一个单独的Lat / Long,我知道它包含在多边形内。

如何确定从单个Lat / Long到多边形最近边缘的距离?是否有一个已知的Java库?

3 个答案:

答案 0 :(得分:1)

我建议使用以下解决方案,这也适用于北极周围的多边形,其中经度和纬度差的计算没有意义。

该解决方案使用World Geodetic System 84将地球上的点的经度和纬度转换为三维坐标。使用这些三维点,您可以计算一个点在三维空间中由另外两个点定义的线上的投影。

这是进行计算的代码。它使用Java 8中提供的类javafx.geometry.Point3D

/** Semi-major axis of earth in meter */
public static final double WGS84_A = 6378137.0;

/** Semi-minor axis of earth in meter */
public static final double WGS84_B = 6356752.314245;

/** Eccentricity of earth */
public static final double WGS84_E =  
        Math.sqrt( (WGS84_A * WGS84_A) / (WGS84_B * WGS84_B) - 1);

public static final double DEGREES_TO_RADIANS = Math.PI / 180;

/**
 * Calculates a three-dimensional point in the 
 * World Geodetic System (WGS84) from latitude and longitude.
 */
public static Point3D latLonToPoint3D(double lat, double lon) {
    double clat = Math.cos(lat * DEGREES_TO_RADIANS);
    double slat = Math.sin(lat * DEGREES_TO_RADIANS);
    double clon = Math.cos(lon * DEGREES_TO_RADIANS);
    double slon = Math.sin(lon * DEGREES_TO_RADIANS);

    double N = WGS84_A / Math.sqrt(1.0 - WGS84_E * WGS84_E * slat * slat);

    double x = N  * clat * clon;
    double y = N  * clat * slon;
    double z = N * (1.0 - WGS84_E * WGS84_E) * slat;
    return new Point3D(x, y, z);
}

/**
 * Calculates distance of projection p of vector a on vector b.
 *
 * Use formula for projection, with p being the projection point:
 * <p>
 * p = a X b / |b|^2 * b
 * </p>
 * X being the dot product, * being multiplication of vector and constant
 */
public static Point3D calculateProjection(Point3D a, Point3D b) {
    return b.multiply(a.dotProduct(b) / (b.dotProduct(b)));
}

/**
 * Calculates shortest distance of vector x and the line defined by 
 * the vectors a and b.
 */
public static double calculateDistanceToLine(Point3D x, Point3D a, Point3D b) {
    Point3D projectionOntoLine = 
            calculateProjection(x.subtract(a), b.subtract(a)).add(a);
    return projectionOntoLine.distance(x);
}

通过使用点和多边形线段调用calculateDistanceToLine&#39;点,您可以找到由边缘点定义的最近的线并扩展到无穷大。如果是凹面多边形,可能不是您想要的,如图所示。

A concave polygon where the next edge (orange) is not the line with the nearest projection point.

考虑到到多边形边缘的距离必须至少与到最近边缘点的距离一样长,您可以得到到边缘的距离:

Math.max(calculateDistanceToLine(x, edgePoint1, edgePoint2), 
    Math.min(x.distance(edgePoint1), x.distance(edgePoint2)));

请注意,此计算也不会产生地球表面上的距离,而是直接穿过地球的距离。无论如何,它应该足以选择最短的距离。

函数latLonToPoint3D是我找到here函数的修改版本。

答案 1 :(得分:0)

你可以循环遍历所有边缘并计算两点之间的距离,如下所示:

function double calculateDistance(
    double edgeLat1, double edgeLng1, 
    double edgeLat2, double edgeLng2, 
    double pointLat, double pointLng) {

  //calculate straight/edge
  double mS = (edgeLng2 - edgeLng1)/(edgeLat2- edgeLat2);
  double tS = edgeLng1 - edgeLng1 * mS;

  //calculate helper straight
  double mH = -mS;
  double tH = pointLng - mH * pointLat;

  //calcuate straight intersection
  xI = (tH - tS)/(mS - mH);
  yI = mH * xI - tH;

  //calculate distance
  /* in degree
  double dInDegree = Math.sqrt((pointLat - xI) * (pointLat - xI) 
                           + (pointLng - yI) * (pointLng - yI));

  return dInDegree;
  */
  //in meter
  double R = 6371000; // m
  double dLat = (pointLat-xI).toRad();
  double dLon = (pointLng-yI).toRad(); 
  double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(x1.toRad()) * Math.cos(pointLat.toRad()) * 
    Math.sin(dLon/2) * Math.sin(dLon/2); 
  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  double distanceInMeter = R * c;
  return distanceInMeter;
}

我希望这适合你,这是“简单的”矢量数学。

答案 2 :(得分:0)

检查Single Separate Lat / Long,查看列表中最近的坐标。

然后收集连接到该坐标的两个点(最接近您的单点的点)所以现在你有4个点。

singlePoint,nearestPointToSinglePoint,neighbor1,neighbor2。我假设你在这一点上有一些基本的触发经验(没有双关语意)。你应该从这里做的是可视化2个三角形。 (singlePoint,nearestPointToSinglePoint,neighbor1)和(singlePoint,nearestPointToSinglePoint,neighbor2)。

此时,从SinglePoint计算三角形的高度作为参考。您现在距离最近的2个边缘有2个距离。比较,享受你的结果。