using System; using Annulus.CSG; using Azimuth; namespace Annulus.UnitTests.CSG { public class BoundaryTrianglesTests : UnitTestSharp.TestFixture { public static Scalar Area(Vector[] corners) { Scalar returnMe = 0; for (int i = 0; i < corners.Length; i += 3) { returnMe += (corners[i + 1] - corners[i]).CrossProduct(corners[i + 2] - corners[i]) / 2; } return returnMe; } public class InteriorTests : UnitTestSharp.TestFixture { public void FewerThanThreePoints_GivesNoTriangles() { CheckEqual(0, BoundaryTriangles.Interior(new Vector[] { new Vector(0, 0), new Vector(1, 0) }).Length); } public void Triangle_GivesItself() { Vector[] corners = BoundaryTriangles.Interior( new Vector[] { new Vector(0, 0), new Vector(2, 0), new Vector(0, 2) }); CheckEqual(3, corners.Length); CheckEqual((Scalar)2, Area(corners)); } public void Square_GivesTwoTriangles() { Vector[] corners = BoundaryTriangles.Interior(new Vector[] { new Vector(0, 0), new Vector(1, 0), new Vector(1, 1), new Vector(0, 1), }); CheckEqual(6, corners.Length); CheckEqual((Scalar)1, Area(corners)); } public void EveryTriangleRunsCounterclockwise() { Vector[] corners = BoundaryTriangles.Interior(new Vector[] { new Vector(0, 0), new Vector(2, 0), new Vector(2, 1), new Vector(1, 1), new Vector(1, 2), new Vector(0, 2), }); for (int i = 0; i < corners.Length; i += 3) { CheckTrue(Area(new Vector[] { corners[i], corners[i + 1], corners[i + 2] }) > 0); } } public void ConcaveOutline_FillsExactlyItsArea() { Vector[] corners = BoundaryTriangles.Interior(new Vector[] { new Vector(0, 0), new Vector(2, 0), new Vector(2, 1), new Vector(1, 1), new Vector(1, 2), new Vector(0, 2), }); CheckEqual(12, corners.Length); CheckEqual((Scalar)3, Area(corners)); } public void ClockwiseOutline_Throws() { CheckThrow(typeof(InvalidOperationException)); BoundaryTriangles.Interior(new Vector[] { new Vector(0, 0), new Vector(0, 1), new Vector(1, 1), new Vector(1, 0), }); } } public class CurveTests : UnitTestSharp.TestFixture { public void ShapeOfStraightPieces_HasNoCurveTriangles() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.LShape()); CheckEqual(0, labelling.CurveTriangles.Length); } public void Crescent_HasOneTriangleForEachPart() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryPartsTests.Crescent()); CheckEqual(4, labelling.CurveTriangles.Length); CheckEqual(new Vector(-1, 0), labelling.CurveTriangles[0].Start); CheckEqual(new Vector(-2.0 / 3, -1), labelling.CurveTriangles[0].Control); CheckEqual(new Vector(-1.0 / 3, -4.0 / 3), labelling.CurveTriangles[0].End); } public void CurveTrianglesRecordWhichWayTheirPartBows() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryPartsTests.Crescent()); bool[] bowsIn = { false, false, false, true }; for (int i = 0; i < bowsIn.Length; ++i) { CheckEqual(bowsIn[i], labelling.CurveTriangles[i].BowsIn); CheckEqual(0, labelling.CurveTriangles[i].Region); } } public void PartsOfAFansReflexJoint_HaveNoCurveTriangle() { BoundaryPart point = BoundaryInvariantsTests.Part(new Vector(1, 1), new Vector(1, 1), new Vector(1, 1)); point.IsPoint = true; CheckEqual(0, BoundaryTriangles.Curve(new BoundaryPart[] { point }).Length); } } public class LabellingTests : UnitTestSharp.TestFixture { public void EachRegionIsFilledWithItsOutlinesAreaAndNothingElse() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.LShape()); Scalar total = 0; CheckEqual(labelling.Regions.Length, labelling.InteriorTriangles.Length); for (int i = 0; i < labelling.Regions.Length; ++i) { CheckEqual(BoundaryOutlinesTests.Area(labelling.Outlines[i]), Area(labelling.InteriorTriangles[i])); total += Area(labelling.InteriorTriangles[i]); } CheckEqual((Scalar)22, total); } public void RegionsOfTheRoundedRectangle_FillItsArea() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.RoundedRectangle()); Scalar total = 0; foreach (Vector[] corners in labelling.InteriorTriangles) { total += Area(corners); } CheckEqual((Scalar)22, total); } } } }