This repository has been archived on 2026-10-29. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
CultMath/tests/CultMath.Tests/PlanetaryProjectionTests.cs
2026-07-13 02:14:11 +01:00

73 lines
3.2 KiB
C#

using Xunit;
namespace CultMath.Tests;
public sealed class PlanetaryProjectionTests
{
[Theory]
[InlineData(PlanetaryProjectionKind.Equirectangular)]
[InlineData(PlanetaryProjectionKind.WebMercator)]
[InlineData(PlanetaryProjectionKind.EqualEarth)]
[InlineData(PlanetaryProjectionKind.Orthographic)]
[InlineData(PlanetaryProjectionKind.AzimuthalEquidistant)]
[InlineData(PlanetaryProjectionKind.AzimuthalEqualArea)]
[InlineData(PlanetaryProjectionKind.LocalTangent)]
public void ProjectionRoundTripsVisibleDirections(PlanetaryProjectionKind kind)
{
var parameters = new PlanetaryProjectionParameters(kind, 0.31, -0.22);
foreach (var longitude in new[] { -0.4, -0.1, 0.2, 0.65 })
foreach (var latitude in new[] { -0.6, -0.15, 0.3, 0.7 })
{
var direction = Direction(longitude + parameters.CenterLongitude, latitude);
if (!PlanetaryProjection.TryForward(direction, parameters, out var map)) continue;
Assert.True(PlanetaryProjection.TryInverse(map, parameters, out var roundTrip));
Assert.InRange(math.distance(direction, roundTrip), 0, 3.0e-5f);
}
}
[Fact]
public void CubeAtlasRoundTripsEveryFaceInterior()
{
var projection = new PlanetaryProjectionParameters(PlanetaryProjectionKind.CubeAtlas);
foreach (var face in Enum.GetValues<PlanetaryCubeFace>())
{
var direction = PlanetaryTopology.Direction(new(face, 0.23, -0.41));
Assert.True(PlanetaryProjection.TryForward(direction, projection, out var map));
Assert.True(PlanetaryProjection.TryInverse(map, projection, out var roundTrip));
Assert.InRange(math.distance(direction, roundTrip), 0, 2.0e-6f);
}
}
[Fact]
public void MercatorRejectsPolarSingularity()
{
var northPole = new float3(0, 0, 1);
Assert.False(PlanetaryProjection.TryForward(northPole, new(PlanetaryProjectionKind.WebMercator), out _));
}
[Fact]
public void MapTileBakerCarriesFieldIdentityAndProjectionValidity()
{
var field = new PlanetaryFieldDefinition(99, 10, 0, AdvancedErosionParameters.Default);
var layout = new PlanetaryMapTileLayout(
new(PlanetaryProjectionKind.Orthographic), 0, 0, 0, 9, 1);
var key = new PlanetaryMapTileKey(field.FieldVersion, 1, 7, layout, PlanetaryQueryScale.AtFootprint(0.1f));
var tile = PlanetaryMapTileBaker.Bake(field, key, new FlatField());
Assert.Equal(key, tile.Key);
Assert.Equal(layout.StorageSize * layout.StorageSize, tile.Samples.Length);
Assert.Contains(tile.Validity, valid => valid);
Assert.Contains(tile.Validity, valid => !valid);
Assert.All(tile.Samples.Where((_, index) => tile.Validity[index]), sample => Assert.Equal(field.FieldVersion, sample.FieldVersion));
}
private static float3 Direction(double longitude, double latitude)
{
var cos = Math.Cos(latitude);
return new((float)(cos * Math.Cos(longitude)), (float)(cos * Math.Sin(longitude)), (float)Math.Sin(latitude));
}
private readonly struct FlatField : IPlanetaryBaseField
{
public PlanetaryBaseFieldSample Sample(float3 unitDirection) => new(0, float3.zero, 0, float3.zero, 0);
}
}