diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs index 2eedab3..d8b09a0 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Abstractions/Contracts.cs @@ -87,6 +87,20 @@ public sealed record GeometrySnapshot public double? Elevation { get; init; } } +// Platform-neutral result of the legacy GetComponentGeometry contract. The +// Plant adapter is responsible for reading Parts/Pipes and normalising units; +// consumers do not take a dependency on Autodesk managed assemblies. +public sealed record ComponentGeometryDefinition( + string Kind, + IReadOnlyDictionary Parameters, + Bounds3Dto Bounds, + bool ImperialDimensions); +public sealed record ComponentGeometryReadResult(bool Success, ComponentGeometryDefinition? Geometry, string? FailureCode = null); +public interface IPlantComponentGeometryReader +{ + ComponentGeometryReadResult Read(string stableEntityId, bool convertToMetric); +} + public sealed record OrthoViewportInfo { public required string Id { get; init; } diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PRecAnnot.Plant3D2026.csproj b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PRecAnnot.Plant3D2026.csproj index 052bce8..cfe7ca8 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PRecAnnot.Plant3D2026.csproj +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PRecAnnot.Plant3D2026.csproj @@ -14,6 +14,7 @@ $(AutoCAD2026ManagedDir)\PnPDataObjects.dllfalsefalse $(Plant3D2026ManagedDir)\PnPProjectManagerMgd.dllfalsefalse $(Plant3D2026ManagedDir)\PnP3dObjectsMgd.dllfalsefalse + $(AutoCAD2026ManagedDir)\PnP3dPartsRepository.dllfalsefalse $(Plant3D2026ManagedDir)\PnP3dProjectPartsMgd.dllfalsefalse $(Plant3D2026ManagedDir)\PnP3dOrthoProjectPart.dllfalsefalse $(Plant3D2026ManagedDir)\PnPDwg2dDef.dllfalsefalse diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PlantComponentGeometryReader.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PlantComponentGeometryReader.cs new file mode 100644 index 0000000..71bd715 --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/PlantComponentGeometryReader.cs @@ -0,0 +1,60 @@ +using Autodesk.AutoCAD.DatabaseServices; +using Autodesk.ProcessPower.PnP3dObjects; +using PRecAnnot.Abstractions; + +namespace PRecAnnot.Plant3D2026; + +// Modern Plant 2026 adapter for the production-useful part of legacy +// GetComponentGeometry.IsGeometryRead: Pipe dimensions and Part extents are +// read from the selected source object with explicit unit normalisation. +internal sealed class PlantComponentGeometryReader(Database database) : IPlantComponentGeometryReader +{ + public ComponentGeometryReadResult Read(string stableEntityId, bool convertToMetric) + { + if (!TryObjectId(stableEntityId, out var id)) return new(false, null, "COMPONENT_GEOMETRY_STABLE_ID_INVALID"); + try + { + using var transaction = database.TransactionManager.StartOpenCloseTransaction(); + if (transaction.GetObject(id, OpenMode.ForRead) is not Entity entity) return new(false, null, "COMPONENT_GEOMETRY_ENTITY_NOT_FOUND"); + var extents = entity.GeometricExtents; + var bounds = new Bounds3Dto(new(extents.MinPoint.X, extents.MinPoint.Y, extents.MinPoint.Z), new(extents.MaxPoint.X, extents.MaxPoint.Y, extents.MaxPoint.Z)); + if (entity is Pipe pipe) + { + var factor = Factor(convertToMetric, pipe.PartSizeProperties.LinearUnit); + var parameters = new Dictionary(StringComparer.Ordinal) + { + ["D"] = Format(pipe.OuterDiameter * factor), + ["L"] = Format(pipe.Length * factor) + }; + return new(true, new("CPP", parameters, bounds, factor != 1)); + } + if (entity is Part part) + { + var factor = Factor(convertToMetric, part.PartSizeProperties.LinearUnit); + var parameters = new Dictionary(StringComparer.Ordinal) + { + ["BoundsX"] = Format((extents.MaxPoint.X - extents.MinPoint.X) * factor), + ["BoundsY"] = Format((extents.MaxPoint.Y - extents.MinPoint.Y) * factor), + ["BoundsZ"] = Format((extents.MaxPoint.Z - extents.MinPoint.Z) * factor) + }; + return new(true, new("PART", parameters, bounds, factor != 1)); + } + return new(false, null, "COMPONENT_GEOMETRY_UNSUPPORTED_ENTITY"); + } + catch (Autodesk.AutoCAD.Runtime.Exception) { return new(false, null, "COMPONENT_GEOMETRY_EXTENTS_UNAVAILABLE"); } + catch (Exception) { return new(false, null, "COMPONENT_GEOMETRY_READ_FAILED"); } + } + + private bool TryObjectId(string stableEntityId, out ObjectId id) + { + id = ObjectId.Null; + const string prefix = "acad:"; + if (string.IsNullOrWhiteSpace(stableEntityId) || !stableEntityId.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return false; + if (!long.TryParse(stableEntityId[prefix.Length..], System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out var handle)) return false; + try { id = database.GetObjectId(false, new Handle(handle), 0); return !id.IsNull; } + catch { return false; } + } + + private static double Factor(bool convertToMetric, object? unit) => convertToMetric && string.Equals(unit?.ToString(), "Inch", StringComparison.OrdinalIgnoreCase) ? 25.4 : 1d; + private static string Format(double value) => value.ToString("0.###############", System.Globalization.CultureInfo.InvariantCulture); +} diff --git a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ComponentGeometryContractTests.cs b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ComponentGeometryContractTests.cs new file mode 100644 index 0000000..729ad15 --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ComponentGeometryContractTests.cs @@ -0,0 +1,15 @@ +using PRecAnnot.Abstractions; + +namespace PRecAnnot.Core.Tests; + +public sealed class ComponentGeometryContractTests +{ + [Fact] + public void GeometryDefinition_PreservesStableParametersAndBounds() + { + var geometry = new ComponentGeometryDefinition("CPP", new Dictionary { ["D"] = "25.4", ["L"] = "508" }, new(new(0, 0, 0), new(1, 2, 3)), true); + Assert.Equal("25.4", geometry.Parameters["D"]); + Assert.Equal(new Point3Dto(1, 2, 3), geometry.Bounds.Maximum); + Assert.True(geometry.ImperialDimensions); + } +}