Skip to content

Commit 4c4f0fd

Browse files
Merge pull request #1391 from specklesystems/dev
dev -> main for release
2 parents 2ba6c33 + bcfffec commit 4c4f0fd

7 files changed

Lines changed: 144 additions & 20 deletions

File tree

Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceUnpacker.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public UnpackResult<AutocadRootObject> UnpackSelection(IEnumerable<AutocadRootOb
4040

4141
foreach (var obj in objects)
4242
{
43+
// Skip hidden attributes from the selection. Their values are kept on the InstanceProxy
44+
// via GetInstanceAttributes, so we just avoid sending them as floating Text.
45+
if (obj.Root is AttributeReference attrRef && (!attrRef.Visible || attrRef.Invisible))
46+
{
47+
continue;
48+
}
49+
4350
// Note: isDynamicBlock always returns false for a selection of doc objects. Instances of dynamic blocks are represented in the document as blocks that have
4451
// a definition reference to the anonymous block table record.
4552
if (obj.Root is BlockReference blockReference && !blockReference.IsDynamicBlock)
@@ -131,6 +138,12 @@ out List<InstanceProxy>? instanceProxiesWithSameDefinition
131138
foreach (ObjectId id in instance.AttributeCollection)
132139
{
133140
var reference = (AttributeReference)transaction.GetObject(id, OpenMode.ForRead);
141+
// Skip hidden attributes. Their values are still kept on the InstanceProxy via
142+
// GetInstanceAttributes, so we just avoid sending them as floating Text.
143+
if (!reference.Visible || reference.Invisible)
144+
{
145+
continue;
146+
}
134147
string refAppId = reference.GetSpeckleApplicationId();
135148
_instanceObjectsManager.AddAtomicObject(refAppId, new(reference, refAppId));
136149
}

Converters/Autocad/Speckle.Converters.AutocadShared/Speckle.Converters.AutocadShared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<Compile Include="$(MSBuildThisFileDirectory)ToHost\Geometry\PointToHostConverter.cs" />
5757
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\DataObjectDisplayValueExtractor.cs" />
5858
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\ArcToSpeckleConverter.cs" />
59+
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\AttributeDefinitionToSpeckleConverter.cs" />
5960
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\HatchToSpeckleConverter.cs" />
6061
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\MTextToSpeckleConverter.cs" />
6162
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Geometry\RegionToSpeckleConverter.cs" />
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Speckle.Converters.Common;
2+
using Speckle.Converters.Common.Objects;
3+
using Speckle.Sdk.Models;
4+
5+
namespace Speckle.Converters.Autocad.ToSpeckle.Geometry;
6+
7+
// AttributeDefinition inherits from DBText. Without this converter, ATTDEF entities
8+
// falls back to DBTextToSpeckleConverter which reads `TextString`
9+
// The default attribute value, typically empty for a ATTDEF
10+
// The visible text in the drawing is the Tag, so we use that instead.
11+
[NameAndRankValue(typeof(ADB.AttributeDefinition), NameAndRankValueAttribute.SPECKLE_DEFAULT_RANK)]
12+
public class AttributeDefinitionToSpeckleConverter : IToSpeckleTopLevelConverter
13+
{
14+
private readonly ITypedConverter<ADB.DBText, SA.Text> _textConverter;
15+
16+
public AttributeDefinitionToSpeckleConverter(ITypedConverter<ADB.DBText, SA.Text> textConverter)
17+
{
18+
_textConverter = textConverter;
19+
}
20+
21+
public Base Convert(object target) => Convert((ADB.AttributeDefinition)target);
22+
23+
public SA.Text Convert(ADB.AttributeDefinition target)
24+
{
25+
SA.Text result = _textConverter.Convert(target);
26+
result.value = !string.IsNullOrEmpty(target.Tag) ? target.Tag : target.TextString;
27+
return result;
28+
}
29+
}

Converters/Autocad/Speckle.Converters.AutocadShared/ToSpeckle/Raw/DBTextToSpeckleRawConverter.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Diagnostics.CodeAnalysis;
12
using Speckle.Converters.Autocad.Helpers;
23
using Speckle.Converters.Common;
34
using Speckle.Converters.Common.Objects;
@@ -9,16 +10,19 @@ public class DBTextToSpeckleRawConverter : ITypedConverter<ADB.DBText, Text>
910
{
1011
private readonly ITypedConverter<AG.Point3d, SOG.Point> _pointConverter;
1112
private readonly ITypedConverter<AG.Vector3d, SOG.Vector> _vectorConverter;
13+
private readonly ITypedConverter<ADB.MText, Text> _mtextConverter;
1214
private readonly IConverterSettingsStore<AutocadConversionSettings> _settingsStore;
1315

1416
public DBTextToSpeckleRawConverter(
1517
ITypedConverter<AG.Point3d, SOG.Point> pointConverter,
1618
ITypedConverter<AG.Vector3d, SOG.Vector> vectorConverter,
19+
ITypedConverter<ADB.MText, Text> mtextConverter,
1720
IConverterSettingsStore<AutocadConversionSettings> settingsStore
1821
)
1922
{
2023
_pointConverter = pointConverter;
2124
_vectorConverter = vectorConverter;
25+
_mtextConverter = mtextConverter;
2226
_settingsStore = settingsStore;
2327
}
2428

@@ -27,12 +31,23 @@ IConverterSettingsStore<AutocadConversionSettings> settingsStore
2731
/// </summary>
2832
/// <param name="target">The AutoCAD DBText to convert.</param>
2933
/// <returns>The converted Speckle Text object.</returns>
30-
public Text Convert(ADB.DBText target) =>
34+
public Text Convert(ADB.DBText target)
35+
{
36+
// Multi-line attributes are backed by an MText. Convert via the MText converter so the
37+
// viewer keeps the wrap and renders multiple lines.
38+
if (TryGetBackingMText(target, out ADB.MText? mtext))
39+
{
40+
using (mtext)
41+
{
42+
return _mtextConverter.Convert(mtext);
43+
}
44+
}
45+
3146
// target.WidthFactor is ignored, because we don't support 1-dimensional text scaling
3247
// AlignmentPoint can be ignored, as, if used for positioning, it will be already reflected in Rotation and Height
33-
new()
48+
return new()
3449
{
35-
value = target.TextString,
50+
value = target.TextString ?? string.Empty,
3651
height = target.Height,
3752
maxWidth = null, // always 1 line
3853
plane = GetTextPlane(target),
@@ -41,6 +56,23 @@ public Text Convert(ADB.DBText target) =>
4156
alignmentV = AlignmentVertical.Bottom, // constant relevant to Position (.Justify & .Alignment Point can be ignored)
4257
units = _settingsStore.Current.SpeckleUnits,
4358
};
59+
}
60+
61+
private static bool TryGetBackingMText(ADB.DBText target, [NotNullWhen(true)] out ADB.MText? mtext)
62+
{
63+
switch (target)
64+
{
65+
case ADB.AttributeReference attRef when attRef.IsMTextAttribute:
66+
mtext = attRef.MTextAttribute;
67+
return true;
68+
case ADB.AttributeDefinition attDef when attDef.IsMTextAttributeDefinition:
69+
mtext = attDef.MTextAttributeDefinition;
70+
return true;
71+
default:
72+
mtext = null;
73+
return false;
74+
}
75+
}
4476

4577
// For DBText, the following properties are stored in:
4678
// - Position: WCS

Converters/Autocad/Speckle.Converters.AutocadShared/ToSpeckle/Raw/MTextToSpeckleRawConverter.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Text.RegularExpressions;
12
using Speckle.Converters.Common;
23
using Speckle.Converters.Common.Objects;
34

@@ -28,7 +29,7 @@ IConverterSettingsStore<AutocadConversionSettings> settingsStore
2829
public SA.Text Convert(ADB.MText target) =>
2930
new()
3031
{
31-
value = target.Text,
32+
value = ConvertMTextToPlainText(target.Contents ?? string.Empty),
3233
height = target.TextHeight,
3334
maxWidth = target.Width,
3435
plane = GetTextPlane(target),
@@ -38,6 +39,32 @@ public SA.Text Convert(ADB.MText target) =>
3839
units = _settingsStore.Current.SpeckleUnits,
3940
};
4041

42+
// Codes with parameters that end in `;` (font, color, height, etc.)
43+
private static readonly Regex s_paramCodeRegex = new(@"\\[A-Za-z][^\\;]*;", RegexOptions.Compiled);
44+
45+
// Toggle codes with no parameters (underline, overline, strikethrough)
46+
private static readonly Regex s_toggleCodeRegex = new(@"\\[LlOoKkX]", RegexOptions.Compiled);
47+
48+
/// <summary>
49+
/// Turns raw MText contents into plain text with real newlines, so the viewer can render it
50+
/// on multiple lines. Covers common formatting; exotic cases may still need cleanup.
51+
/// </summary>
52+
private static string ConvertMTextToPlainText(string contents)
53+
{
54+
if (string.IsNullOrEmpty(contents))
55+
{
56+
return contents;
57+
}
58+
59+
// Convert paragraph breaks first so they aren't eaten by the strip below.
60+
string result = contents.Replace("\\P", "\n");
61+
result = s_paramCodeRegex.Replace(result, string.Empty);
62+
result = s_toggleCodeRegex.Replace(result, string.Empty);
63+
result = result.Replace("\\~", " ");
64+
result = result.Replace("{", string.Empty).Replace("}", string.Empty);
65+
return result;
66+
}
67+
4168
// For MText, the following properties are stored in:
4269
// - Position: WCS
4370
// - Normal: WCS??

Converters/Plant3d/Speckle.Converters.Plant3dShared/ToSpeckle/Geometry/Plant3dEntityToSpeckleConverter.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Speckle.Converters.Autocad.Extensions;
12
using Speckle.Converters.Common.Objects;
23
using Speckle.Converters.Common.Registration;
34
using Speckle.Objects.Data;
@@ -66,9 +67,17 @@ private List<Base> ExtractDisplayValue(ADB.Entity entity)
6667
/// </summary>
6768
private void CollectDisplayObjects(ADB.Entity entity, List<Base> results, int depth)
6869
{
70+
// ATTDEFs in a block definition hold the field template (e.g. "#(TargetObject.Type)"),
71+
// not the rendered text. The real string lives on each instance's AttributeReference,
72+
// which we capture below from the parent BlockReference's AttributeCollection.
73+
if (entity is ADB.AttributeDefinition)
74+
{
75+
return;
76+
}
77+
6978
// If this is NOT a block reference, try converting it directly
7079
// (Line, Arc, Circle, Polyline, Solid3d, etc.)
71-
if (entity is not ADB.BlockReference)
80+
if (entity is not ADB.BlockReference blockRef)
7281
{
7382
try
7483
{
@@ -83,6 +92,32 @@ private void CollectDisplayObjects(ADB.Entity entity, List<Base> results, int de
8392
// Fall through to explode on ConversionNotSupportedException or failed
8493
}
8594
}
95+
else
96+
{
97+
// AttributeReference inherits from DBText, so it resolves
98+
// the existing DBText converter without any template parsing on our side.
99+
foreach (
100+
ADB.AttributeReference attRef in blockRef.GetSubEntities<ADB.AttributeReference>(
101+
source: blockRef.AttributeCollection
102+
)
103+
)
104+
{
105+
if (!attRef.Visible || string.IsNullOrWhiteSpace(attRef.TextString))
106+
{
107+
continue;
108+
}
109+
110+
try
111+
{
112+
var converter = _converterManager.ResolveConverter(attRef.GetType());
113+
results.Add(converter.Convert(attRef));
114+
}
115+
catch (System.Exception)
116+
{
117+
// Skip any attribute reference we can't convert; continue with the rest.
118+
}
119+
}
120+
}
86121

87122
// For BlockReferences or unconvertible entities, explode to get sub-entities
88123
// Explode produces world-coordinate geometry (block transform is applied)

Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/Properties/ClassPropertiesExtractor.cs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,8 @@ public class ClassPropertiesExtractor
9191
elementProperties.Add("fromRoomApplicationId", familyInstance.FromRoom.UniqueId.ToString());
9292
}
9393

94-
Element? parent = null;
95-
96-
#if REVIT2023_OR_GREATER
97-
BuiltInCategory bic = familyInstance.Category.BuiltInCategory;
98-
#else
99-
// Cast for 2022 and older
100-
BuiltInCategory bic = (BuiltInCategory)familyInstance.Category.Id.IntegerValue;
101-
#endif
102-
103-
if (bic == BuiltInCategory.OST_CurtainWallMullions || bic == BuiltInCategory.OST_CurtainWallPanels)
104-
{
105-
parent = familyInstance.Host;
106-
}
107-
108-
parent ??= familyInstance.SuperComponent;
94+
// parent: prefer Host (e.g. wall, floor, ceiling), fall back to SuperComponent (nested family)
95+
Element? parent = familyInstance.Host ?? familyInstance.SuperComponent;
10996

11097
if (parent != null)
11198
{

0 commit comments

Comments
 (0)