¿Cómo encontrar un punto a medio camino entre otros dos puntos?


8

Estoy trabajando en la implementación del formato binario móvil OSM para datos de mapas, y debido a que utiliza un delta de 16 bits para cada punto a lo largo de un camino, no puede representar un camino si hay una gran distancia entre dos puntos.

La solución documentada es inyectar nuevos puntos en el camino, para mantener la brecha más pequeña.

Aquí está la sección relevante de mi código:

// calculate the distance between this point and the previous point,
// multiplied by 1,000,000 so it can be represented as an integer.
int32_t realNodeLatDelta = ((point.latitude - lastPoint.latitude) * 1000000);
int32_t realNodeLonDelta = ((point.longitude - lastPoint.longitude) * 1000000);

// cast as a 16 bit int (reduces filesize by about half)
int16_t nodeLatDelta = realNodeLatDiff;
int16_t nodeLonDelta = realNodeLonDiff;

// check if the cast caused corruption
if (realNodeLatDelta != nodeLatDelta || realNodeLatDelta != nodeLatDelta) {
  // if this point is reached, we need to add new points in the way,
  // which can be represented in a 16 bit delta
}

No estoy seguro de cómo calcular la posición de nuevos puntos en el camino? ¿Asumo que necesita ser un gran círculo?

Los puntos lo suficientemente separados como para causar este problema son raros, pero cuando suceden, generalmente es un límite político o similar, que tiende a ser bastante largo y debe representarse con precisión.


Sugiero hacer esta pregunta en la lista de correo OSM-dev ( lists.openstreetmap.org/listinfo/dev ), es demasiado específica para un foro general de SIG.
Igor Brejc

1
¿Seguramente la matemática para encontrar un punto a medio camino entre otros dos puntos no es muy específica?
Abhi Beckert

No lo es, pero tal vez hay otras formas de abordar este problema, que es específico del formato.
Igor Brejc

No hay métodos alternativos para tratarlo. Un entero de 16 bits es el único formato permitido para puntos de una manera, y (con 6 decimales de precisión) un entero de 16 bits solo es capaz de representar una diferencia de aproximadamente 3.5 km entre dos puntos. La única alternativa es no usar ese formato (que es mi solución provisional). Pero quiero usar algo estándar si es posible.
Abhi Beckert

1
Creo que puede ser un orden de magnitud: las distancias más largas que puede encontrar en la tierra son de unos 20,000 km. Con 16 bits, eso se traduce en una precisión de 300 m.
whuber

Respuestas:


13

La mejor precisión se obtiene con modelos elipsoidales. En aras de la simplicidad, debe evitarlos cuando tenga que codificar distancias usted mismo. Pagamos un precio: dado que el aplanamiento de la Tierra es de aproximadamente 1/300, el uso de un modelo puramente esférico puede potencialmente introducir un error de distancia relativa de hasta 1/300 para rutas muy largas: alrededor de 3000 partes por millón. Vale la pena explorarlo.

Primero, la fórmula esférica : simplemente convierta (lat, lon) a coordenadas cartesianas, promedie los dos puntos cartesianos, luego convierta el promedio nuevamente a coordenadas esféricas. Aquí está el pseudocódigo:

function cartesian(f,l) { // f = latitude, l = longitude
    return (cos(f)*cos(l), cos(f)*sin(l), sin(f))
}
function spherical(x,y,z) {
    r = sqrt(x^2 + y^2)
    if (r == 0) {
        if (z > 0) return (90, 0) 
        elseif (z < 0) return (-90, 0)
        else return Undefined // (x,y,z) == (0,0,0)
    } else {
        return (atan2(r, z), atan2(x, y)) // atan2 must return *degrees*
    }
}
function midpoint(f0,l0, f1,l1) { 
    return spherical((cartesian(f0,l0) + cartesian(f1,l1))/2)
}

(La aritmética para midpointimplica una suma vectorial y una división escalar de esa suma, por lo que realmente oculta tres sumas y tres divisiones).

Ese es el punto medio en geometría esférica. El cálculo requiere dos cosenos, dos senos, una raíz cuadrada, dos arcotangentes y algo de multiplicación y suma: razonablemente rápido y fácil. No habrá problemas cerca de los polos o cruzando el meridiano + -180. El resultado será indefinido cuando los dos puntos son diametralmente opuestos.

Una forma de medir el error es calcular la mayor distancia recorrida a través del punto medio en comparación con la distancia entre los puntos originales. Si el aumento es pequeño en comparación con la distancia original, tenemos poco de qué quejarnos. He calculado estos errores utilizando la distancia elipsoidal precisa para el elipsoide WGS84. Como ejemplo típico de los resultados, aquí hay una gráfica de errores relativos cuando uno de los puntos finales se fija en (lat, lon) = (45, 0):

Errores relativos

Los contornos están en una escala logarítmica (base 10): los contornos -6 muestran puntos donde el error relativo es 10 ^ (- 6); es decir, una parte por millón (ppm). Los contornos -5 (apenas visibles cerca (-45, 180), el punto diametralmente opuesto) son 10 ppm. Los -7, -8, etc. son fracciones de ppm: muy precisos.

Evidentemente, mientras no estemos tratando de calcular puntos medios de dos puntos que son casi diametralmente opuestos, lo haremos bien. (Recuerde, el cálculo es perfectamente correcto para la esfera; estos errores se deben al aplanamiento de la esfera).

Dado que la precisión de 16 bits es de aproximadamente 16 ppm (un registro de base 10 igual a -4.8), parece correcto usar la fórmula esférica para encontrar puntos medios siempre que los dos puntos estén a más de un grado de distancia de ser diametralmente opuestos.

¿Qué pasa con la fórmula lineal más simple? Para estudiar esto, comparemos la distancia entre el punto medio lineal (obtenido promediando las dos latitudes y las dos longitudes) con el punto medio esférico, en relación con la distancia entre los dos puntos finales. La siguiente figura fija un punto final en (45, 180) y explora una región relativamente pequeña a su alrededor.

Errores relativos 2

La mayoría de estos contornos (logaritmos de base 10 una vez más) están cerca de -2: eso es una parte por cien (1%) de error. Para las direcciones norte-sur no hay error, pero para todas las demás direcciones el error es inaceptable para muchas aplicaciones .

Para ver si la aproximación lineal se vuelve correcta, acerquémonos a ese mapa anterior por un factor de 10. Ahora tiene un grado de ancho (50 millas en esta latitud) y medio grado de ancho (35 millas): estamos mirando a la escala de una gran ciudad o una pequeña ciudad y sus suburbios.

Ahora los contornos están alrededor de -3 a -4: eso es de 100 a 1000 partes por millón (0.01% a 0.1%). Bastante crudo y apenas perceptible en una pantalla de computadora de alta resolución si se mira de cerca.

Errores relativos 3

Mirando hacia atrás, es evidente que la fórmula esférica un poco más complicada, pero aún fácilmente implementable, logra una mayor precisión en todo el mundo que la fórmula lineal simple incluso en ubicaciones cercanas. (Estoy bromeando un poco, porque he usado dos formas diferentes de medir errores, por lo que no son directamente comparables).

La línea de fondo:

- La fórmula lineal colocará mal el punto medio por un error relativo de 0.01% a 0.1% a escala de ciudad; en áreas más grandes, la colocación incorrecta puede ser muy incorrecta (1% en hasta cientos de%).

La fórmula esférica es absolutamente correcta para un modelo de tierra esférica. En comparación con la fórmula elipsoidal más precisa, aún debería funcionar bien, excepto por los puntos que son casi diametralmente opuestos.


1
¡Wow gracias! Esa es una muy buena información. No necesito una precisión perfecta, es solo una aplicación de iPhone para uso personal de GPS, principalmente enfocada en calles. Dado que una carretera no es perfectamente recta durante cientos de kilómetros, incluso la precisión lineal es "lo suficientemente buena". Pero los límites políticos son a menudo rectos y largos (el lado derecho de Australia Occidental es de 1.800 km). La fórmula esférica debería ser perfecta para eso. Me gustaría poder darte una recompensa por tu respuesta, te lo mereces.
Abhi Beckert

8

Su solución funciona para distancias pequeñas, pero no funcionará para distancias más grandes. La forma más fácil de ver por qué es mirar el siguiente mapa (tomado de aquí ):

ingrese la descripción de la imagen aquí

Es un mapa mundial en proyección equirectangular: las longitudes y latitudes se proyectan linealmente en los ejes X e Y. Sus matemáticas pueden ser representadas por el rectángulo azul . Sin embargo, la diagonal azul no representa la "línea" más corta entre dos puntos en la superficie de la Tierra. Lo que necesitas es un gran círculo (representado por una curva negra ).

Aunque está utilizando C ++, le recomiendo echar un vistazo a la Biblioteca de Geodesia C # de Mike Gavaghan , es de código abierto y el código es de alta calidad, debería ser capaz de descubrir cómo hacer el cálculo a lo largo del gran círculo. También puede echar un vistazo a las fórmulas de Vincenty si está interesado en las matemáticas detrás del cálculo.


¡Gracias! Eso es exactamente lo que estoy buscando. El código de Mike Gavaghan parece fácil de transferir a C (en realidad estoy usando Objective-C por cierto). Estaba bastante seguro de que mis matemáticas lineales estarían lejos, pero necesitaba tener algo.
Abhi Beckert el

-1

Las matemáticas lineales simples parecen funcionar bien:

double newLat = lastCoord.latitude + ((coord.latitude - lastCoord.latitude) / 2);
double newLon = lastCoord.longitude + ((coord.longitude - lastCoord.longitude) / 2);

Estoy insertando recursivamente puntos nuevos a la mitad en cada sección del camino que es demasiado grande, hasta que todos sean lo suficientemente pequeños.

No estoy seguro de si se necesitan matemáticas más complejas para distancias más grandes (¿alguien puede confirmar esto por mí?), Pero funciona bien en este caso (unos 5 km):

ejemplo de línea recta larga entre puntos

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.