-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathGeoExtensions.cs
More file actions
257 lines (230 loc) · 10.3 KB
/
GeoExtensions.cs
File metadata and controls
257 lines (230 loc) · 10.3 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
using System.Text.RegularExpressions;
namespace Waher.Runtime.Geo
{
/// <summary>
/// Extension methods for geo-spatial calculations.
/// </summary>
public static class GeoExtensions
{
/// <summary>
/// Checks if a position lies outside a given bounding box, using the Mercator projection.
/// If Min.Longitude > Max?.Longitude, the bounding box is considered to pass the +-180 longitude.
/// If any of the Min or Max coordinates are null, the corresponding coordinate is ignored.
/// </summary>
/// <param name="Position">Geo-spatial position</param>
/// <param name="Min">Lower-left corner of bounding box.</param>
/// <param name="Max">Upper-right corner of bounding box.</param>
/// <returns>If the position lies outside of the box.</returns>
public static bool LiesOutside(this GeoPosition Position, GeoPosition Min, GeoPosition Max)
{
return Position.LiesOutside(Min, Max, false, false, false);
}
/// <summary>
/// Checks if a position lies outside a given bounding box, using the Mercator projection.
/// If Min.Longitude > Max?.Longitude, the bounding box is considered to pass the +-180 longitude.
/// If any of the Min or Max coordinates are null, the corresponding coordinate is ignored.
/// </summary>
/// <param name="Position">Geo-spatial position</param>
/// <param name="Min">Lower-left corner of bounding box.</param>
/// <param name="Max">Upper-right corner of bounding box.</param>
/// <param name="IncludeMin">If the min latitude/longitude/altitude should be considered as outside.</param>
/// <param name="IncludeMax">If the max latitude/longitude/altitude should be considered as outside.</param>
/// <returns>If the position lies outside of the box.</returns>
public static bool LiesOutside(this GeoPosition Position, GeoPosition Min, GeoPosition Max,
bool IncludeMin, bool IncludeMax)
{
return Position.LiesOutside(Min, Max, IncludeMin, IncludeMax, false);
}
/// <summary>
/// Checks if a position lies outside a given bounding box, using the Mercator projection.
/// If Min.Longitude > Max?.Longitude, the bounding box is considered to pass the +-180 longitude.
/// If any of the Min or Max coordinates are null, the corresponding coordinate is ignored.
/// </summary>
/// <param name="Position">Geo-spatial position</param>
/// <param name="Min">Lower-left corner of bounding box.</param>
/// <param name="Max">Upper-right corner of bounding box.</param>
/// <param name="IncludeMin">If the min latitude/longitude/altitude should be considered as outside.</param>
/// <param name="IncludeMax">If the max latitude/longitude/altitude should be considered as outside.</param>
/// <param name="IgnoreAltitude">If altitude should be ignored in the comparison.</param>
/// <returns>If the position lies outside of the box.</returns>
public static bool LiesOutside(this GeoPosition Position, GeoPosition Min, GeoPosition Max,
bool IncludeMin, bool IncludeMax, bool IgnoreAltitude)
{
if (Position.Latitude.OutOfRange(Min?.Latitude, Max?.Latitude, IncludeMin, IncludeMax))
return true;
if (!(Min is null) && !(Max is null) && Min.Longitude > Max.Longitude)
{
if (!Position.Longitude.OutOfRange(Max.Longitude, Min.Longitude, !IncludeMin, !IncludeMax))
return true;
}
else
{
if (Position.Longitude.OutOfRange(Min?.Longitude, Max?.Longitude, IncludeMin, IncludeMax))
return true;
}
if (IgnoreAltitude)
return false;
if (Position.Altitude.HasValue &&
Position.Altitude.Value.OutOfRange(Min?.Altitude, Max?.Altitude, IncludeMin, IncludeMax))
{
return true;
}
return false;
}
private static bool OutOfRange(this double Value, double? Min, double? Max,
bool IncludeMin, bool IncludeMax)
{
int MinComp = Min.HasValue ? Value.CompareTo(Min.Value) : 1;
int MaxComp = Max.HasValue ? Value.CompareTo(Max.Value) : -1;
if (MinComp < 0 || IncludeMin && MinComp == 0)
return true;
if (MaxComp > 0 || IncludeMax && MaxComp == 0)
return true;
return false;
}
private static bool InRange(this double Value, double? Min, double? Max,
bool IncludeMin, bool IncludeMax)
{
int MinComp = Min.HasValue ? Value.CompareTo(Min.Value) : 1;
int MaxComp = Max.HasValue ? Value.CompareTo(Max.Value) : -1;
if (MinComp < 0 || (!IncludeMin && MinComp == 0))
return false;
if (MaxComp > 0 || (!IncludeMax && MaxComp == 0))
return false;
return true;
}
/// <summary>
/// If a <paramref name="Position"/> is north of a reference point
/// <paramref name="Reference"/>. The reference point itself will be included
/// if <paramref name="IncludeReference"/> is true.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference point.</param>
/// <param name="IncludeReference">If reference point is included.</param>
/// <returns>If Position is north of reference point.</returns>
public static bool NorthOf(this GeoPosition Position, GeoPosition Reference, bool IncludeReference)
{
int i = Position.Latitude.CompareTo(Reference.Latitude);
return i > 0 || (IncludeReference && i == 0);
}
/// <summary>
/// If a <paramref name="Position"/> is south of a reference point
/// <paramref name="Reference"/>. The reference point itself will be included
/// if <paramref name="IncludeReference"/> is true.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference point.</param>
/// <param name="IncludeReference">If reference point is included.</param>
/// <returns>If Position is south of reference point.</returns>
public static bool SouthOf(this GeoPosition Position, GeoPosition Reference, bool IncludeReference)
{
int i = Position.Latitude.CompareTo(Reference.Latitude);
return i < 0 || (IncludeReference && i == 0);
}
/// <summary>
/// If a <paramref name="Position"/> is east of a reference point
/// <paramref name="Reference"/>. The reference point itself will be included
/// if <paramref name="IncludeReference"/> is true.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference point.</param>
/// <param name="IncludeReference">If reference point is included.</param>
/// <returns>If Position is east of reference point.</returns>
public static bool EastOf(this GeoPosition Position, GeoPosition Reference, bool IncludeReference)
{
int i = Position.Longitude.CompareTo(Reference.Longitude);
return i > 0 || (IncludeReference && i == 0);
}
/// <summary>
/// If a <paramref name="Position"/> is west of a reference point
/// <paramref name="Reference"/>. The reference point itself will be included
/// if <paramref name="IncludeReference"/> is true.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference point.</param>
/// <param name="IncludeReference">If reference point is included.</param>
/// <returns>If Position is west of reference point.</returns>
public static bool WestOf(this GeoPosition Position, GeoPosition Reference, bool IncludeReference)
{
int i = Position.Longitude.CompareTo(Reference.Longitude);
return i < 0 || (IncludeReference && i == 0);
}
/// <summary>
/// If a <paramref name="Position"/> is north of a bounding box
/// <paramref name="Reference"/>.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference bounding box.</param>
/// <returns>If Position is north of reference bounding box.</returns>
public static bool NorthOf(this GeoPosition Position, IGeoBoundingBox Reference)
{
return Position.NorthOf(Reference.Max, !Reference.IncludeMax);
}
/// <summary>
/// If a <paramref name="Position"/> is south of a bounding box
/// <paramref name="Reference"/>.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference bounding box.</param>
/// <returns>If Position is south of reference bounding box.</returns>
public static bool SouthOf(this GeoPosition Position, IGeoBoundingBox Reference)
{
return Position.SouthOf(Reference.Min, !Reference.IncludeMin);
}
/// <summary>
/// If a <paramref name="Position"/> is east of a bounding box
/// <paramref name="Reference"/>.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference bounding box.</param>
/// <returns>If Position is east of reference bounding box.</returns>
public static bool EastOf(this GeoPosition Position, IGeoBoundingBox Reference)
{
if (Reference.LongitudeWrapped)
return Position.EastOf(Reference.Min, !Reference.IncludeMin);
else
return Position.EastOf(Reference.Max, !Reference.IncludeMax);
}
/// <summary>
/// If a <paramref name="Position"/> is west of a bounding box
/// <paramref name="Reference"/>.
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference bounding box.</param>
/// <returns>If Position is west of reference bounding box.</returns>
public static bool WestOf(this GeoPosition Position, IGeoBoundingBox Reference)
{
if (Reference.LongitudeWrapped)
return Position.WestOf(Reference.Max, !Reference.IncludeMax);
else
return Position.WestOf(Reference.Min, !Reference.IncludeMin);
}
/// <summary>
/// If the altitude defined by <paramref name="Position"/> (if any) lies within
/// the scope of the bounding box <paramref name="Reference"/> (if defined).
/// </summary>
/// <param name="Position">Position.</param>
/// <param name="Reference">Reference bounding box.</param>
/// <returns>If Position altitude is within the bounding box (if defined).</returns>
public static bool AltitudeCheck(this GeoPosition Position, IGeoBoundingBox Reference)
{
if (Position.Altitude.HasValue)
{
return Position.Altitude.Value.InRange(Reference.Min?.Altitude, Reference.Max?.Altitude,
Reference.IncludeMin, Reference.IncludeMax);
}
return true;
}
/// <summary>
/// If the Geo-spatial ID matches a given pattern, defined as a regular expression.
/// </summary>
/// <param name="GeoId">Geo-spatial ID</param>
/// <param name="Pattern">Optional regular expression</param>
/// <returns>If the ID matches.</returns>
public static bool GeoIdPatternCheck(this string GeoId, Regex Pattern)
{
Match M = Pattern.Match(GeoId);
return M.Success && M.Index == 0 && M.Length == GeoId.Length;
}
}
}