using TraceCad.Core.Geometry; using TraceCad.Core.Model; using Xunit; namespace TraceCad.Tests; public sealed class GeometryTests { [Fact] public void LineLengthUsesMillimetres() { var line = new LineEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(0, 0), new Point2(3, 4)); Assert.Equal(5.0, line.Length, 9); } [Fact] public void ParallelConstraintPreservesTargetLengthAndMatchesReferenceDirection() { var reference = new LineEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(0, 0), new Point2(10, 0)); var target = new LineEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(0, 5), new Point2(0, 9)); var success = ConstraintGeometry.TryMakeParallel(reference, target, out var replacement); Assert.True(success); Assert.Equal(target.Length, replacement.Length, 9); Assert.Equal(0.0, replacement.Start.Y - replacement.End.Y, 9); } [Fact] public void ParallelDistanceMeasuresPerpendicularSpacing() { var first = new LineEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(0, 0), new Point2(10, 0)); var second = new LineEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(3, 7), new Point2(13, 7)); var success = ConstraintGeometry.TryMeasureParallelDistance(first, second, out var distance); Assert.True(success); Assert.Equal(7.0, distance, 9); } [Fact] public void TangentConstraintMovesLineOntoNearestArcEndpointTangent() { var arc = new ArcEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(0, 0), 10, 0, 90, false); var line = new LineEntity(Guid.NewGuid(), Layer.Cut.Name, new Point2(10.2, 0.1), new Point2(16.2, 2.1)); var success = ConstraintGeometry.TryMakeLineTangentToArc(line, arc, out var replacement); Assert.True(success); Assert.Equal(arc.StartPoint.X, replacement.Start.X, 9); Assert.Equal(arc.StartPoint.Y, replacement.Start.Y, 9); var direction = (replacement.End - replacement.Start).Normalized(); var tangent = GeometryHelpers.TangentAtAngle(arc.StartAngleDeg, arc.IsClockwise); Assert.True(Math.Abs(direction.Dot(tangent)) > 0.999); } [Fact] public void SolverAppliesDrivingRadiusDimension() { var document = SketchDocument.CreateDefault(); var arcId = Guid.NewGuid(); document.AddEntity(new ArcEntity(arcId, Layer.Cut.Name, new Point2(0, 0), 10, 0, 90, false)); document.AddConstraint(new SketchConstraint(Guid.NewGuid(), ConstraintType.Radius, new[] { arcId }, 25)); SketchConstraintSolver.Solve(document); var arc = Assert.IsType(document.Entities.Single(entity => entity.Id == arcId)); Assert.Equal(25.0, arc.Radius, 9); } [Fact] public void SolverAppliesDrivingParallelDistanceDimension() { var document = SketchDocument.CreateDefault(); var firstId = Guid.NewGuid(); var secondId = Guid.NewGuid(); document.AddEntity(new LineEntity(firstId, Layer.Cut.Name, new Point2(0, 0), new Point2(10, 0))); document.AddEntity(new LineEntity(secondId, Layer.Cut.Name, new Point2(0, 2), new Point2(10, 2))); document.AddConstraint(new SketchConstraint(Guid.NewGuid(), ConstraintType.Distance, new[] { firstId, secondId }, 7)); SketchConstraintSolver.Solve(document); var first = Assert.IsType(document.Entities.Single(entity => entity.Id == firstId)); var second = Assert.IsType(document.Entities.Single(entity => entity.Id == secondId)); Assert.True(ConstraintGeometry.TryMeasureParallelDistance(first, second, out var distance)); Assert.Equal(7.0, distance, 9); } [Fact] public void CircleFromThreePointsComputesCenterAndRadius() { var success = GeometryHelpers.TryCreateCircleFromThreePoints( new Point2(1, 0), new Point2(0, 1), new Point2(-1, 0), out var circle); Assert.True(success); Assert.Equal(0.0, circle.Center.X, 9); Assert.Equal(0.0, circle.Center.Y, 9); Assert.Equal(1.0, circle.Radius, 9); } [Fact] public void CircleFromCollinearPointsFails() { var success = GeometryHelpers.TryCreateCircleFromThreePoints( new Point2(0, 0), new Point2(1, 1), new Point2(2, 2), out _); Assert.False(success); } [Fact] public void ArcFromThreePointsPreservesPointOnCounterClockwiseSweep() { var success = GeometryHelpers.TryCreateArcFromThreePoints( new Point2(1, 0), new Point2(0, 1), new Point2(-1, 0), out var arc); Assert.True(success); Assert.False(arc.IsClockwise); Assert.Equal(0.0, arc.StartAngleDeg, 9); Assert.Equal(180.0, arc.EndAngleDeg, 9); Assert.Equal(1.0, arc.Radius, 9); } [Fact] public void ArcFromCollinearPointsFails() { var success = GeometryHelpers.TryCreateArcFromThreePoints( new Point2(0, 0), new Point2(5, 0), new Point2(10, 0), out _); Assert.False(success); } [Fact] public void ArcFromStartTangentAndEndPointMatchesRequestedTangent() { var success = GeometryHelpers.TryCreateArcFromStartTangentAndEndPoint( new Point2(0, 0), new Vector2(1, 0), new Point2(10, 10), new Point2(8, 2), out var arc); Assert.True(success); var tangent = GeometryHelpers.TangentAtAngle(arc.StartAngleDeg, arc.IsClockwise); Assert.True(tangent.Dot(new Vector2(1, 0)) > 0.999); } [Fact] public void ArcFromStartTangentFailsWhenEndPointLiesOnTangentLine() { var success = GeometryHelpers.TryCreateArcFromStartTangentAndEndPoint( new Point2(0, 0), new Vector2(1, 0), new Point2(10, 0), null, out _); Assert.False(success); } [Theory] [InlineData(360, 0)] [InlineData(-90, 270)] [InlineData(725, 5)] public void AngleNormalizationWrapsToPositiveDegrees(double input, double expected) { Assert.Equal(expected, GeometryHelpers.NormalizeAngleDeg(input), 9); } }