using System; using Annulus.BezierCurves; using Annulus.CSG; using Azimuth; namespace Annulus.UnitTests.CSG { public class BoundaryPartsTests : UnitTestSharp.TestFixture { public static QuadraticBezierCurve[] Crescent() { return new QuadraticBezierCurve[] { DiskQueryTests.Piece(new Vector(-1, 0), new Vector(0, -3), new Vector(1, 0)), DiskQueryTests.Piece(new Vector(1, 0), new Vector(0, -1), new Vector(-1, 0)), }; } public class BowsIntoTheShapeTests : UnitTestSharp.TestFixture { public void ControlPointLeftOfTheChord_BowsIn() { CheckTrue(BoundaryParts.BowsIntoTheShape( DiskQueryTests.Piece(new Vector(0, 0), new Vector(1, 1), new Vector(2, 0)))); } public void ControlPointRightOfTheChord_BowsOut() { CheckFalse(BoundaryParts.BowsIntoTheShape( DiskQueryTests.Piece(new Vector(0, 0), new Vector(1, -1), new Vector(2, 0)))); } public void ControlPointOnTheChord_BowsOut() { CheckFalse(BoundaryParts.BowsIntoTheShape(DiskQueryTests.Line(new Vector(0, 0), new Vector(3, 1)))); } public void ChordOfZeroLength_BowsOut() { CheckFalse(BoundaryParts.BowsIntoTheShape( DiskQueryTests.Piece(new Vector(1, 1), new Vector(2, 5), new Vector(1, 1)))); } public void ChordPointingLeft_UsesTheSideOfItsOwnDirection() { CheckTrue(BoundaryParts.BowsIntoTheShape( DiskQueryTests.Piece(new Vector(2, 0), new Vector(1, -1), new Vector(0, 0)))); } } public class BuildTests : UnitTestSharp.TestFixture { public void Square_HasTwoPartsPerSideSplitAtTheSpokes() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.Rectangle(1, 1)); CheckEqual(8, labelling.Parts.Length); CheckEqual(new Vector(-1, -1), labelling.Parts[0].Curve.startPoint); CheckEqual(new Vector(0, -1), labelling.Parts[0].Curve.endPoint); CheckEqual(new Vector(0, -1), labelling.Parts[1].Curve.startPoint); CheckEqual(new Vector(1, -1), labelling.Parts[1].Curve.endPoint); } public void Square_PartsKnowTheirRegionsAndCuts() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.Rectangle(1, 1)); int[] regions = { 0, 1, 1, 2, 2, 3, 3, 0 }; for (int i = 0; i < 8; ++i) { CheckEqual(regions[i], labelling.Parts[i].Region); CheckEqual(i, labelling.Parts[i].StartCut); CheckEqual((i + 1) % 8, labelling.Parts[i].EndCut); CheckEqual(i / 2, labelling.Parts[i].Stretch); CheckFalse(labelling.Parts[i].IsPoint); CheckFalse(labelling.Parts[i].BowsIn); } } public void RectangleLongSide_HasThreePartsWithTheMiddleOneBetweenTheSpokes() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.Rectangle(2, 1)); CheckEqual(new Vector(-2, -1), labelling.Parts[0].Curve.startPoint); CheckEqual(new Vector(-1, -1), labelling.Parts[0].Curve.endPoint); CheckEqual(new Vector(-1, -1), labelling.Parts[1].Curve.startPoint); CheckEqual(new Vector(1, -1), labelling.Parts[1].Curve.endPoint); CheckEqual(new Vector(0, -1), labelling.Parts[1].Curve.controlPoint); CheckEqual(new Vector(1, -1), labelling.Parts[2].Curve.startPoint); CheckEqual(new Vector(2, -1), labelling.Parts[2].Curve.endPoint); } public void CutsThatAreNotLive_DoNotSplitAPart() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.LShape()); foreach (BoundaryPart part in labelling.Parts) { int cut = (part.StartCut + 1) % labelling.Cuts.Length; while (cut != part.EndCut) { CheckFalse(labelling.Cuts[cut].IsLive); cut = (cut + 1) % labelling.Cuts.Length; } } } public void ReflexJointsFan_IsMadeOfPointPartsAtTheJoint() { BoundaryLabelling labelling = new BoundaryLabelling(BoundaryLabellingTests.LShape()); int points = 0; foreach (BoundaryPart part in labelling.Parts) { CheckEqual(labelling.Stretches[part.Stretch].IsFan, part.IsPoint); if (part.IsPoint) { ++points; CheckEqual(new Vector(2, 2), part.Curve.startPoint); CheckEqual(new Vector(2, 2), part.Curve.controlPoint); CheckEqual(new Vector(2, 2), part.Curve.endPoint); CheckFalse(part.BowsIn); } } CheckGreater(points, 0); } public void CrescentsConcavePiece_BowsIntoTheShape() { BoundaryLabelling labelling = new BoundaryLabelling(Crescent()); foreach (BoundaryPart part in labelling.Parts) { CheckEqual(part.Stretch == 1, part.BowsIn); } } public void EveryPartMeetsItsCutsAndTheNextPart() { QuadraticBezierCurve[][] shapes = { BoundaryLabellingTests.LShape(), BoundaryLabellingTests.Heart(), BoundaryLabellingTests.RoundedRectangle(), DiskQueryTests.Lens(bulge: 2), Crescent(), BoundaryLabellingTests.G1Corner(), }; foreach (QuadraticBezierCurve[] shape in shapes) { BoundaryLabelling labelling = new BoundaryLabelling(shape); for (int i = 0; i < labelling.Parts.Length; ++i) { BoundaryPart part = labelling.Parts[i]; BoundaryPart next = labelling.Parts[(i + 1) % labelling.Parts.Length]; if (part.StartCut >= 0) { CheckEqual(labelling.Cuts[part.StartCut].Foot, part.Curve.startPoint); } if (part.EndCut >= 0) { CheckEqual(labelling.Cuts[part.EndCut].Foot, part.Curve.endPoint); } CheckEqual(next.Curve.startPoint, part.Curve.endPoint); CheckEqual(next.StartCut, part.EndCut); } } } } } }