2using System.Diagnostics;
3using System.Globalization;
5using System.Text.RegularExpressions;
14 [DebuggerDisplay(
"{XmlValue}")]
22 public static readonly Regex
XmlGeoPositionPattern =
new Regex(
@"(?'Lat'-?\d+(\.\d+)?),(?'Lon'-?\d+(\.\d+)?)(,(?'Alt'-?\d+(\.\d+)?))?", RegexOptions.Singleline | RegexOptions.Compiled);
28 public static readonly Regex
GpsGeoPositionPattern =
new Regex(
@"^\s*(?'LatDeg'\d+)\s*°?(\s*(?'LatMin'\d+)'(\s*(?'LatSec'\d+(\.\d+)?)"")?)?\s*(?'LatSign'[nNsS])\s*(?'LonDeg'\d+)\s*°?(\s*(?'LonMin'\d+)'(\s*(?'LonSec'\d+(\.\d+)?)"")?)?\s*(?'LonSign'[eEwW])(\s*,)?\s*((Alt|Altitude)\:?\s*)?((?'Alt'-?\d+(\.\d+)?)\s*(?'AltUnit'(m|ft))?)?\s*$", RegexOptions.Singleline | RegexOptions.Compiled);
30 private double latitude;
31 private double longitude;
32 private double? altitude;
74 if (value < -90 || value > 90)
75 throw new ArgumentOutOfRangeException(nameof(this.
Latitude),
"Latitude must be between -90 and 90 degrees.");
77 this.latitude = value;
86 get => this.longitude;
89 if (value < -180 || value > 180)
90 throw new ArgumentOutOfRangeException(nameof(this.
Longitude),
"Longitude must be between -180 and 180 degrees.");
92 this.longitude = value;
101 get => this.altitude;
102 set => this.altitude = value;
112 if (this.latitude < -90 || this.latitude > 90)
113 throw new InvalidOperationException(
"Latitude must be between -90 and 90 degrees.");
115 return (this.latitude + 90) / 180;
126 if (this.longitude < -180 || this.longitude > 180)
127 throw new InvalidOperationException(
"Longitude must be between -180 and 180 degrees.");
129 return (this.longitude + 180) / 360;
144 throw new FormatException(
"Invalid geo-position string: " + s);
173 int i = s.IndexOf(
',');
185 int j = s.IndexOf(
',', i);
211 if (!
TryParse(s.Substring(j + 1), out
double d))
225 private static bool TryParse(
string s, out
double Value)
227 return double.TryParse(s.Replace(
".",
System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
230 internal static string ToString(
double Value)
232 string s = Value.ToString(CultureInfo.InvariantCulture);
236 internal static string ToString(
bool Value)
238 return Value ?
"true" :
"false";
252 if (!M.Success || M.Index > 0 || M.Length < s.Length)
255 if (!
TryParse(M.Groups[
"LatDeg"], M.Groups[
"LatMin"], M.Groups[
"LatSec"],
256 M.Groups[
"LatSign"], -90, 90, out
double Latitude))
261 if (!
TryParse(M.Groups[
"LonDeg"], M.Groups[
"LonMin"], M.Groups[
"LonSec"],
262 M.Groups[
"LonSign"], -180, 180, out
double Longitude))
267 string AltitudeStr = M.Groups[
"Alt"].Value;
268 if (
string.IsNullOrEmpty(AltitudeStr))
275 string Unit = M.Groups[
"AltUnit"].Value;
277 if (!
string.IsNullOrEmpty(Unit))
279 switch (Unit.ToLower())
299 private static bool TryParse(Group Deg, Group Minute, Group Second, Group Sign,
300 double Min,
double Max, out
double Value)
304 if (Second is
null ||
string.IsNullOrEmpty(Second.Value))
306 else if (!
TryParse(Second.Value, out Value))
311 if (!
string.IsNullOrEmpty(Minute?.Value))
313 if (!
int.
TryParse(Minute.Value, out i))
321 if (!
int.
TryParse(Deg.Value, out i))
326 if (Sign is
null ||
string.IsNullOrEmpty(Sign.Value) || Sign.Value.Length != 1)
329 char ch =
char.ToUpper(Sign.Value[0]);
331 if (ch ==
'S' || ch ==
'W')
333 else if (ch !=
'N' && ch !=
'E')
336 if (Value < Min || Value > Max)
349 StringBuilder sb =
new StringBuilder();
353 sb.Append(
ToString(this.longitude));
355 if (this.altitude.HasValue)
358 sb.Append(
ToString(this.altitude.Value));
361 return sb.ToString();
372 StringBuilder sb =
new StringBuilder();
378 if (this.altitude.HasValue)
381 sb.Append(
ToString(this.altitude.Value));
384 return sb.ToString();
395 StringBuilder sb =
new StringBuilder();
397 Append(this.latitude,
'N',
'S', sb);
399 Append(this.longitude,
'E',
'W', sb);
401 if (this.altitude.HasValue)
404 sb.Append(
ToString(this.altitude.Value));
408 return sb.ToString();
412 private static void Append(
double Nr,
char PosChar,
char NegChar, StringBuilder sb)
439 else if (Seconds > 60 - 1e-10)
453 if (Minutes != 0 || Seconds != 0)
479 this.latitude == P.latitude &&
480 this.longitude == P.longitude &&
481 this.altitude == P.altitude;
487 int Result = this.latitude.GetHashCode();
488 Result ^= Result << 5 ^ this.longitude.GetHashCode();
490 if (this.altitude.HasValue)
491 Result ^= Result << 5 ^ this.altitude.Value.GetHashCode();
504 if (A is
null ^ B is
null)
521 if (A is
null ^ B is
null)
Contains information about a position in a geo-spatial coordinate system.
static readonly Regex GpsGeoPositionPattern
Pattern for parsing a geo-position GPS strings. The names groups Lat, Lon and Alt can be used to extr...
double Longitude
Longitude in degrees.
override string ToString()
double NormalizedLongitude
Normalized longitude. The range [-180,180] is linearly mapped to [0,1].
double? Altitude
Altitude in meters. Can be null.
static bool TryParse(string s, out GeoPosition Value)
Tries to parse a string representation of a GeoPosition. If first attempts the XML format....
double NormalizedLatitude
Normalized longitude. The range [-90,90] is linearly mapped to [0,1].
override bool Equals(object obj)
string NormalizedValue
String-representation of the normalized geo-position.
GeoPosition(double Latitude, double Longitude)
Contains information about a position in a geo-spatial coordinate system.
string XmlValue
String-representation of the geo-position, for use in XML.
static bool TryParseXml(string s, out GeoPosition Value)
Tries to parse an XML string representation of a GeoPosition.
double Latitude
Latitude in degrees.
static bool TryParseGps(string s, out GeoPosition Value)
Tries to parse a GPS string representation of a GeoPosition.
static bool operator!=(GeoPosition A, GeoPosition B)
Checks if two geo-positions are not equal.
GeoPosition(double Latitude, double Longitude, double? Altitude)
Contains information about a position in a geo-spatial coordinate system.
static GeoPosition Parse(string s)
Parse a string representation of a GeoPosition. If first attempts the XML format. If not successful,...
static readonly Regex XmlGeoPositionPattern
Pattern for parsing a geo-position XML values. The names groups Lat, Lon and Alt can be used to extra...
static bool operator==(GeoPosition A, GeoPosition B)
Checks if two geo-positions are equal.
override int GetHashCode()
string HumanReadable
Human-readable string-representation of the geo-position.
GeoPosition()
Contains information about a position in a geo-spatial coordinate system.
static string TrimLabel(string Label)
Trims a numeric label, removing apparent roundoff errors.
TypeNameSerialization
How the type name should be serialized.