feat: bridge settings assets and define fixture matrix

This commit is contained in:
codex
2026-08-10 16:20:52 +03:00
parent 8ad3d97edb
commit 990d057ae3
3 changed files with 106 additions and 1 deletions
@@ -0,0 +1,73 @@
{
"schemaVersion": 1,
"policy": "controlled-local-only; fail-closed on ambiguous identity; no production DWG/project writes",
"fixtures": [
{
"id": "LINE_NUMBER_ORTHO_OWNED",
"requiredDocument": "controlled Plant Ortho DWG copy",
"requiredObjects": ["Pipe with DataLinks line number", "owned line-number block", "legacy layers/text styles"],
"selection": "exact owned block handle discovered from drawing",
"preState": "owned annotation baseline and unchanged Plant source",
"mutation": "create/update/delete line annotation",
"repeat": "update or AlreadyExists according to command",
"undo": "native AutoCAD UNDO restores entity and ownership baseline",
"workflows": ["PXP-LN", "PXP-ULN", "PXP-ESN", "PXP-ELN", "PXP-RMP"]
},
{
"id": "CONNECTOR_TOPOLOGY",
"requiredDocument": "controlled Plant project and Ortho copy",
"requiredObjects": ["two connected Plant parts", "connector/port snapshot", "P3dPartConnection", "line-group relationships"],
"selection": "exact connector source identity; no arbitrary entity fallback",
"preState": "no owned connection annotation",
"mutation": "orthogonal connection leader and ownership XData",
"repeat": "recreate/update without duplicate ownership",
"undo": "native AutoCAD UNDO restores pre-annotation state",
"workflows": ["PXP-ALC"]
},
{
"id": "ELEVATION_GOLDEN",
"requiredDocument": "controlled Plant model plus paper/model context",
"requiredObjects": ["positive, negative and zero elevations", "BLOCK_ELEVATION definition", "attribute definitions"],
"selection": "exact Plant source object handle",
"preState": "source object and annotation baseline",
"mutation": "legacy /5, AwayFromZero, *5 elevation annotation",
"repeat": "update existing owned annotation",
"undo": "native AutoCAD UNDO restores baseline",
"workflows": ["PXP-AE", "PXP-IE"]
},
{
"id": "ORTHO_VIEWPORT_EXACT",
"requiredDocument": "controlled Plant Ortho DWG with one-to-one source view mapping",
"requiredObjects": ["exact viewport handle/ObjectId", "layout membership", "Ortho view identity", "visible Plant candidates"],
"selection": "validated AcDbViewport handle and expected Ortho mapping",
"preState": "viewport and annotation baseline",
"mutation": "view annotation/viewport maintenance operation",
"repeat": "deterministic update/no duplicate",
"undo": "native AutoCAD UNDO restores viewport/entity baseline",
"workflows": ["PXP-AAV", "PXP-COV", "PXP-UOB", "PXP-DJ"],
"status": "EXACT_VIEWPORT_FIXTURE_BLOCKED"
},
{
"id": "MANUAL_TEMPLATE_EDIT",
"requiredDocument": "controlled local Template-derived drawing",
"requiredObjects": ["manual annotation blocks", "attributes", "dynamic properties", "required layers/styles", "owned P_REC_ANNOT_MANUAL XData"],
"selection": "exact owned annotation handle for edit/reopen",
"preState": "palette state and owned annotation baseline",
"mutation": "manual insert/update/attribute persistence",
"repeat": "restore and update existing owned annotation",
"undo": "native AutoCAD UNDO restores entity and manual-state baseline",
"workflows": ["mto-ma", "PXP-MA", "CAC", "CAC1", "BJ", "PXP-MAB", "PXP-AC"]
},
{
"id": "ORTHO_BATCH_SAME_NAME",
"requiredDocument": "controlled project copy with two relative drawing paths",
"requiredObjects": ["same filename in different project-relative directories", "one failing controlled drawing"],
"selection": "project-relative identity, never filename-only",
"preState": "unchanged controlled copies",
"mutation": "per-drawing update with continue-on-error",
"repeat": "deterministic ordering and idempotent result",
"undo": "per-drawing recovery/cleanup",
"workflows": ["PXP-IOD"]
}
]
}
@@ -1,5 +1,6 @@
using System.Globalization;
using System.Xml.Linq;
using PRecAnnot.Abstractions;
namespace PRecAnnot.Core;
@@ -21,6 +22,18 @@ public sealed record ProductionSettingsContract(
LineNumberMarkerSettings? LineNumberMarker,
SupportTopViewSettings? SupportTopView)
{
public LineNumberMarkerAsset? ToLineNumberMarkerAsset()
{
if (LineNumberMarker is null) return null;
var texts = LineNumberMarker.Text is { } text
? new[] { new LineNumberTextAsset(text.Layer ?? string.Empty, text.TextStyle ?? string.Empty, text.Size ?? 0, text.TextValue ?? string.Empty, new(text.PositionX ?? 0, text.PositionY ?? 0)) }
: Array.Empty<LineNumberTextAsset>();
var lines = LineNumberMarker.Line is { } line
? new[] { new LineNumberLineAsset(line.Layer ?? string.Empty, new(line.StartX ?? 0, line.StartY ?? 0), new(line.EndX ?? 0, line.EndY ?? 0)) }
: Array.Empty<LineNumberLineAsset>();
return new(LineNumberMarker.Layer, LineNumberMarker.MaskScaleFactor ?? 0, texts, lines);
}
public static ProductionSettingsContract Parse(string xml)
{
var root = XElement.Parse(xml, LoadOptions.PreserveWhitespace);
@@ -104,5 +117,13 @@ public sealed record LayerSetupRule(string FilterType, string FilterValue, int?
public sealed record LineNumberMarkerSettings(string Layer, double? MaskScaleFactor, LineGeometrySettings? Line, TextAnnotationSettings? Text);
public sealed record LineGeometrySettings(double? StartX, double? StartY, double? EndX, double? EndY, string? Layer);
public sealed record TextAnnotationSettings(string? Layer, string? TextStyle, double? Size, string? TextValue, double? PositionX, double? PositionY);
public sealed record SupportTopViewSettings(string? UndefinedSize, IReadOnlyList<SupportRule> Rules);
public sealed record SupportTopViewSettings(string? UndefinedSize, IReadOnlyList<SupportRule> Rules)
{
public SupportRule? Resolve(double nominalDiameter, string nominalUnit, string? selectionValue = null) => Rules
.Where(rule => rule.NominalDiameter is not null && Math.Abs(rule.NominalDiameter.Value - nominalDiameter) < 0.0001)
.Where(rule => string.Equals(rule.NominalUnit, nominalUnit, StringComparison.OrdinalIgnoreCase))
.Where(rule => selectionValue is null || string.Equals(rule.SelectionValue, selectionValue, StringComparison.Ordinal))
.OrderBy(rule => rule.LastDigit ?? int.MaxValue)
.FirstOrDefault();
}
public sealed record SupportRule(string ScriptName, double? NominalDiameter, string? NominalUnit, int? LastDigit, double? Scale, string? SelectionValue);
@@ -65,5 +65,16 @@ public sealed class ProductionSettingsContractTests
Assert.Equal(50.0, rule.NominalDiameter);
Assert.Equal(0.04, rule.Scale);
Assert.Equal("DN50", rule.SelectionValue);
Assert.Same(rule, result.SupportTopView.Resolve(50, "mm", "DN50"));
}
[Fact]
public void BridgesTypedMarkerIntoProductionAsset()
{
const string xml = "<Main><CopyMissingObjects/><LayersSetup/><Annotations layer='TEXT' textstyle='GOSTC' multileaderstyle='PXP'/><LinenumberConnections polylinelayer='AXIS' textlayer='TEXT' textstyle='GOSTC'/><Elevations layer='THIN' textstyle='GOSTC'/><LineNumbers><Marker layer='DIM' maskscalefactor='1,10'><Line layer='DIM' startx='-1,0607' starty='-1,0607' endx='1,0607' endy='1,0607'/><Text layer='TEXT' textstyle='GOSTC' size='2,5' textvalue='' positionx='-4.0' positiony='4.4'/></Marker></LineNumbers><SetLayer name='AXIS'/></Main>";
var asset = ProductionSettingsContract.Parse(xml).ToLineNumberMarkerAsset();
Assert.NotNull(asset);
Assert.Equal("DIM", asset!.Layer);
Assert.Equal(-1.0607, asset.Lines[0].Start.X);
}
}