diff --git a/ACadSharp.Tests/CadObjectTests.cs b/ACadSharp.Tests/CadObjectTests.cs index 2a8f764e..06440833 100644 --- a/ACadSharp.Tests/CadObjectTests.cs +++ b/ACadSharp.Tests/CadObjectTests.cs @@ -2,6 +2,7 @@ using Xunit; using ACadSharp.Tests.Common; using ACadSharp.Tables.Collections; +using ACadSharp.Entities; namespace ACadSharp.Tests { @@ -13,10 +14,47 @@ static CadObjectTests() { foreach (Type item in DataFactory.GetTypes()) { + if (item == typeof(UnknownEntity)) + { + continue; + } + + if (item.IsAbstract) + { + continue; + } + ACadTypes.Add(item); } } + [Theory] + [MemberData(nameof(ACadTypes))] + public void DefaultConstructor(Type t) + { + CadObject cadObject = Factory.CreateObject(t, false); + + Assert.NotNull(cadObject); + Assert.True(0 == cadObject.Handle); + + Assert.NotEqual(ObjectType.UNDEFINED, cadObject.ObjectType); + + Assert.False(string.IsNullOrEmpty(cadObject.ObjectName)); + Assert.False(string.IsNullOrEmpty(cadObject.SubclassMarker)); + + Assert.Null(cadObject.XDictionary); + } + + [Fact] + public void CreateExtendedDictionaryTest() + { + CadObject obj = new Line(); + obj.CreateExtendedDictionary(); + + Assert.NotNull(obj.XDictionary); + Assert.Empty(obj.XDictionary); + } + [Theory(Skip = "Factory refactor needed")] [MemberData(nameof(ACadTypes))] public void Clone(Type t) diff --git a/ACadSharp.Tests/Common/Factory.cs b/ACadSharp.Tests/Common/Factory.cs index c9199057..ca3d559c 100644 --- a/ACadSharp.Tests/Common/Factory.cs +++ b/ACadSharp.Tests/Common/Factory.cs @@ -1,6 +1,8 @@ using ACadSharp.Entities; using ACadSharp.Objects; using ACadSharp.Tables; +using ACadSharp.Tables.Collections; +using CSUtilities.Extensions; using System; using System.Linq; @@ -58,34 +60,30 @@ private static CadObject createObject(Type type, Type original, bool randomize) return null; } - if (type == typeof(XRecord) - || type == typeof(PlotSettings) - || type == typeof(Material) - || type == typeof(MLineStyle) - || type == typeof(Layout) - || type == typeof(Group) - || type == typeof(CadDictionary) - || type == typeof(DictionaryVariable) - || type == typeof(VisualStyle)) + if (type.IsSubclassOf(typeof(NonGraphicalObject))) { - object o = Activator.CreateInstance(type); + object o = Activator.CreateInstance(type, true); if (!randomize) return (CadObject)o; return (CadObject)Factory.map(o); } - if (type.BaseType == typeof(Entity)) + if (type.IsSubclassOf(typeof(Entity))) { return EntityFactory.Create(original, randomize); } - else if (type.BaseType == typeof(TableEntry)) + else if (type.IsSubclassOf(typeof(TableEntry))) { return TableEntryFactory.Create(original, randomize: randomize); } + if (type.HasInterface()) + { + return (CadObject)Activator.CreateInstance(type, true); + } + return createObject(type.BaseType, original, randomize); } - } } diff --git a/ACadSharp.Tests/IO/LocalSampleTests.cs b/ACadSharp.Tests/IO/LocalSampleTests.cs index 9b13bc3b..d83cc742 100644 --- a/ACadSharp.Tests/IO/LocalSampleTests.cs +++ b/ACadSharp.Tests/IO/LocalSampleTests.cs @@ -43,11 +43,6 @@ public void ReadUserDxf(string test) return; CadDocument doc = DxfReader.Read(test, this.onNotification); - - using (DxfReader reader = new DxfReader(test)) - { - var e = reader.ReadEntities(); - } } [Theory] diff --git a/ACadSharp.Tests/Internal/DxfMapTests.cs b/ACadSharp.Tests/Internal/DxfMapTests.cs index 839677dc..22e6f05f 100644 --- a/ACadSharp.Tests/Internal/DxfMapTests.cs +++ b/ACadSharp.Tests/Internal/DxfMapTests.cs @@ -50,7 +50,6 @@ public void CreateMapTest(Type t) } DxfMap map = DxfMap.Create(t); - } [Fact] diff --git a/ACadSharp/DxfFileToken.cs b/ACadSharp/DxfFileToken.cs index 6aa4ca12..71d3213a 100644 --- a/ACadSharp/DxfFileToken.cs +++ b/ACadSharp/DxfFileToken.cs @@ -79,6 +79,7 @@ public static class DxfFileToken public const string EntityMText = "MTEXT"; public const string EntityOleFrame = "OLEFRAME"; public const string EntityOle2Frame = "OLE2FRAME"; + public const string EntityPdfUnderlay = "PDFUNDERLAY"; public const string EntityPoint = "POINT"; public const string EntityPolyline = "POLYLINE"; public const string EntityPolyFaceMesh = "PFACE"; @@ -116,7 +117,9 @@ public static class DxfFileToken public const string ObjectMLeaderStyle = "MLEADERSTYLE"; public const string ObjectImageDefinition = "IMAGEDEF"; public const string ObjectImageDefinitionReactor = "IMAGEDEF_REACTOR"; + public const string ObjectMaterial = "MATERIAL"; public const string ObjectMLineStyle = "MLINESTYLE"; + public const string ObjectPdfDefinition = "PDFDEFINITION"; public const string ObjectVisualStyle = "VISUALSTYLE"; public const string ObjectScale = "SCALE"; public const string ObjectSortEntsTable = "SORTENTSTABLE"; diff --git a/ACadSharp/DxfSubclassMarker.cs b/ACadSharp/DxfSubclassMarker.cs index f428d54e..617e9d14 100644 --- a/ACadSharp/DxfSubclassMarker.cs +++ b/ACadSharp/DxfSubclassMarker.cs @@ -43,6 +43,7 @@ public static class DxfSubclassMarker public const string Vertex = "AcDbVertex"; public const string Polyline = "AcDb2dPolyline"; public const string Leader = "AcDbLeader"; + public const string Material = "AcDbMaterial"; public const string MultiLeader = "AcDbMLeader"; public const string MLeaderStyle = "AcDbMLeaderStyle"; public const string MultiLeaderAnnotContext = "AcDbMultiLeaderAnnotContext"; diff --git a/ACadSharp/Entities/PdfUnderlay.cs b/ACadSharp/Entities/PdfUnderlay.cs new file mode 100644 index 00000000..cb84e20f --- /dev/null +++ b/ACadSharp/Entities/PdfUnderlay.cs @@ -0,0 +1,22 @@ +using ACadSharp.Attributes; + +namespace ACadSharp.Entities +{ + /// + /// Represents a entity. + /// + /// + /// Object name
+ /// Dxf class name + ///
+ [DxfName(DxfFileToken.EntityPdfUnderlay)] + [DxfSubClass(DxfSubclassMarker.Underlay)] + public class PdfUnderlay : UnderlayEntity + { + /// + public override ObjectType ObjectType => ObjectType.UNLISTED; + + /// + public override string ObjectName => DxfFileToken.EntityPdfUnderlay; + } +} diff --git a/ACadSharp/Entities/UnderlayDisplayFlags.cs b/ACadSharp/Entities/UnderlayDisplayFlags.cs new file mode 100644 index 00000000..3d52c5a6 --- /dev/null +++ b/ACadSharp/Entities/UnderlayDisplayFlags.cs @@ -0,0 +1,36 @@ +using System; + +namespace ACadSharp.Entities +{ + /// + /// Underlay display options. + /// + [Flags] + public enum UnderlayDisplayFlags : byte + { + /// + /// Clipping is on. + /// + ClippingOn = 1, + + /// + /// Underlay is on. + /// + ShowUnderlay = 2, + + /// + /// Show as monochrome. + /// + Monochrome = 4, + + /// + /// Adjust for background. + /// + AdjustForBackground = 8, + + /// + /// Clip is inside mode. + /// + ClipInsideMode = 16 + } +} diff --git a/ACadSharp/Entities/UnderlayEntity.cs b/ACadSharp/Entities/UnderlayEntity.cs new file mode 100644 index 00000000..99f43d78 --- /dev/null +++ b/ACadSharp/Entities/UnderlayEntity.cs @@ -0,0 +1,117 @@ +using ACadSharp.Attributes; +using ACadSharp.Objects; +using CSMath; +using System; + +namespace ACadSharp.Entities +{ + /// + /// Common base class for all underlay entities, like . + /// + [DxfSubClass(null, true)] + public abstract class UnderlayEntity : Entity + { + /// + public override string SubclassMarker => DxfSubclassMarker.Underlay; + + /// + /// Specifies the three-dimensional normal unit vector for the object. + /// + [DxfCodeValue(210, 220, 230)] + public XYZ Normal { get; set; } = XYZ.AxisZ; + + /// + /// Insertion point(in WCS) + /// + [DxfCodeValue(10, 20, 30)] + public XYZ InsertPoint { get; set; } + + /// + /// X scale factor + /// + [DxfCodeValue(41)] + public double XScale { get; set; } = 1; + + /// + /// Y scale factor + /// + [DxfCodeValue(42)] + public double YScale { get; set; } = 1; + + /// + /// Z scale factor + /// + [DxfCodeValue(43)] + public double ZScale { get; set; } = 1; + + /// + /// Specifies the rotation angle for the object. + /// + /// + /// The rotation angle in radians. + /// + [DxfCodeValue(DxfReferenceType.IsAngle, 50)] + public double Rotation { get; set; } = 0.0; + + /// + /// Underlay display options. + /// + [DxfCodeValue(280)] + public UnderlayDisplayFlags Flags { get; set; } + + /// + /// Contrast + /// + /// + /// 0-100; default = 50 + /// + [DxfCodeValue(281)] + public byte Contrast + { + get { return this._contrast; } + set + { + if (value < 0 || value > 100) + { + throw new ArgumentException($"Invalid Brightness value: {value}, must be in range 0-100"); + } + + this._contrast = value; + } + } + + /// + /// Fade + /// + /// + /// Range: 0 - 100
+ /// Default: 0 + ///
+ [DxfCodeValue(282)] + public byte Fade + { + get { return this._fade; } + set + { + if (value < 0 || value > 100) + { + throw new ArgumentException($"Invalid Brightness value: {value}, must be in range 0-100"); + } + + this._fade = value; + } + } + + [DxfCodeValue(DxfReferenceType.Handle, 340)] + public UnderlayDefinition Definition { get; set; } + + private byte _contrast = 50; + private byte _fade = 0; + + /// + public override BoundingBox GetBoundingBox() + { + return BoundingBox.Null; + } + } +} diff --git a/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs b/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs index 0fa0d385..7f8b5966 100644 --- a/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs +++ b/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs @@ -11,9 +11,9 @@ using System.Linq; using System.IO; using System; -using static ACadSharp.Objects.MultiLeaderAnnotContext; using CSUtilities.Converters; using CSUtilities.Extensions; +using static ACadSharp.Objects.MultiLeaderAnnotContext; namespace ACadSharp.IO.DWG { @@ -962,10 +962,8 @@ private CadTemplate readUnlistedType(short classNumber) case "ACDBDICTIONARYWDFLT": template = this.readDictionaryWithDefault(); break; - case "ACDBDETAILVIEWSTYLE": - case "ACDBSECTIONVIEWSTYLE": - case "ACAD_TABLE": - case "CELLSTYLEMAP": + case "ACDBPLACEHOLDER": + template = this.readPlaceHolder(); break; case "DBCOLOR": template = this.readDwgColor(); @@ -976,16 +974,12 @@ private CadTemplate readUnlistedType(short classNumber) case "DICTIONARYWDFLT": template = this.readDictionaryWithDefault(); break; - case "FIELD": - break; case "GROUP": template = this.readGroup(); break; case "HATCH": template = this.readHatch(); break; - case "IDBUFFER": - break; case "IMAGE": template = this.readCadImage(new RasterImage()); break; @@ -995,8 +989,6 @@ private CadTemplate readUnlistedType(short classNumber) case "IMAGEDEF_REACTOR": template = this.readImageDefinitionReactor(); break; - case "LAYER_INDEX": - break; case "LAYOUT": template = this.readLayout(); break; @@ -1015,13 +1007,11 @@ private CadTemplate readUnlistedType(short classNumber) case "MLEADERSTYLE": template = this.readMultiLeaderStyle(); break; - case "OLE2FRAME": - break; - case "ACDBPLACEHOLDER": - template = this.readPlaceHolder(); + case "PDFDEFINITION": + template = this.readPdfDefinition(); break; - case "PLOTSETTINGS": - case "RASTERVARIABLES": + case "PDFUNDERLAY": + template = this.readPdfUnderlay(); break; case "SCALE": template = this.readScale(); @@ -1029,22 +1019,12 @@ private CadTemplate readUnlistedType(short classNumber) case "SORTENTSTABLE": template = this.readSortentsTable(); break; - case "SPATIAL_FILTER": - case "SPATIAL_INDEX": - case "TABLEGEOMETRY": - case "TABLESTYLE": - case "TABLESTYLES": - case "VBA_PROJECT": - break; case "VISUALSTYLE": template = this.readVisualStyle(); break; case "WIPEOUT": template = this.readCadImage(new Wipeout()); break; - case "WIPEOUTVARIABLE": - case "WIPEOUTVARIABLES": - break; case "XRECORD": template = this.readXRecord(); break; @@ -5413,6 +5393,46 @@ private CadTemplate readPlaceHolder() return template; } + private CadTemplate readPdfDefinition() + { + PdfUnderlayDefinition definition = new PdfUnderlayDefinition(); + CadNonGraphicalObjectTemplate template = new CadNonGraphicalObjectTemplate(definition); + + this.readCommonNonEntityData(template); + + definition.File = this._objectReader.ReadVariableText(); + definition.Page = this._objectReader.ReadVariableText(); + + return template; + } + + private CadTemplate readPdfUnderlay() + { + PdfUnderlay underlay = new PdfUnderlay(); + CadPdfUnderlayTemplate template = new(underlay); + + this.readCommonEntityData(template); + + underlay.Normal = this._objectReader.Read3BitDouble(); + + underlay.InsertPoint = this._objectReader.Read3BitDouble(); + + underlay.Rotation = this._objectReader.ReadBitDouble(); + + underlay.XScale = this._objectReader.ReadBitDouble(); + underlay.YScale = this._objectReader.ReadBitDouble(); + underlay.ZScale = this._objectReader.ReadBitDouble(); + + underlay.Flags = (UnderlayDisplayFlags)this._objectReader.ReadByte(); + + underlay.Contrast = this._objectReader.ReadByte(); + underlay.Fade = this._objectReader.ReadByte(); + + template.DefinitionHandle = this.handleReference(); + + return template; + } + private CadTemplate readScale() { Scale scale = new Scale(); diff --git a/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs b/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs index 78ddcc54..2bd588df 100644 --- a/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs +++ b/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs @@ -59,6 +59,8 @@ private CadTemplate readObject() return this.readObjectCodes(new CadLayoutTemplate(), this.readLayout); case DxfFileToken.ObjectDictionaryVar: return this.readObjectCodes(new CadTemplate(new DictionaryVariable()), this.readObjectSubclassMap); + case DxfFileToken.ObjectPdfDefinition: + return this.readObjectCodes(new CadNonGraphicalObjectTemplate(new PdfUnderlayDefinition()), this.readObjectSubclassMap); case DxfFileToken.ObjectSortEntsTable: return this.readSortentsTable(); case DxfFileToken.ObjectScale: diff --git a/ACadSharp/IO/DXF/DxfStreamReader/DxfSectionReaderBase.cs b/ACadSharp/IO/DXF/DxfStreamReader/DxfSectionReaderBase.cs index 08afccb3..2aded552 100644 --- a/ACadSharp/IO/DXF/DxfStreamReader/DxfSectionReaderBase.cs +++ b/ACadSharp/IO/DXF/DxfStreamReader/DxfSectionReaderBase.cs @@ -170,6 +170,8 @@ protected CadEntityTemplate readEntity() return this.readEntityCodes(new CadTextEntityTemplate(new MText()), this.readTextEntity); case DxfFileToken.EntityMLine: return this.readEntityCodes(new CadMLineTemplate(), this.readMLine); + case DxfFileToken.EntityPdfUnderlay: + return this.readEntityCodes(new CadPdfUnderlayTemplate(), this.readUnderlayEntity); case DxfFileToken.EntityPoint: return this.readEntityCodes(new CadEntityTemplate(), this.readEntitySubclassMap); case DxfFileToken.EntityPolyline: @@ -188,12 +190,12 @@ protected CadEntityTemplate readEntity() return this.readEntityCodes(new CadVertexTemplate(), this.readVertex); case DxfFileToken.EntityViewport: return this.readEntityCodes(new CadViewportTemplate(), this.readViewport); - case DxfFileToken.EntityXline: - return this.readEntityCodes(new CadEntityTemplate(), this.readEntitySubclassMap); case DxfFileToken.EntityShape: return this.readEntityCodes(new CadShapeTemplate(new Shape()), this.readShape); case DxfFileToken.EntitySpline: return this.readEntityCodes(new CadSplineTemplate(), this.readSpline); + case DxfFileToken.EntityXline: + return this.readEntityCodes(new CadEntityTemplate(), this.readEntitySubclassMap); default: DxfMap map = DxfMap.Create(); CadUnknownEntityTemplate unknownEntityTemplate = null; @@ -913,6 +915,20 @@ private bool readSpline(CadEntityTemplate template, DxfMap map, string subclass } } + private bool readUnderlayEntity(CadEntityTemplate template, DxfMap map, string subclass = null) + { + CadPdfUnderlayTemplate tmp = template as CadPdfUnderlayTemplate; + + switch (this._reader.Code) + { + case 340: + tmp.DefinitionHandle = this._reader.ValueAsHandle; + return true; + default: + return this.tryAssignCurrentValue(template.CadObject, map.SubClasses[tmp.CadObject.SubclassMarker]); + } + } + private bool readVertex(CadEntityTemplate template, DxfMap map, string subclass = null) { CadVertexTemplate tmp = template as CadVertexTemplate; diff --git a/ACadSharp/IO/Templates/CadPdfUnderlayTemplate.cs b/ACadSharp/IO/Templates/CadPdfUnderlayTemplate.cs new file mode 100644 index 00000000..a84a5c0e --- /dev/null +++ b/ACadSharp/IO/Templates/CadPdfUnderlayTemplate.cs @@ -0,0 +1,30 @@ +using ACadSharp.Entities; +using ACadSharp.Objects; + +namespace ACadSharp.IO.Templates +{ + internal class CadPdfUnderlayTemplate : CadEntityTemplate + { + public ulong? DefinitionHandle { get; set; } + + public CadPdfUnderlayTemplate() : base(new PdfUnderlay()) { } + + public CadPdfUnderlayTemplate(PdfUnderlay entity) : base(entity) + { + } + + public override void Build(CadDocumentBuilder builder) + { + base.Build(builder); + + if (builder.TryGetCadObject(this.DefinitionHandle, out UnderlayDefinition definition)) + { + this.CadObject.Definition = definition; + } + else + { + builder.Notify($"UnderlayDefinition not found for {this.CadObject.Handle}", NotificationType.Warning); + } + } + } +} diff --git a/ACadSharp/Objects/ImageDefinitionReactor.cs b/ACadSharp/Objects/ImageDefinitionReactor.cs index ea2d96ae..042e2953 100644 --- a/ACadSharp/Objects/ImageDefinitionReactor.cs +++ b/ACadSharp/Objects/ImageDefinitionReactor.cs @@ -14,7 +14,7 @@ namespace ACadSharp.Objects public class ImageDefinitionReactor : NonGraphicalObject { /// - public override ObjectType ObjectType => ObjectType.UNDEFINED; + public override ObjectType ObjectType => ObjectType.UNLISTED; /// public override string ObjectName => DxfFileToken.ObjectImageDefinitionReactor; diff --git a/ACadSharp/Objects/Material.cs b/ACadSharp/Objects/Material.cs index ccf6eefa..c993678d 100644 --- a/ACadSharp/Objects/Material.cs +++ b/ACadSharp/Objects/Material.cs @@ -2,9 +2,14 @@ { public class Material : NonGraphicalObject { - public override ObjectType ObjectType => ObjectType.INVALID; + /// + public override ObjectType ObjectType => ObjectType.UNLISTED; - public override string SubclassMarker { get; } + /// + public override string ObjectName => DxfFileToken.ObjectMaterial; + + /// + public override string SubclassMarker => DxfSubclassMarker.Material; //1 Material name(string) diff --git a/ACadSharp/Objects/PdfUnderlayDefinition.cs b/ACadSharp/Objects/PdfUnderlayDefinition.cs new file mode 100644 index 00000000..edc50ff4 --- /dev/null +++ b/ACadSharp/Objects/PdfUnderlayDefinition.cs @@ -0,0 +1,36 @@ +using ACadSharp.Attributes; + +namespace ACadSharp.Objects +{ + /// + /// Represents a object + /// + /// + /// Object name
+ /// Dxf class name + ///
+ [DxfName(DxfFileToken.ObjectPdfDefinition)] + [DxfSubClass(DxfSubclassMarker.UnderlayDefinition)] + public class PdfUnderlayDefinition : UnderlayDefinition + { + /// + public override string ObjectName => DxfFileToken.ObjectPdfDefinition; + + /// + /// Gets or sets the PDF page to show. + /// + [DxfCodeValue(2)] + public string Page + { + get { return this._page; } + set { this._page = string.IsNullOrEmpty(value) ? string.Empty : value; } + } + + private string _page; + + /// + public PdfUnderlayDefinition() : base() + { + } + } +} diff --git a/ACadSharp/Objects/UnderlayDefinition.cs b/ACadSharp/Objects/UnderlayDefinition.cs new file mode 100644 index 00000000..bcae425f --- /dev/null +++ b/ACadSharp/Objects/UnderlayDefinition.cs @@ -0,0 +1,26 @@ +using ACadSharp.Attributes; + +namespace ACadSharp.Objects +{ + /// + /// Common base class for all underlay definitions, like . + /// + [DxfSubClass(null, true)] + public abstract class UnderlayDefinition : NonGraphicalObject + { + /// + public override ObjectType ObjectType => ObjectType.UNLISTED; + + /// + public override string SubclassMarker => DxfSubclassMarker.UnderlayDefinition; + + /// + /// Gets or sets the underlay file. + /// + /// + /// The file extension must match the underlay type. + /// + [DxfCodeValue(1)] + public string File { get; set; } + } +} diff --git a/ACadSharp/Tables/Collections/ITable.cs b/ACadSharp/Tables/Collections/ITable.cs new file mode 100644 index 00000000..a701dbcc --- /dev/null +++ b/ACadSharp/Tables/Collections/ITable.cs @@ -0,0 +1,6 @@ +namespace ACadSharp.Tables.Collections +{ + public interface ITable + { + } +} diff --git a/ACadSharp/Tables/Collections/Table.cs b/ACadSharp/Tables/Collections/Table.cs index 20067b42..646ae3fe 100644 --- a/ACadSharp/Tables/Collections/Table.cs +++ b/ACadSharp/Tables/Collections/Table.cs @@ -8,7 +8,7 @@ namespace ACadSharp.Tables.Collections { [DxfSubClass(DxfSubclassMarker.Table)] - public abstract class Table : CadObject, IObservableCollection + public abstract class Table : CadObject, ITable, IObservableCollection where T : TableEntry { public event EventHandler OnAdd; diff --git a/samples/pdf-definition.pdf b/samples/pdf-definition.pdf new file mode 100644 index 00000000..5371e782 Binary files /dev/null and b/samples/pdf-definition.pdf differ diff --git a/samples/sample_base/pdf-definition.pdf b/samples/sample_base/pdf-definition.pdf new file mode 100644 index 00000000..5371e782 Binary files /dev/null and b/samples/sample_base/pdf-definition.pdf differ