using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.ProcessPower.DataObjects; using Autodesk.ProcessPower.Drawings2d; using Autodesk.ProcessPower.PlantInstance; using Autodesk.ProcessPower.PnP3dOrthoDrawingsUI; using PRecAnnot.Abstractions; using PRecAnnot.Core; using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Core.Application; using AcadColor = Autodesk.AutoCAD.Colors.Color; namespace PRecAnnot.Plant3D2026; internal static class UpdateOrthoViewBlocksCommand { public static void Run() { var document = AcadApplication.DocumentManager.MdiActiveDocument; if (document is null) return; try { var settings = Environment.GetEnvironmentVariable("P_REC_ANNOT_LINE_NUMBER_DRAWING_SETTINGS_PATH"); if (string.IsNullOrWhiteSpace(settings) || !File.Exists(settings)) throw new InvalidOperationException("ORTHO_LAYER_CONFIGURATION_REQUIRED"); var rules = new OrthoLayerSettingsLoader().Load(File.ReadAllText(settings)); 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; string viewName; var changes = new List<(string Layer, OrthoLayerRule Rule)>(); using (var transaction = document.Database.TransactionManager.StartOpenCloseTransaction()) { var viewport = (Viewport)transaction.GetObject(selected.ObjectId, OpenMode.ForRead); var context = new PlantRuntimeContextReader().ReadCurrentContext(document); var matched = context.Viewports.Where(x => Math.Abs(x.CenterX - viewport.CenterPoint.X) < .001 && Math.Abs(x.CenterY - viewport.CenterPoint.Y) < .001 && Math.Abs(x.Width - viewport.Width) < .001 && Math.Abs(x.Height - viewport.Height) < .001).ToArray(); viewName = matched.Length == 1 ? matched[0].ViewName ?? matched[0].DisplayName : throw new InvalidOperationException(matched.Length == 0 ? "ORTHO_VIEW_NOT_FOUND" : "ORTHO_VIEW_AMBIGUOUS"); var layers = (LayerTable)transaction.GetObject(document.Database.LayerTableId, OpenMode.ForRead); foreach (ObjectId id in layers) { var layer = (LayerTableRecord)transaction.GetObject(id, OpenMode.ForRead); var rule = rules.FirstOrDefault(x => x.MatchesLayer(viewName, layer.Name)); if (rule is not null) changes.Add((layer.Name, rule)); } } document.Editor.WriteMessage($"\nPXP-UOB preview: view={viewName}; matching-layers={changes.Count}. DWG не изменён."); RuntimeDiagnostics.Write("UpdateOrthoViewBlocksPreviewCompleted", commandName: "PXP-UOB", resultStatus: "PreviewCompleted", document: document, details: new Dictionary { ["ViewName"] = viewName, ["LayerCount"] = changes.Count }); if (!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 layerTable = (LayerTable)write.GetObject(document.Database.LayerTableId, OpenMode.ForRead); var linetypes = (LinetypeTable)write.GetObject(document.Database.LinetypeTableId, OpenMode.ForRead); var representationCount = ApplyRepresentationRules(document, selected.ObjectId, viewName, rules, write, linetypes); foreach (var change in changes) { var layer = (LayerTableRecord)write.GetObject(layerTable[change.Layer], OpenMode.ForWrite); Apply(layer, change.Rule, linetypes); } var viewportToUpdate = (Viewport)write.GetObject(selected.ObjectId, OpenMode.ForWrite); if (layerTable.Has("Defpoints")) viewportToUpdate.LayerId = layerTable["Defpoints"]; write.Commit(); document.Editor.WriteMessage($"\nPXP-UOB Apply: updated-layers={changes.Count}; updated-representations={representationCount}; AutoCAD UNDO is available."); RuntimeDiagnostics.Write("UpdateOrthoViewBlocksApplyCompleted", commandName: "PXP-UOB", resultStatus: "Applied", document: document, details: new Dictionary { ["LayerCount"] = changes.Count, ["RepresentationCount"] = representationCount }); } catch (Exception exception) { RuntimeDiagnostics.Write("UpdateOrthoViewBlocksFailed", "ERROR", commandName: "PXP-UOB", resultStatus: exception.Message, exception: exception, document: document); document.Editor.WriteMessage("\nPXP-UOB: " + exception.Message); } } private static void Apply(LayerTableRecord layer, OrthoLayerRule rule, LinetypeTable linetypes) { if (rule.LineWeight.HasValue) layer.LineWeight = (LineWeight)rule.LineWeight.Value; if (!string.IsNullOrWhiteSpace(rule.LineType) && linetypes.Has(rule.LineType)) layer.LinetypeObjectId = linetypes[rule.LineType]; if (rule.Red.HasValue) layer.Color = AcadColor.FromRgb(rule.Red.Value, rule.Green!.Value, rule.Blue!.Value); else if (rule.ColorIndex.HasValue) layer.Color = AcadColor.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByColor, rule.ColorIndex.Value); } private static int ApplyRepresentationRules(Autodesk.AutoCAD.ApplicationServices.Document document, ObjectId viewportId, string viewName, IReadOnlyList rules, Transaction transaction, LinetypeTable linetypes) { var manager = PlantApplication.ProjectPart("Piping")?.DataLinksManager ?? throw new InvalidOperationException("ORTHO_PIPING_DATALINKS_UNAVAILABLE"); var database = manager.GetPnPDatabase(); IDwgSheetDef sheet; IDwgViewDef view; List representations; if (!UIUtils.GetDwgSheetFromOrthoDrawingName(document.Database.Filename, out sheet) || !UIUtils.GetViewDefByViewName(viewName, sheet, out view) || !UIUtils.GetOrthoEntityListInView(UIUtils.GetDwgSheetDefResolvedPath(sheet), viewName, out representations)) throw new InvalidOperationException("ORTHO_VIEW_REPRESENTATIONS_UNAVAILABLE"); var changed = 0; foreach (var id in representations.Where(value => !value.IsNull).OrderBy(value => value.Handle.Value)) { if (transaction.GetObject(id, OpenMode.ForWrite, false) is not BlockReference block) continue; var modelId = PnPDwg2dUtil.GetModelObjectId(id, document.Database); var rowId = PnPDwg2dUtil.PipingRowId(modelId); var engineering = database.Tables["EngineeringItems"].Select("PnPID=" + rowId); var equipment = database.Tables["Equipment"].Select("PnPID=" + rowId); if (engineering.Length == 1 && equipment.Length == 0) { var status = Convert.ToString(engineering[0]["Status"]) ?? string.Empty; var statusRule = rules.FirstOrDefault(rule => rule.MatchesStatus(status)); if (statusRule is not null) Apply(block, statusRule, linetypes); } else if (engineering.Length == 1 && equipment.Length == 1) block.LineWeight = LineWeight.ByLineWeightDefault; if (transaction.GetObject(block.BlockTableRecord, OpenMode.ForRead) is BlockTableRecord definition) foreach (ObjectId nestedId in definition) if (transaction.GetObject(nestedId, OpenMode.ForWrite, false) is Entity nested && rules.FirstOrDefault(rule => rule.MatchesLayer(viewName, nested.Layer)) is { } nestedRule) Apply(nested, nestedRule, linetypes); changed++; } return changed; } private static void Apply(Entity entity, OrthoLayerRule rule, LinetypeTable linetypes) { if (rule.LineWeight.HasValue) entity.LineWeight = (LineWeight)rule.LineWeight.Value; if (!string.IsNullOrWhiteSpace(rule.LineType) && linetypes.Has(rule.LineType)) entity.LinetypeId = linetypes[rule.LineType]; if (rule.Red.HasValue) entity.Color = AcadColor.FromRgb(rule.Red.Value, rule.Green!.Value, rule.Blue!.Value); else if (rule.ColorIndex.HasValue) entity.Color = AcadColor.FromColorIndex(Autodesk.AutoCAD.Colors.ColorMethod.ByColor, rule.ColorIndex.Value); } private static void ValidateFixture(Autodesk.AutoCAD.ApplicationServices.Document document) { var marker = Environment.GetEnvironmentVariable("P_REC_ANNOT_ORTHO_MAINTENANCE_FIXTURE_MARKER"); if (string.IsNullOrWhiteSpace(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"); } }