using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using PRecAnnot.Abstractions; using PRecAnnot.Core; using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Core.Application; namespace PRecAnnot.Plant3D2026; internal static class AutoAnnotateViewCommand { public static void Run() { 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; var context = new PlantRuntimeContextReader().ReadCurrentContext(document); if (!context.HasPlantProject || !context.IsOrthoDrawing) throw new InvalidOperationException("AUTO_ANNOTATE_VIEW_ORTHO_CONTEXT_REQUIRED"); OrthoViewportInfo viewport; using (var transaction = document.Database.TransactionManager.StartOpenCloseTransaction()) { var entity = (Viewport)transaction.GetObject(selected.ObjectId, OpenMode.ForRead); var matches = context.Viewports.Where(x => Math.Abs(x.CenterX - entity.CenterPoint.X) < .001 && Math.Abs(x.CenterY - entity.CenterPoint.Y) < .001 && Math.Abs(x.Width - entity.Width) < .001 && Math.Abs(x.Height - entity.Height) < .001).ToArray(); viewport = matches.Length == 1 ? matches[0] : throw new InvalidOperationException(matches.Length == 0 ? "AUTO_ANNOTATE_VIEW_NOT_FOUND" : "AUTO_ANNOTATE_VIEW_AMBIGUOUS"); } var objects = new PlantObjectReader().ReadObjects(viewport, CancellationToken.None); var classifications = objects.OrderBy(x => x.SnapshotId, StringComparer.Ordinal) .Select(x => new OrthoAnnotationClassifier().Classify(x, new(true, true, true, true, true))).ToArray(); var permit = string.Equals(Environment.GetEnvironmentVariable("P_REC_ANNOT_RUNTIME_MODE"), "Apply", StringComparison.OrdinalIgnoreCase) ? FirstLimitedApplyPermitReader.ReadFor(document) : null; var plan = new AnnotationPlanBuilder().Build(new AnnotationPlanningRequest { CommandName = "PXP-AAV", Viewport = viewport, Objects = objects, LimitedApplyTargetSnapshotId = permit?.TargetSnapshotId, LimitedApplyRuleId = permit is null ? null : FirstLimitedApplyPlanner.RuleId }); var leaders = classifications.Count(x => x.Representation == OrthoAnnotationRepresentation.MultiLeader); var bubbles = classifications.Count(x => x.Representation == OrthoAnnotationRepresentation.BubbleBlock); document.Editor.WriteMessage($"\nPXP-AAV preview: examined={plan.Summary.ObjectsExamined}; create={plan.Summary.CreateCount}; update={plan.Summary.UpdateCount}; leaders={leaders}; bubbles={bubbles}; skip={plan.Summary.SkipCount}; conflicts={plan.Summary.ConflictCount}; PlanId={plan.PlanId}. DWG не изменён."); RuntimeDiagnostics.Write("AutoAnnotateViewPreviewCompleted", commandName: "PXP-AAV", resultStatus: "PreviewCompleted", document: document, details: new Dictionary { ["PlanId"] = plan.PlanId, ["ObjectsExamined"] = plan.Summary.ObjectsExamined, ["MultiLeaderCandidates"] = leaders, ["BubbleCandidates"] = bubbles }); if (permit is null) return; if (!string.Equals(permit.ExpectedPlanId, plan.PlanId, StringComparison.Ordinal)) throw new InvalidOperationException("APPLY_PLAN_ID_MISMATCH"); var selectedSource = objects.SingleOrDefault(x => string.Equals(x.SnapshotId, permit.TargetSnapshotId, StringComparison.Ordinal)) ?? throw new InvalidOperationException("APPLY_TARGET_NOT_FOUND"); var selectedClassification = classifications.Single(x => string.Equals(x.StableId, permit.TargetSnapshotId, StringComparison.Ordinal)); if (selectedClassification.Representation != OrthoAnnotationRepresentation.None) { var settingsPath = Environment.GetEnvironmentVariable("P_REC_ANNOT_LINE_NUMBER_DRAWING_SETTINGS_PATH"); if (string.IsNullOrWhiteSpace(settingsPath) || !File.Exists(settingsPath)) throw new InvalidOperationException("ORTHO_ANNOTATION_CONFIGURATION_REQUIRED"); var assets = new OrthoAnnotationSettingsLoader().Load(File.ReadAllText(settingsPath)); var result = new OrthoAnnotationWriter().Replace(document, viewport, selectedSource, selectedClassification, assets); document.Editor.WriteMessage("\nPXP-AAV Apply: " + result + "; AutoCAD UNDO is available."); RuntimeDiagnostics.Write("AutoAnnotateViewApplyCompleted", commandName: "PXP-AAV", resultStatus: result, document: document, details: new Dictionary { ["PlanId"] = plan.PlanId, ["Representation"] = selectedClassification.Representation.ToString() }); return; } var corePermit = new FirstLimitedApplyPermit { FixtureMarker = FirstLimitedApplyPlanner.FixtureMarker, AllowApply = permit.AllowApply, TargetSnapshotId = permit.TargetSnapshotId, ExpectedPlanId = permit.ExpectedPlanId }; var preflight = new FirstLimitedApplyPlanner().Prepare(PRecAnnotExecutionMode.Apply, plan, viewport, objects, corePermit); var outcome = new FirstLimitedPipeAnnotationWriter().Write(document, preflight.Operation, permit.VisibilityState, permit.AnnotationTemplateDwgPath); document.Editor.WriteMessage("\nPXP-AAV Apply: " + outcome + "; AutoCAD UNDO is available."); RuntimeDiagnostics.Write("AutoAnnotateViewApplyCompleted", commandName: "PXP-AAV", resultStatus: outcome.ToString(), document: document, details: new Dictionary { ["PlanId"] = plan.PlanId }); } catch (Exception exception) { RuntimeDiagnostics.Write("AutoAnnotateViewFailed", "ERROR", commandName: "PXP-AAV", resultStatus: exception.Message, exception: exception, document: document); document.Editor.WriteMessage("\nPXP-AAV: " + exception.Message); } } }