feat: activate p-rec-annot line-number edit commands

This commit is contained in:
codex
2026-08-07 09:09:47 +03:00
parent 6e909f89bc
commit 2626b64e63
4 changed files with 193 additions and 3 deletions
@@ -0,0 +1,76 @@
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using PRecAnnot.Abstractions;
namespace PRecAnnot.Plant3D2026;
internal sealed class LineNumberOwnedAnnotationReader
{
private const string ApplicationName = "PXP-LN";
public IReadOnlyList<LineNumberOwnedRow> ReadList(Document document, ObjectId listId)
{
using var transaction = document.Database.TransactionManager.StartOpenCloseTransaction();
if (transaction.GetObject(listId, OpenMode.ForRead) is not BlockReference list || !HasRole(list, "LIST"))
throw new InvalidOperationException("LINE_NUMBER_LIST_NOT_SELECTED");
var rows = new Dictionary<int, (string? StableId, string? Text)>();
foreach (ObjectId id in list.AttributeCollection)
{
var attribute = (AttributeReference)transaction.GetObject(id, OpenMode.ForRead);
var ownership = ReadOwnership(attribute);
if (ownership is null) continue;
rows.TryGetValue(ownership.Value.MarkerNumber, out var row);
rows[ownership.Value.MarkerNumber] = ownership.Value.Role == "LINENUMBER"
? (ownership.Value.StableId, attribute.TextString.Replace("\\P", "\n", StringComparison.Ordinal))
: (ownership.Value.StableId ?? row.StableId, row.Text);
}
var result = rows.OrderBy(value => value.Key)
.Select(value => new LineNumberOwnedRow(
value.Value.StableId ?? throw new InvalidOperationException("LINE_NUMBER_ROW_STABLE_ID_MISSING"),
value.Key,
value.Value.Text ?? throw new InvalidOperationException("LINE_NUMBER_ROW_TEXT_MISSING"),
default))
.ToArray();
if (result.Length == 0) throw new InvalidOperationException("LINE_NUMBER_LIST_EMPTY");
return result;
}
public LineNumberOwnedRow ReadMarker(Document document, ObjectId markerId)
{
using var transaction = document.Database.TransactionManager.StartOpenCloseTransaction();
if (transaction.GetObject(markerId, OpenMode.ForRead) is not BlockReference marker)
throw new InvalidOperationException("LINE_NUMBER_MARKER_NOT_SELECTED");
var values = marker.GetXDataForApplication(ApplicationName)?.AsArray() ?? [];
var stableId = values.Where(value => value.TypeCode == 1000).Select(value => value.Value as string)
.FirstOrDefault(value => !string.Equals(value, "MARKER", StringComparison.OrdinalIgnoreCase));
var markerNumber = values.Where(value => value.TypeCode == 1071).Select(value => Convert.ToInt32(value.Value)).FirstOrDefault();
var text = values.Where(value => value.TypeCode == 1000).Select(value => value.Value as string).LastOrDefault() ?? string.Empty;
if (string.IsNullOrWhiteSpace(stableId) || markerNumber <= 0) throw new InvalidOperationException("LINE_NUMBER_MARKER_OWNERSHIP_MISSING");
var localPosition = Point3d.Origin;
foreach (ObjectId id in marker.AttributeCollection)
{
var attribute = (AttributeReference)transaction.GetObject(id, OpenMode.ForRead);
if (!string.Equals(attribute.Tag, "NUMBER", StringComparison.OrdinalIgnoreCase)) continue;
localPosition = attribute.Position.TransformBy(marker.BlockTransform.Inverse());
break;
}
return new(stableId, markerNumber, text, new(localPosition.X, localPosition.Y, localPosition.Z));
}
private static bool HasRole(BlockReference reference, string role) =>
reference.GetXDataForApplication(ApplicationName)?.AsArray().Any(value =>
value.TypeCode == 1000 && string.Equals(value.Value as string, role, StringComparison.OrdinalIgnoreCase)) == true;
private static (string? StableId, string Role, int MarkerNumber)? ReadOwnership(AttributeReference attribute)
{
var values = attribute.GetXDataForApplication(ApplicationName)?.AsArray();
if (values is null) return null;
var strings = values.Where(value => value.TypeCode == 1000).Select(value => value.Value as string).ToArray();
var role = strings.FirstOrDefault(value => value is "MARKER" or "LINENUMBER");
var number = values.Where(value => value.TypeCode == 1071).Select(value => Convert.ToInt32(value.Value)).FirstOrDefault();
return role is null || number <= 0 ? null : (strings.FirstOrDefault(value => value != role), role, number);
}
}