feat: complete p-rec-annot line connection pipeline
This commit is contained in:
@@ -83,7 +83,9 @@ public sealed record LineConnectionBoundaryCandidate(
|
||||
double Rotation,
|
||||
string? FirstLineGroupStableId = null,
|
||||
string? SecondLineGroupStableId = null);
|
||||
public sealed record LineConnectionBoundaryPlan(string StableId, string Text, AnnotationPoint Position, double Rotation, IReadOnlyList<string> Reasons);
|
||||
public sealed record LineConnectionBoundaryPlan(string StableId, string Text, AnnotationPoint Position, double Rotation, IReadOnlyList<string> Reasons, string? FirstText = null, string? SecondText = null);
|
||||
public sealed record LineConnectionAssets(string PolylineLayer, string TextLayer, string TextStyle, string BlockName = "BLOCK_LINENUMBER_CONNECTION");
|
||||
public sealed record LineConnectionApplyResult(int Deleted, int Created);
|
||||
// The geometry adapter supplies the paper-space connector point and orientation.
|
||||
// Keeping it separate from the PnP relation snapshot prevents Autodesk objects
|
||||
// from crossing into the deterministic PXP-ALC planning layer.
|
||||
@@ -138,6 +140,7 @@ public sealed record GeometrySnapshot
|
||||
public Bounds2Dto? ProjectedBounds { get; init; }
|
||||
public double? Rotation { get; init; }
|
||||
public double? Elevation { get; init; }
|
||||
public Vector2Dto? PaperDirection { get; init; }
|
||||
}
|
||||
|
||||
// Platform-neutral result of the legacy GetComponentGeometry contract. The
|
||||
|
||||
@@ -41,7 +41,7 @@ public sealed class LineConnectionBoundaryPlanner
|
||||
continue;
|
||||
}
|
||||
var ordered = new[] { first, second }.OrderBy(value => value, StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
result.Add(new(candidate.StableId, string.Join(" / ", ordered), candidate.Position, candidate.Rotation, Array.Empty<string>()));
|
||||
result.Add(new(candidate.StableId, string.Join(" / ", ordered), candidate.Position, candidate.Rotation, Array.Empty<string>(), first, second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Xml.Linq;
|
||||
using PRecAnnot.Abstractions;
|
||||
|
||||
namespace PRecAnnot.Core;
|
||||
|
||||
public sealed class LineConnectionSettingsLoader
|
||||
{
|
||||
public LineConnectionAssets Load(string xml)
|
||||
{
|
||||
try
|
||||
{
|
||||
var element = XDocument.Parse(xml).Root?.Element("LinenumberConnections") ?? throw new InvalidOperationException("LINE_CONNECTION_SETTINGS_MISSING");
|
||||
string Required(string name) => string.IsNullOrWhiteSpace((string?)element.Attribute(name))
|
||||
? throw new InvalidOperationException("LINE_CONNECTION_SETTING_MISSING:" + name)
|
||||
: (string)element.Attribute(name)!;
|
||||
return new(Required("polylinelayer"), Required("textlayer"), Required("textstyle"));
|
||||
}
|
||||
catch (System.Xml.XmlException exception) { throw new InvalidOperationException("LINE_CONNECTION_SETTINGS_XML_INVALID", exception); }
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ public sealed class EntryPoint : IExtensionApplication
|
||||
[CommandMethod("PXP-ESN")] public void EditLineNumberStartCommand() => LineNumberEditCommands.Renumber();
|
||||
[CommandMethod("PXP-ELN")] public void EditLineNumbersCommand() => LineNumberEditCommands.EditText();
|
||||
[CommandMethod("PXP-RMP")] public void ResetMarkerPositionCommand() => LineNumberEditCommands.ResetMarkerPosition();
|
||||
[CommandMethod("PXP-ALC")] public void AutoLineNumberConnectionsCommand() => LineConnectionCommand.Run();
|
||||
|
||||
[CommandMethod("PHP_REC_AUTOMATION_START", CommandFlags.Session)]
|
||||
public void AutomationStartCommand() => FirstLimitedApplyAutomationBootstrap.Arm();
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.Geometry;
|
||||
using PRecAnnot.Abstractions;
|
||||
|
||||
namespace PRecAnnot.Plant3D2026;
|
||||
|
||||
internal sealed class LineConnectionAnnotationWriter
|
||||
{
|
||||
private const string ApplicationName = "PXP-ALC";
|
||||
|
||||
public LineConnectionApplyResult Replace(Document document, string viewportStableId, IReadOnlyList<LineConnectionBoundaryPlan> plans, LineConnectionAssets assets)
|
||||
{
|
||||
var insertable = plans.Where(plan => plan.Reasons.Count == 0).OrderBy(plan => plan.Position.X).ThenByDescending(plan => plan.Position.Y).ToArray();
|
||||
using var documentLock = document.LockDocument();
|
||||
var database = document.Database;
|
||||
using var transaction = database.TransactionManager.StartTransaction();
|
||||
var blocks = (BlockTable)transaction.GetObject(database.BlockTableId, OpenMode.ForRead);
|
||||
var layers = (LayerTable)transaction.GetObject(database.LayerTableId, OpenMode.ForRead);
|
||||
var styles = (TextStyleTable)transaction.GetObject(database.TextStyleTableId, OpenMode.ForRead);
|
||||
if (!blocks.Has(assets.BlockName)) throw new InvalidOperationException("LINE_CONNECTION_BLOCK_MISSING:" + assets.BlockName);
|
||||
if (!layers.Has(assets.PolylineLayer)) throw new InvalidOperationException("LINE_CONNECTION_POLYLINE_LAYER_MISSING:" + assets.PolylineLayer);
|
||||
if (!layers.Has(assets.TextLayer)) throw new InvalidOperationException("LINE_CONNECTION_TEXT_LAYER_MISSING:" + assets.TextLayer);
|
||||
if (!styles.Has(assets.TextStyle)) throw new InvalidOperationException("LINE_CONNECTION_TEXT_STYLE_MISSING:" + assets.TextStyle);
|
||||
EnsureRegApp(transaction, database);
|
||||
var paper = (BlockTableRecord)transaction.GetObject(blocks[BlockTableRecord.PaperSpace], OpenMode.ForWrite);
|
||||
var deleted = 0;
|
||||
foreach (ObjectId id in paper)
|
||||
{
|
||||
var value = transaction.GetObject(id, OpenMode.ForRead);
|
||||
var data = value.GetXDataForApplication(ApplicationName)?.AsArray();
|
||||
if (data is null || !data.Any(item => item.TypeCode == (int)DxfCode.ExtendedDataAsciiString && string.Equals(item.Value?.ToString(), viewportStableId, StringComparison.Ordinal))) continue;
|
||||
value.UpgradeOpen(); value.Erase(); deleted++;
|
||||
}
|
||||
var definition = (BlockTableRecord)transaction.GetObject(blocks[assets.BlockName], OpenMode.ForRead);
|
||||
foreach (var plan in insertable)
|
||||
{
|
||||
using var reference = new BlockReference(new Point3d(plan.Position.X, plan.Position.Y, plan.Position.Z), definition.ObjectId) { LayerId = layers[assets.PolylineLayer], Rotation = plan.Rotation };
|
||||
reference.XData = Ownership(viewportStableId, plan);
|
||||
paper.AppendEntity(reference); transaction.AddNewlyCreatedDBObject(reference, true);
|
||||
var values = new[] { plan.FirstText ?? string.Empty, plan.SecondText ?? string.Empty };
|
||||
var index = 0;
|
||||
foreach (ObjectId entityId in definition)
|
||||
{
|
||||
if (transaction.GetObject(entityId, OpenMode.ForRead) is not AttributeDefinition source || source.Constant) continue;
|
||||
using var attribute = new AttributeReference();
|
||||
attribute.SetAttributeFromBlock(source, reference.BlockTransform);
|
||||
attribute.TextString = values[Math.Min(index++, 1)].Replace("\n", "\\P", StringComparison.Ordinal);
|
||||
attribute.LayerId = layers[assets.TextLayer]; attribute.TextStyleId = styles[assets.TextStyle];
|
||||
attribute.UpdateMTextAttribute(); reference.AttributeCollection.AppendAttribute(attribute); transaction.AddNewlyCreatedDBObject(attribute, true);
|
||||
}
|
||||
}
|
||||
transaction.Commit();
|
||||
return new(deleted, insertable.Length);
|
||||
}
|
||||
|
||||
private static ResultBuffer Ownership(string viewport, LineConnectionBoundaryPlan plan) => new(
|
||||
new TypedValue((int)DxfCode.ExtendedDataRegAppName, ApplicationName),
|
||||
new TypedValue((int)DxfCode.ExtendedDataAsciiString, viewport),
|
||||
new TypedValue((int)DxfCode.ExtendedDataAsciiString, plan.StableId),
|
||||
new TypedValue((int)DxfCode.ExtendedDataAsciiString, "LINENUMBER1"),
|
||||
new TypedValue((int)DxfCode.ExtendedDataAsciiString, plan.FirstText ?? string.Empty),
|
||||
new TypedValue((int)DxfCode.ExtendedDataAsciiString, "LINENUMBER2"),
|
||||
new TypedValue((int)DxfCode.ExtendedDataAsciiString, plan.SecondText ?? string.Empty));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Text.Json;
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using PRecAnnot.Abstractions;
|
||||
|
||||
namespace PRecAnnot.Plant3D2026;
|
||||
|
||||
internal sealed record LineConnectionApplyPermit
|
||||
{
|
||||
public required bool AllowApply { get; init; }
|
||||
public required string FixtureMarkerPath { get; init; }
|
||||
public required string ExpectedViewportStableId { get; init; }
|
||||
public required IReadOnlyList<string> ExpectedConnectorStableIds { get; init; }
|
||||
}
|
||||
|
||||
internal static class LineConnectionApplyPermitReader
|
||||
{
|
||||
private const string MarkerContent = "P_REC_ANNOT_TEST_FIXTURE=LINE_CONNECTION_APPLY";
|
||||
|
||||
public static LineConnectionApplyPermit Read()
|
||||
{
|
||||
var path = Environment.GetEnvironmentVariable("P_REC_ANNOT_LINE_CONNECTION_APPLY_PERMIT_PATH");
|
||||
if (string.IsNullOrWhiteSpace(path) || !Path.IsPathFullyQualified(path) || path.StartsWith("\\\\", StringComparison.Ordinal) || !File.Exists(path))
|
||||
throw new InvalidOperationException("LINE_CONNECTION_APPLY_PERMIT_REQUIRED");
|
||||
return JsonSerializer.Deserialize<LineConnectionApplyPermit>(File.ReadAllText(path), new JsonSerializerOptions { PropertyNameCaseInsensitive = true })
|
||||
?? throw new InvalidOperationException("LINE_CONNECTION_APPLY_PERMIT_INVALID");
|
||||
}
|
||||
|
||||
public static void Validate(Document document, LineConnectionApplyPermit permit, string viewportId, IReadOnlyList<LineConnectionBoundaryPlan> plans)
|
||||
{
|
||||
var actual = plans.Where(plan => plan.Reasons.Count == 0).Select(plan => plan.StableId).OrderBy(value => value, StringComparer.Ordinal).ToArray();
|
||||
var expected = permit.ExpectedConnectorStableIds.OrderBy(value => value, StringComparer.Ordinal).ToArray();
|
||||
if (!permit.AllowApply || !string.Equals(permit.ExpectedViewportStableId, viewportId, StringComparison.Ordinal) || !actual.SequenceEqual(expected, StringComparer.Ordinal))
|
||||
throw new InvalidOperationException("LINE_CONNECTION_APPLY_PERMIT_PLAN_MISMATCH");
|
||||
if (!Path.IsPathFullyQualified(permit.FixtureMarkerPath) || permit.FixtureMarkerPath.StartsWith("\\\\", StringComparison.Ordinal) || !File.Exists(permit.FixtureMarkerPath) || !string.Equals(File.ReadAllText(permit.FixtureMarkerPath).Trim(), MarkerContent, StringComparison.Ordinal))
|
||||
throw new InvalidOperationException("LINE_CONNECTION_APPLY_TEST_FIXTURE_REQUIRED");
|
||||
var root = Path.GetDirectoryName(Path.GetFullPath(permit.FixtureMarkerPath))! + Path.DirectorySeparatorChar;
|
||||
if (!Path.GetFullPath(document.Name).StartsWith(root, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("LINE_CONNECTION_APPLY_TEST_FIXTURE_REQUIRED");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
using Autodesk.ProcessPower.PlantInstance;
|
||||
using Autodesk.ProcessPower.P3dProjectParts;
|
||||
using PRecAnnot.Abstractions;
|
||||
using PRecAnnot.Core;
|
||||
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Core.Application;
|
||||
|
||||
namespace PRecAnnot.Plant3D2026;
|
||||
|
||||
internal static class LineConnectionCommand
|
||||
{
|
||||
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;
|
||||
OrthoViewportInfo viewport;
|
||||
using (var transaction = document.Database.TransactionManager.StartOpenCloseTransaction())
|
||||
{
|
||||
var entity = (Viewport)transaction.GetObject(selected.ObjectId, OpenMode.ForRead);
|
||||
viewport = ResolveViewport(document, entity);
|
||||
}
|
||||
var manager = PlantApplication.ProjectPart("Piping")?.DataLinksManager ?? throw new InvalidOperationException("LINE_CONNECTION_PIPING_DATALINKS_UNAVAILABLE");
|
||||
var relationships = new PlantConnectorRelationshipReader(manager).Read();
|
||||
if (!relationships.Success) throw new InvalidOperationException(relationships.FailureCode);
|
||||
var objects = new PlantObjectReader().ReadObjects(viewport, CancellationToken.None);
|
||||
var byRow = objects.Where(value => value.MembershipStatus == ViewMembershipStatus.Resolved && value.Geometry.PaperPosition is not null)
|
||||
.Select(value => (Object: value, Row: ReadRowId(value)))
|
||||
.Where(value => value.Row.HasValue).ToDictionary(value => value.Row!.Value, value => value.Object);
|
||||
var placements = new Dictionary<string, LineConnectionPlacement>(StringComparer.Ordinal);
|
||||
foreach (var relationship in relationships.Connectors)
|
||||
{
|
||||
if (!byRow.TryGetValue(relationship.ConnectorRowId, out var connector) || connector.Geometry.PaperPosition is not { } point) continue;
|
||||
var direction = connector.Geometry.PaperDirection ?? new Vector2Dto(1, 0);
|
||||
var horizontalLeader = Math.Abs(direction.Y) >= Math.Abs(direction.X);
|
||||
var block = horizontalLeader ? new AnnotationPoint(viewport.CenterX, point.Y) : new AnnotationPoint(point.X, viewport.CenterY);
|
||||
var endpoint = new Point3Dto(point.X, point.Y, 0);
|
||||
placements[relationship.StableId] = new(endpoint, endpoint, new(endpoint, endpoint), block, 0);
|
||||
}
|
||||
var configuration = LineNumberRuntimeConfigurationReader.Read();
|
||||
var definition = configuration.Annotations.Annotations.OrderBy(value => value.Nickname, StringComparer.Ordinal).First();
|
||||
var preview = new LineConnectionPreviewService(new LineNumberFieldResolver(new PlantDataLinksPropertyReader(manager)), new LineNumberAnnotationFormatter(), new LineConnectionBoundaryPlanner())
|
||||
.Preview(definition, relationships.Connectors, placements);
|
||||
var ready = preview.Plans.Count(plan => plan.Reasons.Count == 0);
|
||||
document.Editor.WriteMessage($"\nPXP-ALC preview: connectors={relationships.Connectors.Count}; eligible={ready}; skipped={preview.Plans.Count - ready}. DWG не изменён.");
|
||||
RuntimeDiagnostics.Write("LineConnectionPreviewCompleted", commandName: "PXP-ALC", resultStatus: "PreviewCompleted", document: document, details: new Dictionary<string, object?> { ["ConnectorCount"] = relationships.Connectors.Count, ["EligibleCount"] = ready });
|
||||
if (!string.Equals(Environment.GetEnvironmentVariable("P_REC_ANNOT_RUNTIME_MODE"), "Apply", StringComparison.OrdinalIgnoreCase)) return;
|
||||
var permit = LineConnectionApplyPermitReader.Read();
|
||||
LineConnectionApplyPermitReader.Validate(document, permit, viewport.Id, preview.Plans);
|
||||
var result = new LineConnectionAnnotationWriter().Replace(document, viewport.Id, preview.Plans, configuration.Connections);
|
||||
document.Editor.WriteMessage($"\nPXP-ALC Apply: deleted={result.Deleted}; created={result.Created}.");
|
||||
RuntimeDiagnostics.Write("LineConnectionApplyCompleted", commandName: "PXP-ALC", resultStatus: "Applied", document: document, details: new Dictionary<string, object?> { ["Deleted"] = result.Deleted, ["Created"] = result.Created });
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
RuntimeDiagnostics.Write("LineConnectionCommandFailed", "ERROR", commandName: "PXP-ALC", resultStatus: exception.Message, exception: exception, document: document);
|
||||
document.Editor.WriteMessage("\nPXP-ALC: " + exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static OrthoViewportInfo ResolveViewport(Document document, Viewport selected)
|
||||
{
|
||||
var project = PlantApplication.ProjectPart("Ortho") as OrthoProject ?? throw new InvalidOperationException("LINE_CONNECTION_ORTHO_PROJECT_UNAVAILABLE");
|
||||
var matches = new PlantOrthoViewportReader(project, document.Name).ReadViewports(CancellationToken.None)
|
||||
.Where(value => Math.Abs(value.CenterX - selected.CenterPoint.X) < 0.001 && Math.Abs(value.CenterY - selected.CenterPoint.Y) < 0.001 && Math.Abs(value.Width - selected.Width) < 0.001 && Math.Abs(value.Height - selected.Height) < 0.001)
|
||||
.ToArray();
|
||||
return matches.Length == 1 ? matches[0] : throw new InvalidOperationException(matches.Length == 0 ? "LINE_CONNECTION_ORTHO_VIEW_NOT_FOUND" : "LINE_CONNECTION_ORTHO_VIEW_AMBIGUOUS");
|
||||
}
|
||||
|
||||
private static long? ReadRowId(PlantObjectSnapshot value) => value.Properties.TryGetValue("PRecAnnot.RowId", out var text) && long.TryParse(text, out var row) ? row : null;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using PRecAnnot.Core;
|
||||
|
||||
namespace PRecAnnot.Plant3D2026;
|
||||
|
||||
internal sealed record LineNumberRuntimeConfiguration(LineNumberAnnotationSettings Annotations, AnnotateLineNumbersAssets Assets);
|
||||
internal sealed record LineNumberRuntimeConfiguration(LineNumberAnnotationSettings Annotations, AnnotateLineNumbersAssets Assets, LineConnectionAssets Connections);
|
||||
|
||||
internal static class LineNumberRuntimeConfigurationReader
|
||||
{
|
||||
@@ -11,7 +11,8 @@ internal static class LineNumberRuntimeConfigurationReader
|
||||
{
|
||||
var annotationPath = RequiredLocalFile("P_REC_ANNOT_LINE_NUMBER_ANNOTATION_SETTINGS_PATH");
|
||||
var drawingPath = RequiredLocalFile("P_REC_ANNOT_LINE_NUMBER_DRAWING_SETTINGS_PATH");
|
||||
return new(new LineNumberAnnotationSettingsLoader().Load(File.ReadAllText(annotationPath)), new AnnotateLineNumbersSettingsLoader().Load(File.ReadAllText(drawingPath)));
|
||||
var drawingXml = File.ReadAllText(drawingPath);
|
||||
return new(new LineNumberAnnotationSettingsLoader().Load(File.ReadAllText(annotationPath)), new AnnotateLineNumbersSettingsLoader().Load(drawingXml), new LineConnectionSettingsLoader().Load(drawingXml));
|
||||
}
|
||||
|
||||
private static string RequiredLocalFile(string variable)
|
||||
|
||||
@@ -294,6 +294,7 @@ internal sealed class PlantObjectReader : IPlantObjectReader
|
||||
var properties = dataLinks.GetAllProperties(rowId, true)
|
||||
.GroupBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(x => x.Key, x => x.Last().Value, StringComparer.OrdinalIgnoreCase);
|
||||
properties["PRecAnnot.RowId"] = rowId.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
string? Value(params string[] names) => properties.FirstOrDefault(x => names.Any(name => string.Equals(name, x.Key, StringComparison.OrdinalIgnoreCase))).Value;
|
||||
snapshots.Add(new PlantObjectSnapshot
|
||||
{
|
||||
@@ -447,7 +448,7 @@ internal sealed class PlantViewportMembershipReader
|
||||
if (sourceRows.Contains(rowId))
|
||||
{
|
||||
selectedRows.Add(rowId);
|
||||
if (TryReadPipePlacement(sourceId, dataLinks, out var placement)) geometry[rowId] = placement;
|
||||
if (TryReadPlacement(sourceId, dataLinks, out var placement)) geometry[rowId] = placement;
|
||||
}
|
||||
}
|
||||
catch (DLException)
|
||||
@@ -476,7 +477,7 @@ internal sealed class PlantViewportMembershipReader
|
||||
// whose PrjObjectId identifies the source entity and whose Xform projects
|
||||
// that source entity into the particular Ortho view. This is not a sheet
|
||||
// coordinate heuristic.
|
||||
private static bool TryReadPipePlacement(MdObjectId sourceId, DataLinksManager dataLinks, out GeometrySnapshot geometry)
|
||||
private static bool TryReadPlacement(MdObjectId sourceId, DataLinksManager dataLinks, out GeometrySnapshot geometry)
|
||||
{
|
||||
geometry = new GeometrySnapshot();
|
||||
var stage = "GetDatabase";
|
||||
@@ -492,14 +493,27 @@ internal sealed class PlantViewportMembershipReader
|
||||
using var transaction = sourceDatabase.TransactionManager.StartOpenCloseTransaction();
|
||||
stage = "MakeAcDbObjectId";
|
||||
var objectId = dataLinks.MakeAcDbObjectId(sourceId.PrjObjectId, sourceDatabase);
|
||||
stage = "OpenPipe";
|
||||
if (transaction.GetObject(objectId, OpenMode.ForRead) is not Pipe pipe) return false;
|
||||
stage = "TransformStartPoint";
|
||||
var point = pipe.StartPoint.TransformBy(sourceId.Xform);
|
||||
stage = "OpenPlantEntity";
|
||||
var entity = transaction.GetObject(objectId, OpenMode.ForRead);
|
||||
Autodesk.AutoCAD.Geometry.Point3d modelPoint;
|
||||
Autodesk.AutoCAD.Geometry.Vector3d? modelDirection = null;
|
||||
if (entity is Pipe pipe) modelPoint = pipe.StartPoint;
|
||||
else if (entity is Connector connector)
|
||||
{
|
||||
var ports = connector.GetPorts(PortType.Both);
|
||||
if (ports.Count != 2) return false;
|
||||
modelPoint = ports[1].Position;
|
||||
modelDirection = ports[0].Direction;
|
||||
}
|
||||
else return false;
|
||||
stage = "TransformPlacement";
|
||||
var point = modelPoint.TransformBy(sourceId.Xform);
|
||||
var direction = modelDirection?.TransformBy(sourceId.Xform);
|
||||
geometry = new GeometrySnapshot
|
||||
{
|
||||
PaperPosition = new Point2Dto(point.X, point.Y),
|
||||
Rotation = 0
|
||||
Rotation = 0,
|
||||
PaperDirection = direction is null ? null : new Vector2Dto(direction.Value.X, direction.Value.Y)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
@@ -17,6 +17,8 @@ public sealed class LineConnectionPreviewServiceTests
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal(["a", "b"], result.Plans.Select(plan => plan.StableId));
|
||||
Assert.Equal("L-100 / L-200", result.Plans[1].Text);
|
||||
Assert.Equal("L-200", result.Plans[1].FirstText);
|
||||
Assert.Equal("L-100", result.Plans[1].SecondText);
|
||||
Assert.Empty(result.Plans[1].Reasons);
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
using PRecAnnot.Core;
|
||||
|
||||
namespace PRecAnnot.Core.Tests;
|
||||
|
||||
public sealed class LineConnectionSettingsLoaderTests
|
||||
{
|
||||
[Fact]
|
||||
public void LoadsLegacyLineConnectionAssetContract()
|
||||
{
|
||||
var assets = new LineConnectionSettingsLoader().Load("<Main><LinenumberConnections polylinelayer='Осевые' textlayer='ТЕКСТ' textstyle='GOSTC'/></Main>");
|
||||
Assert.Equal("Осевые", assets.PolylineLayer);
|
||||
Assert.Equal("ТЕКСТ", assets.TextLayer);
|
||||
Assert.Equal("GOSTC", assets.TextStyle);
|
||||
Assert.Equal("BLOCK_LINENUMBER_CONNECTION", assets.BlockName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RejectsMissingProductionSetting()
|
||||
{
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => new LineConnectionSettingsLoader().Load("<Main><LinenumberConnections polylinelayer='Осевые'/></Main>"));
|
||||
Assert.Equal("LINE_CONNECTION_SETTING_MISSING:textlayer", exception.Message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user