diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs index 8e3285f..64255be 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs @@ -21,6 +21,8 @@ public readonly record struct Point2Dto(double X, double Y); public readonly record struct Point3Dto(double X, double Y, double Z); public readonly record struct Vector2Dto(double X, double Y); public sealed record Bounds2Dto(Point2Dto Minimum, Point2Dto Maximum); +public sealed record Bounds3Dto(Point3Dto Minimum, Point3Dto Maximum); +public enum ExtentsIntersectionType { DoNotIntersect, Intersect, ExtentsMatch, FirstExtentsInsideSecondExtents, SecondExtentsInsideFirstExtents } public sealed record LineNumberAnnotationSettings { diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ExtentsIntersectionClassifier.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ExtentsIntersectionClassifier.cs new file mode 100644 index 0000000..55393c4 --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ExtentsIntersectionClassifier.cs @@ -0,0 +1,18 @@ +using PRecAnnot.Abstractions; + +namespace PRecAnnot.Core; + +public static class ExtentsIntersectionClassifier +{ + // Source-backed port of ExtentsIntersect.Commands without Autodesk types. + public static ExtentsIntersectionType Classify(Bounds3Dto first, Bounds3Dto second) + { + if (Same(first, second)) return ExtentsIntersectionType.ExtentsMatch; + if (Contains(first, second)) return ExtentsIntersectionType.SecondExtentsInsideFirstExtents; + if (Contains(second, first)) return ExtentsIntersectionType.FirstExtentsInsideSecondExtents; + return Overlaps(first, second) ? ExtentsIntersectionType.Intersect : ExtentsIntersectionType.DoNotIntersect; + } + private static bool Contains(Bounds3Dto outer, Bounds3Dto inner) => outer.Minimum.X <= inner.Minimum.X && outer.Minimum.Y <= inner.Minimum.Y && outer.Minimum.Z <= inner.Minimum.Z && outer.Maximum.X >= inner.Maximum.X && outer.Maximum.Y >= inner.Maximum.Y && outer.Maximum.Z >= inner.Maximum.Z; + private static bool Overlaps(Bounds3Dto a, Bounds3Dto b) => a.Minimum.X <= b.Maximum.X && a.Maximum.X >= b.Minimum.X && a.Minimum.Y <= b.Maximum.Y && a.Maximum.Y >= b.Minimum.Y && a.Minimum.Z <= b.Maximum.Z && a.Maximum.Z >= b.Minimum.Z; + private static bool Same(Bounds3Dto a, Bounds3Dto b) => a == b; +} diff --git a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ExtentsIntersectionClassifierTests.cs b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ExtentsIntersectionClassifierTests.cs new file mode 100644 index 0000000..7038f7e --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ExtentsIntersectionClassifierTests.cs @@ -0,0 +1,13 @@ +using PRecAnnot.Abstractions; +using PRecAnnot.Core; +namespace PRecAnnot.Core.Tests; +public sealed class ExtentsIntersectionClassifierTests +{ + [Theory] + [InlineData(0, 0, 2, 2, ExtentsIntersectionType.ExtentsMatch)] + [InlineData(0, 0, 4, 4, ExtentsIntersectionType.FirstExtentsInsideSecondExtents)] + [InlineData(3, 3, 5, 5, ExtentsIntersectionType.DoNotIntersect)] + public void ClassifiesPlanarExtents(double min, double minY, double max, double maxY, ExtentsIntersectionType expected) => Assert.Equal(expected, ExtentsIntersectionClassifier.Classify(Box(0, 0, 2, 2), Box(min, minY, max, maxY))); + [Fact] public void TouchingExtents_Intersect() => Assert.Equal(ExtentsIntersectionType.Intersect, ExtentsIntersectionClassifier.Classify(Box(0, 0, 2, 2), Box(2, 1, 3, 2))); + private static Bounds3Dto Box(double x1, double y1, double x2, double y2) => new(new(x1, y1, 0), new(x2, y2, 1)); +}