¿Encontrar la distancia perpendicular y el vector perpendicular mínimo entre el punto y la línea usando GeoTools y JTS?

8

Tengo una línea formada por 2 pares lat / lon, y el lat / lon de un punto. Me gustaría averiguar la distancia perpendicular entre la línea y el punto en la superficie de la Tierra (puede asumir la Tierra como gran esfera), y el vector perpendicular mínimo (es decir, el "punto de cruce" proyectado en la línea).

Estoy tratando de usar Geotools 8.0 y JTS para esto. A continuación capturó mi código de prueba:

    //Coordinates in lon, lat
    Coordinate linePt1 = new Coordinate(-5.71472, 50.06639);
    Coordinate linePt2 = new Coordinate(-3.07000, 58.64389);

    //Multiply all longitudes by the cosine of latitude.
    //http://gis.stackexchange.com/a/29713/10772
    linePt1.x = linePt1.x * Math.cos(linePt1.y);
    linePt2.x = linePt2.x * Math.cos(linePt2.y);

    LineString line = createLine(new Coordinate[]{linePt1, linePt2});

    Coordinate pt1 = new Coordinate(-6, 54);
    pt1.x = pt1.x * Math.cos(pt1.y);
    Point point = createPoint(pt1.x, pt1.y);

    double distanceOp = DistanceOp.distance(line, point);
    System.out.println("Distance = " + distanceOp);

    //Find the minimum perpendicular vector using "closestPoints()"
    for (Coordinate c : DistanceOp.closestPoints(line, point)) {
        System.out.println("=== " + c);
        //verify if the point is on the line
        System.out.println(CGAlgorithms.isOnLine(c, new Coordinate[]{linePt1, linePt2}));
    }

los métodos createPoint () y createLine ():

public static LineString createLine(Coordinate[] coordinates){
    GeometryFactory factory = new GeometryFactory(new PrecisionModel(
            PrecisionModel.FLOATING), WGS84_SRID);
    LineString line = (LineString) factory.createLineString(coordinates);
    return line;
}

public static Point createPoint(double longitude, double latitude) {
    if (longitude < -180 || longitude > 180) {
        throw new IllegalArgumentException(
                "Longitude should be between -180 and 180");
    }
    if (latitude < -90 || latitude > 90) {
        throw new IllegalArgumentException(
                "latitude should be between -90 and 90");
    }
    GeometryFactory factory = new GeometryFactory(new PrecisionModel(
            PrecisionModel.FLOATING), WGS84_SRID);
    Point point = (Point) factory.createPoint(new Coordinate(longitude,
            latitude));
    return point;
}

Sin embargo, el resultado de "isOnLine ()" devuelve falso. Me preguntaba si hay algo mal.

¿Hay algún problema con mi método de verificación, o en realidad la forma en que solía averiguar la distancia perpendicular y el "punto de cruce" en la superficie de la Tierra no es correcta?

xlogger
fuente
¿Has intentado usar PrecisionModel.FIXED? No puedo comentar sobre el resto de su código, pero una precisión doble puede introducir errores. Consulte Robustez y precisión en las preguntas frecuentes de JTS.
hepiladron
@hepiladron, gracias por tu sugerencia. Intenté usar PrecisionModel.FIXED pero aún obtuve el mismo resultado ...
xlogger
Para futuros lectores, es poco probable que esto funcione para usted, ya que JTS asume un marco cartesiano y no maneja la geometría esférica en absoluto.
Ian Turton

Respuestas:

3

También hay una solución que utiliza la proyección gonomónica presentada por Charles Karnes en Algoritmos para geodésicas. Hay una implementación en Java disponible con la biblioteca Barefoot: https://github.com/bmwcarit/barefoot

SpatialOperator spatial = new Geography();

Point reykjavik = new Point(-21.933333, 64.15);
Point moskva = new Point(37.616667, 55.75);
Point berlin = new Point(13.408056, 52.518611);

double f = spatial.intercept(reykjavik, moskva, berlin);
Point interception = spatial.interpolate(reykjavik, moskva, f);

Para obtener más detalles, consulte la respuesta aquí: https://gis.stackexchange.com/a/184695/29490

Funciona para proyecciones de punto a línea de gran distancia, pero también para cálculos de corta distancia (ver imágenes).

ingrese la descripción del enlace aquí

sema
fuente