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

DomCR / ACadSharp / 17322384007

29 Aug 2025 11:17AM UTC coverage: 78.217% (-0.03%) from 78.245%
17322384007

Pull #758

github

web-flow
Merge 22680f4ef into b16e4689c
Pull Request #758: Issue 756 xref

6554 of 9107 branches covered (71.97%)

Branch coverage included in aggregate %.

35 of 39 new or added lines in 9 files covered. (89.74%)

13 existing lines in 3 files now uncovered.

25397 of 31742 relevant lines covered (80.01%)

105436.12 hits per line

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

82.11
/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 CSUtilities.Extensions;
9
using System;
10
using System.Collections.Generic;
11
using System.IO;
12
using System.Linq;
13

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

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

43
                                return record;
751✔
44
                        }
751✔
45
                }
46

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

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

63
                                return record;
751✔
64
                        }
751✔
65
                }
66

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

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

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

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

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

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

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

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

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

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

188
                /// <summary>
189
                /// Specifies whether the block can be exploded.
190
                /// </summary>
191
                [DxfCodeValue(DxfReferenceType.Optional, 280)]
192
                public bool IsExplodable { get; set; }
8,043✔
193

194
                /// <summary>
195
                /// Associated Layout.
196
                /// </summary>
197
                [DxfCodeValue(DxfReferenceType.Handle, 340)]
198
                public Layout Layout
199
                {
200
                        get { return this._layout; }
10,326✔
201
                        internal set
202
                        {
5,213✔
203
                                this._layout = value;
5,213✔
204
                        }
5,213✔
205
                }
206

207
                /// <inheritdoc/>
208
                public override string ObjectName => DxfFileToken.TableBlockRecord;
68,866✔
209

210
                /// <inheritdoc/>
211
                public override ObjectType ObjectType => ObjectType.BLOCK_HEADER;
1,208✔
212

213
                /// <summary>
214
                /// DXF: Binary data for bitmap preview.
215
                /// </summary>
216
                /// <remarks>
217
                /// Optional
218
                /// </remarks>
219
                [DxfCodeValue(DxfReferenceType.Optional, 310)]
220
                public byte[] Preview { get; set; }
18,189✔
221

222
                /// <summary>
223
                /// Sort entities table for this block record.
224
                /// </summary>
225
                public SortEntitiesTable SortEntitiesTable
226
                {
227
                        get
228
                        {
10,764✔
229
                                if (this.XDictionary == null)
10,764✔
230
                                {
10,176✔
231
                                        return null;
10,176✔
232
                                }
233
                                else if (this.XDictionary.TryGetEntry(SortEntitiesTable.DictionaryEntryName, out SortEntitiesTable table))
588✔
234
                                {
430✔
235
                                        return table;
430✔
236
                                }
237
                                else
238
                                {
158✔
239
                                        return null;
158✔
240
                                }
241
                        }
10,764✔
242
                }
243

244
                /// <inheritdoc/>
245
                public override string SubclassMarker => DxfSubclassMarker.BlockRecord;
72,235✔
246

247
                /// <summary>
248
                /// Block insertion units
249
                /// </summary>
250
                // [DxfCodeValue(70)]        //Table entry uses flags and has the same code but dwg saves also the block record flags
251
                public UnitsType Units { get; set; }
3,883✔
252

253
                /// <summary>
254
                /// ViewPorts attached to this block
255
                /// </summary>
256
                public IEnumerable<Viewport> Viewports
257
                {
258
                        get
259
                        {
1,671✔
260
                                return this.Entities.OfType<Viewport>();
1,671✔
261
                        }
1,671✔
262
                }
263

264
                /// <summary>
265
                /// Prefix used for naming any anonymous block managed by ACadSharp.
266
                /// </summary>
267
                public const string AnonymousPrefix = "*A";
268

269
                /// <summary>
270
                /// Default block record name for the model space
271
                /// </summary>
272
                public const string ModelSpaceName = "*Model_Space";
273

274
                /// <summary>
275
                /// Default block record name for the paper space
276
                /// </summary>
277
                public const string PaperSpaceName = "*Paper_Space";
278

279
                private BlockEnd _blockEnd;
280

281
                private Block _blockEntity;
282

283
                private Layout _layout;
284

285
                /// <summary>
286
                /// Default constructor.
287
                /// </summary>
288
                /// <param name="name">Unique name for this block record.</param>
289
                public BlockRecord(string name) : base(name)
6,680✔
290
                {
6,680✔
291
                        this.BlockEntity = new Block(this);
6,680✔
292
                        this.BlockEnd = new BlockEnd(this);
6,680✔
293
                        this.Entities = new CadObjectCollection<Entity>(this);
6,680✔
294
                }
6,680✔
295

296
                /// <summary>
297
                /// Initializes a new instance of the <c>BlockRecord</c> class as an external reference drawing.
298
                /// </summary>
299
                /// <param name="name">Block name.</param>
300
                /// <param name="xrefFile">External reference path name.</param>
301
                /// <param name="isOverlay">Specifies if the external reference is an overlay, by default it is set to false.</param>
302
                /// <remarks>Only DWG files can be used as externally referenced blocks.</remarks>
303
                public BlockRecord(string name, string xrefFile, bool isOverlay = false) : this(name)
2✔
304
                {
2✔
305
                        if (string.IsNullOrEmpty(xrefFile))
2!
NEW
306
                        {
×
NEW
307
                                throw new ArgumentNullException(nameof(xrefFile));
×
308
                        }
309

310
                        if (xrefFile.IndexOfAny(Path.GetInvalidPathChars()) == 0)
2!
NEW
311
                        {
×
NEW
312
                                throw new ArgumentException("File path contains invalid characters.", nameof(xrefFile));
×
313
                        }
314

315
                        this.BlockEntity.XRefPath = xrefFile;
2✔
316
                        this.Flags = BlockTypeFlags.XRef | BlockTypeFlags.XRefResolved;
2✔
317
                        if (isOverlay)
2✔
318
                        {
1✔
319
                                this.Flags = this.Flags.AddFlag(BlockTypeFlags.XRefOverlay);
1✔
320
                        }
1✔
321
                }
2✔
322

323
                internal BlockRecord() : base()
17,190✔
324
                {
17,190✔
325
                        this.BlockEntity = new Block(this);
17,190✔
326
                        this.BlockEnd = new BlockEnd(this);
17,190✔
327
                        this.Entities = new CadObjectCollection<Entity>(this);
17,190✔
328
                }
17,190✔
329

330
                /// <inheritdoc/>
331
                public void ApplyTransform(Transform transform)
332
                {
×
333
                        foreach (Entity item in this.Entities)
×
334
                        {
×
335
                                item.ApplyTransform(transform);
×
336
                        }
×
337
                }
×
338

339
                /// <inheritdoc/>
340
                public override CadObject Clone()
341
                {
837✔
342
                        BlockRecord clone = (BlockRecord)base.Clone();
837✔
343

344
                        clone.Layout = null;
837✔
345

346
                        if (this.SortEntitiesTable != null)
837✔
347
                        {
61✔
348
                                clone.CreateSortEntitiesTable();
61✔
349
                        }
61✔
350

351
                        clone.Entities = new CadObjectCollection<Entity>(clone);
837✔
352
                        foreach (var item in this.Entities)
21,981✔
353
                        {
9,735✔
354
                                var e = (Entity)item.Clone();
9,735✔
355
                                clone.Entities.Add(e);
9,735✔
356

357
                                if (this.SortEntitiesTable != null
9,735✔
358
                                        && this.SortEntitiesTable.Select(s => s.Entity).Contains(item))
9,747✔
359
                                {
3✔
360
                                        clone.SortEntitiesTable.Add(e, this.SortEntitiesTable.GetSorterHandle(item));
3✔
361
                                }
3✔
362
                        }
9,735✔
363

364
                        clone.BlockEntity = (Block)this.BlockEntity.Clone();
837✔
365
                        clone.BlockEntity.Owner = clone;
837✔
366
                        clone.BlockEnd = (BlockEnd)this.BlockEnd.Clone();
837✔
367
                        clone.BlockEnd.Owner = clone;
837✔
368

369
                        return clone;
837✔
370
                }
837✔
371

372
                /// <summary>
373
                /// Create an entity sorter table for this block.
374
                /// </summary>
375
                /// <returns></returns>
376
                public SortEntitiesTable CreateSortEntitiesTable()
377
                {
64✔
378
                        CadDictionary dictionary = this.CreateExtendedDictionary();
64✔
379

380
                        if (dictionary.TryGetEntry(SortEntitiesTable.DictionaryEntryName, out SortEntitiesTable table))
64✔
381
                        {
61✔
382
                                return table;
61✔
383
                        }
384

385
                        table = new SortEntitiesTable(this);
3✔
386

387
                        dictionary.Add(table);
3✔
388

389
                        return table;
3✔
390
                }
64✔
391

392
                /// <summary>
393
                /// Get the bounding box for all the entities in the block.
394
                /// </summary>
395
                /// <returns></returns>
396
                public BoundingBox GetBoundingBox()
397
                {
4✔
398
                        return this.GetBoundingBox(true);
4✔
399
                }
4✔
400

401
                /// <summary>
402
                /// Get the bounding box for all the entities in the block.
403
                /// </summary>
404
                /// <param name="ignoreInfinite">Ignore infinite entities, default: true</param>
405
                /// <returns></returns>
406
                public BoundingBox GetBoundingBox(bool ignoreInfinite)
407
                {
4✔
408
                        BoundingBox box = BoundingBox.Null;
4✔
409
                        foreach (var item in this.Entities)
60✔
410
                        {
24✔
411
                                if (item.GetBoundingBox().Extent == BoundingBoxExtent.Infinite
24!
412
                                        && ignoreInfinite)
24✔
413
                                {
×
414
                                        continue;
×
415
                                }
416

417
                                box = box.Merge(item.GetBoundingBox());
24✔
418
                        }
24✔
419

420
                        return box;
4✔
421
                }
4✔
422

423
                /// <summary>
424
                /// Get the entities in this block record sorted by it's handle and the sorter assigned if is present.
425
                /// </summary>
426
                /// <remarks>
427
                /// If the record is not in a document the entities will not be sorted unless there is a
428
                /// <see cref="SortEntitiesTable"/> assigned to the block.
429
                /// </remarks>
430
                /// <returns></returns>
431
                public IEnumerable<Entity> GetSortedEntities()
432
                {
×
433
                        if (this.SortEntitiesTable != null)
×
434
                        {
×
435
                                return this.Entities.OrderBy(e => e.Handle);
×
436
                        }
437

438
                        List<(ulong, Entity)> entities = new();
×
439

440
                        foreach (var entity in this.Entities)
×
441
                        {
×
442
                                ulong sorter = this.SortEntitiesTable.GetSorterHandle(entity);
×
443
                                entities.Add((sorter, entity));
×
444
                        }
×
445

446
                        return entities.OrderBy(e => e.Item1).Select(e => e.Item2);
×
447
                }
×
448

449
                internal override void AssignDocument(CadDocument doc)
450
                {
15,444✔
451
                        base.AssignDocument(doc);
15,444✔
452

453
                        doc.RegisterCollection(this.Entities);
15,444✔
454
                }
15,444✔
455

456
                internal override void UnassignDocument()
457
                {
5✔
458
                        this.Document.UnregisterCollection(this.Entities);
5✔
459

460
                        base.UnassignDocument();
5✔
461
                }
5✔
462
        }
463
}
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