tipo para longitud latitud dato encoding types latitude-longitude

encoding - para - latitud y longitud tipo de dato sql



apropiado/mejor tipo para almacenar latitud y longitud (11)

La resolución de 0.3 pulgadas se está reduciendo al punto donde los terremotos en unos pocos años hacen la diferencia. Es posible que desee reconsiderar por qué cree que necesita una resolución tan fina en todo el mundo.

Algunos de los centros de expansión en el Océano Pacífico cambian hasta 15 cm / año .

En un lenguaje de programación de nivel de sistema como C, C ++ o D, ¿cuál es el mejor tipo / codificación para almacenar latitud y longitud?

Las opciones que veo son:

  • IEEE-754 FP como grados o radianes
  • grados o radianes almacenados como un valor de punto fijo en un int de 32 o 64 bit
  • mapeo de un rango entero al rango de grados: -> deg = (360/2^32)*val
  • grados, minutos, segundos y segundos fraccionarios almacenados como campos de bits en un int
  • una estructura de algún tipo.

La solución fácil (FP) tiene la desventaja principal de que tiene una resolución altamente no uniforme (en algún lugar de Inglaterra puede medir en micras, en Japón, no puede). También esto tiene todos los problemas de la comparación de FP y otras cosas. Las otras opciones requieren un esfuerzo extra en diferentes partes del ciclo de vida de los datos. (generación, presentación, cálculos, etc.)

Una opción interesante es un tipo de precisión flotante que, a medida que Latitude aumenta, obtiene más bits y Longitude obtiene menos (a medida que se acercan más hacia los polos).

Preguntas relacionadas que no cubren completamente esto:

Por cierto: 32 bits te da una resolución E / W en el ecuador de aproximadamente 0.3 pulg. Esto está cerca de la escala en la que las configuraciones de GPS de alto grado pueden funcionar (IIRC pueden bajar a aproximadamente 0.5 pulgadas en algunos modos).

OTOH si los 32 bits están distribuidos uniformemente sobre la superficie de la tierra, puede indexar cuadrados de aproximadamente 344m en un lado, 5 bytes dan 21m, 6B-> 1.3m y 8B-> 5mm.

No tengo un uso específico en mente en este momento, pero he trabajado con este tipo de cosas antes y espero volver a hacerlo, en algún momento.


Longitudes y latitudes generalmente no se conocen con una precisión mayor que un flotador de 32 bits. Entonces, si le preocupa el espacio de almacenamiento, puede usar flotadores. Pero, en general, es más conveniente trabajar con números como dobles.

Los radianes son más convenientes para la matemática teórica. (Por ejemplo, la derivada del seno es coseno solo cuando se usan radianes). Pero los grados suelen ser más familiares y más fáciles de interpretar para las personas, por lo que es posible que desee mantener los grados.


¿Podrían convertirse en un problema los problemas que mencionó con los valores de coma flotante? Si la respuesta es no, sugeriría simplemente usar el valor de radianes con doble precisión; lo necesitará si va a hacer cálculos trigonométricos de todos modos.

Si puede haber un problema con la pérdida de precisión al usar dobles o no hará la trigonometría, sugeriría su solución de mapeo a un rango entero: esto le dará la mejor resolución, puede convertirse fácilmente a cualquier formato de visualización su configuración regional estará en uso y, después de elegir un meridiano 0 apropiado, se puede usar para convertir a valores de punto flotante de alta precisión.

PD: Siempre me he preguntado por qué parece que no hay nadie que use coordenadas esféricas geocéntricas; deben estar razonablemente cerca de las coordenadas geográficas, y no requerirán toda esta matemática sofisticada en esferoides para hacer cálculos; para divertirme, quería convertir Gauss-Krüger-Koordinaten (que están en uso por el Katasteramt alemán) en coordenadas GPS. Déjame decirte que eso fue feo: uno usa el elipsoide Bessel, el otro WGS84 y el Gauss-Krüger. el mapeo en sí mismo es bastante loco por sí mismo ...


Si al "almacenar" te refieres a "tener en la memoria", la verdadera pregunta es: ¿qué vas a hacer con ellos?

Sospecho que antes de que estas coordenadas hagan algo interesante, se habrán canalizado como radianes a través de las funciones en math.h. A menos que planee implementar bastantes funciones trascendentales que operan en Deg / Min / Secs empaquetadas en un campo de bit.

Entonces, ¿por qué no mantener las cosas simples y simplemente almacenarlas en IEEE-754 grados o radianes con la precisión de sus requisitos?


Qué codificación es la "mejor" realmente depende de tus objetivos / requisitos.

Si realiza aritmética, latitud de punto flotante, la longitud suele ser bastante conveniente. Otras veces las coordenadas cartesianas (es decir, x, y, z) pueden ser más convenientes. Por ejemplo, si solo le interesan los puntos en la superficie de la tierra, podría usar un n-vector .

En cuanto al almacenamiento a largo plazo, el punto flotante IEEE desperdiciará bits para rangos que no le interesan (para lat / lon) o para la precisión que puede no importar en el caso de las coordenadas cartesianas (a menos que desee una precisión muy buena en el origen por cualquier razón). Por supuesto, puede asignar cualquier tipo de coordenadas a las entradas de su tamaño preferido, de modo que todo el rango de dichas operaciones cubra el rango que le interese a la resolución que le interesa.

Por supuesto, hay otras cosas en las que pensar que simplemente no desperdiciar bits en la codificación. Por ejemplo, (Geohashes) [https://en.wikipedia.org/wiki/Geohash] tiene la buena propiedad de que es fácil encontrar otros geoashes en la misma área. (La mayoría tendrá el mismo prefijo, y puede calcular el prefijo que tendrán los demás). Desafortunadamente, mantienen la misma precisión en grados de longitud cerca del ecuador, cerca de los polos. Actualmente estoy usando geohashes de 64 bits para el almacenamiento, lo que da una resolución de aproximadamente 3 m en el ecuador.

El sistema localizador de Maidenhead tiene algunas características similares, pero parece estar más optimizado para comunicarse entre personas que para almacenar en una computadora. (El almacenamiento de cadenas MLS podría desperdiciar una gran cantidad de bits para una detección de errores bastante trivial.)

El único sistema que encontré que maneja los polos de manera diferente es el Sistema de referencia de cuadrícula militar , aunque también parece más orientado a las comunicaciones humanas. (Y parece un dolor convertir desde o hacia lat / lon).

Dependiendo de lo que quieras exactamente, podrías usar algo similar al sistema de coordenadas polares universales de Universal cerca de los polos junto con algo más computacionalmente sano que UTM para el resto del mundo, y usar como máximo un bit para indicar cuál de los dos sistemas estás usando Digo a lo sumo un poco, porque es poco probable que la mayoría de los puntos que le interesan estén cerca de los polos. Por ejemplo, puede usar "medio bit" diciendo que 11 indica el uso del sistema polar, mientras que 00, 01 y 10 indican el uso del otro sistema y son parte de la representación.

Lo siento, este es un poco largo, pero quería guardar lo que había aprendido recientemente. Tristemente, no he encontrado ninguna manera estándar, sensata y eficiente de representar un punto en la tierra con precisión uniforme.

Editar: Encontré otro enfoque que se parece mucho más a lo que quería, ya que aprovecha más directamente la menor precisión necesaria para la longitud más cercana a los polos. Resulta que hay mucha investigación sobre el almacenamiento de vectores normales. La codificación de vectores normales utilizando coordenadas esféricas optimizadas describe un sistema de este tipo para codificar vectores normales, manteniendo un nivel mínimo de precisión, pero también podría utilizarse para coordenadas geográficas.


Puedes usar decimal tipo de datos decimal :

CREATE TABLE IF NOT EXISTS `map` ( `latitude` decimal(18,15) DEFAULT NULL, `longitude` decimal(18,15) DEFAULT NULL );


http://www.esri.com/news/arcuser/0400/wdside.html
En el ecuador, un segundo de arco de longitud es aproximadamente igual a un segundo de arco de latitud, que es 1 / 60th de una milla náutica (o 101.27 pies o 30.87 metros).

El flotador de 32 bits contiene 23 bits de datos explícitos.
180 * 3600 requiere log2 (648000) = 19.305634287546711769425914064259 bits de datos. Tenga en cuenta que el bit de signo se almacena por separado y, por lo tanto, necesitamos sumar solo 180 grados.
Después de restar de 23 los bits para log2 (648000), tenemos 3.694365712453288230574085935741 bits extra restantes para los datos del segundo segundo.
Eso es 2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053 partes por segundo.
Por lo tanto, un tipo de datos de flotación puede tener 30.87 / 12.945382716049382716049382716053 ~ = 2,38 metros de precisión en el ecuador.


Un programa de Java para cometer el máximo error de redondeo en metros desde la conversión de valores lat / long en Float / Double:

import java.util.*; import java.lang.*; import com.javadocmd.simplelatlng.*; import com.javadocmd.simplelatlng.util.*; public class MaxError { public static void main(String[] args) { Float flng = 180f; Float flat = 0f; LatLng fpos = new LatLng(flat, flng); double flatprime = Float.intBitsToFloat(Float.floatToIntBits(flat) ^ 1); double flngprime = Float.intBitsToFloat(Float.floatToIntBits(flng) ^ 1); LatLng fposprime = new LatLng(flatprime, flngprime); double fdistanceM = LatLngTool.distance(fpos, fposprime, LengthUnit.METER); System.out.println("Float max error (meters): " + fdistanceM); Double dlng = 180d; Double dlat = 0d; LatLng dpos = new LatLng(dlat, dlng); double dlatprime = Double.longBitsToDouble(Double.doubleToLongBits(dlat) ^ 1); double dlngprime = Double.longBitsToDouble(Double.doubleToLongBits(dlng) ^ 1); LatLng dposprime = new LatLng(dlatprime, dlngprime); double ddistanceM = LatLngTool.distance(dpos, dposprime, LengthUnit.METER); System.out.println("Double max error (meters): " + ddistanceM); } }

Salida:

Float max error (meters): 1.7791213425235692 Double max error (meters): 0.11119508289500799


El siguiente código contiene las coordenadas WGS84 sin pérdidas en un largo sin signo (es decir, en 8 bytes):

using System; using System.Collections.Generic; using System.Text; namespace Utils { /// <summary> /// Lossless conversion of OSM coordinates to a simple long. /// </summary> unsafe class CoordinateStore { private readonly double _lat, _lon; private readonly long _encoded; public CoordinateStore(double lon,double lat) { // Ensure valid lat/lon if (lon < -180.0) lon = 180.0+(lon+180.0); else if (lon > 180.0) lon = -180.0 + (lon-180.0); if (lat < -90.0) lat = 90.0 + (lat + 90.0); else if (lat > 90.0) lat = -90.0 + (lat - 90.0); _lon = lon; _lat = lat; // Move to 0..(180/90) var dlon = (decimal)lon + 180m; var dlat = (decimal)lat + 90m; // Calculate grid var grid = (((int)dlat) * 360) + ((int)dlon); // Get local offset var ilon = (uint)((dlon - (int)(dlon))*10000000m); var ilat = (uint)((dlat - (int)(dlat))*10000000m); var encoded = new byte[8]; fixed (byte* pEncoded = &encoded[0]) { ((ushort*)pEncoded)[0] = (ushort) grid; ((ushort*)pEncoded)[1] = (ushort)(ilon&0xFFFF); ((ushort*)pEncoded)[2] = (ushort)(ilat&0xFFFF); pEncoded[6] = (byte)((ilon >> 16)&0xFF); pEncoded[7] = (byte)((ilat >> 16)&0xFF); _encoded = ((long*) pEncoded)[0]; } } public CoordinateStore(long source) { // Extract grid and local offset int grid; decimal ilon, ilat; var encoded = new byte[8]; fixed(byte *pEncoded = &encoded[0]) { ((long*) pEncoded)[0] = source; grid = ((ushort*) pEncoded)[0]; ilon = ((ushort*)pEncoded)[1] + (((uint)pEncoded[6]) << 16); ilat = ((ushort*)pEncoded)[2] + (((uint)pEncoded[7]) << 16); } // Recalculate 0..(180/90) coordinates var dlon = (uint)(grid % 360) + (ilon / 10000000m); var dlat = (uint)(grid / 360) + (ilat / 10000000m); // Returns to WGS84 _lon = (double)(dlon - 180m); _lat = (double)(dlat - 90m); } public double Lon { get { return _lon; } } public double Lat { get { return _lat; } } public long Encoded { get { return _encoded; } } public static long PackCoord(double lon,double lat) { return (new CoordinateStore(lon, lat)).Encoded; } public static KeyValuePair<double, double> UnPackCoord(long coord) { var tmp = new CoordinateStore(coord); return new KeyValuePair<double, double>(tmp.Lat,tmp.Lon); } } }

Fuente: http://www.dupuis.me/node/35


La forma más fácil es almacenarlo como un flotador / doble en grados. Positivo para N y E, negativo para S y W. Solo recuerde que los minutos y los segundos están fuera de los 60 (entonces 31 45''N es 31.75). Es fácil entender cuáles son los valores al observarlos y, cuando es necesario, la conversión a radianes es trivial.

Los cálculos de latitudes y longitudes, como la distancia del Gran Círculo entre dos coordenadas, dependen en gran medida de las funciones trigonométricas, que generalmente usan dobles. Cualquier otro formato va a depender de otra implementación de seno, coseno, atan2 y raíz cuadrada, como mínimo. Los números de precisión arbitrarios (por ejemplo, BigDecimal en Java) no funcionarán para esto. Algo así como int, donde 2 ^ 32 se propaga uniformemente, tendrá problemas similares.

El punto de uniformidad ha surgido en varios comentarios. Sobre esto simplemente señalaré que la Tierra, con respecto a la longitud, no es uniforme. Una longitud de arco de segundo en el Círculo Polar Ártico es una distancia más corta que en el Ecuador. Los flotadores de doble precisión brindan precisión submilimétrica en cualquier lugar de la Tierra. ¿Esto no es suficiente? ¿Si no, porque no?

También valdría la pena señalar lo que desea hacer con esa información, ya que los tipos de cálculos que necesite tendrán un impacto en el formato de almacenamiento que utilice.


Una representación decimal con una precisión de 8 debería ser más que suficiente de acuerdo con este artículo de Wikipedia sobre grados decimales .

0 decimal places, 1.0 = 111 km ... 7 decimal places, 0.0000001 = 1.11 cm 8 decimal places, 0.00000001 = 1.11 mm