Update README with project details and setup instructions; add data directories to .gitignore
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace TheLivingWorld.Core.Geo;
|
||||
|
||||
/// <summary>
|
||||
/// Flattens WGS84 coordinates onto a local metric plane centred on an origin: X grows east, Y grows north,
|
||||
/// both in metres. This is an equirectangular projection with the scale factor frozen at the origin latitude,
|
||||
/// which stays sub-metre accurate across the 5-20 km worlds this game generates and — unlike Web Mercator —
|
||||
/// keeps distances usable directly as game units.
|
||||
/// </summary>
|
||||
public sealed class LocalProjection
|
||||
{
|
||||
public const double EarthRadiusMeters = 6378137.0;
|
||||
public const double MetersPerDegreeLatitude = EarthRadiusMeters * Math.PI / 180.0;
|
||||
|
||||
private readonly double _metersPerDegreeLongitude;
|
||||
|
||||
public LocalProjection(GeoPoint origin)
|
||||
{
|
||||
if (!origin.IsValid)
|
||||
throw new ArgumentOutOfRangeException(nameof(origin), origin, "Origin is not a valid WGS84 coordinate.");
|
||||
|
||||
Origin = origin;
|
||||
var cosLat = Math.Cos(origin.Latitude * Math.PI / 180.0);
|
||||
_metersPerDegreeLongitude = MetersPerDegreeLatitude * Math.Max(cosLat, 1e-6);
|
||||
}
|
||||
|
||||
public GeoPoint Origin { get; }
|
||||
|
||||
public Vector2 Project(GeoPoint point) => Project(point.Latitude, point.Longitude);
|
||||
|
||||
public Vector2 Project(double latitude, double longitude) => new(
|
||||
(float)((longitude - Origin.Longitude) * _metersPerDegreeLongitude),
|
||||
(float)((latitude - Origin.Latitude) * MetersPerDegreeLatitude));
|
||||
|
||||
public GeoPoint Unproject(Vector2 local) => new(
|
||||
Origin.Latitude + local.Y / MetersPerDegreeLatitude,
|
||||
Origin.Longitude + local.X / _metersPerDegreeLongitude);
|
||||
}
|
||||
Reference in New Issue
Block a user