Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/ACadSharp.Tests/IO/AecProxyFallbackTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using ACadSharp.Classes;
using ACadSharp.IO.DWG;
using Xunit;

namespace ACadSharp.Tests.IO
{
public class AecProxyFallbackTests
{
[Theory]
[InlineData("AEC_MODI", "TDbSymbModi", true)]
[InlineData("AEC_SYMB_SECTION", "TDbSymbSection", true)]
[InlineData("AEC_DBCONFIG", "TDbConfig", true)]
[InlineData("AEC_DOOR", "AecDbDoor", true)]
[InlineData("AECS_MEMBER", "AecsDbMember", true)]
[InlineData("AECB_PIPE", "AecbDbPipe", true)]
[InlineData("AEC_INTERFACESRECO", "AecInterfaceRecord", true)]
[InlineData("SOME_CUSTOM_ENTITY", "AecDbCustom", true)]
[InlineData("SOME_TIANZHENG_ENTITY", "TDbCustom", true)]
[InlineData("aec_wall", "AecDbWall", true)]
[InlineData("ACDBDICTIONARYWDFLT", "AcDbDictionaryWithDefault", false)]
[InlineData("ACDBDETAILVIEWSTYLE", "AcDbDetailViewStyle", false)]
[InlineData("CELLSTYLEMAP", "AcDbCellStyleMap", false)]
[InlineData("LINE", "AcDbLine", false)]
public void IsAecClass_DetectsAecFamilies(string dxfName, string cppClassName, bool expected)
{
DxfClass dxfClass = new DxfClass
{
DxfName = dxfName,
CppClassName = cppClassName,
};

Assert.Equal(expected, DwgObjectReader.IsAecClass(dxfClass));
}

[Fact]
public void IsAecClass_DetectsAecApplicationName()
{
DxfClass dxfClass = new DxfClass
{
DxfName = "SOME_CUSTOM_ENTITY",
CppClassName = "SomeCustomObject",
ApplicationName = "AEC_KERNAL|missing interpreter",
};

Assert.True(DwgObjectReader.IsAecClass(dxfClass));
}

[Fact]
public void IsAecClass_NullClass_ReturnsFalse()
{
Assert.False(DwgObjectReader.IsAecClass(null));
}
}
}
93 changes: 93 additions & 0 deletions src/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5787,6 +5787,11 @@ private CadTemplate readUnlistedType(short classNumber)
break;
}

if (template == null && IsAecClass(c))
{
template = this.readAecProxy(c);
}

if (template == null && c.IsAnEntity)
{
template = this.readUnknownEntity(c);
Expand All @@ -5806,6 +5811,94 @@ private CadTemplate readUnlistedType(short classNumber)
return template;
}

/// <summary>
/// Reads an unlisted AEC object as a proxy object keeping the proxy graphics and the class definition.
/// </summary>
/// <remarks>
/// AEC objects saved without their application are stored in proxy format and can be parsed by the
/// proxy readers. If the object is stored in its native format the proxy readers fail, in that case
/// the object is read by the unknown object readers instead.
/// </remarks>
private CadTemplate readAecProxy(DxfClass c)
{
//Read the object on a copy of the readers, if the object is stored in its native format the
//proxy readers fail and the original readers remain untouched for the unknown object readers
IDwgStreamReader objectReader = this._objectReader;
IDwgStreamReader textReader = this._textReader;
IDwgStreamReader handlesReader = this._handlesReader;
IDwgStreamReader mergedReaders = this._mergedReaders;

this._objectReader = DwgStreamReaderBase.GetStreamHandler(this._version, HugeMemoryStream.Clone(this._memoryStream), this._reader.Encoding);
this._objectReader.SetPositionInBits(objectReader.PositionInBits());
this._textReader = DwgStreamReaderBase.GetStreamHandler(this._version, HugeMemoryStream.Clone(this._memoryStream), this._reader.Encoding);
this._textReader.SetPositionInBits(textReader.PositionInBits());
this._handlesReader = DwgStreamReaderBase.GetStreamHandler(this._version, HugeMemoryStream.Clone(this._memoryStream), this._reader.Encoding);
this._handlesReader.SetPositionInBits(handlesReader.PositionInBits());
this._mergedReaders = new DwgMergedReader(this._objectReader, this._textReader, this._handlesReader);

try
{
if (c.IsAnEntity)
{
CadTemplate template = this.readProxyEntity();
((ProxyEntity)template.CadObject).DxfClass = c;
this._builder.Notify($"Unlisted AEC entity with DXF name {c.DxfName} has been read as a ProxyEntity", NotificationType.Warning);
return template;
}
else
{
CadTemplate template = this.readProxyObject();
((ProxyObject)template.CadObject).DxfClass = c;
this._builder.Notify($"Unlisted AEC object with DXF name {c.DxfName} has been read as a ProxyObject", NotificationType.Warning);
return template;
}
}
catch (Exception)
{
//The object is stored in its native format, restore the original readers so the
//unknown object readers can read its common data
this._objectReader = objectReader;
this._textReader = textReader;
this._handlesReader = handlesReader;
this._mergedReaders = mergedReaders;

if (!this._builder.Configuration.Failsafe)
throw;

return null;
}
}

/// <summary>
/// Checks if a dxf class belongs to an AEC (Architecture, Engineering and Construction) application
/// based on the naming of its dxf, application and cpp class names.
/// </summary>
/// <remarks>
/// AEC class names are not limited to the <c>AEC_*</c> dxf name, structural members use <c>AECS_*</c>
/// and the MEP family uses <c>AECB_*</c>. The application name uses the <c>Aec*</c> prefix and the
/// cpp class name is used as a secondary signal for the Autodesk <c>AecDb*</c>/<c>AecsDb*</c> families
/// and for the Tianzheng/Revit <c>TDb*</c> family.
/// </remarks>
internal static bool IsAecClass(DxfClass c)
{
if (c == null)
return false;

if (c.DxfName?.StartsWith("AEC", StringComparison.OrdinalIgnoreCase) == true)
return true;

if (c.ApplicationName?.StartsWith("AEC", StringComparison.OrdinalIgnoreCase) == true)
return true;

if (c.CppClassName?.StartsWith("Aec", StringComparison.OrdinalIgnoreCase) == true)
return true;

if (c.CppClassName?.StartsWith("TDb", StringComparison.OrdinalIgnoreCase) == true)
return true;

return false;
}

#region Evaluation Graph, Enhanced Block etc.

private Matrix4 read4x3Matrix()
Expand Down
1 change: 1 addition & 0 deletions src/ACadSharp/IO/Templates/CadTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void Build(CadDocumentBuilder builder)
switch (this.CadObject)
{
case ProxyEntity:
case ProxyObject:
case UnknownEntity:
case UnknownNonGraphicalObject:
break;
Expand Down