feat: port p-rec-annot ortho dimension workflow
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ApplicationPackage SchemaVersion="1.0" Name="P_Rec_Annot" Description="P_Rec_Annot Plant 3D 2026" AppVersion="0.2.6" ProductCode="b455ee6eaed79d76f084846a60ce3284" Author="NBIM">
|
<ApplicationPackage SchemaVersion="1.0" Name="P_Rec_Annot" Description="P_Rec_Annot Plant 3D 2026" AppVersion="0.2.7" ProductCode="b455ee6eaed79d76f084846a60ce3284" Author="NBIM">
|
||||||
<Components>
|
<Components>
|
||||||
<!-- SeriesMin/SeriesMax and platform token are pending official/runtime verification. -->
|
<!-- SeriesMin/SeriesMax and platform token are pending official/runtime verification. -->
|
||||||
<RuntimeRequirements OS="Win64" />
|
<RuntimeRequirements OS="Win64" />
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public sealed class EntryPoint : IExtensionApplication
|
|||||||
[CommandMethod("PXP-UOB")] public void UpdateOrthoViewBlocksCommand() => PRecAnnot.Plant3D2026.UpdateOrthoViewBlocksCommand.Run();
|
[CommandMethod("PXP-UOB")] public void UpdateOrthoViewBlocksCommand() => PRecAnnot.Plant3D2026.UpdateOrthoViewBlocksCommand.Run();
|
||||||
[CommandMethod("PXP-RA", CommandFlags.Session)] public void RemoveOrthoAnnotationsCommand() => OrthoAnnotationRemovalCommand.Run();
|
[CommandMethod("PXP-RA", CommandFlags.Session)] public void RemoveOrthoAnnotationsCommand() => OrthoAnnotationRemovalCommand.Run();
|
||||||
[CommandMethod("PXP-OSI", CommandFlags.Session)] public void ShowOrthoSourceInModelCommand() => OrthoSourceNavigationCommand.Run();
|
[CommandMethod("PXP-OSI", CommandFlags.Session)] public void ShowOrthoSourceInModelCommand() => OrthoSourceNavigationCommand.Run();
|
||||||
|
[CommandMethod("PXP-DJ")] public void DimensionOrthoAnnotationsCommand() => OrthoDimensionCommand.Run();
|
||||||
[CommandMethod("PXP-AC", CommandFlags.UsePickSet)] public void SwapAttributesCommand() => PRecAnnot.Plant3D2026.SwapAttributesCommand.Run();
|
[CommandMethod("PXP-AC", CommandFlags.UsePickSet)] public void SwapAttributesCommand() => PRecAnnot.Plant3D2026.SwapAttributesCommand.Run();
|
||||||
[CommandMethod("PXP-IOD", CommandFlags.Session)] public void UpdateOrthoDrawingsCommand() => PRecAnnot.Plant3D2026.UpdateOrthoDrawingsCommand.Run();
|
[CommandMethod("PXP-IOD", CommandFlags.Session)] public void UpdateOrthoDrawingsCommand() => PRecAnnot.Plant3D2026.UpdateOrthoDrawingsCommand.Run();
|
||||||
[CommandMethod("mto-ma")] public void ShowManualAnnotationPaletteCommand() => ManualAnnotationPalette.Show();
|
[CommandMethod("mto-ma")] public void ShowManualAnnotationPaletteCommand() => ManualAnnotationPalette.Show();
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using Autodesk.AutoCAD.DatabaseServices;
|
||||||
|
using Autodesk.AutoCAD.EditorInput;
|
||||||
|
using Autodesk.AutoCAD.Geometry;
|
||||||
|
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application;
|
||||||
|
|
||||||
|
namespace PRecAnnot.Plant3D2026;
|
||||||
|
|
||||||
|
// Source-backed PXP-DJ mutation boundary. The legacy command dimensions the
|
||||||
|
// selected PXP-OA annotation blocks, rejects mixed viewport scales and keeps
|
||||||
|
// all dimension creation in one transaction so native UNDO restores the prior
|
||||||
|
// state. The Plant-specific candidate discovery remains deliberately typed
|
||||||
|
// through the PXP-OA ownership contract.
|
||||||
|
internal static class OrthoDimensionCommand
|
||||||
|
{
|
||||||
|
private const string AnnotationApp = "PXP-OA";
|
||||||
|
private const string DimensionApp = "PXP-DJ";
|
||||||
|
|
||||||
|
public static void Run()
|
||||||
|
{
|
||||||
|
var document = AcadApplication.DocumentManager.MdiActiveDocument;
|
||||||
|
if (document is null) return;
|
||||||
|
var selection = document.Editor.GetSelection(new SelectionFilter(new[] { new TypedValue((int)DxfCode.ExtendedDataRegAppName, AnnotationApp) }));
|
||||||
|
if (selection.Status != PromptStatus.OK || selection.Value.Count < 2)
|
||||||
|
{
|
||||||
|
document.Editor.WriteMessage("\nSelect at least two PXP-OA annotations.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var read = document.Database.TransactionManager.StartOpenCloseTransaction();
|
||||||
|
var points = new List<(ObjectId Id, Point3d Position, string Viewport)>();
|
||||||
|
foreach (var id in selection.Value.GetObjectIds())
|
||||||
|
{
|
||||||
|
if (read.GetObject(id, OpenMode.ForRead) is not BlockReference reference) continue;
|
||||||
|
if (!TryReadViewport(reference, out var viewport)) continue;
|
||||||
|
points.Add((id, reference.Position, viewport));
|
||||||
|
}
|
||||||
|
read.Commit();
|
||||||
|
if (points.Count < 2 || points.Select(point => point.Viewport).Distinct(StringComparer.Ordinal).Count() != 1)
|
||||||
|
{
|
||||||
|
document.Editor.WriteMessage("\nSelected annotations must belong to one Ortho viewport.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
points = points.OrderBy(point => point.Position.X).ThenBy(point => point.Position.Y).ThenBy(point => point.Id.Handle.Value).ToList();
|
||||||
|
var defaultAngle = Math.Abs(points[^1].Position.X - points[0].Position.X) >= Math.Abs(points[^1].Position.Y - points[0].Position.Y) ? 0d : Math.PI / 2d;
|
||||||
|
var angle = document.Editor.GetAngle(new PromptAngleOptions("\nDimension rotation <automatic>: ") { AllowNone = true });
|
||||||
|
if (angle.Status is not (PromptStatus.OK or PromptStatus.None)) return;
|
||||||
|
var rotation = angle.Status == PromptStatus.OK ? angle.Value : defaultAngle;
|
||||||
|
var offset = document.Editor.GetPoint("\nDimension line location: ");
|
||||||
|
if (offset.Status != PromptStatus.OK) return;
|
||||||
|
|
||||||
|
using var documentLock = document.LockDocument();
|
||||||
|
using var transaction = document.Database.TransactionManager.StartTransaction();
|
||||||
|
var table = (BlockTable)transaction.GetObject(document.Database.BlockTableId, OpenMode.ForRead);
|
||||||
|
var paper = (BlockTableRecord)transaction.GetObject(table[BlockTableRecord.PaperSpace], OpenMode.ForWrite);
|
||||||
|
EnsureRegApp(transaction, document.Database);
|
||||||
|
EraseOwnedDimensions(transaction, paper, points[0].Viewport, points.Select(point => point.Id.Handle.ToString()).ToHashSet(StringComparer.OrdinalIgnoreCase));
|
||||||
|
for (var index = 1; index < points.Count; index++)
|
||||||
|
{
|
||||||
|
var first = points[index - 1].Position;
|
||||||
|
var second = points[index].Position;
|
||||||
|
var dimension = new RotatedDimension(rotation, first, second, offset.Value, string.Empty, document.Database.Dimstyle);
|
||||||
|
dimension.LayerId = document.Database.Clayer;
|
||||||
|
dimension.XData = Ownership(points[0].Viewport, points.Select(point => point.Id.Handle.ToString()));
|
||||||
|
paper.AppendEntity(dimension);
|
||||||
|
transaction.AddNewlyCreatedDBObject(dimension, true);
|
||||||
|
}
|
||||||
|
transaction.Commit();
|
||||||
|
document.Editor.WriteMessage($"\nCreated {points.Count - 1} Ortho dimensions; native UNDO is available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryReadViewport(BlockReference reference, out string viewport)
|
||||||
|
{
|
||||||
|
viewport = string.Empty;
|
||||||
|
using var data = reference.GetXDataForApplication(AnnotationApp);
|
||||||
|
var values = data?.AsArray().Where(value => value.TypeCode == (int)DxfCode.ExtendedDataAsciiString).Select(value => value.Value?.ToString() ?? string.Empty).ToArray();
|
||||||
|
if (values is null) return false;
|
||||||
|
for (var index = 0; index + 1 < values.Length; index++) if (string.Equals(values[index], "VIEWPORT", StringComparison.Ordinal)) { viewport = values[index + 1]; break; }
|
||||||
|
return !string.IsNullOrWhiteSpace(viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EraseOwnedDimensions(Transaction transaction, BlockTableRecord paper, string viewport, HashSet<string> handles)
|
||||||
|
{
|
||||||
|
foreach (ObjectId id in paper)
|
||||||
|
{
|
||||||
|
if (transaction.GetObject(id, OpenMode.ForRead) is not Entity entity) continue;
|
||||||
|
using var data = entity.GetXDataForApplication(DimensionApp);
|
||||||
|
var values = data?.AsArray().Where(value => value.TypeCode == (int)DxfCode.ExtendedDataAsciiString).Select(value => value.Value?.ToString() ?? string.Empty).ToArray();
|
||||||
|
if (values is null || !values.Contains(viewport, StringComparer.Ordinal)) continue;
|
||||||
|
if (!handles.Any(handle => values.Contains(handle, StringComparer.OrdinalIgnoreCase))) continue;
|
||||||
|
entity.UpgradeOpen();
|
||||||
|
entity.Erase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResultBuffer Ownership(string viewport, IEnumerable<string> handles) => new(
|
||||||
|
new TypedValue((int)DxfCode.ExtendedDataRegAppName, DimensionApp),
|
||||||
|
new TypedValue((int)DxfCode.ExtendedDataAsciiString, viewport),
|
||||||
|
new TypedValue((int)DxfCode.ExtendedDataAsciiString, "SOURCES"),
|
||||||
|
new TypedValue((int)DxfCode.ExtendedDataAsciiString, string.Join(",", handles)));
|
||||||
|
|
||||||
|
private static void EnsureRegApp(Transaction transaction, Database database)
|
||||||
|
{
|
||||||
|
var table = (RegAppTable)transaction.GetObject(database.RegAppTableId, OpenMode.ForRead);
|
||||||
|
if (table.Has(DimensionApp)) return;
|
||||||
|
table.UpgradeOpen();
|
||||||
|
using var record = new RegAppTableRecord { Name = DimensionApp };
|
||||||
|
table.Add(record);
|
||||||
|
transaction.AddNewlyCreatedDBObject(record, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,6 @@ $moduleManifestPath=Join-Path $bundleRoot 'Contents\module-manifest.json'
|
|||||||
$files=Get-ChildItem $bundleRoot -Recurse -File | Where-Object { $_.FullName -ne $moduleManifestPath } | Sort-Object FullName | ForEach-Object {
|
$files=Get-ChildItem $bundleRoot -Recurse -File | Where-Object { $_.FullName -ne $moduleManifestPath } | Sort-Object FullName | ForEach-Object {
|
||||||
[ordered]@{ relativePath=$_.FullName.Substring($bundleRoot.Length + 1).Replace('\','/'); sha256=(Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant(); required=$true }
|
[ordered]@{ relativePath=$_.FullName.Substring($bundleRoot.Length + 1).Replace('\','/'); sha256=(Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant(); required=$true }
|
||||||
}
|
}
|
||||||
$manifest=[ordered]@{ schemaVersion=2; package='P_Rec_Annot'; version='0.2.6'; modules=$modules; assemblies=$assemblies; files=$files }
|
$manifest=[ordered]@{ schemaVersion=2; package='P_Rec_Annot'; version='0.2.7'; modules=$modules; assemblies=$assemblies; files=$files }
|
||||||
$manifest | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $bundleRoot 'Contents\module-manifest.json') -Encoding utf8
|
$manifest | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $bundleRoot 'Contents\module-manifest.json') -Encoding utf8
|
||||||
Write-Host 'Bundle assembly build completed; deployment is intentionally not performed.'
|
Write-Host 'Bundle assembly build completed; deployment is intentionally not performed.'
|
||||||
|
|||||||
Reference in New Issue
Block a user