Last active
May 2, 2022 11:00
-
-
Save FObermaier/0f88895bac6160b3ac0e380d3e12b421 to your computer and use it in GitHub Desktop.
Lat-/Longitude Utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Globalization; | |
using NetTopologySuite.Geometries; | |
namespace NetTopologySuite.Geography | |
{ | |
public struct LatLon | |
{ | |
/// <summary> | |
/// Initializes this LatLon struct with the provided <paramref name="lat"/> and <paramref name="lon"/> values | |
/// </summary> | |
/// <param name="lat">A latitude</param> | |
/// <param name="lon">A longitude</param> | |
public LatLon(double lat, double lon) | |
{ | |
if (lat < -90 || lat > 90) | |
throw new ArgumentException("latitude outside of valid range", nameof(lat)); | |
if (lon < -180 || lon > 180) | |
throw new ArgumentException("longitude outside of valid range", nameof(lon)); | |
Lat = lat; | |
Lon = lon; | |
} | |
/// <summary> | |
/// Initializes this LatLon struct with <see cref="Lat"/>=<see cref="Coordinate.Z"/> and | |
/// <see cref="Lon"/>=<see cref="Coordinate.X"/> values of <paramref name="coordinate"/> values | |
/// </summary> | |
/// <param name="lat">A latitude</param> | |
/// <param name="lon">A longitude</param> | |
public LatLon(Coordinate coordinate) | |
:this(coordinate.Y, coordinate.X) | |
{ | |
} | |
/// <summary> | |
/// Gets a value indicating the latitude | |
/// </summary> | |
public double Lat { get; } | |
/// <summary> | |
/// Gets a value indicating the longitude | |
/// </summary> | |
public double Lon { get; } | |
/// <inheritdoc/> | |
public override string ToString() | |
{ | |
return string.Format(NumberFormatInfo.InvariantInfo,"LL({0:R},{1:R})", Lat, Lon); | |
} | |
/// <summary> | |
/// Implict conversion operator to transform a <see cref="Coordinate"/> into a <see cref="LatLon"/> | |
/// </summary> | |
/// <param name="coordinate">A coordinate</param> | |
public static implicit operator LatLon(Coordinate coordinate) | |
{ | |
return new LatLon(coordinate); | |
} | |
/// <summary> | |
/// Implict conversion operator to transform a <see cref="LatLon"/> into a <see cref="Coordinate"/> | |
/// </summary> | |
/// <param name="ll">A LatLon</param> | |
public static implicit operator Coordinate(LatLon ll) | |
{ | |
return new Coordinate(ll.Lon, ll.Lat); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using NetTopologySuite.Geography; | |
namespace NetTopologySuite.Algorithm | |
{ | |
public static class LatLonDistance | |
{ | |
/// <summary> | |
/// Conversion factor degrees to radians | |
/// </summary> | |
const double DegToRad = Math.PI / 180d; //0.01745329252; // Convert Degrees to Radians | |
/// <summary> | |
/// Meters per inch | |
/// </summary> | |
const double MetersPerInch = 0.0254; | |
/// <summary> | |
/// Meters per mile | |
/// </summary> | |
const double MetersPerMile = 1609.347219; | |
/// <summary> | |
/// Miles per degree at equator | |
/// </summary> | |
const double MilesPerDegreeAtEquator = 69.171; | |
/// <summary> | |
/// Meters per degree at equator | |
/// </summary> | |
const double MetersPerDegreeAtEquator = MetersPerMile * MilesPerDegreeAtEquator; | |
/// <summary> | |
/// Calculate the distance between 2 points on the great circle | |
/// </summary> | |
/// <param name="ll1">Lat/lon of the 1st point</param> | |
/// <param name="ll2">Lat/lon of the 2nd point</param> | |
/// <returns>The distance in meters</returns> | |
public static double Distance(LatLon ll1, LatLon ll2) | |
{ | |
double lonDistance = DiffLongitude(ll1.Lon, ll2.Lon); | |
double arg1 = Math.Sin(ll1.Lat * DegToRad) * Math.Sin(ll2.Lat * DegToRad); | |
double arg2 = Math.Cos(ll1.Lat * DegToRad) * Math.Cos(ll2.Lat * DegToRad) * Math.Cos(lonDistance * DegToRad); | |
return MetersPerDegreeAtEquator * Math.Acos(arg1 + arg2) / DegToRad; | |
} | |
/// <summary> | |
/// Calculate the difference between two longitudinal values | |
/// </summary> | |
/// <param name="lon1">The first longitude value in degrees</param> | |
/// <param name="lon2">The second longitude value in degrees</param> | |
/// <returns>The distance in degrees</returns> | |
private static double DiffLongitude(double lon1, double lon2) | |
{ | |
double diff; | |
if (lon1 > 180.0) | |
lon1 = 360.0 - lon1; | |
if (lon2 > 180.0) | |
lon2 = 360.0 - lon2; | |
if ((lon1 >= 0.0) && (lon2 >= 0.0)) | |
diff = lon2 - lon1; | |
else if ((lon1 < 0.0) && (lon2 < 0.0)) | |
diff = lon2 - lon1; | |
else | |
{ | |
// different hemispheres | |
if (lon1 < 0) | |
lon1 = -1 * lon1; | |
if (lon2 < 0) | |
lon2 = -1 * lon2; | |
diff = lon1 + lon2; | |
if (diff > 180.0) | |
diff = 360.0 - diff; | |
} | |
return diff; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using NetTopologySuite.Algorithm; | |
using NetTopologySuite.Geometries; | |
namespace NetTopologySuite.Geography | |
{ | |
public static class LatLonExtensions | |
{ | |
public static LatLon GetLatLon(this CoordinateSequence self, int index) | |
{ | |
return (LatLon)self.GetCoordinate(index); | |
} | |
public static void SetLatLon(this CoordinateSequence self, int index, LatLon ll) | |
{ | |
self.SetOrdinate(index, Ordinate.Y, ll.Lat); | |
self.SetOrdinate(index, Ordinate.X, ll.Lon); | |
} | |
public static IEnumerable<LatLon> GetLatLons(this ICoordinateSequence self) | |
{ | |
if (self == null) | |
yield break; | |
for (int i = 0; i < self.Count; i++) | |
yield return self.GetLatLon(i); | |
} | |
public static ICoordinateSequence Create(this ICoordinateSequenceFactory self, IList<LatLon> lls) | |
{ | |
var llList = new List<Coordinate>(); | |
foreach (var ll in lls) | |
llList.Add(ll); | |
return self.Create(llList.ToArray()); | |
} | |
public static LatLon GetLatLon(this Coordinate self) | |
{ | |
return self; | |
} | |
public static LatLon GetLatLon(this IGeometry self) | |
{ | |
return self.Coordinate; | |
} | |
public static Point CreateGeoPoint(this GeometryFactory self, LatLon ll) | |
{ | |
if (self.SRID != 4326) | |
throw new ArgumentException("Factory has invalid SRID", nameof(self)); | |
return self.CreatePoint(self.CoordinateSequenceFactory.Create(new[] { ll })); | |
} | |
public static LineString CreateGeoLineString(this GeometryFactory self, IList<LatLon> lls) | |
{ | |
if (self.SRID != 4326) | |
throw new ArgumentException("Factory has invalid SRID", nameof(self)); | |
return self.CreateLineString(self.CoordinateSequenceFactory.Create(lls)); | |
} | |
public static Polygon CreateGeoPolygon(this GeometryFactory self, IList<LatLon> lls) | |
{ | |
if (self.SRID != 4326) | |
throw new ArgumentException("Factory has invalid SRID", nameof(self)); | |
var ring = self.CreateLinearRing(self.CoordinateSequenceFactory.Create(lls)); | |
return self.CreatePolygon(ring, null); | |
} | |
public static double GetLength(this IEnumerable<LatLon> self) | |
{ | |
double res = 0; | |
var last = new LatLon(); | |
int i = 0; | |
foreach(var ll in self) | |
{ | |
if (i > 0) | |
res += LatLonDistance.Distance(last, ll); | |
last = ll; | |
i++; | |
} | |
return res; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment