135 lines
4.1 KiB
C#
135 lines
4.1 KiB
C#
using System.Numerics;
|
|
using TheLivingWorld.Core.Geo;
|
|
using TheLivingWorld.Core.Worlds;
|
|
|
|
namespace TheLivingWorld.Tests;
|
|
|
|
public class LocalProjectionTests
|
|
{
|
|
// Robert Lee, Texas - the town the first worlds were generated around.
|
|
private static readonly GeoPoint Origin = new(31.8966010, -100.4858591);
|
|
|
|
[Fact]
|
|
public void Origin_projects_to_world_zero()
|
|
{
|
|
var projection = new LocalProjection(Origin);
|
|
|
|
var projected = projection.Project(Origin);
|
|
|
|
Assert.Equal(0f, projected.X, 3);
|
|
Assert.Equal(0f, projected.Y, 3);
|
|
}
|
|
|
|
[Fact]
|
|
public void One_kilometre_north_lands_one_kilometre_up()
|
|
{
|
|
var projection = new LocalProjection(Origin);
|
|
var north = new GeoPoint(Origin.Latitude + 1000.0 / LocalProjection.MetersPerDegreeLatitude, Origin.Longitude);
|
|
|
|
var projected = projection.Project(north);
|
|
|
|
Assert.Equal(0f, projected.X, 2);
|
|
Assert.Equal(1000f, projected.Y, 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void Unproject_reverses_project()
|
|
{
|
|
var projection = new LocalProjection(Origin);
|
|
var point = new Vector2(-4321.5f, 6789.25f);
|
|
|
|
var roundTripped = projection.Project(projection.Unproject(point));
|
|
|
|
Assert.Equal(point.X, roundTripped.X, 1);
|
|
Assert.Equal(point.Y, roundTripped.Y, 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void Rejects_coordinates_outside_the_globe()
|
|
{
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => new LocalProjection(new GeoPoint(91, 0)));
|
|
}
|
|
}
|
|
|
|
public class GeoBoundsTests
|
|
{
|
|
[Theory]
|
|
[InlineData(31.8966010, -100.4858591, 10_000)]
|
|
[InlineData(60.0, 30.3, 20_000)]
|
|
[InlineData(-33.87, 151.21, 5_000)]
|
|
public void FromCenter_produces_a_square_of_the_requested_size(double lat, double lon, double sizeMeters)
|
|
{
|
|
var center = new GeoPoint(lat, lon);
|
|
var bounds = GeoBounds.FromCenter(center, sizeMeters);
|
|
var projection = new LocalProjection(center);
|
|
|
|
var southWest = projection.Project(bounds.South, bounds.West);
|
|
var northEast = projection.Project(bounds.North, bounds.East);
|
|
|
|
// Half a metre of slack over a 20 km span is the float rounding in the projection.
|
|
Assert.Equal(sizeMeters, northEast.X - southWest.X, 0.5);
|
|
Assert.Equal(sizeMeters, northEast.Y - southWest.Y, 0.5);
|
|
}
|
|
|
|
[Fact]
|
|
public void Overpass_bbox_is_south_west_north_east()
|
|
{
|
|
var bounds = new GeoBounds(South: 1, West: 2, North: 3, East: 4);
|
|
|
|
Assert.Equal("1.0000000,2.0000000,3.0000000,4.0000000", bounds.ToOverpassBbox());
|
|
}
|
|
}
|
|
|
|
public class ChunkGridTests
|
|
{
|
|
[Fact]
|
|
public void Covers_the_whole_world_square()
|
|
{
|
|
var grid = new ChunkGrid(worldSizeMeters: 2048, chunkSizeMeters: 512);
|
|
|
|
Assert.Equal(4, grid.CountX);
|
|
Assert.Equal(4, grid.CountY);
|
|
Assert.Equal(-1024f, grid.MinX);
|
|
}
|
|
|
|
[Fact]
|
|
public void Rounds_the_count_up_when_the_size_does_not_divide_evenly()
|
|
{
|
|
var grid = new ChunkGrid(worldSizeMeters: 10_000, chunkSizeMeters: 512);
|
|
|
|
Assert.Equal(20, grid.CountX);
|
|
}
|
|
|
|
[Fact]
|
|
public void Maps_points_to_the_chunk_containing_them()
|
|
{
|
|
var grid = new ChunkGrid(worldSizeMeters: 2048, chunkSizeMeters: 512);
|
|
|
|
Assert.Equal(new ChunkCoord(0, 0), grid.CoordOf(new Vector2(-1024, -1024)));
|
|
Assert.Equal(new ChunkCoord(2, 2), grid.CoordOf(new Vector2(1, 1)));
|
|
Assert.Equal(new ChunkCoord(3, 3), grid.CoordOf(new Vector2(1023, 1023)));
|
|
}
|
|
|
|
[Fact]
|
|
public void Clamps_points_that_fall_outside_the_world()
|
|
{
|
|
var grid = new ChunkGrid(worldSizeMeters: 2048, chunkSizeMeters: 512);
|
|
|
|
Assert.Equal(new ChunkCoord(0, 0), grid.CoordOf(new Vector2(-99_999, -99_999)));
|
|
Assert.Equal(new ChunkCoord(3, 3), grid.CoordOf(new Vector2(99_999, 99_999)));
|
|
}
|
|
|
|
[Fact]
|
|
public void Chunk_bounds_line_up_with_the_grid()
|
|
{
|
|
var grid = new ChunkGrid(worldSizeMeters: 2048, chunkSizeMeters: 512);
|
|
|
|
var bounds = grid.BoundsOf(new ChunkCoord(1, 2));
|
|
|
|
Assert.Equal(-512f, bounds.MinX);
|
|
Assert.Equal(0f, bounds.MinY);
|
|
Assert.Equal(0f, bounds.MaxX);
|
|
Assert.Equal(512f, bounds.MaxY);
|
|
}
|
|
}
|