feat: port p-rec-annot elevation subsystem
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.Geometry;
|
||||
using PRecAnnot.Abstractions;
|
||||
|
||||
namespace PRecAnnot.Plant3D2026;
|
||||
|
||||
internal sealed class ElevationAnnotationWriter
|
||||
{
|
||||
private const string ApplicationName = "PXP-AE";
|
||||
|
||||
public IReadOnlyList<ExistingElevationAnnotation> ReadExisting(Document document)
|
||||
{
|
||||
var result = new List<ExistingElevationAnnotation>();
|
||||
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);
|
||||
foreach (ObjectId id in paper)
|
||||
{
|
||||
if (transaction.GetObject(id, OpenMode.ForRead) is not BlockReference reference) continue;
|
||||
var data = reference.GetXDataForApplication(ApplicationName)?.AsArray();
|
||||
if (data is null) continue;
|
||||
var strings = data.Where(x => x.TypeCode == (int)DxfCode.ExtendedDataAsciiString).Select(x => x.Value?.ToString() ?? string.Empty).ToArray();
|
||||
var source = Value(strings, "SOURCE"); var text = Value(strings, "ANNOTATIONTEXT");
|
||||
if (source is null || text is null) continue;
|
||||
result.Add(new ExistingElevationAnnotation(reference.Handle.ToString(), source, text, new AnnotationPoint(reference.Position.X, reference.Position.Y, reference.Position.Z)));
|
||||
}
|
||||
return result.OrderBy(x => x.SourceStableId, StringComparer.Ordinal).ToArray();
|
||||
}
|
||||
|
||||
public ElevationApplyResult Apply(Document document, IReadOnlyList<ElevationAnnotationOperation> operations, ElevationAssets assets, bool manual = false)
|
||||
{
|
||||
using var documentLock = document.LockDocument();
|
||||
using var transaction = document.Database.TransactionManager.StartTransaction();
|
||||
var blocks = (BlockTable)transaction.GetObject(document.Database.BlockTableId, OpenMode.ForRead);
|
||||
var layers = (LayerTable)transaction.GetObject(document.Database.LayerTableId, OpenMode.ForRead);
|
||||
var styles = (TextStyleTable)transaction.GetObject(document.Database.TextStyleTableId, OpenMode.ForRead);
|
||||
if (!blocks.Has(assets.BlockName)) throw new InvalidOperationException("ELEVATION_BLOCK_MISSING:" + assets.BlockName);
|
||||
if (!layers.Has(assets.Layer)) throw new InvalidOperationException("ELEVATION_LAYER_MISSING:" + assets.Layer);
|
||||
if (!styles.Has(assets.TextStyle)) throw new InvalidOperationException("ELEVATION_TEXT_STYLE_MISSING:" + assets.TextStyle);
|
||||
EnsureRegApp(transaction, document.Database);
|
||||
var paper = (BlockTableRecord)transaction.GetObject(blocks[BlockTableRecord.PaperSpace], OpenMode.ForWrite);
|
||||
var definition = (BlockTableRecord)transaction.GetObject(blocks[assets.BlockName], OpenMode.ForRead);
|
||||
var owned = paper.Cast<ObjectId>().Select(id => transaction.GetObject(id, OpenMode.ForRead)).OfType<BlockReference>()
|
||||
.Select(reference => (reference, source: Source(reference))).Where(x => x.source is not null)
|
||||
.GroupBy(x => x.source!, StringComparer.OrdinalIgnoreCase).ToDictionary(x => x.Key, x => x.ToArray(), StringComparer.OrdinalIgnoreCase);
|
||||
var created = 0; var updated = 0; var unchanged = 0;
|
||||
foreach (var operation in operations.Where(x => x.Kind is AnnotationOperationKind.Create or AnnotationOperationKind.Update))
|
||||
{
|
||||
if (operation.Text is null) continue;
|
||||
var matches = owned.GetValueOrDefault(operation.StableId, []);
|
||||
BlockReference reference;
|
||||
if (matches.Length == 0)
|
||||
{
|
||||
reference = new BlockReference(ToPoint(operation.Position), definition.ObjectId) { LayerId = layers[assets.Layer], Rotation = operation.Rotation };
|
||||
paper.AppendEntity(reference); transaction.AddNewlyCreatedDBObject(reference, true); created++;
|
||||
AddAttributes(transaction, definition, reference, operation.Text, styles[assets.TextStyle]);
|
||||
}
|
||||
else
|
||||
{
|
||||
reference = matches[0].reference; reference.UpgradeOpen();
|
||||
reference.Position = ToPoint(operation.Position); reference.Rotation = operation.Rotation; reference.LayerId = layers[assets.Layer]; updated++;
|
||||
foreach (ObjectId attributeId in reference.AttributeCollection)
|
||||
{
|
||||
var attribute = (AttributeReference)transaction.GetObject(attributeId, OpenMode.ForWrite);
|
||||
attribute.TextString = operation.Text + (attribute.Tag.Contains('*') ? "*" : string.Empty); attribute.TextStyleId = styles[assets.TextStyle]; attribute.UpdateMTextAttribute();
|
||||
}
|
||||
}
|
||||
reference.XData = Ownership(operation.StableId, operation.Text, manual);
|
||||
ApplyLegacyDynamicProperties(reference);
|
||||
}
|
||||
unchanged += operations.Count(x => x.Kind == AnnotationOperationKind.Skip && x.Reasons.Contains("ALREADY_CURRENT"));
|
||||
transaction.Commit();
|
||||
return new(created, updated, unchanged);
|
||||
}
|
||||
|
||||
private static void AddAttributes(Transaction transaction, BlockTableRecord definition, BlockReference reference, string text, ObjectId style)
|
||||
{
|
||||
foreach (ObjectId id in definition)
|
||||
{
|
||||
if (transaction.GetObject(id, OpenMode.ForRead) is not AttributeDefinition source || source.Constant) continue;
|
||||
using var attribute = new AttributeReference(); attribute.SetAttributeFromBlock(source, reference.BlockTransform);
|
||||
attribute.TextString = text + (attribute.Tag.Contains('*') ? "*" : string.Empty); attribute.TextStyleId = style;
|
||||
attribute.UpdateMTextAttribute(); reference.AttributeCollection.AppendAttribute(attribute); transaction.AddNewlyCreatedDBObject(attribute, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyLegacyDynamicProperties(BlockReference reference)
|
||||
{
|
||||
if (!reference.IsDynamicBlock) return;
|
||||
foreach (DynamicBlockReferenceProperty property in reference.DynamicBlockReferencePropertyCollection)
|
||||
if (string.Equals(property.PropertyName, "V1", StringComparison.OrdinalIgnoreCase) && !property.ReadOnly) property.Value = "От объекта";
|
||||
}
|
||||
|
||||
private static string? Source(BlockReference reference)
|
||||
{
|
||||
var strings = reference.GetXDataForApplication(ApplicationName)?.AsArray().Where(x => x.TypeCode == (int)DxfCode.ExtendedDataAsciiString).Select(x => x.Value?.ToString() ?? string.Empty).ToArray();
|
||||
return strings is null ? null : Value(strings, "SOURCE");
|
||||
}
|
||||
private static string? Value(string[] values, string key) { var index = Array.FindIndex(values, x => string.Equals(x, key, StringComparison.Ordinal)); return index >= 0 && index + 1 < values.Length ? values[index + 1] : null; }
|
||||
private static Point3d ToPoint(AnnotationPoint point) => new(point.X, point.Y, point.Z);
|
||||
private static ResultBuffer Ownership(string source, string text, bool manual) => new(new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationName), new TypedValue((int)DxfCode.ExtendedDataAsciiString, "SOURCE"), new TypedValue((int)DxfCode.ExtendedDataAsciiString, source), new TypedValue((int)DxfCode.ExtendedDataAsciiString, "ANNOTATIONTEXT"), new TypedValue((int)DxfCode.ExtendedDataAsciiString, text), new TypedValue((int)DxfCode.ExtendedDataAsciiString, manual ? "MANUAL" : "AUTO"));
|
||||
private static void EnsureRegApp(Transaction transaction, Database database) { var table = (RegAppTable)transaction.GetObject(database.RegAppTableId, OpenMode.ForRead); if (table.Has(ApplicationName)) return; table.UpgradeOpen(); using var record = new RegAppTableRecord { Name = ApplicationName }; table.Add(record); transaction.AddNewlyCreatedDBObject(record, true); }
|
||||
}
|
||||
Reference in New Issue
Block a user