using System; using Annulus.BezierCurves; using Annulus.CSG; using Azimuth; namespace Annulus.UnitTests.CSG { public class BoundaryMergesTests : UnitTestSharp.TestFixture { // A box under a pointed arch, whose tight curvature at the top grows a branch back into the shape. public static QuadraticBezierCurve[] Arch(Scalar height, Scalar apexControlX) { return new QuadraticBezierCurve[] { DiskQueryTests.Line(new Vector(-2, 0), new Vector(2, 0)), DiskQueryTests.Line(new Vector(2, 0), new Vector(2, height)), DiskQueryTests.Piece(new Vector(2, height), new Vector(apexControlX, height + 6), new Vector(-2, height)), DiskQueryTests.Line(new Vector(-2, height), new Vector(-2, 0)), }; } public static int BranchInterval(BoundaryLabelling labelling) { for (int i = 0; i < labelling.Intervals.Length; ++i) { if (labelling.Intervals[i].Own == 2 && labelling.Intervals[i].Across == 2) { return i; } } throw new InvalidOperationException("The arch has no branch into its own top piece."); } public class AddPieceTests : UnitTestSharp.TestFixture { public static BoundaryRegion Empty() { return new BoundaryRegion { First = -1, Second = -1 }; } public void FirstPiece_FillsBothSlots() { BoundaryRegion label = Empty(); BoundaryMerges.AddPiece(ref label, 4); CheckEqual(4, label.First); CheckEqual(4, label.Second); } public void RepeatedPiece_ChangesNothing() { BoundaryRegion label = Empty(); BoundaryMerges.AddPiece(ref label, 4); BoundaryMerges.AddPiece(ref label, 4); CheckEqual(4, label.First); CheckEqual(4, label.Second); } public void SecondPieceBelowTheFirst_GoesInFront() { BoundaryRegion label = Empty(); BoundaryMerges.AddPiece(ref label, 4); BoundaryMerges.AddPiece(ref label, 2); CheckEqual(2, label.First); CheckEqual(4, label.Second); } public void SecondPieceAboveTheFirst_GoesBehind() { BoundaryRegion label = Empty(); BoundaryMerges.AddPiece(ref label, 2); BoundaryMerges.AddPiece(ref label, 4); CheckEqual(2, label.First); CheckEqual(4, label.Second); } public void EitherOfTwoPiecesAddedAgain_ChangesNothing() { BoundaryRegion label = Empty(); BoundaryMerges.AddPiece(ref label, 2); BoundaryMerges.AddPiece(ref label, 4); BoundaryMerges.AddPiece(ref label, 4); BoundaryMerges.AddPiece(ref label, 2); CheckEqual(2, label.First); CheckEqual(4, label.Second); } public void ThirdPiece_Throws() { BoundaryRegion label = Empty(); BoundaryMerges.AddPiece(ref label, 2); BoundaryMerges.AddPiece(ref label, 4); CheckThrow(typeof(InvalidOperationException)); BoundaryMerges.AddPiece(ref label, 7); } } public class BuildTests : UnitTestSharp.TestFixture { public void TightLens_JoinsItsSingleCandidateWedgesAndEverythingBetweenThemIntoOneRegion() { BoundaryLabelling labelling = new BoundaryLabelling(DiskQueryTests.Lens(bulge: 2)); CheckEqual(1, labelling.Regions.Length); CheckEqual(0, labelling.Regions[0].First); CheckEqual(1, labelling.Regions[0].Second); foreach (BoundaryCut cut in labelling.Cuts) { CheckFalse(cut.IsLive); } } public void SingleCandidateRegionsWhoseNeighboursDoNotNameItsPiece_StayAsTheyAre() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.CircleArcs(4)); CheckEqual(4, labelling.Regions.Length); for (int i = 0; i < 4; ++i) { CheckEqual(i, labelling.Regions[i].First); CheckEqual(i, labelling.Regions[i].Second); } } public void BranchBetweenTwoRegionsWithTheSamePieces_JoinsThemAllIntoOne() { BoundaryLabelling labelling = new BoundaryLabelling(Arch(height: 2, apexControlX: 0)); int branch = BranchInterval(labelling); int count = labelling.Intervals.Length; int before = labelling.Intervals[(branch + count - 1) % count].Region; int after = labelling.Intervals[(branch + 1) % count].Region; CheckEqual(5, labelling.Regions.Length); CheckEqual(before, labelling.Intervals[branch].Region); CheckEqual(after, labelling.Intervals[branch].Region); } public void BranchBetweenTwoDifferentRegions_JoinsTheOneMetFirstWhenBothAreEquallyCheap() { BoundaryLabelling labelling = new BoundaryLabelling(Arch(height: 6, apexControlX: 0)); int branch = BranchInterval(labelling); int count = labelling.Intervals.Length; int before = labelling.Intervals[(branch + count - 1) % count].Region; int after = labelling.Intervals[(branch + 1) % count].Region; CheckEqual(5, labelling.Regions.Length); CheckEqual(before, labelling.Intervals[branch].Region); CheckTrue(before != after); } } } }