2015-10-15 2 views
3

У меня есть список координат Lat/Long, который представляет собой многоугольник и один отдельный Lat/Long, который, как я знаю, содержится внутри полигона.Расстояние между Lat/Long и ближайшим краем многоугольника, состоящего из Lat/Longs?

Как определить расстояние от одиночного Lat/Long до ближайшего края многоугольника? Есть ли для этого известная библиотека Java?

ответ

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; 
} 

Я надеюсь, что это работает для вас, это «просто» вектор математики.

+0

Это находит ближайший угол, а не ближайший край.Это также потенциально неправильно, если вопроситель заботится о расстоянии в фиксированной единице (например, км/мили), а не в градусах лат/долго. – Sbodd

+0

Простите, что это заняло так много времени, но я не смог сделать это раньше. Перед моим первым ответом я не мог прочитать;) Теперь это должно сработать для вас! –

0

Проверьте одиночный разделитель Lat/Long, для ближайшей координаты, которая существует в вашем списке.

Затем соберите две точки, которые связаны с этим координатом (тот, который ближе всего к вашей единственной точке). Теперь у вас есть 4 точки.

singlePoint, ближайшийPointToSinglePoint, соседний1, сосед2. Я предполагаю, что у вас есть базовый опыт триггера в данный момент (каламбур не предназначен). То, что вы должны сделать здесь, - это визуализировать 2 треугольника. (singlePoint, closeestPointToSinglePoint, соседний1) и (singlePoint, ближайшийPointToSinglePoint, соседний 2).

На этом этапе вычислите высоту треугольников из SinglePoint в качестве эталона. Теперь у вас есть 2 расстояния до двух ближайших краев. Сравните и наслаждайтесь результатами.

+0

Для пояснения используйте Edge (сторона между соседним и ближайшим точками) в качестве базы для расчета. Площадь = 1/2 Высота основания *. поэтому для Height = h = 2 * A/b – Lencalot

1

Я предлагаю следующее решение, которое также работает в случае многоугольника, расположенного вокруг северного полюса, где расчет долготы и разности широт не имеет смысла.

Решение преобразует долготу и широту точек на Землю в трехмерные координаты, используя World Geodetic System 84. С этими трехмерными точками вы можете рассчитать проекцию одной точки на линию, определяемую двумя другими точками в трехмерном пространстве.

Вот код, выполняющий расчеты. Он использует класс javafx.geometry.Point3D, доступный в Java 8.

/** 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 с точкой и точками Сегменты многоугольника, вы можете найти ближайшую линию, определяемую краевые точки и расширенную до бесконечности. В случае вогнутого многоугольника это может быть не то, что вы хотите, как вы видите на картинке.

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.

Смежные вопросы