Encoding 用于存储纬度和经度的合适/最佳类型 在C、C++或D等系统级编程语言中,存储纬度和经度的最佳类型/编码是什么?

Encoding 用于存储纬度和经度的合适/最佳类型 在C、C++或D等系统级编程语言中,存储纬度和经度的最佳类型/编码是什么?,encoding,types,latitude-longitude,Encoding,Types,Latitude Longitude,我看到的选择是: IEEE-754 FP以度或弧度表示 度或弧度存储为32或64位整数中的固定点值 整数范围到度范围的映射:->deg=(360/2^32)*val 度、分、秒和分数秒存储为整数中的位字段 某种结构 easy solution(FP)有一个主要的缺点,就是它的分辨率非常不均匀(在英国的某个地方,它可以用微米来测量,而在日本,它不能)。此外,这还涉及到计划生育比较等所有问题。其他选项需要在数据生命周期的不同部分付出额外的努力。(生成、表示、计算等) 一个有趣的选择是浮动精度类型

我看到的选择是:

  • IEEE-754 FP以度或弧度表示
  • 度或弧度存储为32或64位整数中的固定点值
  • 整数范围到度范围的映射:->
    deg=(360/2^32)*val
  • 度、分、秒和分数秒存储为整数中的位字段
  • 某种结构
easy solution(FP)有一个主要的缺点,就是它的分辨率非常不均匀(在英国的某个地方,它可以用微米来测量,而在日本,它不能)。此外,这还涉及到计划生育比较等所有问题。其他选项需要在数据生命周期的不同部分付出额外的努力。(生成、表示、计算等)

一个有趣的选择是浮动精度类型,当纬度增加时,它得到更多的位,而经度得到更少的位(当它们靠近两极时)

相关问题没有完全涵盖这一点:

ldLatitude = (double)li32LatFromGps / 10000000.0;

顺便说一句:32位在赤道上的E/W分辨率约为0.3英寸。这接近于高等级GPS设置可以工作的范围(在某些模式下,IIRC可以降到0.5左右)

如果32位均匀地分布在地球表面,你可以在一个边上索引大约344m的正方形,5个字节表示21m,6B->1.3m和8B->5mm


我现在想不出具体的用途,但我以前使用过这种东西,希望在某个时候再次使用。

最简单的方法就是将其存储为浮点/双精度度数。N和E为正,S和W为负。记住分和秒是60分之一(所以31 45’N是31.75)。通过查看这些值很容易理解它们是什么,并且在必要时,转换为弧度是很简单的

纬度和经度的计算,如两个坐标之间的距离,严重依赖三角函数,通常使用双精度。任何其他格式都将至少依赖于正弦、余弦、atan2和平方根的另一种实现。任意精度数字(如Java中的BigDecimal)对此不起作用。类似于2^32均匀分布的int也会有类似的问题

有几条评论提到了一致性的问题。在这一点上,我要简单地指出,地球相对于经度来说是不均匀的。北极圈的一弧秒经度比赤道短。双精度浮标在地球上任何地方都能提供亚毫米的精度。这还不够吗?若否,原因为何


还值得注意的是,您希望如何处理这些信息,因为您需要的计算类型将对您使用的存储格式产生影响。

经度和纬度通常不会比32位浮点更精确。因此,如果您关心存储空间,可以使用浮动。但一般来说,将数字作为双倍运算更方便


弧度对于理论数学来说更方便。(例如,只有在使用弧度时,正弦的导数才是余弦。)但度通常更为人们所熟悉,也更易于理解,因此您可能希望坚持使用度。

您提到的浮点值问题是否会成为一个问题?如果答案是否定的,我建议只使用弧度值的双精度-你需要它,如果你要做三角计算无论如何

如果使用double时可能会出现精度损失问题,或者您不会进行三角运算,我建议您使用映射到整数范围的解决方案-这将为您提供最佳分辨率,可以轻松地转换为您所在地区将使用的任何显示格式,并且在选择适当的0-meridian后,可以用于转换为高精度的浮点值


PS:我一直想知道为什么似乎没有人使用地心球坐标-它们应该相当接近地理坐标,并且不需要所有这些关于球体的奇特数学来进行计算;为了好玩,我想将Gauss Krüger Koorderin(德国Katasteramt公司正在使用)转换为GPS坐标-让我告诉你,这很难看:一个使用贝塞尔椭球体,另一个使用WGS84,而高斯-克鲁格(Gauss-Krüger)地图本身就相当疯狂…

0.3英寸的分辨率已经下降到了几年内地震会带来不同的程度。你可能想重新考虑一下,为什么你认为你需要在全世界范围内得到如此好的解决方案

太平洋上的一些传播中心的变化多达。

如果“存储”是指“记忆中的保存”,那么真正的问题是:你打算如何处理它们

我怀疑在这些坐标做任何有趣的事情之前,它们将以弧度的形式通过math.h中的函数。除非你计划实现很多超越函数,这些函数在Deg/Min/Secs上运行,并压缩到一个位域中


那么,为什么不让事情简单化,按照您的要求将它们存储在IEEE-754度或弧度中呢?

根据维基百科上的这篇文章,精度为8的十进制表示应该足够了

什么是“最佳”编码实际上取决于您的目标/需求

如果您正在执行算术,浮点纬度、经度通常非常方便。其他时候,笛卡尔坐标(即x,y,z)可能更方便。例如,如果您只关心地球表面的点,则可以使用

至于长期存储,IEEE浮点将浪费位用于您不关心的范围(lat/lon)或精度
CREATE TABLE IF NOT EXISTS `map` (
  `latitude` decimal(18,15) DEFAULT NULL,
  `longitude` decimal(18,15) DEFAULT NULL 
);
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);
  }
}
Float max error (meters): 1.7791213425235692
Double max error (meters): 0.11119508289500799
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);
        }
    }
}
double   ldLatitude;
int32_t  li32LatFromGps;
ldLatitude = (double)li32LatFromGps * 0.0000001;
ldLatitude = (double)li32LatFromGps / 10000000.0;