Update README with project details and setup instructions; add data directories to .gitignore

This commit is contained in:
Leonid Pershin
2026-08-16 17:09:16 +03:00
parent 9d09d6e97f
commit 8460921bfa
73 changed files with 6978 additions and 1 deletions
@@ -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);
}