feat: plan p-rec-annot connector annotations
This commit is contained in:
@@ -80,8 +80,23 @@ public sealed record LineConnectionBoundaryCandidate(
|
||||
Point3Dto SecondEndpoint,
|
||||
Bounds3Dto Bounds,
|
||||
AnnotationPoint Position,
|
||||
double Rotation);
|
||||
double Rotation,
|
||||
string? FirstLineGroupStableId = null,
|
||||
string? SecondLineGroupStableId = null);
|
||||
public sealed record LineConnectionBoundaryPlan(string StableId, string Text, AnnotationPoint Position, double Rotation, IReadOnlyList<string> Reasons);
|
||||
// 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.
|
||||
public sealed record LineConnectionPlacement(
|
||||
Point3Dto FirstEndpoint,
|
||||
Point3Dto SecondEndpoint,
|
||||
Bounds3Dto Bounds,
|
||||
AnnotationPoint Position,
|
||||
double Rotation);
|
||||
public sealed record LineConnectionPreviewResult(
|
||||
bool Success,
|
||||
IReadOnlyList<LineConnectionBoundaryPlan> Plans,
|
||||
string? FailureCode = null);
|
||||
public sealed record PlantConnectorRelationshipSnapshot(
|
||||
string StableId,
|
||||
long ConnectorRowId,
|
||||
|
||||
@@ -20,6 +20,16 @@ public sealed class LineConnectionBoundaryPlanner
|
||||
}
|
||||
var first = candidate.FirstLineNumber?.Trim() ?? string.Empty;
|
||||
var second = candidate.SecondLineNumber?.Trim() ?? string.Empty;
|
||||
// The legacy command gates insertion on the two P3dLineGroup
|
||||
// relationship IDs, not just on their rendered text. Equal text in
|
||||
// distinct groups remains a real connector boundary; equal group IDs
|
||||
// never does.
|
||||
if (!string.IsNullOrWhiteSpace(candidate.FirstLineGroupStableId) &&
|
||||
string.Equals(candidate.FirstLineGroupStableId, candidate.SecondLineGroupStableId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
result.Add(new(candidate.StableId, string.Empty, candidate.Position, candidate.Rotation, ["SAME_LINE_GROUP"]));
|
||||
continue;
|
||||
}
|
||||
if (first.Length == 0 || second.Length == 0)
|
||||
{
|
||||
result.Add(new(candidate.StableId, string.Empty, candidate.Position, candidate.Rotation, ["LINE_GROUP_NOT_RESOLVED"]));
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using PRecAnnot.Abstractions;
|
||||
|
||||
namespace PRecAnnot.Core;
|
||||
|
||||
// Source-backed bridge for AutoLinenumberConnections: each endpoint uses the
|
||||
// same GetLinenumberAnnotationText formatting contract as PXP-LN, while the
|
||||
// connector itself remains the stable annotation ownership key.
|
||||
public sealed class LineConnectionPreviewService(
|
||||
LineNumberFieldResolver fieldResolver,
|
||||
ILineNumberAnnotationFormatter formatter,
|
||||
LineConnectionBoundaryPlanner boundaryPlanner)
|
||||
{
|
||||
public LineConnectionPreviewResult Preview(
|
||||
LineNumberAnnotationDefinition definition,
|
||||
IEnumerable<PlantConnectorRelationshipSnapshot> connectors,
|
||||
IReadOnlyDictionary<string, LineConnectionPlacement> placements)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(definition);
|
||||
ArgumentNullException.ThrowIfNull(connectors);
|
||||
ArgumentNullException.ThrowIfNull(placements);
|
||||
|
||||
var candidates = new List<LineConnectionBoundaryCandidate>();
|
||||
foreach (var connector in connectors.OrderBy(value => value.StableId, StringComparer.Ordinal))
|
||||
{
|
||||
if (!placements.TryGetValue(connector.StableId, out var placement))
|
||||
{
|
||||
candidates.Add(new(connector.StableId, string.Empty, string.Empty, new(), new(), new(new(), new()), new(), 0,
|
||||
connector.FirstLineGroupRowId.ToString(System.Globalization.CultureInfo.InvariantCulture),
|
||||
connector.SecondLineGroupRowId.ToString(System.Globalization.CultureInfo.InvariantCulture)));
|
||||
continue;
|
||||
}
|
||||
|
||||
var fields = definition.Tags.Select(tag => tag.Field).Where(field => !string.IsNullOrWhiteSpace(field));
|
||||
var first = ResolveText(definition, connector.FirstPartRowId, fields);
|
||||
var second = ResolveText(definition, connector.SecondPartRowId, fields);
|
||||
candidates.Add(new(
|
||||
connector.StableId,
|
||||
first.Text,
|
||||
second.Text,
|
||||
placement.FirstEndpoint,
|
||||
placement.SecondEndpoint,
|
||||
placement.Bounds,
|
||||
placement.Position,
|
||||
placement.Rotation,
|
||||
connector.FirstLineGroupRowId.ToString(System.Globalization.CultureInfo.InvariantCulture),
|
||||
connector.SecondLineGroupRowId.ToString(System.Globalization.CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
var plans = boundaryPlanner.Build(candidates);
|
||||
// Per-connector property failures are represented as non-insertable
|
||||
// plans, matching legacy's continue-on-one-bad-connector behaviour.
|
||||
var repaired = plans.Select(plan =>
|
||||
{
|
||||
var connector = connectors.First(value => string.Equals(value.StableId, plan.StableId, StringComparison.Ordinal));
|
||||
if (!placements.ContainsKey(plan.StableId)) return plan with { Reasons = plan.Reasons.Append("CONNECTOR_GEOMETRY_UNAVAILABLE").Distinct(StringComparer.Ordinal).ToArray() };
|
||||
var fields = definition.Tags.Select(tag => tag.Field).Where(field => !string.IsNullOrWhiteSpace(field));
|
||||
var first = ResolveText(definition, connector.FirstPartRowId, fields);
|
||||
var second = ResolveText(definition, connector.SecondPartRowId, fields);
|
||||
var reasons = plan.Reasons.Concat(first.Error is null ? [] : [first.Error]).Concat(second.Error is null ? [] : [second.Error]).Distinct(StringComparer.Ordinal).ToArray();
|
||||
return reasons.Length == plan.Reasons.Count ? plan : plan with { Text = reasons.Length == 0 ? plan.Text : string.Empty, Reasons = reasons };
|
||||
}).ToArray();
|
||||
return new(true, repaired);
|
||||
}
|
||||
|
||||
private (string Text, string? Error) ResolveText(LineNumberAnnotationDefinition definition, long rowId, IEnumerable<string> fields)
|
||||
{
|
||||
var resolved = fieldResolver.Resolve(rowId, fields);
|
||||
if (!resolved.Success) return (string.Empty, resolved.FailureCode ?? "DATALINKS_PROPERTY_READ_FAILED");
|
||||
var formatted = formatter.Format(definition, resolved.Values);
|
||||
return formatted.Success ? (formatted.Text, null) : (string.Empty, formatted.ErrorCode ?? "LINE_NUMBER_FORMAT_FAILED");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user