using System; using System.Collections.Generic; using System.Linq; using Azimuth; using Blacklight.Core.Drawables; namespace Blacklight.Core.UnitTests.Drawables { public class PolylineTests : UnitTestSharp.TestFixture { public static readonly Scalar Diagonal = Math.Sqrt(0.5); public static readonly Vector[] OneSegment = { new Vector(0, 0), new Vector(10, 0) }; // Both legs face each other across a pocket 10 wide that the wavefronts close at x = 5. public static readonly Vector[] CShape = { new Vector(10, 10), new Vector(0, 10), new Vector(0, 0), new Vector(10, 0), }; public static bool HasVertices(PolylineTriangle triangle, params Vector[] expected) { var actual = new[] { triangle.VertexA, triangle.VertexB, triangle.VertexC }; return expected.All(vertex => actual.Any(other => other.Equals(vertex))); } public static Scalar Area(PolylineTriangle triangle) { Vector ab = triangle.VertexB - triangle.VertexA; Vector ac = triangle.VertexC - triangle.VertexA; return Math.Abs(ab.X * ac.Y - ab.Y * ac.X) / 2; } public class CtorTests : UnitTestSharp.TestFixture { public void FewerThanTwoPoints_Throws() { CheckThrow(typeof(ArgumentException)); new Polyline(new[] { new Vector(1, 1) }); } public void OneSegment_HasNoBoundedTriangles() { CheckEqual(0, new Polyline(OneSegment).Triangles.Count); } public void OneSegment_HasAnOpenFaceForEachSideAndEachEnd() { CheckEqual(4, new Polyline(OneSegment).OpenFaces.Count); } public void OneSegment_LeftSideOpensUpwardFromBothEnds() { var face = new Polyline(OneSegment).OpenFaces[0]; CheckEqual(new Vector(10, 0), face.StartOrigin); CheckEqual(new Vector(0, 0), face.EndOrigin); CheckEqual(new Vector(Diagonal, Diagonal), face.StartDirection); CheckEqual(new Vector(-Diagonal, Diagonal), face.EndDirection); CheckEqual(new Vector(0, 1), face.Normal); CheckEqual(0, face.Offset); } public void OneSegment_RightSideOpensDownwardFromBothEnds() { var face = new Polyline(OneSegment).OpenFaces[1]; CheckEqual(new Vector(0, 0), face.StartOrigin); CheckEqual(new Vector(10, 0), face.EndOrigin); CheckEqual(new Vector(-Diagonal, -Diagonal), face.StartDirection); CheckEqual(new Vector(Diagonal, -Diagonal), face.EndDirection); CheckEqual(new Vector(0, -1), face.Normal); CheckEqual(0, face.Offset); } public void OneSegment_LastEndOpensForwardFromAPoint() { var face = new Polyline(OneSegment).OpenFaces[2]; CheckEqual(new Vector(10, 0), face.StartOrigin); CheckEqual(new Vector(10, 0), face.EndOrigin); CheckEqual(new Vector(Diagonal, -Diagonal), face.StartDirection); CheckEqual(new Vector(Diagonal, Diagonal), face.EndDirection); CheckEqual(new Vector(1, 0), face.Normal); CheckEqual(-10, face.Offset); } public void OneSegment_FirstEndOpensBackwardFromAPoint() { var face = new Polyline(OneSegment).OpenFaces[3]; CheckEqual(new Vector(0, 0), face.StartOrigin); CheckEqual(new Vector(0, 0), face.EndOrigin); CheckEqual(new Vector(-Diagonal, Diagonal), face.StartDirection); CheckEqual(new Vector(-Diagonal, -Diagonal), face.EndDirection); CheckEqual(new Vector(-1, 0), face.Normal); CheckEqual(0, face.Offset); } public void ClosingPocket_FillsTheMiddleLegsFaceWithOneTriangle() { var triangles = new Polyline(CShape).Triangles .Where(triangle => triangle.Normal.Equals(new Vector(1, 0)) && triangle.Offset == 0) .ToList(); CheckEqual(1, triangles.Count); CheckTrue(HasVertices(triangles[0], new Vector(0, 10), new Vector(0, 0), new Vector(5, 5))); } public void ClosingPocket_FillsEachOuterLegsFaceWithAParallelogram() { var topLeg = new Polyline(CShape).Triangles .Where(triangle => triangle.Normal.Equals(new Vector(0, -1)) && triangle.Offset == 10) .ToList(); CheckEqual(2, topLeg.Count); CheckEqual(50, Area(topLeg[0]) + Area(topLeg[1])); CheckTrue(topLeg.All(triangle => HasVertices(triangle, new Vector(10, 10)) || HasVertices(triangle, new Vector(15, 5)))); } public void ClosingPocket_FillsEachCapFaceWithOneTriangleOutToTheMeetingPoint() { var cap = new Polyline(CShape).Triangles .Where(triangle => triangle.Normal.Equals(new Vector(1, 0)) && triangle.Offset == -10) .ToList(); CheckEqual(2, cap.Count); CheckTrue(cap.Any(triangle => HasVertices(triangle, new Vector(10, 10), new Vector(15, 5), new Vector(15, 15)))); CheckTrue(cap.Any(triangle => HasVertices(triangle, new Vector(10, 0), new Vector(15, 5), new Vector(15, -5)))); } } public class InsidePixelThicknessTests : UnitTestSharp.TestFixture { public void DefaultsToZero() { CheckEqual(0, new Polyline(OneSegment).InsidePixelThickness); } public void Negative_Throws() { var polyline = new Polyline(OneSegment); CheckThrow(typeof(ArgumentOutOfRangeException)); polyline.InsidePixelThickness = -1; } public void Positive_IsKept() { var polyline = new Polyline(OneSegment) { InsidePixelThickness = 3 }; CheckEqual(3, polyline.InsidePixelThickness); } } public class ShellModelSpaceThicknessTests : UnitTestSharp.TestFixture { public void IsZero() { CheckEqual(0, new Polyline(OneSegment).ShellModelSpaceThickness); } public void SettingZero_IsAccepted() { new Polyline(OneSegment) { ShellModelSpaceThickness = 0 }; } public void SettingAnythingElse_Throws() { var polyline = new Polyline(OneSegment); CheckThrow(typeof(NotSupportedException)); polyline.ShellModelSpaceThickness = 0.5; } } } }