feat: port p-rec-annot ortho viewport maintenance foundation

This commit is contained in:
codex
2026-08-07 12:43:08 +03:00
parent ba39a649be
commit 7d8cc570df
8 changed files with 116 additions and 6 deletions
@@ -47,6 +47,7 @@ public sealed class EntryPoint : IExtensionApplication
[CommandMethod("PXP-ALC")] public void AutoLineNumberConnectionsCommand() => LineConnectionCommand.Run();
[CommandMethod("PXP-AE")] public void AutoElevationCommand() => ElevationCommands.RunAutomatic();
[CommandMethod("PXP-IE")] public void InsertElevationCommand() => ElevationCommands.RunManual();
[CommandMethod("PXP-COV")] public void CheckOrthoViewportCommand() => OrthoMaintenanceCommands.CheckViewport();
[CommandMethod("PHP_REC_AUTOMATION_START", CommandFlags.Session)]
public void AutomationStartCommand() => FirstLimitedApplyAutomationBootstrap.Arm();
@@ -49,6 +49,16 @@ internal sealed class LineConnectionAnnotationWriter
attribute.LayerId = layers[assets.TextLayer]; attribute.TextStyleId = styles[assets.TextStyle];
attribute.UpdateMTextAttribute(); reference.AttributeCollection.AppendAttribute(attribute); transaction.AddNewlyCreatedDBObject(attribute, true);
}
if (plan.ConnectorPosition is { } connector)
{
using var leader = new Polyline(3) { LayerId = layers[assets.PolylineLayer], XData = Ownership(viewportStableId, plan) };
leader.AddVertexAt(0, new Point2d(connector.X, connector.Y), 0, 0, 0);
// Legacy PXP-ALC uses an orthogonal two-segment leader. Its
// elbow shares the annotation Y coordinate for a stable route.
leader.AddVertexAt(1, new Point2d(connector.X, plan.Position.Y), 0, 0, 0);
leader.AddVertexAt(2, new Point2d(plan.Position.X, plan.Position.Y), 0, 0, 0);
paper.AppendEntity(leader); transaction.AddNewlyCreatedDBObject(leader, true);
}
}
transaction.Commit();
return new(deleted, insertable.Length);
@@ -0,0 +1,67 @@
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.ProcessPower.PlantInstance;
using Autodesk.ProcessPower.P3dProjectParts;
using PRecAnnot.Abstractions;
using PRecAnnot.Core;
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Core.Application;
namespace PRecAnnot.Plant3D2026;
internal static class OrthoMaintenanceCommands
{
public static void CheckViewport()
{
var document = AcadApplication.DocumentManager.MdiActiveDocument;
if (document is null) return;
try
{
var options = new PromptEntityOptions("\nВыберите видовой экран для проверки: ");
options.SetRejectMessage("\nДолжен быть видовой экран."); options.AddAllowedClass(typeof(Viewport), true);
var selected = document.Editor.GetEntity(options); if (selected.Status != PromptStatus.OK) return;
OrthoViewportInfo view;
ViewportLayerPlan layerPlan;
using (var transaction = document.Database.TransactionManager.StartOpenCloseTransaction())
{
var viewport = (Viewport)transaction.GetObject(selected.ObjectId, OpenMode.ForRead);
var layers = (LayerTable)transaction.GetObject(document.Database.LayerTableId, OpenMode.ForRead);
layerPlan = new ViewportLayerPlanner().Build(viewport.Layer, layers.Has("Defpoints"));
view = Resolve(document, viewport);
}
if (layerPlan.FailureCode is not null) throw new InvalidOperationException(layerPlan.FailureCode);
var objects = new PlantObjectReader().ReadObjects(view, CancellationToken.None);
var resolved = objects.Count(x => x.MembershipStatus == ViewMembershipStatus.Resolved);
var outside = objects.Count(x => x.MembershipStatus == ViewMembershipStatus.ObjectOutsideView);
var unresolved = objects.Count - resolved - outside;
document.Editor.WriteMessage($"\nPXP-COV preview: resolved={resolved}; outside={outside}; unresolved={unresolved}; viewport-layer-change={layerPlan.RequiresChange}. DWG не изменён.");
RuntimeDiagnostics.Write("OrthoViewportCheckCompleted", commandName: "PXP-COV", resultStatus: "PreviewCompleted", document: document, details: new Dictionary<string, object?> { ["Resolved"] = resolved, ["Outside"] = outside, ["Unresolved"] = unresolved, ["LayerChange"] = layerPlan.RequiresChange });
if (!layerPlan.RequiresChange || !string.Equals(Environment.GetEnvironmentVariable("P_REC_ANNOT_RUNTIME_MODE"), "Apply", StringComparison.OrdinalIgnoreCase)) return;
ValidateFixture(document);
using var documentLock = document.LockDocument();
using var write = document.Database.TransactionManager.StartTransaction();
var target = (Viewport)write.GetObject(selected.ObjectId, OpenMode.ForWrite);
var layerTable = (LayerTable)write.GetObject(document.Database.LayerTableId, OpenMode.ForRead);
target.LayerId = layerTable[layerPlan.TargetLayer];
write.Commit();
document.Editor.WriteMessage("\nPXP-COV Apply: viewport moved to Defpoints; AutoCAD UNDO is available.");
}
catch (Exception exception) { RuntimeDiagnostics.Write("OrthoViewportCheckFailed", "ERROR", commandName: "PXP-COV", resultStatus: exception.Message, exception: exception, document: document); document.Editor.WriteMessage("\nPXP-COV: " + exception.Message); }
}
private static OrthoViewportInfo Resolve(Document document, Viewport selected)
{
var project = PlantApplication.ProjectPart("Ortho") as OrthoProject ?? throw new InvalidOperationException("ORTHO_PROJECT_UNAVAILABLE");
var matches = new PlantOrthoViewportReader(project, document.Name).ReadViewports(CancellationToken.None)
.Where(x => Math.Abs(x.CenterX - selected.CenterPoint.X) < .001 && Math.Abs(x.CenterY - selected.CenterPoint.Y) < .001 && Math.Abs(x.Width - selected.Width) < .001 && Math.Abs(x.Height - selected.Height) < .001).ToArray();
return matches.Length == 1 ? matches[0] : throw new InvalidOperationException(matches.Length == 0 ? "ORTHO_VIEW_NOT_FOUND" : "ORTHO_VIEW_AMBIGUOUS");
}
private static void ValidateFixture(Document document)
{
var marker = Environment.GetEnvironmentVariable("P_REC_ANNOT_ORTHO_MAINTENANCE_FIXTURE_MARKER");
if (string.IsNullOrWhiteSpace(marker) || !Path.IsPathFullyQualified(marker) || !File.Exists(marker) || !string.Equals(File.ReadAllText(marker).Trim(), "P_REC_ANNOT_TEST_FIXTURE=ORTHO_MAINTENANCE_APPLY", StringComparison.Ordinal)) throw new InvalidOperationException("ORTHO_MAINTENANCE_TEST_FIXTURE_REQUIRED");
var root = Path.GetDirectoryName(Path.GetFullPath(marker))! + Path.DirectorySeparatorChar;
if (!Path.GetFullPath(document.Name).StartsWith(root, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("ORTHO_MAINTENANCE_TEST_FIXTURE_REQUIRED");
}
}