using System; using Azimuth; using UnitTestSharp; namespace Blacklight.Bezier.UnitTests { public class CubicInputUncertaintyTests : TestFixture { public static readonly Vector InnerPoint1 = new Vector(0.3, 0.8); public static readonly Vector InnerPoint2 = new Vector(0.9, 0.6); /// /// Returns a sample a little off the curve's interior, where every input moves the distance. /// public static CubicSample OffTheMiddle() { CubicPiece piece = CubicSample.PieceInFrame(InnerPoint1, InnerPoint2); return new CubicSample(CubicSampleSets.AlongNormal(piece, t: 0.4, offset: 0.05), InnerPoint1, InnerPoint2); } public static CubicReferenceResult Solve(CubicSample sample) { return CubicReferenceDistance.Solve(sample.ToPiece(), sample.Pixel); } /// /// Returns the point moved by one float spacing per coordinate, each in the direction given by its sign. /// public static Vector NudgedBySpacing(Vector point, Vector direction) { return point + new Vector(Math.Sign(direction.X) * InputUncertainty.FloatSpacing(point.X), Math.Sign(direction.Y) * InputUncertainty.FloatSpacing(point.Y)); } public class TowardPixelTests : TestFixture { public void OffTheCurve_IsTheUnitNormalAtTheFoot() { CubicSample sample = OffTheMiddle(); Vector normal = sample.ToPiece().DerivativeAt(0.4).NormalizedCopy().PerpCCW(); CheckGreater(1e-12, (CubicInputUncertainty.TowardPixel(sample, Solve(sample)) - normal).Length() .Value); } public void OnTheCurve_IsZero() { var sample = new CubicSample(Vector.Zero, InnerPoint1, InnerPoint2); CheckEqual(Vector.Zero, CubicInputUncertainty.TowardPixel(sample, Solve(sample))); } } public class SpacingAlongTests : TestFixture { public void AlongAnAxis_IsThatCoordinatesSpacing() { CheckEqual(InputUncertainty.FloatSpacing(5), CubicInputUncertainty.SpacingAlong(new Vector(0, -1), new Vector(3, 5))); } public void Diagonally_WeighsBothSpacings() { CheckEqual(0.6 * InputUncertainty.FloatSpacing(3) + 0.8 * InputUncertainty.FloatSpacing(5), CubicInputUncertainty.SpacingAlong(new Vector(-0.6, 0.8), new Vector(3, 5))); } } public class OfPixelTests : TestFixture { public void IsHowFarRoundingThePixelCanMoveTheDistance() { CubicSample sample = OffTheMiddle(); CubicReferenceResult reference = Solve(sample); Vector toward = CubicInputUncertainty.TowardPixel(sample, reference); var nudged = new CubicSample(NudgedBySpacing(sample.Pixel, toward), sample.P1, sample.P2); double moved = Solve(nudged).Distance - reference.Distance; CheckGreater(1e-4, Math.Abs(moved / CubicInputUncertainty.OfPixel(sample, reference) - 1)); } } public class OfShapeTests : TestFixture { public void IsHowFarRoundingTheInnerPointsCanMoveTheDistance() { CubicSample sample = OffTheMiddle(); CubicReferenceResult reference = Solve(sample); Vector away = -CubicInputUncertainty.TowardPixel(sample, reference); var nudged = new CubicSample(sample.Pixel, NudgedBySpacing(sample.P1, away), NudgedBySpacing(sample.P2, away)); double moved = Solve(nudged).Distance - reference.Distance; CheckGreater(1e-4, Math.Abs(moved / CubicInputUncertainty.OfShape(sample, reference) - 1)); } public void ClosestAtAnEnd_IsZero() { var sample = new CubicSample(new Vector(-1, -1), InnerPoint1, InnerPoint2); CheckEqual(0.0, CubicInputUncertainty.OfShape(sample, Solve(sample))); } } public class OfTests : TestFixture { public void IsThePixelAndShapeTogether() { CubicSample sample = OffTheMiddle(); CubicReferenceResult reference = Solve(sample); CheckEqual(CubicInputUncertainty.OfPixel(sample, reference) + CubicInputUncertainty.OfShape(sample, reference), CubicInputUncertainty.Of(sample, reference)); } } } }