From 909ca796c207b0bb9b465c389e008f6265a40036 Mon Sep 17 00:00:00 2001 From: DomCR Date: Sun, 20 Oct 2024 19:14:24 +0200 Subject: [PATCH] get scale from xrecord --- src/ACadSharp.Tests/IO/MultiLeaderTests.cs | 1 - src/ACadSharp.Tests/IO/ViewportTests.cs | 38 +++++++++ .../IO/WriterSingleObjectTests.cs | 6 ++ src/ACadSharp/Entities/Viewport.cs | 80 +++++++++++++++++++ .../DWG/DwgStreamReaders/DwgObjectReader.cs | 32 ++++---- .../DwgObjectWriter.Objects.cs | 2 +- .../DxfObjectsSectionReader.cs | 4 +- .../IO/Templates/CadDictionaryTemplate.cs | 6 +- .../IO/Templates/CadViewportTemplate.cs | 20 ++++- .../Collections/ObjectDictionaryCollection.cs | 2 +- .../Objects/Collections/ScaleCollection.cs | 20 ++++- src/ACadSharp/Objects/XRecord.Entry.cs | 45 +++++++++++ src/ACadSharp/Objects/XRecrod.cs | 27 ++++--- 13 files changed, 244 insertions(+), 39 deletions(-) create mode 100644 src/ACadSharp.Tests/IO/ViewportTests.cs create mode 100644 src/ACadSharp/Objects/XRecord.Entry.cs diff --git a/src/ACadSharp.Tests/IO/MultiLeaderTests.cs b/src/ACadSharp.Tests/IO/MultiLeaderTests.cs index 5c251833..5786a681 100644 --- a/src/ACadSharp.Tests/IO/MultiLeaderTests.cs +++ b/src/ACadSharp.Tests/IO/MultiLeaderTests.cs @@ -2,7 +2,6 @@ using ACadSharp.IO; using ACadSharp.Tests.TestModels; using System.Collections.Generic; -using System.IO; using Xunit; using Xunit.Abstractions; diff --git a/src/ACadSharp.Tests/IO/ViewportTests.cs b/src/ACadSharp.Tests/IO/ViewportTests.cs new file mode 100644 index 00000000..339ad0f2 --- /dev/null +++ b/src/ACadSharp.Tests/IO/ViewportTests.cs @@ -0,0 +1,38 @@ +using ACadSharp.Entities; +using ACadSharp.IO; +using ACadSharp.Tests.TestModels; +using System.IO; +using Xunit; +using Xunit.Abstractions; + +namespace ACadSharp.Tests.IO +{ + public class ViewportTests : IOTestsBase + { + public ViewportTests(ITestOutputHelper output) : base(output) + { + } + + [Theory] + [MemberData(nameof(DwgFilePaths))] + [MemberData(nameof(DxfAsciiFiles))] + public void ScaleInViewport(FileModel test) + { + CadDocument doc; + if (Path.GetExtension(test.FileName).Equals(".dxf")) + { + doc = DxfReader.Read(test.Path); + } + else + { + doc = DwgReader.Read(test.Path); + } + + ACadSharp.Tables.BlockRecord paper = doc.PaperSpace; + foreach (Viewport v in paper.Viewports) + { + Assert.NotNull(v.Scale); + } + } + } +} diff --git a/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs b/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs index e0614709..722321ac 100644 --- a/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs +++ b/src/ACadSharp.Tests/IO/WriterSingleObjectTests.cs @@ -404,6 +404,11 @@ public void ChangedEncoding() this.Document.Layers.Add(new Layer("我的自定义层")); } + public void AddCustomScale() + { + this.Document.Scales.Add(new Scale("Hello")); + } + public void AddBlockWithAttributes() { BlockRecord record = new("my_block"); @@ -491,6 +496,7 @@ static WriterSingleObjectTests() Data.Add(new(nameof(SingleCaseGenerator.CreateCircleHatch))); Data.Add(new(nameof(SingleCaseGenerator.ChangedEncoding))); Data.Add(new(nameof(SingleCaseGenerator.AddBlockWithAttributes))); + Data.Add(new(nameof(SingleCaseGenerator.AddCustomScale))); } protected string getPath(string name, string ext, ACadVersion version) diff --git a/src/ACadSharp/Entities/Viewport.cs b/src/ACadSharp/Entities/Viewport.cs index 118b0641..5cdd6466 100644 --- a/src/ACadSharp/Entities/Viewport.cs +++ b/src/ACadSharp/Entities/Viewport.cs @@ -4,6 +4,7 @@ using CSMath; using System; using System.Collections.Generic; +using System.Linq; namespace ACadSharp.Entities { @@ -23,6 +24,8 @@ public class Viewport : Entity /// public const int PaperViewId = 1; + public const string ASDK_XREC_ANNOTATION_SCALE_INFO = "ASDK_XREC_ANNOTATION_SCALE_INFO"; + /// public override ObjectType ObjectType => ObjectType.VIEWPORT; @@ -322,6 +325,31 @@ public double ViewWidth //Soft pointer reference to viewport object (for layer VP property override) + /// + /// + /// + public Scale Scale + { + get + { + return this._scale; + } + set + { + if (this.Document != null) + { + this._scale = this.updateCollection(value, this.Document.Scales); + this.updateScaleXRecord(); + } + else + { + this._scale = value; + } + } + } + + private Scale _scale; + /// public override CadObject Clone() { @@ -372,5 +400,57 @@ public List SelectEntities(bool includePartial = true) return entities; } + + internal override void AssignDocument(CadDocument doc) + { + base.AssignDocument(doc); + + this._scale = this.updateCollection(this.Scale, doc.Scales); + + this.Document.Scales.OnRemove += this.scalesOnRemove; + } + + internal override void UnassignDocument() + { + this.Document.Scales.OnRemove -= this.scalesOnRemove; + + base.UnassignDocument(); + + this._scale = (Scale)this.Scale.Clone(); + } + + private void scalesOnRemove(object sender, CollectionChangedEventArgs e) + { + if (e.Item.Equals(this.Scale)) + { + this.Scale = this.Document.Scales.FirstOrDefault(); + } + } + + private void updateScaleXRecord() + { + if (this.Document == null) + { + return; + } + + if (this.XDictionary.TryGetEntry(ASDK_XREC_ANNOTATION_SCALE_INFO, out XRecord record)) + { + foreach (XRecord.Entry item in record.Entries) + { + if (item.Code == 340) + { + item.Value = this._scale.Handle; + } + } + } + else + { + record = new XRecord(ASDK_XREC_ANNOTATION_SCALE_INFO); + this.XDictionary.Add(record); + + record.CreateEntry(340, _scale.Handle); + } + } } } diff --git a/src/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs b/src/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs index 7d98092a..437f252e 100644 --- a/src/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs +++ b/src/ACadSharp/IO/DWG/DwgStreamReaders/DwgObjectReader.cs @@ -1777,7 +1777,7 @@ private CadTemplate readDimOrdinate() //14 - pt 3BD 14 See DXF documentation. dimension.LeaderEndpoint = this._objectReader.Read3BitDouble(); - byte flags = (this._objectReader.ReadByte()); + byte flags = this._objectReader.ReadByte(); dimension.IsOrdinateTypeX = (flags & 0b01) != 0; this.readCommonDimensionHandles(template); @@ -1936,7 +1936,7 @@ private void readCommonDimensionData(CadDimensionTemplate template) //The actual 70 - group value comes from 3 things: //6 for being an ordinate DIMENSION, plus whatever bits "Flags 1" and "Flags 2" specify. - byte flags = (this._objectReader.ReadByte()); + byte flags = this._objectReader.ReadByte(); dimension.IsTextUserDefinedLocation = (flags & 0b01) == 0; //User text TV 1 @@ -5297,50 +5297,50 @@ private CadTemplate readXRecord() { case GroupCodeValueType.String: case GroupCodeValueType.ExtendedDataString: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadTextUnicode())); + xRecord.CreateEntry(code, this._objectReader.ReadTextUnicode()); break; case GroupCodeValueType.Point3D: - xRecord.Entries.Add(new XRecord.Entry(code, + xRecord.CreateEntry(code, new XYZ( this._objectReader.ReadDouble(), this._objectReader.ReadDouble(), this._objectReader.ReadDouble() - ))); + )); break; case GroupCodeValueType.Double: case GroupCodeValueType.ExtendedDataDouble: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadDouble())); + xRecord.CreateEntry(code, this._objectReader.ReadDouble()); break; case GroupCodeValueType.Byte: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadByte())); + xRecord.CreateEntry(code, this._objectReader.ReadByte()); break; case GroupCodeValueType.Int16: case GroupCodeValueType.ExtendedDataInt16: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadShort())); + xRecord.CreateEntry(code, this._objectReader.ReadShort()); break; case GroupCodeValueType.Int32: case GroupCodeValueType.ExtendedDataInt32: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadRawLong())); + xRecord.CreateEntry(code, this._objectReader.ReadRawLong()); break; case GroupCodeValueType.Int64: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadRawULong())); + xRecord.CreateEntry(code, this._objectReader.ReadRawULong()); break; case GroupCodeValueType.Handle: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadTextUnicode())); + xRecord.CreateEntry(code, this._objectReader.ReadTextUnicode()); break; case GroupCodeValueType.Bool: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadByte() > 0)); + xRecord.CreateEntry(code, this._objectReader.ReadByte() > 0); break; case GroupCodeValueType.Chunk: case GroupCodeValueType.ExtendedDataChunk: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadBytes(this._objectReader.ReadByte()))); + xRecord.CreateEntry(code, this._objectReader.ReadBytes(this._objectReader.ReadByte())); break; case GroupCodeValueType.ObjectId: case GroupCodeValueType.ExtendedDataHandle: - xRecord.Entries.Add(new XRecord.Entry(code, this._objectReader.ReadRawULong())); + xRecord.CreateEntry(code, this._objectReader.ReadRawULong()); break; default: - this.notify($"Unedintified GroupCodeValueType {code} for XRecord [{xRecord.Handle}]", NotificationType.Warning); + this.notify($"Unidentified GroupCodeValueType {code} for XRecord [{xRecord.Handle}]", NotificationType.Warning); break; } } @@ -5349,7 +5349,7 @@ private CadTemplate readXRecord() if (this.R2000Plus) { //Cloning flag BS 280 - xRecord.ClonningFlags = (DictionaryCloningFlags)this._objectReader.ReadBitShort(); + xRecord.CloningFlags = (DictionaryCloningFlags)this._objectReader.ReadBitShort(); } long size = this._objectInitialPos + (long)(this._size * 8U) - 7L; diff --git a/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Objects.cs b/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Objects.cs index c36ac818..31e81664 100644 --- a/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Objects.cs +++ b/src/ACadSharp/IO/DWG/DwgStreamWriters/DwgObjectWriter.Objects.cs @@ -680,7 +680,7 @@ private void writeXRecord(XRecord xrecord) if (this.R2000Plus) { //Cloning flag BS 280 - this._writer.WriteBitShort((short)xrecord.ClonningFlags); + this._writer.WriteBitShort((short)xrecord.CloningFlags); } } diff --git a/src/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs b/src/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs index f261d9c2..56c1842f 100644 --- a/src/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs +++ b/src/ACadSharp/IO/DXF/DxfStreamReader/DxfObjectsSectionReader.cs @@ -194,8 +194,6 @@ private bool readXRecord(CadTemplate template, DxfMap map) { CadXRecordTemplate tmp = template as CadXRecordTemplate; - //TODO: Finsih cadXrecordtemplate - switch (this._reader.Code) { case 100 when this._reader.ValueAsString == DxfSubclassMarker.XRecord: @@ -212,7 +210,7 @@ private void readXRecordEntries(XRecord recrod) while (this._reader.DxfCode != DxfCode.Start) { - recrod.Entries.Add(new XRecord.Entry(this._reader.Code, this._reader.Value)); + recrod.CreateEntry(this._reader.Code, this._reader.Value); this._reader.ReadNext(); } diff --git a/src/ACadSharp/IO/Templates/CadDictionaryTemplate.cs b/src/ACadSharp/IO/Templates/CadDictionaryTemplate.cs index 3aef681a..6700113c 100644 --- a/src/ACadSharp/IO/Templates/CadDictionaryTemplate.cs +++ b/src/ACadSharp/IO/Templates/CadDictionaryTemplate.cs @@ -35,6 +35,10 @@ public override void Build(CadDocumentBuilder builder) { if (builder.TryGetCadObject(item.Value, out NonGraphicalObject entry)) { + //This section basically sets the key and name to the same value to make sure that the + //different collections and dictionaries work properly. + //For some collections like Scales there are some cases where the key doesn't match the name + //but regarding changing the key doesn't seem to take an effect on it. if (string.IsNullOrEmpty(entry.Name)) { entry.Name = item.Key; @@ -42,7 +46,7 @@ public override void Build(CadDocumentBuilder builder) try { - this.CadObject.Add(item.Key, entry); + this.CadObject.Add(entry.Name, entry); } catch (System.Exception ex) { diff --git a/src/ACadSharp/IO/Templates/CadViewportTemplate.cs b/src/ACadSharp/IO/Templates/CadViewportTemplate.cs index af13ce1a..b6404c12 100644 --- a/src/ACadSharp/IO/Templates/CadViewportTemplate.cs +++ b/src/ACadSharp/IO/Templates/CadViewportTemplate.cs @@ -1,10 +1,11 @@ using ACadSharp.Entities; +using ACadSharp.Objects; using ACadSharp.Tables; using System.Collections.Generic; namespace ACadSharp.IO.Templates { - internal class CadViewportTemplate : CadEntityTemplate + internal class CadViewportTemplate : CadEntityTemplate { public ulong? ViewportHeaderHandle { get; set; } @@ -39,7 +40,7 @@ public override void Build(CadDocumentBuilder builder) { viewport.Boundary = entity; } - else if(this.BoundaryHandle.HasValue && this.BoundaryHandle > 0) + else if (this.BoundaryHandle.HasValue && this.BoundaryHandle > 0) { builder.Notify($"Boundary {this.BoundaryHandle} not found for viewport {this.CadObject.Handle}", NotificationType.Warning); } @@ -54,6 +55,21 @@ public override void Build(CadDocumentBuilder builder) builder.Notify($"Base ucs not implemented for Viewport, handle {this.BaseUcsHandle}"); } + if (this.CadObject.XDictionary != null && + this.CadObject.XDictionary.TryGetEntry(Viewport.ASDK_XREC_ANNOTATION_SCALE_INFO, out XRecord record)) + { + foreach (XRecord.Entry item in record.Entries) + { + if (item.Code == 340) + { + if (builder.TryGetCadObject((ulong?)item.Value, out Scale scale)) + { + this.CadObject.Scale = scale; + } + } + } + } + foreach (var handle in this.FrozenLayerHandles) { if (builder.TryGetCadObject(handle, out Layer layer)) diff --git a/src/ACadSharp/Objects/Collections/ObjectDictionaryCollection.cs b/src/ACadSharp/Objects/Collections/ObjectDictionaryCollection.cs index 6c9dc9d1..0fab922c 100644 --- a/src/ACadSharp/Objects/Collections/ObjectDictionaryCollection.cs +++ b/src/ACadSharp/Objects/Collections/ObjectDictionaryCollection.cs @@ -31,7 +31,7 @@ protected ObjectDictionaryCollection(CadDictionary dictionary) /// Add an entry to the collection /// /// - public void Add(T entry) + public virtual void Add(T entry) { this._dictionary.Add(entry); } diff --git a/src/ACadSharp/Objects/Collections/ScaleCollection.cs b/src/ACadSharp/Objects/Collections/ScaleCollection.cs index f0af6f46..94ba7a07 100644 --- a/src/ACadSharp/Objects/Collections/ScaleCollection.cs +++ b/src/ACadSharp/Objects/Collections/ScaleCollection.cs @@ -1,10 +1,28 @@ -namespace ACadSharp.Objects.Collections +using System.Collections.Generic; + +namespace ACadSharp.Objects.Collections { public class ScaleCollection : ObjectDictionaryCollection { + private readonly Dictionary _scales = new Dictionary(); + public ScaleCollection(CadDictionary dictionary) : base(dictionary) { this._dictionary = dictionary; + + foreach (Scale item in this._dictionary) + { + this._scales.Add(item.Name, item); + } + } + + /// + /// + /// + /// + public override void Add(Scale entry) + { + base.Add(entry); } } } diff --git a/src/ACadSharp/Objects/XRecord.Entry.cs b/src/ACadSharp/Objects/XRecord.Entry.cs new file mode 100644 index 00000000..c3080849 --- /dev/null +++ b/src/ACadSharp/Objects/XRecord.Entry.cs @@ -0,0 +1,45 @@ +namespace ACadSharp.Objects +{ + public partial class XRecord + { + public class Entry + { + public int Code { get; } + + public object Value { get; set; } + + public GroupCodeValueType GroupCode + { + get + { + return GroupCodeValue.TransformValue(this.Code); + } + } + + public bool HasLinkedObject + { + get + { + switch (this.GroupCode) + { + case GroupCodeValueType.Handle: + case GroupCodeValueType.ObjectId: + case GroupCodeValueType.ExtendedDataHandle: + return true; + default: + return false; + } + } + } + + public XRecord Owner { get; set; } + + internal Entry(int code, object value, XRecord owner) + { + this.Code = code; + this.Value = value; + this.Owner = owner; + } + } + } +} diff --git a/src/ACadSharp/Objects/XRecrod.cs b/src/ACadSharp/Objects/XRecrod.cs index 7bee708b..0cbbf28e 100644 --- a/src/ACadSharp/Objects/XRecrod.cs +++ b/src/ACadSharp/Objects/XRecrod.cs @@ -4,15 +4,18 @@ namespace ACadSharp.Objects { /// - /// Represents a object + /// Represents a object. /// /// /// Object name
/// Dxf class name + ///
+ ///
+ /// Is not recommended to modify, add or remove entries to an XRecord unless you know what consequences will cause in the document. ///
[DxfName(DxfFileToken.ObjectXRecord)] [DxfSubClass(DxfSubclassMarker.XRecord)] - public class XRecord : NonGraphicalObject + public partial class XRecord : NonGraphicalObject { /// public override ObjectType ObjectType => ObjectType.XRECORD; @@ -27,22 +30,20 @@ public class XRecord : NonGraphicalObject /// Duplicate record cloning flag (determines how to merge duplicate entries) /// [DxfCodeValue(280)] - public DictionaryCloningFlags ClonningFlags { get; set; } + public DictionaryCloningFlags CloningFlags { get; set; } //1-369 (except 5 and 105) These values can be used by an application in any way - public List Entries { get; set; } = new List(); + public IEnumerable Entries { get { return this._entries; } } - public class Entry - { - public int Code { get; } + private readonly List _entries = new List(); + + public XRecord() : base() { } - public object Value { get; } + public XRecord(string name) : base(name) { } - public Entry(int code, object value) - { - this.Code = code; - this.Value = value; - } + public void CreateEntry(int code, object value) + { + this._entries.Add(new Entry(code, value, this)); } } }