Files
autodesk/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/LineNumberOwnedAnnotationReader.cs
T

97 lines
5.9 KiB
C#

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));
}
public IReadOnlyList<LineNumberOwnedRow> ReadMarkers(Document document)
{
using var transaction = document.Database.TransactionManager.StartOpenCloseTransaction();
var blocks = (BlockTable)transaction.GetObject(document.Database.BlockTableId, OpenMode.ForRead);
var paper = (BlockTableRecord)transaction.GetObject(blocks[BlockTableRecord.PaperSpace], OpenMode.ForRead);
var rows = new List<LineNumberOwnedRow>();
foreach (ObjectId id in paper)
{
if (transaction.GetObject(id, OpenMode.ForRead) is not BlockReference marker || !HasRole(marker, "MARKER")) continue;
var values = marker.GetXDataForApplication(ApplicationName)?.AsArray() ?? [];
var strings = values.Where(value => value.TypeCode == 1000).Select(value => value.Value as string).ToArray();
var stableId = strings.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 = strings.LastOrDefault() ?? string.Empty;
if (string.IsNullOrWhiteSpace(stableId) || markerNumber <= 0) continue;
rows.Add(new(stableId, markerNumber, text, default));
}
return rows.OrderBy(value => value.MarkerNumber).ThenBy(value => value.SourceStableId, StringComparer.Ordinal).ToArray();
}
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);
}
}