Chubrik.LatLng64 1.0.0

dotnet add package Chubrik.LatLng64 --version 1.0.0
                    
NuGet\Install-Package Chubrik.LatLng64 -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Chubrik.LatLng64" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Chubrik.LatLng64" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Chubrik.LatLng64" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Chubrik.LatLng64 --version 1.0.0
                    
#r "nuget: Chubrik.LatLng64, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Chubrik.LatLng64@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Chubrik.LatLng64&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Chubrik.LatLng64&version=1.0.0
                    
Install as a Cake Tool

LatLng64

NuGet CI

A 64-bit struct that packs [latitude, longitude] into a single ulong with ±2.8 mm precision in populated latitudes and ±5.6 mm in polar zones. Decodes to clean decimals. Half the size of a (double, double) pair; ideal for geographic databases.

Install

dotnet add package Chubrik.LatLng64

Targets net8.0 and netstandard2.0. Both builds implement IEquatable<LatLng64>, IComparable, IComparable<LatLng64>, and IFormattable. The net8.0 build adds ISpanFormattable, IParsable<LatLng64>, ISpanParsable<LatLng64>, IUtf8SpanFormattable, and IUtf8SpanParsable<LatLng64>.

Quick start

using Chubrik.LatLng64;

var coord = new LatLng64(55.7558, 37.6173);
var (lat, lng) = coord.GetCoordinates();

// Persist as a single 64-bit value (great for a database column)
ulong raw = coord.Data;
var restored = LatLng64.FromData(raw);

API at a glance

Member Purpose
new LatLng64(lat, lng) Construct from degrees
GetCoordinates() Decode to (double, double)
Data / FromData(ulong) Serialize / deserialize as ulong
Parse / TryParse Convert from text
ToString / TryFormat Convert to text
Equals, ==, !=, CompareTo Equality (by encoding) and ordering

Database storage

The Data property is a stable ulong — bytes are platform-independent and round-trip on any process. Entity Framework Core:

modelBuilder.Entity<Place>()
    .Property(p => p.Location)
    .HasConversion(v => v.Data, raw => LatLng64.FromData(raw));

JSON serialization

System.Text.Json doesn’t serialize LatLng64 out of the box. A small converter handles it — Data is wrapped as a JSON string to keep precision through JavaScript’s Number type (values exceed 2^53):

public sealed class LatLng64JsonConverter : JsonConverter<LatLng64>
{
    public override LatLng64 Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => LatLng64.FromData(ulong.Parse(reader.GetString()!, CultureInfo.InvariantCulture));

    public override void Write(
        Utf8JsonWriter writer, LatLng64 value, JsonSerializerOptions options)
        => writer.WriteStringValue(value.Data.ToString(CultureInfo.InvariantCulture));
}

Register it via [JsonConverter(typeof(LatLng64JsonConverter))] on a property, or globally via JsonSerializerOptions.Converters.

Note: serializing a default(LatLng64) writes {"Data":"0"} and fails to deserialize back — initialize values before persisting.

Notes

  • default(LatLng64) is intentionally invalid. Calling GetCoordinates, ToString, or TryFormat on it throws InvalidOperationException — uninitialized values fail loudly instead of silently mapping to (0, 0).
  • NaN and ±Infinity are rejected. Constructor throws ArgumentOutOfRangeException; Parse throws OverflowException (TryParse returns false). Latitude must be in [−90, +90], longitude in [−180, +180].
  • Parse / ToString are culture-sensitive. A null provider resolves to CultureInfo.CurrentCulture (not Invariant). Cultures with a , decimal separator use ; as the pair separator: "55,7558; 37,6173". For cross-machine text round-trips, pass an explicit CultureInfo — typically Invariant.
  • CompareTo is not a spatial order. Orders by raw Data — deterministic and useful for sorting and database indexing, but geographically close points may be far apart in this order.

Precision by zone

The 64-bit budget is split unevenly across seven zones so that linear precision stays within ±2.8 mm in populated latitudes and ±5.6 mm in polar zones. Coarser angular longitude steps in higher zones compensate for the shrinking longitudinal degree (cos lat).

Zone Latitude range Latitude step Longitude step Precision Habitability
Northern +85° … +90° 0.0000001° 0.000001° ±5.6 mm No
Arctic +72° … +85° 0.0000001° 0.0000002° ±5.6 mm No
Aurora +60° … +72° 0.00000005° 0.0000001° ±2.8 mm Inhabited
Central −56° … +60° 0.00000005° 0.00000005° ±2.8 mm Inhabited
Interim −60° … −56° 0.0000001° 0.0000001° ±5.6 mm No
Antarctic −85° … −60° 0.0000001° 0.0000002° ±5.6 mm No
Southern −90° … −85° 0.0000001° 0.000001° ±5.6 mm No

The split is asymmetric on purpose: only northern mid-latitudes host populated land; the southern counterpart is mostly open ocean, so the Antarctic zone absorbs the whole −60° … −85° range at coarser steps.

Comparison

Format Size Precision
LatLng64 64 bits ±2.8 mm populated, ±5.6 mm polar zones (see table above)
(float, float) 64 bits up to ±1.7 m — variable, often unacceptable
(double, double) 128 bits sub-nanometer — twice the storage, far past meaningful precision
(int, int) × 10⁷ 64 bits ±5.6 mm uniform — 4× fewer bins per area than populated zones

License

Released under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 103 5/10/2026