using System; using Annulus.BezierCurves; using Annulus.CSG; using Azimuth; namespace Annulus.UnitTests.CSG { public class BoundaryOutlinesTests : UnitTestSharp.TestFixture { public static Scalar Area(Vector[] outline) { Scalar returnMe = 0; for (int i = 0; i < outline.Length; ++i) { Vector from = outline[i]; Vector to = outline[(i + 1) % outline.Length]; returnMe += from.CrossProduct(to) / 2; } return returnMe; } public class BuildTests : UnitTestSharp.TestFixture { public void Square_GivesEachSideItsQuadrantCounterclockwise() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.Rectangle(1, 1)); CheckEqual(4, labelling.Outlines.Length); foreach (Vector[] outline in labelling.Outlines) { CheckEqual(4, outline.Length); CheckEqual((Scalar)1, Area(outline)); } CheckEqual(new Vector(-1, 0), labelling.Outlines[0][0]); CheckEqual(new Vector(-1, -1), labelling.Outlines[0][1]); CheckEqual(new Vector(0, -1), labelling.Outlines[0][2]); CheckEqual(new Vector(0, 0), labelling.Outlines[0][3]); } public void Rectangle_GivesTheLongSideTheTrapezoidBetweenTheSpokes() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.Rectangle(2, 1)); Scalar[] areas = { 1, 4, 1, 1, 1 }; CheckEqual(areas.Length, labelling.Outlines.Length); for (int i = 0; i < areas.Length; ++i) { CheckEqual(areas[i], Area(labelling.Outlines[i])); } } public void LShape_RegionsTileTheShape() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.LShape()); Scalar total = 0; CheckEqual(7, labelling.Outlines.Length); foreach (Vector[] outline in labelling.Outlines) { total += Area(outline); } CheckEqual((Scalar)22, total); } public void RoundedRectangle_RegionsTileTheShape() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.RoundedRectangle()); Scalar total = 0; foreach (Vector[] outline in labelling.Outlines) { total += Area(outline); } CheckEqual((Scalar)22, total); } public void RegionWithNoLiveCuts_WalksTheWholeLoop() { BoundaryLabelling labelling = new BoundaryLabelling(DiskQueryTests.Lens(bulge: 2)); CheckEqual(1, labelling.Outlines.Length); CheckEqual(2, labelling.Outlines[0].Length); CheckEqual(new Vector(-1, 0), labelling.Outlines[0][0]); CheckEqual(new Vector(1, 0), labelling.Outlines[0][1]); } public void ConcaveCrescentPiece_AddsItsControlPointToTheOutline() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryPartsTests.Crescent()); bool found = false; foreach (Vector[] outline in labelling.Outlines) { if (Array.IndexOf(outline, new Vector(0, -1)) >= 0) { found = true; } } CheckTrue(found); } public void SpokeThatReachesNoVertex_Throws() { BoundaryPart[] parts = { new BoundaryPart { Region = 0, StartCut = 0, EndCut = 1 }, new BoundaryPart { Region = 1, StartCut = 1, EndCut = 0 }, }; BoundaryCut[] cuts = { new BoundaryCut { Vertex = -1 }, new BoundaryCut { Vertex = -1 }, }; CheckThrow(typeof(InvalidOperationException)); BoundaryOutlines.Build(parts, cuts, new BoundaryVertex[0], new BoundaryInterval[0], regionCount: 2); } } } }