La distancia desde la función de círculo grande de punto a línea no funciona correctamente.

StackOverflow https://stackoverflow.com/questions/1051723

Pregunta

Necesito obtener la distancia desde un punto lat / lng a una línea. Por supuesto, debe seguir el Gran Círculo.

Encontré un excelente artículo sobre esto en http: //www.movable -type.co.uk/scripts/latlong.html

pero el código no funciona correctamente. O estoy haciendo algo mal o falta algo. Aquí está la función en cuestión. Vea el enlace para las otras funciones si es necesario.

    var R = 3961.3
    LatLon.crossTrack = function(lat1, lon1, lat2, lon2, lat3, lon3) {
     var d13 = LatLon.distHaversine(lat1, lon1, lat3, lon3);
     var brng12 = LatLon.bearing(lat1, lon1, lat2, lon2);
     var brng13 = LatLon.bearing(lat1, lon1, lat3, lon3);
     var dXt = Math.asin(Math.sin(d13/R)*Math.sin(brng13-brng12)) * R;
     return dXt;
    } 

lat / lon1 = -94.127592, 41.81762

lat / lon2 = -94.087257, 41.848202

lat / lon3 = -94.046875, 41.791057

Esto reporta 0.865 millas. La distancia real es de 4.29905 millas.

¿Alguna pista sobre cómo solucionar esto? No soy matemático, solo soy un programador de dientes.

¿Fue útil?

Solución

La mayoría de las funciones trigonométricas necesitan radianes. ¿Son sus medidas angulares en grados? Quizás necesiten convertirse utilizando la fórmula habitual:

  

2 * & # 960; radianes = 360 grados

Si mira debajo de la fórmula de Haversine, verá esto:

  

(Tenga en cuenta que los ángulos deben estar en radianes para pasar a las funciones trigonométricas).

Otros consejos

¿Su función devuelve el mismo valor para estas coordenadas:

crossTrack(0,0,0,1,0.1,0.5);
crossTrack(0,0,0,1,0.1,0.6);
crossTrack(0,0,0,1,0.1,0.4);

Creo que debería, pero el mío no. El tercer punto es siempre 0.1 hacia el norte desde el ecuador. solo cambia la longitud que no debería afectar el resultado. Como parece que lo hace.

Probé esta prueba de resistencia puntual enviándole aalatlon, etc.

private static final double _eQuatorialEarthRadius = 6378.1370D;
private static final double _d2r = (Math.PI / 180D);
private static double PRECISION = 1;





// Haversine Algorithm
// source: http://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates

private static double HaversineInM(double lat1, double long1, double lat2, double long2) {
    return  (1000D * HaversineInKM(lat1, long1, lat2, long2));



}

private static double HaversineInKM(double lat1, double long1, double lat2, double long2) {
    double dlong = (long2 - long1) * _d2r;
    double dlat = (lat2 - lat1) * _d2r;
    double a = Math.pow(Math.sin(dlat / 2D), 2D) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r)
            * Math.pow(Math.sin(dlong / 2D), 2D);
    double c = 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
    double d = _eQuatorialEarthRadius * c;





    return d;
}

// Distance between a point and a line

public static double pointLineDistanceTest(double[] aalatlng,double[] bblatlng,double[]cclatlng){



    double [] a = aalatlng;
    double [] b = bblatlng;
    double [] c = cclatlng;




    double[] nearestNode = nearestPointGreatCircle(a, b, c);
    //        System.out.println("nearest node: " + Double.toString(nearestNode[0])
    + ","+Double.toString(nearestNode[1]));
    double result =  HaversineInM(c[0], c[1], nearestNode[0], nearestNode[1]);

       //        System.out.println("result: " + Double.toString(result));



          return (result);






}

// source: http://stackoverflow.com/questions/1299567/how-to-calculate-distance-from-a-point-to-a-line-segment-on-a-sphere
private static double[] nearestPointGreatCircle(double[] a, double[] b, double c[])
{
    double[] a_ = toCartsian(a);
    double[] b_ = toCartsian(b);
    double[] c_ = toCartsian(c);

    double[] G = vectorProduct(a_, b_);
    double[] F = vectorProduct(c_, G);
    double[] t = vectorProduct(G, F);

    return fromCartsian(multiplyByScalar(normalize(t), _eQuatorialEarthRadius));
}

@SuppressWarnings("unused")
private static double[] nearestPointSegment (double[] a, double[] b, double[] c)
{
   double[] t= nearestPointGreatCircle(a,b,c);
   if (onSegment(a,b,t))
     return t;

   return (HaversineInKM(a[0], a[1], c[0], c[1]) < HaversineInKM(b[0], b[1], c[0], c[1])) ? a : b;
}

 private static boolean onSegment (double[] a, double[] b, double[] t)
   {
     // should be   return distance(a,t)+distance(b,t)==distance(a,b), 
     // but due to rounding errors, we use: 
     return Math.abs(HaversineInKM(a[0], a[1], b[0], b[1])-HaversineInKM(a[0], a[1], t[0], t[1])-HaversineInKM(b[0], b[1], t[0], t[1])) < PRECISION;
   }


// source: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates
private static double[] toCartsian(double[] coord) {
    double[] result = new double[3];
    result[0] = _eQuatorialEarthRadius * Math.cos(Math.toRadians(coord[0])) * Math.cos(Math.toRadians(coord[1]));
    result[1] = _eQuatorialEarthRadius * Math.cos(Math.toRadians(coord[0])) * Math.sin(Math.toRadians(coord[1]));
    result[2] = _eQuatorialEarthRadius * Math.sin(Math.toRadians(coord[0]));


    return result;
}

private static double[] fromCartsian(double[] coord){
    double[] result = new double[2];
    result[0] = Math.toDegrees(Math.asin(coord[2] / _eQuatorialEarthRadius));
    result[1] = Math.toDegrees(Math.atan2(coord[1], coord[0]));

    return result;
}


// Basic functions
private static double[] vectorProduct (double[] a, double[] b){
    double[] result = new double[3];
    result[0] = a[1] * b[2] - a[2] * b[1];
    result[1] = a[2] * b[0] - a[0] * b[2];
    result[2] = a[0] * b[1] - a[1] * b[0];

    return result;
}

private static double[] normalize(double[] t) {
    double length = Math.sqrt((t[0] * t[0]) + (t[1] * t[1]) + (t[2] * t[2]));
    double[] result = new double[3];
    result[0] = t[0]/length;
    result[1] = t[1]/length;
    result[2] = t[2]/length;
    return result;
}

private static double[] multiplyByScalar(double[] normalize, double k) {
    double[] result = new double[3];
    result[0] = normalize[0]*k;
    result[1] = normalize[1]*k;
    result[2] = normalize[2]*k;
    return result;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top