위도 및 경도 저장에 적합한 / 최적 유형
C, C ++ 또는 D와 같은 시스템 수준 프로그래밍 언어에서 위도와 경도를 저장하는 데 가장 적합한 유형 / 인코딩은 무엇입니까?
내가 보는 옵션은 다음과 같습니다.
- 도 또는 라디안으로서의 IEEE-754 FP
- 32 또는 64 비트 정수에 고정 소수점 값으로 저장된 각도 또는 라디안
- 정수 범위를 정도 범위로 매핑 :->
deg = (360/2^32)*val
- int의 비트 필드로 저장된도, 분, 초 및 소수 초
- 어떤 종류의 구조체.
이지 솔루션 (FP)은 해상도가 균일하지 않다는 단점이 있습니다 (영국에서는 마이크론으로 측정 할 수 있지만 일본에서는 측정 할 수 없습니다). 또한 이것은 FP 비교와 그 밖의 모든 문제를 가지고 있습니다. 다른 옵션은 데이터 수명주기의 다른 부분에서 추가 노력이 필요합니다. (생성, 표현, 계산 등)
한 가지 흥미로운 옵션은 위도가 증가할수록 더 많은 비트를 얻고 경도는 더 적은 (극에 가까워 질수록) 부동 정밀도 유형입니다.
이를 다루지 않는 관련 질문 :
BTW : 32 비트는 적도에서 약 0.3 인치의 E / W 해상도를 제공합니다. 이것은 고급 GPS 설정이 작동 할 수있는 규모에 가깝습니다 (일부 모드에서는 IIRC가 약 0.5로 낮아질 수 있음).
OTOH 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와 같은 것은 비슷한 문제가있을 것입니다.
일관성의 요점은 여러 의견에서 나왔습니다. 이것에 대해 나는 단순히 경도와 관련하여 지구가 균일하지 않다는 점에 주목할 것입니다. 북극권에서 1 호 초 경도는 적도에서보다 거리가 더 짧습니다. 배정 밀도 플로트는 지구상 어디에서나 1 밀리미터 미만의 정밀도를 제공합니다. 이것으로 충분하지 않습니까? 그렇지 않다면 왜 안됩니까?
필요한 계산 유형이 사용하는 저장 형식에 영향을 미치므로 해당 정보로 무엇을 하려는지 주목할 가치가 있습니다.
경도와 위도는 일반적으로 32 비트 부동 소수점보다 더 높은 정밀도로 알려져 있지 않습니다. 따라서 저장 공간이 걱정된다면 플로트를 사용할 수 있습니다. 그러나 일반적으로 숫자를 두 배로 사용하는 것이 더 편리합니다.
라디안은 이론적 수학에 더 편리합니다. (예를 들어, 사인의 미분은 라디안을 사용할 때만 코사인입니다.) 그러나 각도는 일반적으로 사람들이 해석하기 더 친숙하고 더 쉽기 때문에 각도를 고수하는 것이 좋습니다.
정밀도가 8 인 Decimal 표현은 Decimal Degrees 에 대한이 wikipedia 기사에 따라 충분해야합니다 .
0 decimal places, 1.0 = 111 km
...
7 decimal places, 0.0000001 = 1.11 cm
8 decimal places, 0.00000001 = 1.11 mm
부동 소수점 값에 대해 언급 한 문제가 문제가 될 수 있습니까? 대답이 '아니요'인 경우 라디안 값을 배정 밀도로 사용하는 것이 좋습니다. 어쨌든 삼각법 계산을 수행하는 경우 필요합니다.
double을 사용할 때 정밀도 손실에 문제가 있거나 삼각법을 사용하지 않을 경우 정수 범위에 매핑하는 솔루션을 제안합니다. 이것은 최상의 해상도를 제공하고 어떤 디스플레이 형식으로도 쉽게 변환 할 수 있습니다. 로케일이 사용되며 적절한 0 자오선을 선택한 후 고정밀도의 부동 소수점 값으로 변환하는 데 사용할 수 있습니다.
추신 : 왜 지구 중심의 구형 좌표를 사용하는 사람이 없는지 항상 궁금했습니다. 그들은 지리적 좌표에 합리적으로 가까워 야하며 계산을하기 위해 스페 로이드에 대한이 멋진 수학을 요구하지 않을 것입니다. 재미를 위해 Gauss-Krüger-Koordinaten (독일 Katasteramt에서 사용중인)을 GPS 좌표로 변환하고 싶었습니다. 하나는 Bessel 타원체를 사용하고 다른 하나는 WGS84 및 Gauss-Krüger를 사용합니다. 매핑 자체는 그 자체로 꽤 미쳤습니다 ...
http://www.esri.com/news/arcuser/0400/wdside.html
적도에서 경도의 호초는 위도의 호초와 거의 같으며 해리의 1/60 (또는 101.27)입니다. 30.87 미터).
32 비트 부동 소수점에는 23 개의 명시 적 데이터 비트가 포함됩니다.
180 * 3600에는 log2 (648000) = 19.305634287546711769425914064259 비트 데이터가 필요합니다. 부호 비트는 별도로 저장되므로 180 도만 계산하면됩니다.
log2 (648000)에 대한 비트를 23에서 빼면 1 초 미만의 데이터에 대해 추가 3.694365712453288230574085935741 비트가 남습니다.
그것은 2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053 초당 부품입니다.
따라서 float 데이터 유형은 적도에서 30.87 / 12.945382716049382716049382716053 ~ = 2.38 미터 정밀도를 가질 수 있습니다.
0.3 인치 해상도는 몇 년에 걸친 지진이 영향을 미치는 지점까지 내려 가고 있습니다. 전 세계적으로 이러한 정밀한 해결책이 필요하다고 생각하는 이유를 재고 할 수 있습니다.
태평양의 일부 확산 센터는 연간 15cm 정도 변경됩니다 .
어떤 인코딩이 "최고"인지는 실제로 목표 / 요구 사항에 따라 다릅니다.
산술, 부동 소수점 위도, 경도를 수행하는 경우 종종 매우 편리합니다. 다른 경우에는 데카르트 좌표 (예 : x, y, z)가 더 편리 할 수 있습니다. 예를 들어 지구 표면의 점에만 관심이 있다면 n- 벡터를 사용할 수 있습니다 .
As for longer term storage, IEEE floating point will waste bits for ranges you don't care about (for lat/lon) or for precision you may not care about in the case of cartesian coordinates (unless you want very good precision at the origin for whatever reason). You can of course map either type of coordinates to ints of your preferred size, such that the entire range of said ints covers the range you are interested in at the resolution you care about.
There are of course other things to think about than merely not wasting bits in the encoding. For example, (Geohashes)[https://en.wikipedia.org/wiki/Geohash] have the nice property that it is easy to find other geohashes in the same area. (Most will have the same prefix, and you can compute the prefix the others will have.) Unfortunately, they maintain the same precision in degrees longitude near the equator as near the poles. I'm currently using 64-bit geohashes for storage, which gives about 3 m resolution at the equator.
The Maidenhead Locator System has some similar characteristics, but seems more optimized for communicating locations between humans rather than storing on a computer. (Storing MLS strings would waste a lot of bits for some rather trivial error detection.)
극을 다르게 처리하는 한 가지 시스템은 Military Grid Reference System 이지만 인간과 의사 소통을 지향하는 것 같습니다. (그리고 위도 / 경도로 변환하는 것은 고통스러워 보입니다.)
정확히 무엇을 원하는지에 따라 , 나머지 세계에서는 UTM 보다 계산적으로 더 건전한 것과 함께 극 근처 의 범용 극좌표 좌표계 와 유사한 것을 사용하고 최대 1 비트를 사용하여 두 시스템 중 어느 것을 나타낼 수 있습니다. 당신은 사용하고 있습니다. 나는 당신이 관심을 갖는 대부분의 포인트가 극 근처에있을 것 같지 않기 때문에 기껏해야 조금만 말한다. 예를 들어 11은 극좌표 시스템의 사용을 나타내며 00, 01, 10은 다른 시스템의 사용을 나타내며 표현의 일부라고 말하여 "반 비트"를 사용할 수 있습니다.
조금 길어서 미안하지만 최근에 배운 내용을 저장하고 싶었습니다. 슬프게도 저는 지구상의 한 지점을 균일 한 정밀도로 표현하는 표준적이고 건전하며 효율적인 방법을 찾지 못했습니다.
편집 : 극에 더 가까운 경도에 필요한 낮은 정밀도를 더 직접적으로 활용하기 때문에 원하는 것과 훨씬 더 유사한 다른 접근 방식을 찾았습니다. 법선 벡터를 저장하는 방법에 대한 많은 연구가 있습니다. 최적화 된 구면 좌표를 사용하여 정규 벡터 인코딩은 최소 수준의 정확도를 유지하면서 정규 벡터를 인코딩하는 이러한 시스템을 설명하지만 지리적 좌표에도 사용할 수 있습니다.
위도 / 경도 값을 Float / Double로 캐스팅 할 때 미터 단위의 최대 반올림 오류를 계산하는 Java 프로그램 :
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
"저장"이 "기억 유지"를 의미하는 경우 실제 질문은 다음과 같습니다. 그들로 무엇을 할 것인가?
이 좌표가 흥미로운 작업을 수행하기 전에 math.h의 함수를 통해 라디안으로 퍼널 링되었을 것입니다. 비트 필드에 압축 된 Deg / Min / Secs에서 작동하는 초월적인 기능을 상당히 많이 구현할 계획이 없다면.
그렇다면 간단하게 유지하고 요구 사항의 정밀도에 따라 IEEE-754도 또는 라디안으로 저장하는 것이 어떻습니까?
다음 코드는 WGS84 좌표를 unsigned long (즉, 8 바이트)으로 무손실 좌표로 압축합니다.
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);
}
}
}
출처 : http://www.dupuis.me/node/35
좋은 질문입니다!
I know this question is 9 years old now, and I only know a part of the answer you were seeking, but I just came here having a similar question, and many things have changed since that question was asked, such as hardware and GPSes available. I work with this subject frequently in firmware dealing with different kinds of GPSes in different kinds of applications, and have lost count of the hours (and days) I have spent working out "the best design" for different applications that I have worked with or developed.
As always, different solutions are going to provide benefits and costs, and ultimately, a "best design" is always going to be a "best fit" of the benefits and costs against system requirements. Here are some things that I have to consider when I ask the same question:
CPU Time Cost
If CPU does not have a built-in floating-point co-processor (as is the case with many microcontrollers), then dealing with 'float', 'double', and 'long double' can be extremely costly. For example, with one 16-bit microcontroller I work with regularly, a multiplication using 'double' values costs 326 CPU clock cycles, and a division costs 1193 clock cycles. Very expensive!
Accuracy Trade-Off
At the equator, a 'float' (IEEE-754 32-bit floating point value), needing to represent a signed degree value, assuming 7 "clean" significant decimal digits able to be represented, the change of one least-significant decimal digit (e.g. from 179.9999 to 180.0000) is going to represent a distance of about 11.12 meters. This may or may not meet hard system accuracy requirements. Whereas a 'double' (with 15 "clean" significant decimal digits represented, thus a change from 179.999999999999 to 180.000000000000) represents about 0.00011 mm.
Input Accuracy Limitations
If you're dealing with input from a GPS, how many digits of real accuracy are you getting, and how many do you need to preserve?
Development Time Costs
An IEEE-754 64-bit double-precision value ('double') and 32-bit single-precision value ('float') are VERY convenient to deal with in the C language since math libraries for both come with virtually every C compiler, and are usually very reliable. If your CPU comes with a hardware floating-point processor, this is an easy choice.
RAM and Storage Costs
If you have to keep a large number of these values in RAM (or storage e.g. MYSQL), available RAM (and storage space) might have an impact on the workability of the solution.
Available Data vs Required Data
One example I'm dealing with at this writing (the reason I came here to this question) is that I am dealing with a u-blox M8 GPS which is able to give me binary GPS information (saving the CPU overhead of translating ASCII NMEA sentences). In this binary format (called "UBX Protocol") latitude and longitude are represented as signed 32-bit integers, which representation is able to represent accuracy (at the equator) of down to about 1.11 cm. For example, -105.0269805 degrees longitude is represented as -1050269805 (using all 32 bits) and one LSb change represents about 1.11 cm change in latitude anywhere, and 1.11 cm longitude at the equator (and less at higher latitudes, in proportion to the cosine of the latitude). The application this GPS is in does navigation tasks, which (already existing and well-tested code) requires 'double' data types. Unfortunately, converting this integer to an IEEE-754 64-bit 'double' cannot be easily done just by moving the base-2 bits of the integer into the internal representation bits of the 'double' since the decimal shift to be performed is a base-10 decimal shift. Were it a base-2 decimal shift instead, then the base-2 bits of the integer could be moved into the bit-fields of the 'double' with very little translation required. But alas, this is not the case with the signed integer I have. So it is going to cost me a multiplication on a CPU that doesn't have a hardware floating-point processor: 326 CPU clock cycles.
double ldLatitude;
int32_t li32LatFromGps;
ldLatitude = (double)li32LatFromGps * 0.0000001;
Note this multiplication was chosen over this:
ldLatitude = (double)li32LatFromGps / 10000000.0;
because 'double' multiplication is about 3.6X faster than 'double' division on the CPU that I'm dealing with. Such is life in the microcontroller world. :-)
What would have been BRILLIANT (and may be in the future if I can spare the time on weekends) is if the navigation tasks could be done directly with the 32-bit signed integer! Then no conversion would be needed.... But would it cost more to do the navigation tasks with such an integer? CPU costs, probably much more efficient. Development time costs? That's another question, especially with a well-tested system already in place, that uses IEEE-754 64-bit 'double' values! Plus there is already-existing software that provides map data (using 'double' degree values), which software would have to be converted to use the signed integer as well -- not an overnight task!
One VERY interesting option is to directly (without translation) represent intersections between approximations of "rectangles" (actually trapezoids, which become triangles at the poles) using the raw latitude/longitude integers. At the equator these rectangles would have dimensions of approximately 1.11 cm east-west by 1.11 cm north-south, whereas at a latitude of say London, England, the dimensions would be approximately 0.69 cm east-west by 1.11 cm north-south. That may or may not be easy to deal with, depending on what the application needs.
Anyway, I hope these thoughts and discussion help others who are looking at this topic for "the best design" for their system.
Kind regards, Vic
You can use decimal
datatype:
CREATE TABLE IF NOT EXISTS `map` (
`latitude` decimal(18,15) DEFAULT NULL,
`longitude` decimal(18,15) DEFAULT NULL
);
참고URL : https://stackoverflow.com/questions/385132/proper-best-type-for-storing-latitude-and-longitude
'IT박스' 카테고리의 다른 글
완전히 오프라인으로 작동하도록 Android Studio를 설정하려면 어떻게해야합니까? (0) | 2020.11.25 |
---|---|
신속하게 NSCoder를 사용하여 enum을 인코딩하는 방법은 무엇입니까? (0) | 2020.11.25 |
매개 변수 이름 지정 : 파일 이름 또는 파일 이름? (0) | 2020.11.25 |
최고의 자바 트위터 라이브러리? (0) | 2020.11.25 |
RabbitMQ : 토픽 교환이있는 지속성 메시지 (0) | 2020.11.25 |