From ca24db1cdcf23650781e2a8e790c30503bbb9524 Mon Sep 17 00:00:00 2001 From: DomCR Date: Tue, 13 Aug 2024 13:22:20 +0200 Subject: [PATCH 1/3] test for hatch --- ACadSharp.Tests/IO/CadReaderTestsBase.cs | 8 +++- ACadSharp.Tests/IO/WriterSingleObjectTests.cs | 47 +++++++++++++++++++ ACadSharp/Entities/Hatch.cs | 4 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/ACadSharp.Tests/IO/CadReaderTestsBase.cs b/ACadSharp.Tests/IO/CadReaderTestsBase.cs index f4b3e417..918a8f13 100644 --- a/ACadSharp.Tests/IO/CadReaderTestsBase.cs +++ b/ACadSharp.Tests/IO/CadReaderTestsBase.cs @@ -1,7 +1,9 @@ -using ACadSharp.Header; +using ACadSharp.Entities; +using ACadSharp.Header; using ACadSharp.IO; using System; using System.Collections.Generic; +using System.Linq; using Xunit; using Xunit.Abstractions; @@ -29,6 +31,10 @@ public virtual void ReadTest(string test) { CadDocument doc = this.getDocument(test); + foreach (var h in doc.Entities.OfType()) + { + } + Assert.NotNull(doc); } diff --git a/ACadSharp.Tests/IO/WriterSingleObjectTests.cs b/ACadSharp.Tests/IO/WriterSingleObjectTests.cs index 12282329..5d52a4de 100644 --- a/ACadSharp.Tests/IO/WriterSingleObjectTests.cs +++ b/ACadSharp.Tests/IO/WriterSingleObjectTests.cs @@ -259,6 +259,52 @@ public void EntityTransparency() this.Document.Entities.Add(line); } + public void CreateHatch() + { + Hatch hatch = new Hatch(); + hatch.IsSolid = true; + + hatch.SeedPoints.Add(new XY()); + + List edges = new List(); + + //edges + Hatch.BoundaryPath.Line edge1 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(0, 0), + End = new CSMath.XY(1, 0) + }; + edges.Add(edge1); + + Hatch.BoundaryPath.Line edge2 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(1, 0), + End = new CSMath.XY(1, 1) + }; + edges.Add(edge2); + + Hatch.BoundaryPath.Line edge3 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(1, 1), + End = new CSMath.XY(0, 1) + }; + edges.Add(edge3); + + Hatch.BoundaryPath.Line edge4 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(0, 1), + End = new CSMath.XY(0, 0) + }; + edges.Add(edge4); + + + Hatch.BoundaryPath path = new Hatch.BoundaryPath(); + path.Edges.AddRange(edges); + hatch.Paths.Add(path); + + this.Document.Entities.Add(hatch); + } + public void Deserialize(IXunitSerializationInfo info) { this.Name = info.GetValue(nameof(this.Name)); @@ -303,6 +349,7 @@ static WriterSingleObjectTests() Data.Add(new(nameof(SingleCaseGenerator.CreateLayout))); Data.Add(new(nameof(SingleCaseGenerator.EntityTransparency))); Data.Add(new(nameof(SingleCaseGenerator.LineTypeWithSegments))); + Data.Add(new(nameof(SingleCaseGenerator.CreateHatch))); } protected string getPath(string name, string ext, ACadVersion version) diff --git a/ACadSharp/Entities/Hatch.cs b/ACadSharp/Entities/Hatch.cs index df982834..669e1b1e 100644 --- a/ACadSharp/Entities/Hatch.cs +++ b/ACadSharp/Entities/Hatch.cs @@ -55,13 +55,13 @@ public partial class Hatch : Entity //63 For MPolygon, pattern fill color as the ACI /// - /// Associativity flag + /// Associativity flag. /// [DxfCodeValue(71)] public bool IsAssociative { get; set; } /// - /// Hatch style + /// Hatch style. /// [DxfCodeValue(75)] public HatchStyleType Style { get; set; } From d7aac2fc28ccae1f100266770e121642b859f21f Mon Sep 17 00:00:00 2001 From: DomCR Date: Mon, 19 Aug 2024 09:21:02 +0200 Subject: [PATCH 2/3] test fix --- src/ACadSharp.Tests/IO/CadReaderTestsBase.cs | 4 ---- src/ACadSharp.Tests/IO/IOTestsBase.cs | 2 +- .../IO/WriterSingleObjectTests.cs | 23 +++++++++++++++++++ .../Entities/Hatch.BoundaryPath.Edge.cs | 3 +++ .../Entities/Hatch.BoundaryPath.Polyline.cs | 9 +++++--- src/ACadSharp/Entities/Hatch.cs | 8 +++---- .../DwgObjectWriter.Entities.cs | 1 - 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/ACadSharp.Tests/IO/CadReaderTestsBase.cs b/src/ACadSharp.Tests/IO/CadReaderTestsBase.cs index 30bb4481..594b41c9 100644 --- a/src/ACadSharp.Tests/IO/CadReaderTestsBase.cs +++ b/src/ACadSharp.Tests/IO/CadReaderTestsBase.cs @@ -32,10 +32,6 @@ public virtual void ReadTest(FileModel test) { CadDocument doc = this.getDocument(test); - foreach (var h in doc.Entities.OfType()) - { - } - Assert.NotNull(doc); } diff --git a/src/ACadSharp.Tests/IO/IOTestsBase.cs b/src/ACadSharp.Tests/IO/IOTestsBase.cs index c3146e3b..608165a8 100644 --- a/src/ACadSharp.Tests/IO/IOTestsBase.cs +++ b/src/ACadSharp.Tests/IO/IOTestsBase.cs @@ -73,7 +73,7 @@ protected void onNotification(object sender, NotificationEventArgs e) protected static void loadLocalSamples(string folder, string ext, TheoryData files) { - string path = Path.Combine(TestVariables.SamplesFolder, "local", folder); + string path = Path.Combine("local", folder); loadSamples(path, ext, files); } diff --git a/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs b/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs index efcee99a..39c4dbc1 100644 --- a/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs +++ b/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs @@ -2,6 +2,7 @@ using ACadSharp.Objects; using ACadSharp.Tables; using CSMath; +using CSUtilities.Extensions; using System.Collections.Generic; using System.IO; using System.Linq; @@ -278,6 +279,27 @@ public void EntityTransparency() this.Document.Entities.Add(line); } + public void CreateHatchPolyline() + { + Hatch hatch = new Hatch(); + hatch.IsSolid = true; + + Hatch.BoundaryPath path = new Hatch.BoundaryPath(); + + Hatch.BoundaryPath.Polyline pline = new Hatch.BoundaryPath.Polyline(); + pline.Vertices.Add(new XYZ(0, 0, 0)); + pline.Vertices.Add(new XYZ(1, 0, 0)); + pline.Vertices.Add(new XYZ(1, 1, 0)); + pline.Vertices.Add(new XYZ(0, 1, 0)); + pline.Vertices.Add(new XYZ(0, 0, 0)); + + path.Edges.Add(pline); + path.Flags = path.Flags.AddFlag(BoundaryPathFlags.Polyline); + hatch.Paths.Add(path); + + this.Document.Entities.Add(hatch); + } + public void CreateHatch() { Hatch hatch = new Hatch(); @@ -377,6 +399,7 @@ static WriterSingleObjectTests() Data.Add(new(nameof(SingleCaseGenerator.CreateLayout))); Data.Add(new(nameof(SingleCaseGenerator.EntityTransparency))); Data.Add(new(nameof(SingleCaseGenerator.LineTypeWithSegments))); + Data.Add(new(nameof(SingleCaseGenerator.CreateHatchPolyline))); Data.Add(new(nameof(SingleCaseGenerator.CreateHatch))); Data.Add(new(nameof(SingleCaseGenerator.ChangedEncoding))); } diff --git a/src/ACadSharp/Entities/Hatch.BoundaryPath.Edge.cs b/src/ACadSharp/Entities/Hatch.BoundaryPath.Edge.cs index 1aaaf88c..5fdb91b8 100644 --- a/src/ACadSharp/Entities/Hatch.BoundaryPath.Edge.cs +++ b/src/ACadSharp/Entities/Hatch.BoundaryPath.Edge.cs @@ -2,6 +2,9 @@ { public partial class Hatch { + /// + /// Defines a hatch boundary. + /// public partial class BoundaryPath { public enum EdgeType diff --git a/src/ACadSharp/Entities/Hatch.BoundaryPath.Polyline.cs b/src/ACadSharp/Entities/Hatch.BoundaryPath.Polyline.cs index 71cd0fa8..93298c77 100644 --- a/src/ACadSharp/Entities/Hatch.BoundaryPath.Polyline.cs +++ b/src/ACadSharp/Entities/Hatch.BoundaryPath.Polyline.cs @@ -15,13 +15,13 @@ public class Polyline : Edge public override EdgeType Type => EdgeType.Polyline; /// - /// The polyline has bulges with value different than 0 + /// The polyline has bulges with value different than 0. /// [DxfCodeValue(72)] public bool HasBulge => this.Bulges.Any(b => b != 0); /// - /// Is closed flag + /// Is closed flag. /// [DxfCodeValue(73)] public bool IsClosed { get; set; } @@ -35,8 +35,11 @@ public class Polyline : Edge [DxfCodeValue(DxfReferenceType.Optional, 42)] public IEnumerable Bulges { get { return this.Vertices.Select(v => v.Z); } } + /// + /// Position values are only X and Y. + /// /// - /// Position values are only X and Y + /// The vertex bulge is stored in the Z component. /// [DxfCodeValue(DxfReferenceType.Count, 93)] public List Vertices { get; set; } = new(); diff --git a/src/ACadSharp/Entities/Hatch.cs b/src/ACadSharp/Entities/Hatch.cs index 669e1b1e..218b0116 100644 --- a/src/ACadSharp/Entities/Hatch.cs +++ b/src/ACadSharp/Entities/Hatch.cs @@ -116,22 +116,20 @@ public partial class Hatch : Entity public List SeedPoints { get; set; } = new List(); /// - /// Gradient color pattern, if exists + /// Gradient color pattern, if exists. /// [DxfCodeValue(DxfReferenceType.Name, 470)] public HatchGradientPattern GradientColor { get; set; } = new HatchGradientPattern(); /// - /// Boundary paths (loops) + /// Boundary paths (loops). /// [DxfCodeValue(DxfReferenceType.Count, 91)] public List Paths { get; set; } = new List(); private HatchPattern _pattern = HatchPattern.Solid; - /// - /// Default constructor. - /// + /// public Hatch() : base() { } /// diff --git a/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Entities.cs b/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Entities.cs index e9fe7b3c..6fa314b9 100644 --- a/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Entities.cs +++ b/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Entities.cs @@ -850,7 +850,6 @@ private void writeHatch(Hatch hatch) if (boundaryPath.Flags.HasFlag(BoundaryPathFlags.Polyline)) { - //TODO: Polyline may need to be treated different than the regular edges Hatch.BoundaryPath.Polyline pline = boundaryPath.Edges.First() as Hatch.BoundaryPath.Polyline; //bulgespresent B 72 bulges are present if 1 From 9281c34af51b6d20fdaa87a43492222216084d6b Mon Sep 17 00:00:00 2001 From: DomCR Date: Mon, 19 Aug 2024 10:21:25 +0200 Subject: [PATCH 3/3] HatchTests --- src/ACadSharp.Tests/Entities/HatchTests.cs | 117 ++++++++++++++++++ .../IO/WriterSingleObjectTests.cs | 6 +- src/ACadSharp/CadDocument.cs | 4 +- src/ACadSharp/CadObjectCollection.cs | 2 +- src/ACadSharp/Entities/Hatch.BoundaryPath.cs | 65 +++++++++- ...lection.cs => IObservableCadCollection.cs} | 2 +- src/ACadSharp/Objects/CadDictionary.cs | 2 +- src/ACadSharp/Tables/Collections/Table.cs | 2 +- 8 files changed, 191 insertions(+), 9 deletions(-) create mode 100644 src/ACadSharp.Tests/Entities/HatchTests.cs rename src/ACadSharp/{IObservableCollection.cs => IObservableCadCollection.cs} (86%) diff --git a/src/ACadSharp.Tests/Entities/HatchTests.cs b/src/ACadSharp.Tests/Entities/HatchTests.cs new file mode 100644 index 00000000..c92b04d1 --- /dev/null +++ b/src/ACadSharp.Tests/Entities/HatchTests.cs @@ -0,0 +1,117 @@ +using ACadSharp.Entities; +using CSMath; +using CSUtilities.Extensions; +using System; +using System.Collections.Generic; +using Xunit; + +namespace ACadSharp.Tests.Entities +{ + public class HatchTests + { + [Fact] + public void CreateHatch() + { + Hatch hatch = new Hatch(); + hatch.IsSolid = true; + + hatch.SeedPoints.Add(new XY()); + + List edges = new List(); + + //edges + Hatch.BoundaryPath.Line edge1 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(0, 0), + End = new CSMath.XY(1, 0) + }; + edges.Add(edge1); + + Hatch.BoundaryPath.Line edge2 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(1, 0), + End = new CSMath.XY(1, 1) + }; + edges.Add(edge2); + + Hatch.BoundaryPath.Line edge3 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(1, 1), + End = new CSMath.XY(0, 1) + }; + edges.Add(edge3); + + Hatch.BoundaryPath.Line edge4 = new Hatch.BoundaryPath.Line + { + Start = new CSMath.XY(0, 1), + End = new CSMath.XY(0, 0) + }; + edges.Add(edge4); + + + Hatch.BoundaryPath path = new Hatch.BoundaryPath(); + foreach (var item in edges) + { + path.Edges.Add(item); + } + + hatch.Paths.Add(path); + + Assert.NotEmpty(hatch.Paths); + Assert.NotEmpty(path.Edges); + Assert.False(path.IsPolyline); + } + + [Fact] + public void CreatePolylineHatch() + { + Hatch hatch = new Hatch(); + hatch.IsSolid = true; + + Hatch.BoundaryPath path = new Hatch.BoundaryPath(); + + Hatch.BoundaryPath.Polyline pline = new Hatch.BoundaryPath.Polyline(); + pline.Vertices.Add(new XYZ(0, 0, 0)); + pline.Vertices.Add(new XYZ(1, 0, 0)); + pline.Vertices.Add(new XYZ(1, 1, 0)); + pline.Vertices.Add(new XYZ(0, 1, 0)); + pline.Vertices.Add(new XYZ(0, 0, 0)); + + path.Edges.Add(pline); + path.Flags = path.Flags.AddFlag(BoundaryPathFlags.Polyline); + hatch.Paths.Add(path); + + Assert.True(path.IsPolyline); + } + + [Fact] + public void PolylineHatchNotAllowMoreEdges() + { + Hatch hatch = new Hatch(); + hatch.IsSolid = true; + + Hatch.BoundaryPath path = new Hatch.BoundaryPath(); + + Hatch.BoundaryPath.Polyline pline = new Hatch.BoundaryPath.Polyline(); + pline.Vertices.Add(new XYZ(0, 0, 0)); + pline.Vertices.Add(new XYZ(1, 0, 0)); + pline.Vertices.Add(new XYZ(1, 1, 0)); + pline.Vertices.Add(new XYZ(0, 1, 0)); + pline.Vertices.Add(new XYZ(0, 0, 0)); + + path.Edges.Add(pline); + + Assert.Throws(() => + { + path.Edges.Add(new Hatch.BoundaryPath.Line()); + } + ); + + Assert.Throws(() => + { + path.Edges.Add(new Hatch.BoundaryPath.Polyline()); + } + ); + } + } +} diff --git a/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs b/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs index 39c4dbc1..6d4b30fb 100644 --- a/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs +++ b/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs @@ -340,7 +340,11 @@ public void CreateHatch() Hatch.BoundaryPath path = new Hatch.BoundaryPath(); - path.Edges.AddRange(edges); + foreach (var item in edges) + { + path.Edges.Add(item); + } + hatch.Paths.Add(path); this.Document.Entities.Add(hatch); diff --git a/src/ACadSharp/CadDocument.cs b/src/ACadSharp/CadDocument.cs index 0f4f9059..0b519372 100644 --- a/src/ACadSharp/CadDocument.cs +++ b/src/ACadSharp/CadDocument.cs @@ -423,7 +423,7 @@ private void onRemove(object sender, CollectionChangedEventArgs e) } } - internal void RegisterCollection(IObservableCollection collection) + internal void RegisterCollection(IObservableCadCollection collection) where T : CadObject { switch (collection) @@ -498,7 +498,7 @@ internal void RegisterCollection(IObservableCollection collection) } } - internal void UnregisterCollection(IObservableCollection collection) + internal void UnregisterCollection(IObservableCadCollection collection) where T : CadObject { switch (collection) diff --git a/src/ACadSharp/CadObjectCollection.cs b/src/ACadSharp/CadObjectCollection.cs index 3b7796cc..f3f3b5ed 100644 --- a/src/ACadSharp/CadObjectCollection.cs +++ b/src/ACadSharp/CadObjectCollection.cs @@ -6,7 +6,7 @@ namespace ACadSharp { - public class CadObjectCollection : IObservableCollection + public class CadObjectCollection : IObservableCadCollection where T : CadObject { public event EventHandler OnAdd; diff --git a/src/ACadSharp/Entities/Hatch.BoundaryPath.cs b/src/ACadSharp/Entities/Hatch.BoundaryPath.cs index 105d79d5..084381d9 100644 --- a/src/ACadSharp/Entities/Hatch.BoundaryPath.cs +++ b/src/ACadSharp/Entities/Hatch.BoundaryPath.cs @@ -1,5 +1,9 @@ using ACadSharp.Attributes; +using CSUtilities.Extensions; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; namespace ACadSharp.Entities { @@ -7,11 +11,32 @@ public partial class Hatch { public partial class BoundaryPath { + public bool IsPolyline { get { return this.Edges.OfType().Any(); } } + /// /// Boundary path type flag /// [DxfCodeValue(92)] - public BoundaryPathFlags Flags { get; set; } + public BoundaryPathFlags Flags + { + get + { + if (this.IsPolyline) + { + this._flags = this._flags.AddFlag(BoundaryPathFlags.Polyline); + } + else + { + this._flags = this._flags.RemoveFlag(BoundaryPathFlags.Polyline); + } + + return this._flags; + } + set + { + this._flags = value; + } + } /// /// Number of edges in this boundary path @@ -20,7 +45,7 @@ public partial class BoundaryPath /// only if boundary is not a polyline /// [DxfCodeValue(DxfReferenceType.Count, 93)] - public List Edges { get; set; } = new List(); + public ObservableCollection Edges { get; } = new(); /// /// Source boundary objects @@ -28,10 +53,46 @@ public partial class BoundaryPath [DxfCodeValue(DxfReferenceType.Count, 97)] public List Entities { get; set; } = new List(); + private BoundaryPathFlags _flags; + + public BoundaryPath() + { + Edges.CollectionChanged += this.onEdgesCollectionChanged; + } + public BoundaryPath Clone() { throw new System.NotImplementedException(); } + + private void onEdgesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case System.Collections.Specialized.NotifyCollectionChangedAction.Add: + onAdd(e); + break; + case System.Collections.Specialized.NotifyCollectionChangedAction.Remove: + break; + case System.Collections.Specialized.NotifyCollectionChangedAction.Replace: + break; + case System.Collections.Specialized.NotifyCollectionChangedAction.Move: + break; + case System.Collections.Specialized.NotifyCollectionChangedAction.Reset: + break; + } + } + + private void onAdd(NotifyCollectionChangedEventArgs e) + { + foreach (Edge edge in e.NewItems) + { + if (this.Edges.Count > 1 && this.IsPolyline) + { + throw new System.InvalidOperationException(); + } + } + } } } } diff --git a/src/ACadSharp/IObservableCollection.cs b/src/ACadSharp/IObservableCadCollection.cs similarity index 86% rename from src/ACadSharp/IObservableCollection.cs rename to src/ACadSharp/IObservableCadCollection.cs index 2069b377..3e52753f 100644 --- a/src/ACadSharp/IObservableCollection.cs +++ b/src/ACadSharp/IObservableCadCollection.cs @@ -3,7 +3,7 @@ namespace ACadSharp { - public interface IObservableCollection : IEnumerable + public interface IObservableCadCollection : IEnumerable where T : CadObject { /// diff --git a/src/ACadSharp/Objects/CadDictionary.cs b/src/ACadSharp/Objects/CadDictionary.cs index e9aa8bde..e35e6083 100644 --- a/src/ACadSharp/Objects/CadDictionary.cs +++ b/src/ACadSharp/Objects/CadDictionary.cs @@ -16,7 +16,7 @@ namespace ACadSharp.Objects /// [DxfName(DxfFileToken.ObjectDictionary)] [DxfSubClass(DxfSubclassMarker.Dictionary)] - public class CadDictionary : NonGraphicalObject, IObservableCollection + public class CadDictionary : NonGraphicalObject, IObservableCadCollection { public event EventHandler OnAdd; public event EventHandler OnRemove; diff --git a/src/ACadSharp/Tables/Collections/Table.cs b/src/ACadSharp/Tables/Collections/Table.cs index 646ae3fe..8a2c0180 100644 --- a/src/ACadSharp/Tables/Collections/Table.cs +++ b/src/ACadSharp/Tables/Collections/Table.cs @@ -8,7 +8,7 @@ namespace ACadSharp.Tables.Collections { [DxfSubClass(DxfSubclassMarker.Table)] - public abstract class Table : CadObject, ITable, IObservableCollection + public abstract class Table : CadObject, ITable, IObservableCadCollection where T : TableEntry { public event EventHandler OnAdd;