• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DomCR / ACadSharp / 17578897032

09 Sep 2025 09:56AM UTC coverage: 78.234% (+0.03%) from 78.209%
17578897032

Pull #779

github

web-flow
Merge 0a573cab6 into b4f69248d
Pull Request #779: Issue 723 dynamic blocks true name

6634 of 9207 branches covered (72.05%)

Branch coverage included in aggregate %.

15 of 18 new or added lines in 3 files covered. (83.33%)

2 existing lines in 1 file now uncovered.

25639 of 32045 relevant lines covered (80.01%)

105044.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.67
/src/ACadSharp/Tables/BlockRecord.cs
1
using ACadSharp.Attributes;
2
using ACadSharp.Blocks;
3
using ACadSharp.Entities;
4
using ACadSharp.Objects;
5
using ACadSharp.Objects.Evaluations;
6
using ACadSharp.Types.Units;
7
using CSMath;
8
using ACadSharp.XData;
9
using CSUtilities.Extensions;
10
using System;
11
using System.Collections.Generic;
12
using System.IO;
13
using System.Linq;
14

15
namespace ACadSharp.Tables
16
{
17
        /// <summary>
18
        /// Represents a <see cref="BlockRecord"/> entry
19
        /// </summary>
20
        /// <remarks>
21
        /// Object name <see cref="DxfFileToken.TableBlockRecord"/> <br/>
22
        /// Dxf class name <see cref="DxfSubclassMarker.BlockRecord"/>
23
        /// </remarks>
24
        [DxfName(DxfFileToken.TableBlockRecord)]
25
        [DxfSubClass(DxfSubclassMarker.BlockRecord)]
26
        public class BlockRecord : TableEntry, IGeometricEntity
27
        {
28
                /// <summary>
29
                /// Create an instance of the *Model_Space block.
30
                /// </summary>
31
                /// <remarks>
32
                /// It only can be one Model in each document.
33
                /// </remarks>
34
                public static BlockRecord ModelSpace
35
                {
36
                        get
37
                        {
764✔
38
                                BlockRecord record = new BlockRecord(ModelSpaceName);
764✔
39

40
                                Layout layout = new Layout();
764✔
41
                                layout.Name = Layout.ModelLayoutName;
764✔
42
                                layout.AssociatedBlock = record;
764✔
43

44
                                return record;
764✔
45
                        }
764✔
46
                }
47

48
                /// <summary>
49
                /// Create an instance of the *Paper_Space block.
50
                /// </summary>
51
                /// <remarks>
52
                /// This is the default paper space in the document.
53
                /// </remarks>
54
                public static BlockRecord PaperSpace
55
                {
56
                        get
57
                        {
764✔
58
                                BlockRecord record = new BlockRecord(PaperSpaceName);
764✔
59

60
                                Layout layout = new Layout();
764✔
61
                                layout.Name = Layout.PaperLayoutName;
764✔
62
                                layout.AssociatedBlock = record;
764✔
63

64
                                return record;
764✔
65
                        }
764✔
66
                }
67

68
                /// <summary>
69
                /// Attribute definitions in this block
70
                /// </summary>
71
                public IEnumerable<AttributeDefinition> AttributeDefinitions
72
                {
73
                        get
74
                        {
76✔
75
                                return this.Entities.OfType<AttributeDefinition>();
76✔
76
                        }
76✔
77
                }
78

79
                /// <summary>
80
                /// End block entity for this Block record.
81
                /// </summary>
82
                public BlockEnd BlockEnd
83
                {
84
                        get { return this._blockEnd; }
90,792✔
85
                        internal set
86
                        {
28,396✔
87
                                this._blockEnd = value;
28,396✔
88
                                this._blockEnd.Owner = this;
28,396✔
89
                        }
28,396✔
90
                }
91

92
                /// <summary>
93
                /// Block entity for this record
94
                /// </summary>
95
                public Block BlockEntity
96
                {
97
                        get { return this._blockEntity; }
188,445✔
98
                        internal set
99
                        {
37,534✔
100
                                this._blockEntity = value;
37,534✔
101
                                this._blockEntity.Owner = this;
37,534✔
102
                        }
37,534✔
103
                }
104

105
                /// <summary>
106
                /// Specifies the scaling allowed for the block.
107
                /// </summary>
108
                [DxfCodeValue(DxfReferenceType.Optional, 281)]
109
                public bool CanScale { get; set; } = true;
31,974✔
110

111
                /// <summary>
112
                /// Entities owned by this block.
113
                /// </summary>
114
                /// <remarks>
115
                /// Entities with an owner cannot be added to another block.
116
                /// </remarks>
117
                public CadObjectCollection<Entity> Entities { get; private set; }
316,069✔
118

119
                /// <summary>
120
                /// Gets the evaluation graph for this block if it has dynamic properties attached to it.
121
                /// </summary>
122
                public EvaluationGraph EvaluationGraph
123
                {
124
                        get
125
                        {
13✔
126
                                if (this.XDictionary == null)
13!
127
                                {
×
128
                                        return null;
×
129
                                }
130
                                else if (this.XDictionary.TryGetEntry(EvaluationGraph.DictionaryEntryName, out EvaluationGraph table))
13!
131
                                {
13✔
132
                                        return table;
13✔
133
                                }
134
                                else
135
                                {
×
136
                                        return null;
×
137
                                }
138
                        }
13✔
139
                }
140

141
                //This seems to be the right way to set the flags for the block records
142
                public new BlockTypeFlags Flags { get { return this.BlockEntity.Flags; } set { this.BlockEntity.Flags = value; } }
58,368✔
143

144
                /// <summary>
145
                /// Flag indicating if the Block has Attributes attached
146
                /// </summary>
147
                public bool HasAttributes
148
                {
149
                        get
150
                        {
612✔
151
                                return this.Entities.OfType<AttributeDefinition>().Any();
612✔
152
                        }
612✔
153
                }
154

155
                /// <summary>
156
                /// Blocks with the anonymous flag set are managed by this library or the editing software,
157
                /// this may affect the entities or the block properties.
158
                /// </summary>
159
                public bool IsAnonymous
160
                {
161
                        get
162
                        {
15,503✔
163
                                return (this.Flags & BlockTypeFlags.Anonymous) != 0;
15,503✔
164
                        }
15,503✔
165
                        set
166
                        {
133✔
167
                                if (value)
133✔
168
                                {
107✔
169
                                        this.Flags |= BlockTypeFlags.Anonymous;
107✔
170
                                }
107✔
171
                                else
172
                                {
26✔
173
                                        this.Flags &= ~BlockTypeFlags.Anonymous;
26✔
174
                                }
26✔
175
                        }
133✔
176
                }
177

178
                /// <summary>
179
                /// Active flag if it has an <see cref="Objects.Evaluations.EvaluationGraph"/> attached to it with dynamic expressions.
180
                /// </summary>
181
                public bool IsDynamic
182
                {
183
                        get
184
                        {
13✔
185
                                //Doesn't seem to be reliable
186
                                return this.EvaluationGraph != null;
13✔
187
                        }
13✔
188
                }
189

190
                /// <summary>
191
                /// Gets the source block. <br/>
192
                /// Only present if the block is dynamic and is in the same document as its source.
193
                /// </summary>
194
                public BlockRecord Source
195
                {
196
                        get
197
                        {
26✔
198
                                if (this.Document == null
26!
199
                                        || !this.IsAnonymous
26✔
200
                                        || this.ExtendedData == null)
26✔
NEW
201
                                {
×
NEW
202
                                        return null;
×
203
                                }
204

205
                                if (this.ExtendedData.TryGet(AppId.BlockRepBTag, out ExtendedData data))
26!
206
                                {
26✔
207
                                        ExtendedDataHandle handle = data.Records.OfType<ExtendedDataHandle>().FirstOrDefault();
26✔
208
                                        return (BlockRecord)handle.ResolveReference(this.Document);
26✔
209
                                }
210

NEW
211
                                return null;
×
212
                        }
26✔
213
                }
214

215
                /// <summary>
216
                /// Specifies whether the block can be exploded.
217
                /// </summary>
218
                [DxfCodeValue(DxfReferenceType.Optional, 280)]
219
                public bool IsExplodable { get; set; }
8,058✔
220

221
                /// <summary>
222
                /// Associated Layout.
223
                /// </summary>
224
                [DxfCodeValue(DxfReferenceType.Handle, 340)]
225
                public Layout Layout
226
                {
227
                        get { return this._layout; }
10,458✔
228
                        internal set
229
                        {
5,238✔
230
                                this._layout = value;
5,238✔
231
                        }
5,238✔
232
                }
233

234
                /// <inheritdoc/>
235
                public override string ObjectName => DxfFileToken.TableBlockRecord;
69,506✔
236

237
                /// <inheritdoc/>
238
                public override ObjectType ObjectType => ObjectType.BLOCK_HEADER;
1,224✔
239

240
                /// <summary>
241
                /// DXF: Binary data for bitmap preview.
242
                /// </summary>
243
                /// <remarks>
244
                /// Optional
245
                /// </remarks>
246
                [DxfCodeValue(DxfReferenceType.Optional, 310)]
247
                public byte[] Preview { get; set; }
18,189✔
248

249
                /// <summary>
250
                /// Sort entities table for this block record.
251
                /// </summary>
252
                public SortEntitiesTable SortEntitiesTable
253
                {
254
                        get
255
                        {
10,763✔
256
                                if (this.XDictionary == null)
10,763✔
257
                                {
10,175✔
258
                                        return null;
10,175✔
259
                                }
260
                                else if (this.XDictionary.TryGetEntry(SortEntitiesTable.DictionaryEntryName, out SortEntitiesTable table))
588✔
261
                                {
430✔
262
                                        return table;
430✔
263
                                }
264
                                else
265
                                {
158✔
266
                                        return null;
158✔
267
                                }
268
                        }
10,763✔
269
                }
270

271
                /// <inheritdoc/>
272
                public override string SubclassMarker => DxfSubclassMarker.BlockRecord;
72,255✔
273

274
                /// <summary>
275
                /// Block insertion units
276
                /// </summary>
277
                // [DxfCodeValue(70)]        //Table entry uses flags and has the same code but dwg saves also the block record flags
278
                public UnitsType Units { get; set; }
3,899✔
279

280
                /// <summary>
281
                /// ViewPorts attached to this block
282
                /// </summary>
283
                public IEnumerable<Viewport> Viewports
284
                {
285
                        get
286
                        {
1,695✔
287
                                return this.Entities.OfType<Viewport>();
1,695✔
288
                        }
1,695✔
289
                }
290

291
                /// <summary>
292
                /// Prefix used for naming any anonymous block managed by ACadSharp.
293
                /// </summary>
294
                public const string AnonymousPrefix = "*A";
295

296
                /// <summary>
297
                /// Default block record name for the model space
298
                /// </summary>
299
                public const string ModelSpaceName = "*Model_Space";
300

301
                /// <summary>
302
                /// Default block record name for the paper space
303
                /// </summary>
304
                public const string PaperSpaceName = "*Paper_Space";
305

306
                private BlockEnd _blockEnd;
307

308
                private Block _blockEntity;
309

310
                private Layout _layout;
311

312
                /// <summary>
313
                /// Default constructor.
314
                /// </summary>
315
                /// <param name="name">Unique name for this block record.</param>
316
                public BlockRecord(string name) : base(name)
6,726✔
317
                {
6,726✔
318
                        this.BlockEntity = new Block(this);
6,726✔
319
                        this.BlockEnd = new BlockEnd(this);
6,726✔
320
                        this.Entities = new CadObjectCollection<Entity>(this);
6,726✔
321
                }
6,726✔
322

323
                /// <summary>
324
                /// Initializes a new instance of the <c>BlockRecord</c> class as an external reference drawing.
325
                /// </summary>
326
                /// <param name="name">Block name.</param>
327
                /// <param name="xrefFile">External reference path name.</param>
328
                /// <param name="isOverlay">Specifies if the external reference is an overlay, by default it is set to false.</param>
329
                /// <remarks>Only DWG files can be used as externally referenced blocks.</remarks>
330
                public BlockRecord(string name, string xrefFile, bool isOverlay = false) : this(name)
2✔
331
                {
2✔
332
                        if (string.IsNullOrEmpty(xrefFile))
2!
333
                        {
×
334
                                throw new ArgumentNullException(nameof(xrefFile));
×
335
                        }
336

337
                        if (xrefFile.IndexOfAny(Path.GetInvalidPathChars()) == 0)
2!
338
                        {
×
339
                                throw new ArgumentException("File path contains invalid characters.", nameof(xrefFile));
×
340
                        }
341

342
                        this.BlockEntity.XRefPath = xrefFile;
2✔
343
                        this.Flags = BlockTypeFlags.XRef | BlockTypeFlags.XRefResolved;
2✔
344
                        if (isOverlay)
2✔
345
                        {
1✔
346
                                this.Flags = this.Flags.AddFlag(BlockTypeFlags.XRefOverlay);
1✔
347
                        }
1✔
348
                }
2✔
349

350
                internal BlockRecord() : base()
17,190✔
351
                {
17,190✔
352
                        this.BlockEntity = new Block(this);
17,190✔
353
                        this.BlockEnd = new BlockEnd(this);
17,190✔
354
                        this.Entities = new CadObjectCollection<Entity>(this);
17,190✔
355
                }
17,190✔
356

357
                /// <inheritdoc/>
358
                public void ApplyTransform(Transform transform)
359
                {
×
360
                        foreach (Entity item in this.Entities)
×
361
                        {
×
362
                                item.ApplyTransform(transform);
×
363
                        }
×
364
                }
×
365

366
                /// <inheritdoc/>
367
                public override CadObject Clone()
368
                {
836✔
369
                        BlockRecord clone = (BlockRecord)base.Clone();
836✔
370

371
                        clone.Layout = null;
836✔
372

373
                        if (this.SortEntitiesTable != null)
836✔
374
                        {
61✔
375
                                clone.CreateSortEntitiesTable();
61✔
376
                        }
61✔
377

378
                        clone.Entities = new CadObjectCollection<Entity>(clone);
836✔
379
                        foreach (var item in this.Entities)
21,978✔
380
                        {
9,735✔
381
                                var e = (Entity)item.Clone();
9,735✔
382
                                clone.Entities.Add(e);
9,735✔
383

384
                                if (this.SortEntitiesTable != null
9,735✔
385
                                        && this.SortEntitiesTable.Select(s => s.Entity).Contains(item))
9,747✔
386
                                {
3✔
387
                                        clone.SortEntitiesTable.Add(e, this.SortEntitiesTable.GetSorterHandle(item));
3✔
388
                                }
3✔
389
                        }
9,735✔
390

391
                        clone.BlockEntity = (Block)this.BlockEntity.Clone();
836✔
392
                        clone.BlockEntity.Owner = clone;
836✔
393
                        clone.BlockEnd = (BlockEnd)this.BlockEnd.Clone();
836✔
394
                        clone.BlockEnd.Owner = clone;
836✔
395

396
                        return clone;
836✔
397
                }
836✔
398

399
                /// <summary>
400
                /// Create an entity sorter table for this block.
401
                /// </summary>
402
                /// <returns></returns>
403
                public SortEntitiesTable CreateSortEntitiesTable()
404
                {
64✔
405
                        CadDictionary dictionary = this.CreateExtendedDictionary();
64✔
406

407
                        if (dictionary.TryGetEntry(SortEntitiesTable.DictionaryEntryName, out SortEntitiesTable table))
64✔
408
                        {
61✔
409
                                return table;
61✔
410
                        }
411

412
                        table = new SortEntitiesTable(this);
3✔
413

414
                        dictionary.Add(table);
3✔
415

416
                        return table;
3✔
417
                }
64✔
418

419
                /// <summary>
420
                /// Get the bounding box for all the entities in the block.
421
                /// </summary>
422
                /// <returns></returns>
423
                public BoundingBox GetBoundingBox()
424
                {
4✔
425
                        return this.GetBoundingBox(true);
4✔
426
                }
4✔
427

428
                /// <summary>
429
                /// Get the bounding box for all the entities in the block.
430
                /// </summary>
431
                /// <param name="ignoreInfinite">Ignore infinite entities, default: true</param>
432
                /// <returns></returns>
433
                public BoundingBox GetBoundingBox(bool ignoreInfinite)
434
                {
4✔
435
                        BoundingBox box = BoundingBox.Null;
4✔
436
                        foreach (var item in this.Entities)
60✔
437
                        {
24✔
438
                                if (item.GetBoundingBox().Extent == BoundingBoxExtent.Infinite
24!
439
                                        && ignoreInfinite)
24✔
440
                                {
×
441
                                        continue;
×
442
                                }
443

444
                                box = box.Merge(item.GetBoundingBox());
24✔
445
                        }
24✔
446

447
                        return box;
4✔
448
                }
4✔
449

450
                /// <summary>
451
                /// Get the entities in this block record sorted by it's handle and the sorter assigned if is present.
452
                /// </summary>
453
                /// <remarks>
454
                /// If the record is not in a document the entities will not be sorted unless there is a
455
                /// <see cref="SortEntitiesTable"/> assigned to the block.
456
                /// </remarks>
457
                /// <returns></returns>
458
                public IEnumerable<Entity> GetSortedEntities()
459
                {
×
460
                        if (this.SortEntitiesTable != null)
×
461
                        {
×
462
                                return this.Entities.OrderBy(e => e.Handle);
×
463
                        }
464

465
                        List<(ulong, Entity)> entities = new();
×
466

467
                        foreach (var entity in this.Entities)
×
468
                        {
×
469
                                ulong sorter = this.SortEntitiesTable.GetSorterHandle(entity);
×
470
                                entities.Add((sorter, entity));
×
471
                        }
×
472

473
                        return entities.OrderBy(e => e.Item1).Select(e => e.Item2);
×
474
                }
×
475

476
                internal override void AssignDocument(CadDocument doc)
477
                {
15,471✔
478
                        base.AssignDocument(doc);
15,471✔
479

480
                        doc.RegisterCollection(this.Entities);
15,471✔
481
                }
15,471✔
482

483
                internal override void UnassignDocument()
484
                {
5✔
485
                        this.Document.UnregisterCollection(this.Entities);
5✔
486

487
                        base.UnassignDocument();
5✔
488
                }
5✔
489
        }
490
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc