-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathLatLon.cs
120 lines (100 loc) · 3.39 KB
/
LatLon.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Bulldozer
{
public readonly struct LatLon : IEquatable<LatLon>
{
private readonly int _lat;
private readonly int _lng;
public float Lat => Precision == 1 ? _lat : _lat / (float) Precision;
public float Long => Precision == 1 ? _lng : _lng / (float) Precision;
public static LatLon Empty => new (-1000, -1000, 1);
private static readonly Dictionary<int, Dictionary<int, LatLon>> PoolLatToLonToInstance = new();
public readonly int Precision;
private LatLon(int lat, int lng, int precision)
{
_lat = lat;
_lng = lng;
Precision = precision;
}
public int RawLat()
{
return _lat;
}
public int RawLon()
{
return _lng;
}
public static LatLon FromCoords(double lat, double lon, int precisionMultiple = 1)
{
if (precisionMultiple != 1)
{
if (precisionMultiple < 1)
throw new InvalidDataException("Invalid precision multiple " + precisionMultiple);
if (precisionMultiple % 10 != 0)
throw new InvalidDataException("Invalid precision multiple " + precisionMultiple);
}
int newLat = lat < 0 ? Mathf.CeilToInt((float)lat * precisionMultiple) : Mathf.FloorToInt((float)lat * precisionMultiple);
int newLon = lon < 0 ? Mathf.CeilToInt((float)lon * precisionMultiple) : Mathf.FloorToInt((float)lon * precisionMultiple);
if (!PoolLatToLonToInstance.TryGetValue(newLat, out var lonLookup))
{
lonLookup = new Dictionary<int, LatLon>();
PoolLatToLonToInstance[newLat] = lonLookup;
}
if (!lonLookup.TryGetValue(newLon, out var inst))
{
lonLookup[newLon] = inst = new LatLon(lat: newLat, lng: newLon, precisionMultiple);
}
return inst;
}
public bool Equals(LatLon other)
{
return _lat == other._lat && _lng == other._lng;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((LatLon)obj);
}
public override int GetHashCode()
{
unchecked
{
return (_lat * 397) ^ _lng;
}
}
public bool IsEmpty()
{
return Precision == 0 || _lat == Empty._lat && _lng == Empty._lng;
}
public override string ToString()
{
return $"{Lat},{Long}";
}
public LatLon Offset(int latOffset, int lonOffset)
{
return FromCoords(Lat + latOffset, Long + lonOffset, Precision);
}
public static HashSet<LatLon> GetKnownValues()
{
var result = new HashSet<LatLon>();
foreach (var lonLookup in PoolLatToLonToInstance.Values)
{
foreach (var value in lonLookup.Values)
{
result.Add(value);
}
}
return result;
}
}
}