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

DomCR / ACadSharp / 28004914840

23 Jun 2026 05:40AM UTC coverage: 76.868% (-0.3%) from 77.204%
28004914840

Pull #1019

github

web-flow
Merge 650fbff88 into 7f35d38e6
Pull Request #1019: Add mechanical entities and proxy graphics

8925 of 12557 branches covered (71.08%)

Branch coverage included in aggregate %.

513 of 899 new or added lines in 44 files covered. (57.06%)

6 existing lines in 1 file now uncovered.

32287 of 41057 relevant lines covered (78.64%)

155058.53 hits per line

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

67.55
/src/ACadSharp/Entities/ProxyGraphics/ProxyGeometry.cs
1
using ACadSharp.IO;
2
using ACadSharp.IO.DWG;
3
using CSMath;
4
using CSUtilities.Converters;
5
using CSUtilities.IO;
6
using System;
7
using System.Collections.Generic;
8
using System.Diagnostics;
9
using System.Linq;
10
using System.Text;
11

12
namespace ACadSharp.Entities.ProxyGraphics;
13

14
// "TODO: VALIDATE" comments used to indicate type parser that have not yet been tested
15

16
public class ProxyGeometry
17
{
18
        internal static IEnumerable<IProxyGeometry> ReadGeometries(CadDocumentBuilder builder, byte[] arr)
19
        {
3,246✔
20
                List<IProxyGeometry> geometries = new();
3,246✔
21

22
                StreamIO stream = new StreamIO(arr);
3,246✔
23
                stream.EndianConverter = new LittleEndianConverter();
3,246✔
24
                var size = stream.ReadInt();
3,246✔
25
                var count = stream.ReadInt();
3,246✔
26

27
                for (int i = 0; i < count; i++)
367,836✔
28
                {
180,672✔
29
                        var objSize = stream.ReadInt(); //Includes size and type
180,672✔
30
                        GraphicsType type = (GraphicsType)stream.ReadInt();
180,672✔
31

32
                        var pos = stream.Position;
180,672✔
33

34
                        switch (type)
180,672!
35
                        {
36
                                case GraphicsType.Extents:
NEW
37
                                        geometries.Add(readExtents(stream));
×
NEW
38
                                        break;
×
39
                                case GraphicsType.Circle:
40
                                        geometries.Add(readCircle(stream));
441✔
41
                                        break;
441✔
42
                                case GraphicsType.CirclePt3:
NEW
43
                                        geometries.Add(readCirclePt3(stream));
×
NEW
44
                                        break;
×
45
                                case GraphicsType.CircularArc:
NEW
46
                                        geometries.Add(readCircularArc(stream));
×
NEW
47
                                        break;
×
48
                                case GraphicsType.CircularArc3Pt:
NEW
49
                                        geometries.Add(readCircularArc3Pt(stream));
×
NEW
50
                                        break;
×
51
                                case GraphicsType.Polyline:
52
                                        geometries.Add(readPolyline(stream));
45,282✔
53
                                        break;
45,282✔
54
                                case GraphicsType.Polygon:
55
                                        geometries.Add(readPolygon(stream));
2,205✔
56
                                        break;
2,205✔
57
                                case GraphicsType.Mesh:
NEW
58
                                        geometries.Add(readMesh(stream));
×
NEW
59
                                        break;
×
60
                                case GraphicsType.Shell:
61
                                        geometries.Add(readShell(stream));
147✔
62
                                        break;
147✔
63
                                case GraphicsType.Text:
NEW
64
                                        geometries.Add(readText(stream));
×
NEW
65
                                        break;
×
66
                                case GraphicsType.Text2:
67
                                        geometries.Add(readText2(stream));
3,717✔
68
                                        break;
3,717✔
69
                                case GraphicsType.XLine:
NEW
70
                                        geometries.Add(readXLine(stream));
×
NEW
71
                                        break;
×
72
                                case GraphicsType.Ray:
NEW
73
                                        geometries.Add(readRay(stream));
×
NEW
74
                                        break;
×
75
                                case GraphicsType.SubentColor:
76
                                        geometries.Add(readSubentColor(stream));
3,024✔
77
                                        break;
3,024✔
78
                                case GraphicsType.SubentLayer:
79
                                        geometries.Add(readSubentLayer(stream));
4,116✔
80
                                        break;
4,116✔
81
                                case GraphicsType.SubentLineType:
82
                                        geometries.Add(readSubentLineType(stream));
14,322✔
83
                                        break;
14,322✔
84
                                case GraphicsType.SubentMarker:
85
                                        geometries.Add(readSubentMarker(stream));
49,245✔
86
                                        break;
49,245✔
87
                                case GraphicsType.SubentFillon:
88
                                        geometries.Add(readSubentFillon(stream));
5,586✔
89
                                        break;
5,586✔
90
                                case GraphicsType.SubentTrueColor:
91
                                        geometries.Add(readSubentTrueColor(stream));
16,842✔
92
                                        break;
16,842✔
93
                                case GraphicsType.SubentLineWeight:
94
                                        geometries.Add(readSubentLineWeight(stream));
12,999✔
95
                                        break;
12,999✔
96
                                case GraphicsType.SubentLineTypeScale:
97
                                        geometries.Add(readSubentLineTypeScale(stream));
882✔
98
                                        break;
882✔
99
                                case GraphicsType.SubentThickness:
100
                                        geometries.Add(readSubentThickness(stream));
882✔
101
                                        break;
882✔
102
                                case GraphicsType.SubentPlotStyleName:
103
                                        geometries.Add(readSubentPlotStyleName(stream));
882✔
104
                                        break;
882✔
105
                                case GraphicsType.PushClip:
NEW
106
                                        geometries.Add(readPushClip(stream));
×
NEW
107
                                        break;
×
108
                                case GraphicsType.PopClip:
NEW
109
                                        geometries.Add(readPopClip(stream));
×
NEW
110
                                        break;
×
111
                                case GraphicsType.PushModelTransform:
112
                                        geometries.Add(readPushModelTransform(stream));
840✔
113
                                        break;
840✔
114
                                case GraphicsType.PushModelTransform2:
NEW
115
                                        geometries.Add(readPushModelTransform2(stream));
×
NEW
116
                                        break;
×
117
                                case GraphicsType.PophModelTransform:
118
                                        geometries.Add(readPopModelTransform(stream));
840✔
119
                                        break;
840✔
120
                                case GraphicsType.PolylineWithNormal:
121
                                        geometries.Add(readPolylineWithNormal(stream));
3,255✔
122
                                        break;
3,255✔
123
                                case GraphicsType.LwPolyine:
NEW
124
                                        geometries.Add(readLwPolyine(builder, stream));
×
NEW
125
                                        break;
×
126
                                case GraphicsType.SubEntityMaterial:
127
                                        geometries.Add(readSubEntityMaterial(stream));
630✔
128
                                        break;
630✔
129
                                case GraphicsType.SubEntityMapper:
NEW
130
                                        geometries.Add(readSubEntityMapper(stream));
×
NEW
131
                                        break;
×
132
                                case GraphicsType.UnicodeText:
133
                                        geometries.Add(readUnicodeText(stream));
12✔
134
                                        break;
12✔
135
                                case GraphicsType.Unknown37:
NEW
136
                                        geometries.Add(readUnknown37(stream));
×
NEW
137
                                        break;
×
138
                                case GraphicsType.UnicodeText2:
139
                                        geometries.Add(readUnicodeText2(stream));
4,956✔
140
                                        break;
4,956✔
141
                                case GraphicsType.Unknown:
142
                                default:
143
                                        // Type 51 (size 12, data: zeros)
144
                                        break;
9,567✔
145
                        }
146

147
                        long readDiff = objSize - (stream.Position - pos) - 8;
180,672✔
148
                        if (readDiff > 0)
180,672✔
149
                        {
9,702✔
150
                                //jump not implemented proxies
151
                                stream.ReadBytes((int) readDiff);
9,702✔
152
                        }
9,702✔
153
                }
180,672✔
154

155
                return geometries;
3,246✔
156
        }
3,246✔
157

158
        private static IProxyGeometry readCircle(StreamIO stream)
159
        {
441✔
160
                ProxyCircle circle = new ProxyCircle();
441✔
161
                circle.Center = readPoint(stream);
441✔
162
                circle.Radius = stream.ReadDouble();
441✔
163
                circle.Normal = readPoint(stream);
441✔
164
                return circle;
441✔
165
        }
441✔
166

167
        private static IProxyGeometry readCirclePt3(StreamIO stream)
NEW
168
        {
×
NEW
169
                ProxyCirclePt3 circle = new ProxyCirclePt3();
×
170

NEW
171
                circle.Point1 = readPoint(stream);
×
NEW
172
                circle.Point2 = readPoint(stream);
×
NEW
173
                circle.Point3 = readPoint(stream);
×
174

NEW
175
                Debugger.Break();        // TODO: VALIDATE
×
NEW
176
                return circle;
×
NEW
177
        }
×
178

179
        private static IProxyGeometry readCircularArc(StreamIO stream)
NEW
180
        {
×
NEW
181
                ProxyCircularArc arc = new ProxyCircularArc();
×
182

NEW
183
                arc.Center = readPoint(stream);
×
NEW
184
                arc.Radius = stream.ReadDouble();
×
NEW
185
                arc.Normal = readPoint(stream);
×
NEW
186
                arc.StartVectorDirection = readPoint(stream);
×
NEW
187
                arc.SweepAngle = stream.ReadDouble();
×
NEW
188
                arc.ArcType = stream.ReadInt();
×
189

NEW
190
                return arc;
×
NEW
191
        }
×
192

193
        private static IProxyGeometry readCircularArc3Pt(StreamIO stream)
NEW
194
        {
×
NEW
195
                ProxyCircularArc3Pt arc = new ProxyCircularArc3Pt();
×
196

NEW
197
                arc.Point1 = readPoint(stream);
×
NEW
198
                arc.Point2 = readPoint(stream);
×
NEW
199
                arc.Point3 = readPoint(stream);
×
NEW
200
                arc.ArcType = stream.ReadInt();
×
201

NEW
202
                return arc;
×
NEW
203
        }
×
204

205
        private static IProxyGeometry readExtents(StreamIO stream)
NEW
206
        {
×
NEW
207
                ProxyExtents extents = new ProxyExtents();
×
208

NEW
209
                extents.Min = readPoint(stream);
×
NEW
210
                extents.Max = readPoint(stream);
×
211

NEW
212
                return extents;
×
NEW
213
        }
×
214

215
        private static IProxyGeometry readLwPolyine(CadDocumentBuilder builder, StreamIO stream)
NEW
216
        {
×
NEW
217
                int dataSize = stream.ReadInt();
×
NEW
218
                ProxyLwPolyine polyline = new ProxyLwPolyine();
×
219

NEW
220
                IDwgStreamReader reader = DwgStreamReaderBase.GetStreamHandler(builder.Version, stream.Stream);
×
221

NEW
222
                polyline.Entity = new LwPolyline();
×
NEW
223
                DwgObjectReader.readLWPolyline(reader, builder.Version, polyline.Entity);
×
224
                // TODO: Read LwPolyline entity w/o common data
225

NEW
226
                polyline.Unknown1 = stream.ReadByte();
×
NEW
227
                polyline.Unknown2 = stream.ReadByte();
×
NEW
228
                polyline.Unknown3 = stream.ReadByte();
×
229

NEW
230
                return polyline;
×
NEW
231
        }
×
232

233
        private static IProxyGeometry readMesh(StreamIO stream)
NEW
234
        {
×
NEW
235
                throw new NotImplementedException();
×
236
        }
237

238
        private static IProxyGeometry readPolygon(StreamIO stream)
239
        {
2,205✔
240
                ProxyPolygon polygon = new ProxyPolygon();
2,205✔
241
                polygon.Points = [];
2,205✔
242

243
                int pointCount = stream.ReadInt();
2,205✔
244
                for (int i = 0; i < pointCount; i++)
17,640✔
245
                {
6,615✔
246
                        polygon.Points.Add(readPoint(stream));
6,615✔
247
                }
6,615✔
248

249
                return polygon;
2,205✔
250
        }
2,205✔
251

252
        private static IProxyGeometry readPolyline(StreamIO stream)
253
        {
45,282✔
254
                ProxyPolyline polyline = new ProxyPolyline();
45,282✔
255
                int pointCount = stream.ReadInt();
45,282✔
256
                for (int i = 0; i < pointCount; i++)
279,720✔
257
                {
94,578✔
258
                        polyline.Points.Add(readPoint(stream));
94,578✔
259
                }
94,578✔
260
                return polyline;
45,282✔
261
        }
45,282✔
262

263
        private static IProxyGeometry readPolylineWithNormal(StreamIO stream)
264
        {
3,255✔
265
                ProxyPolylineWithNormal polyline = new ProxyPolylineWithNormal();
3,255✔
266

267
                int pointCount = stream.ReadInt();
3,255✔
268
                for (int i = 0; i < pointCount; i++)
19,530✔
269
                {
6,510✔
270
                        polyline.Points.Add(readPoint(stream));
6,510✔
271
                }
6,510✔
272
                polyline.Normal = readPoint(stream);
3,255✔
273

274
                return polyline;
3,255✔
275
        }
3,255✔
276

277
        private static IProxyGeometry readPopClip(StreamIO stream)
NEW
278
        {
×
NEW
279
                return new ProxyPopClip();
×
NEW
280
        }
×
281

282
        private static IProxyGeometry readPopModelTransform(StreamIO stream)
283
        {
840✔
284
                return new ProxyPopModelTransform();
840✔
285
        }
840✔
286

287
        private static IProxyGeometry readPushClip(StreamIO stream)
NEW
288
        {
×
NEW
289
                ProxyPushClip clip = new ProxyPushClip();
×
290

NEW
291
                clip.Extrusion = readPoint(stream);
×
NEW
292
                clip.ClipBoundaryOrigin = readPoint(stream);
×
NEW
293
                clip.PointCount = stream.ReadInt();
×
NEW
294
                clip.Points = [];
×
NEW
295
                for (int i = 0; i < clip.PointCount; i++)
×
NEW
296
                {
×
NEW
297
                        clip.Points.Add(new XY(stream.ReadDouble(), stream.ReadDouble()));
×
NEW
298
                }
×
NEW
299
                clip.ClipBoundaryTransformMatrix = readMatrix(stream);
×
NEW
300
                clip.InverseBlockTransformMatrix = readMatrix(stream);
×
NEW
301
                clip.FrontClipOn = stream.ReadInt();
×
NEW
302
                clip.BackClipOn = stream.ReadInt();
×
NEW
303
                clip.FrontClip = stream.ReadDouble();
×
NEW
304
                clip.BackClip = stream.ReadDouble();
×
NEW
305
                clip.DrawBoundary = stream.ReadInt() == 1;
×
306

NEW
307
                Debugger.Break();    // TODO: VALIDATE
×
NEW
308
                return clip;
×
NEW
309
        }
×
310

311
        private static IProxyGeometry readPushModelTransform(StreamIO stream)
312
        {
840✔
313
                ProxyPushModelTransform modelTransform = new ProxyPushModelTransform();
840✔
314

315
                modelTransform.TransformationMatrix = readMatrix(stream);
840✔
316
                return modelTransform;
840✔
317
        }
840✔
318

319
        private static IProxyGeometry readPushModelTransform2(StreamIO stream)
NEW
320
        {
×
NEW
321
                throw new NotImplementedException();
×
322
        }
323

324
        private static IProxyGeometry readRay(StreamIO stream)
NEW
325
        {
×
NEW
326
                ProxyRay ray = new ProxyRay();
×
327

NEW
328
                ray.ConstructionLinePoint = readPoint(stream);
×
NEW
329
                ray.Point2 = readPoint(stream);
×
330

NEW
331
                Debugger.Break();    // TODO: VALIDATE
×
NEW
332
                return ray;
×
NEW
333
        }
×
334

335
        private static IProxyGeometry readShell(StreamIO stream)
336
        {
147✔
337
                ProxyShell shell = new ProxyShell();
147✔
338

339
                Func<int, bool> adHasPrimTraits = a => (a & 0xFFFFL) != 0;
588✔
340
                Func<int, bool> adPrimsHaveColors = a => (a & 0x0001L) != 0;
441✔
341
                Func<int, bool> adPrimsHaveLayers = a => (a & 0x0002L) != 0;
441✔
342
                Func<int, bool> adPrimsHaveLinetypes = a => (a & 0x0004L) != 0;
441✔
343
                Func<int, bool> adPrimsHaveMarkers = a => (a & 0x0020L) != 0;
441✔
344
                Func<int, bool> adPrimsHaveVisibilities = a => (a & 0x0040L) != 0;
441✔
345
                Func<int, bool> adPrimsHaveNormals = a => (a & 0x0080L) != 0;
294✔
346
                Func<int, bool> adPrimsHaveOrientation = a => (a & 0x0400L) != 0;
294✔
347

348
                shell.PointCount = stream.ReadInt();
147✔
349
                shell.Vertices = [];
147✔
350
                for (int i = 0; i < shell.PointCount; i++) {
2,058✔
351
                        shell.Vertices.Add(readPoint(stream));
588✔
352
                }
588✔
353
                shell.FaceCount = stream.ReadInt();
147✔
354
                shell.Faces = [];
147✔
355
                List<int> face = [];
147✔
356
                for (int i = 0; i < shell.FaceCount; i++) {
2,499✔
357
                        int value = stream.ReadInt();
735✔
358
                        if (value < 0) {
735!
NEW
359
                                int vertexCount = value * -1;
×
NEW
360
                                shell.Faces.Add(face);
×
NEW
361
                                face = [];
×
NEW
362
                                for (int j = 0; j < vertexCount; j++) {
×
NEW
363
                                        face.Add(stream.ReadInt());
×
NEW
364
                                }
×
NEW
365
                                shell.Faces.Add(face);
×
NEW
366
                                face = [];
×
NEW
367
                        }
×
368
                        else {
735✔
369
                                // TODO: Check if this ever happens and if so, if this is correct
370
                                face.Add(value);
735✔
371
                        }
735✔
372
                }
735✔
373
                if (face.Count > 0) {
294✔
374
                        shell.Faces.Add(face);
147✔
375
                }
147✔
376

377
                // TODO: Validate and fix the below logic
378

379
                int edgePrimitiveFlags = stream.ReadInt();
147✔
380
                if (adHasPrimTraits(edgePrimitiveFlags)) {
294✔
381
                        // TODO: Actually get edge count
382
                        if (adPrimsHaveColors(edgePrimitiveFlags)) {
147!
NEW
383
                                int edgeColor = stream.ReadInt();                // color for each edge
×
NEW
384
                        }
×
385
                        if (adPrimsHaveLayers(edgePrimitiveFlags)) {
147!
NEW
386
                                int layerIds = stream.ReadInt();                // layer ids, 1 for each edge
×
NEW
387
                        }
×
388
                        if (adPrimsHaveLinetypes(edgePrimitiveFlags)) {
147!
NEW
389
                                int linetypeIds = stream.ReadInt();                // linetype ids, 1 for each edge
×
NEW
390
                        }
×
391
                        if (adPrimsHaveMarkers(edgePrimitiveFlags)) {
294✔
392
                                int markerIndices = stream.ReadInt();        // marker indices, 1 for each edge
147✔
393
                        }
147✔
394
                        if (adPrimsHaveVisibilities(edgePrimitiveFlags)) {
294✔
395
                                for (int i = 0; i < shell.Faces.SelectMany(x => x).Where(x => x >= 0 && x < shell.Vertices.Count).Distinct().Count(); i++) {
6,468!
396
                                        int visibilityIndicator = stream.ReadInt();                // visibility indicator, 1 for each edge
588✔
397
                                }
588✔
398
                        }
147✔
399
                }
147✔
400

401
                int facePrimitiveFlags = stream.ReadInt();
147✔
402
                if (adHasPrimTraits(facePrimitiveFlags)) {
294✔
403
                        if (adPrimsHaveColors(facePrimitiveFlags)) {
294✔
404
                                int edgeColor = stream.ReadInt();                // color for each face
147✔
405
                        }
147✔
406
                        if (adPrimsHaveLayers(facePrimitiveFlags)) {
147!
NEW
407
                                int layerIds = stream.ReadInt();        // layer ids, 1 for each face
×
NEW
408
                        }
×
409
                        if (adPrimsHaveLinetypes(facePrimitiveFlags)) {
147!
NEW
410
                                int linetypeIds = stream.ReadInt();     // linetype ids, 1 for each face
×
NEW
411
                        }
×
412
                        if (adPrimsHaveMarkers(facePrimitiveFlags)) {
147!
NEW
413
                                int markerIndices = stream.ReadInt();   // marker indices, 1 for each face
×
NEW
414
                        }
×
415
                        if (adPrimsHaveVisibilities(facePrimitiveFlags)) {
147!
NEW
416
                                int visibilityIndicator = stream.ReadInt();     // visibility indicator, 1 for each face
×
NEW
417
                        }
×
418
                }
147✔
419

420
                int vertexPrimitiveFlags = stream.ReadInt();
147✔
421
                if (adHasPrimTraits(vertexPrimitiveFlags)) {
294✔
422
                        int vertexCount = /* TODO: rows * cols */ 0;
147✔
423
                        if (adPrimsHaveNormals(vertexPrimitiveFlags)) {
147!
NEW
424
                                XYZ normal = readPoint(stream);                        // normal, 1 for each vertex
×
NEW
425
                        }
×
426
                        if (adPrimsHaveOrientation(vertexPrimitiveFlags)) {
147!
NEW
427
                                int orientation = stream.ReadInt();                // orientation indicator, 1 ONLY
×
NEW
428
                        }
×
429
                }
147✔
430

431
                return shell;
147✔
432
        }
147✔
433

434
        private static IProxyGeometry readSubentColor(StreamIO stream)
435
        {
3,024✔
436
                ProxySubentColor color = new ProxySubentColor();
3,024✔
437

438
                color.ColorIndex = stream.ReadInt();
3,024✔
439

440
                if (color.ColorIndex > 256) Debugger.Break();        // seen 257
3,024!
441

442
                return color;
3,024✔
443
        }
3,024✔
444

445
        private static IProxyGeometry readSubentFillon(StreamIO stream)
446
        {
5,586✔
447
                ProxySubentFillon fillOn = new ProxySubentFillon();
5,586✔
448

449
                int fillValue = stream.ReadInt();
5,586✔
450
                fillOn.IsOn = fillValue == 1;        // Also seen value 2 as well
5,586✔
451

452
                return fillOn;
5,586✔
453
        }
5,586✔
454

455
        private static IProxyGeometry readSubEntityMapper(StreamIO stream)
NEW
456
        {
×
NEW
457
                ProxySubEntityMapper mapper = new ProxySubEntityMapper();
×
458

NEW
459
                mapper.DummyValue1 = stream.ReadInt();
×
NEW
460
                mapper.DummyValue2 = stream.ReadInt();
×
NEW
461
                mapper.Projection = stream.ReadInt();
×
NEW
462
                mapper.UTiling = stream.ReadInt();
×
NEW
463
                mapper.VTiling = stream.ReadInt();
×
NEW
464
                mapper.AutoTransform = stream.ReadInt();
×
NEW
465
                mapper.DummyValue3 = stream.ReadInt();
×
466

NEW
467
                Debugger.Break();    // TODO: VALIDATE
×
NEW
468
                return mapper;
×
NEW
469
        }
×
470

471
        private static IProxyGeometry readSubEntityMaterial(StreamIO stream)
472
        {
630✔
473
                ProxySubEntityMaterial material = new ProxySubEntityMaterial();
630✔
474

475
                //material.MaterialHandle = new DwgStreamReaderAC24(stream.Stream, false).HandleReference();
476
                material.MaterialHandle = (ulong) stream.ReadInt();
630✔
477
                int unknown1 = stream.ReadInt();
630✔
478

479
                return material;
630✔
480
        }
630✔
481

482
        private static IProxyGeometry readSubentLayer(StreamIO stream)
483
        {
4,116✔
484
                ProxySubentLayer layer = new ProxySubentLayer();
4,116✔
485

486
                layer.LayerIndex = stream.ReadInt();
4,116✔
487

488
                return layer;
4,116✔
489
        }
4,116✔
490

491
        private static IProxyGeometry readSubentLineType(StreamIO stream)
492
        {
14,322✔
493
                ProxySubentLineType lineType = new ProxySubentLineType();
14,322✔
494

495
                lineType.LineTypeIndex = stream.ReadUInt();
14,322✔
496

497
                return lineType;
14,322✔
498
        }
14,322✔
499

500
        private static IProxyGeometry readSubentLineTypeScale(StreamIO stream)
501
        {
882✔
502
                ProxySubentLineTypeScale scale = new ProxySubentLineTypeScale();
882✔
503

504
                scale.LineTypeScale = stream.ReadDouble();
882✔
505

506
                return scale;
882✔
507
        }
882✔
508

509
        private static IProxyGeometry readSubentLineWeight(StreamIO stream)
510
        {
12,999✔
511
                ProxySubentLineWeight lineWeight= new ProxySubentLineWeight();
12,999✔
512

513
                lineWeight.LineWeight = (LineWeightType) stream.ReadInt();
12,999✔
514

515
                return lineWeight;
12,999✔
516
        }
12,999✔
517

518
        private static IProxyGeometry readSubentMarker(StreamIO stream)
519
        {
49,245✔
520
                ProxySubentMarker marker = new ProxySubentMarker();
49,245✔
521

522
                marker.MarkerIndex = stream.ReadInt();
49,245✔
523

524
                return marker;
49,245✔
525
        }
49,245✔
526

527
        private static IProxyGeometry readSubentPlotStyleName(StreamIO stream)
528
        {
882✔
529
                ProxySubentPlotStyleName psName = new ProxySubentPlotStyleName();
882✔
530

531
                psName.Type = (ProxyPlotStyleType) stream.ReadInt();
882✔
532
                psName.PlotStyleIndex = stream.ReadInt();
882✔
533

534
                return psName;
882✔
535
        }
882✔
536

537
        private static IProxyGeometry readSubentThickness(StreamIO stream)
538
        {
882✔
539
                ProxySubentThickness thickness = new ProxySubentThickness();
882✔
540

541
                thickness.Thickness = stream.ReadDouble();
882✔
542

543
                return thickness;
882✔
544
        }
882✔
545

546
        private static IProxyGeometry readSubentTrueColor(StreamIO stream)
547
        {
16,842✔
548
                ProxySubentTrueColor trueColor = new ProxySubentTrueColor();
16,842✔
549

550
                // The first three bytes are the value and the fourth byte indicates how
551
                // those 3 previous bytes should be interpreted (see https://help.autodesk.com/view/OARX/2025/ENU/?guid=OARX-RefGuide-AcGiSubEntityTraits__setTrueColor_AcCmEntityColor_)
552

553
                byte b1 = stream.ReadByte();
16,842✔
554
                byte b2 = stream.ReadByte();
16,842✔
555
                byte b3 = stream.ReadByte();
16,842✔
556
                ProxyColorMethod method = (ProxyColorMethod) stream.ReadByte();
16,842✔
557

558
                switch (method) 
16,842!
559
                {
560
                        case ProxyColorMethod.ByLayer:
561
                                trueColor.Color = Color.ByLayer;
9,849✔
562
                                break;
9,849✔
563
                        case ProxyColorMethod.ByBlock:
NEW
564
                                trueColor.Color = Color.ByBlock;
×
NEW
565
                                break;
×
566
                        case ProxyColorMethod.ByColor:
NEW
567
                                trueColor.Color = new Color(b1, b2, b3);
×
NEW
568
                                break;
×
569
                        case ProxyColorMethod.ByACI:
570
                                trueColor.Color = new Color(b1);
6,993✔
571
                                break;
6,993✔
572
                        case ProxyColorMethod.Foreground:
NEW
573
                                trueColor.Color = new Color(7);        // TODO: Check if this is what foreground actually means
×
NEW
574
                                break;
×
575
                        case ProxyColorMethod.None:
NEW
576
                                break;
×
577
                        default:
NEW
578
                                break;
×
579
                }
580

581
                return trueColor;
16,842✔
582
        }
16,842✔
583

584
        private static IProxyGeometry readText(StreamIO stream)
NEW
585
        {
×
NEW
586
                ProxyText text = new ProxyText();
×
587

NEW
588
                text.StartPoint = readPoint(stream);
×
NEW
589
                text.Normal = readPoint(stream);
×
NEW
590
                text.TextDirection = readPoint(stream);
×
NEW
591
                text.Height = stream.ReadDouble();
×
NEW
592
                text.WidthFactor = stream.ReadDouble();
×
NEW
593
                text.ObliqueAngle = stream.ReadDouble();
×
NEW
594
                text.Text = readPaddedString(stream);
×
595

596
                // Padding to align the text to the next 4-byte boundary
NEW
597
                if ((text.Text.Length + 1) % 4 != 0)
×
NEW
598
                {
×
NEW
599
                        stream.ReadBytes(4 - (text.Text.Length + 1) % 4);
×
NEW
600
                }
×
601

NEW
602
                return text;
×
NEW
603
        }
×
604

605
        private static IProxyGeometry readText2(StreamIO stream)
606
        {
3,717✔
607
                ProxyText2 text = new ProxyText2();
3,717✔
608
                text.StartPoint = readPoint(stream);
3,717✔
609
                text.Normal = readPoint(stream);
3,717✔
610
                text.TextDirection = readPoint(stream);
3,717✔
611
                text.Text = readPaddedString(stream);
3,717✔
612

613
                // Padding to align the text to the next 4-byte boundary
614
                if ((text.Text.Length + 1) % 4 != 0)
3,717✔
615
                {
2,205✔
616
                        stream.ReadBytes(4 - (text.Text.Length + 1) % 4);
2,205✔
617
                }
2,205✔
618

619
                text.TextLength = stream.ReadInt();
3,717✔
620
                text.IsRaw = stream.ReadInt() == 0;
3,717✔
621
                text.Height = stream.ReadDouble();
3,717✔
622
                text.WidthFactor = stream.ReadDouble();
3,717✔
623
                text.ObliqueAngle = stream.ReadDouble();
3,717✔
624
                text.TrackingPercentage = stream.ReadDouble();
3,717✔
625

626
                text.IsBackwards = stream.ReadInt() == 1;
3,717✔
627
                text.IsUpsideDown = stream.ReadInt() == 1;
3,717✔
628
                text.IsVertical = stream.ReadInt() == 1;
3,717✔
629
                text.IsUnderlined = stream.ReadInt() == 1;
3,717✔
630
                text.IsOverlined = stream.ReadInt() == 1;
3,717✔
631

632
                text.FontFilename = readPaddedString(stream);
3,717✔
633

634
                // Padding to align the text to the next 4-byte boundary
635
                if ((text.FontFilename.Length + 1) % 4 != 0)
3,717✔
636
                {
3,717✔
637
                        stream.ReadBytes(4 - (text.FontFilename.Length + 1) % 4);
3,717✔
638
                }
3,717✔
639

640
                text.BigFontFilename = readPaddedString(stream);
3,717✔
641

642
                // Padding to align the text to the next 4-byte boundary
643
                if ((text.BigFontFilename.Length + 1) % 4 != 0)
3,717✔
644
                {
3,717✔
645
                        stream.ReadBytes(4 - (text.BigFontFilename.Length + 1) % 4);
3,717✔
646
                }
3,717✔
647

648
                return text;
3,717✔
649
        }
3,717✔
650

651
        private static IProxyGeometry readUnicodeText(StreamIO stream)
652
        {
12✔
653
                ProxyUnicodeText text = new ProxyUnicodeText();
12✔
654

655
                text.StartPoint = readPoint(stream);
12✔
656
                text.Normal = readPoint(stream);
12✔
657
                text.TextDirection = readPoint(stream);
12✔
658
                text.Height = stream.ReadDouble();
12✔
659
                text.WidthFactor = stream.ReadDouble();
12✔
660
                text.ObliqueAngle = stream.ReadDouble();
12✔
661
                text.Text = readPaddedUnicodeString(stream);
12✔
662

663
                // Padding to align the text to the next 4-byte boundary
664
                if (text.Text.Length % 2 == 0)
12!
NEW
665
                {
×
NEW
666
                        stream.ReadShort();
×
NEW
667
                }
×
668

669
                return text;
12✔
670
        }
12✔
671

672
        private static IProxyGeometry readUnicodeText2(StreamIO stream)
673
        {
4,956✔
674
                ProxyUnicodeText2 text = new ProxyUnicodeText2();
4,956✔
675
                text.StartPoint = readPoint(stream);
4,956✔
676
                text.Normal = readPoint(stream);
4,956✔
677
                text.TextDirection = readPoint(stream);
4,956✔
678
                text.Text = readPaddedUnicodeString(stream);
4,956✔
679

680
                // Padding to align the text to the next 4-byte boundary
681
                if (text.Text.Length % 2 == 0)
4,956✔
682
                {
2,184✔
683
                        stream.ReadShort();
2,184✔
684
                }
2,184✔
685

686
                text.TextLength = stream.ReadInt();
4,956✔
687
                text.IsRaw = stream.ReadInt() == 0;
4,956✔
688
                text.Height = stream.ReadDouble();
4,956✔
689
                text.WidthFactor = stream.ReadDouble();
4,956✔
690
                text.ObliqueAngle = stream.ReadDouble();
4,956✔
691
                text.TrackingPercentage = stream.ReadDouble();
4,956✔
692

693
                text.IsBackwards = stream.ReadInt() == 1;
4,956✔
694
                text.IsUpsideDown = stream.ReadInt() == 1;
4,956✔
695
                text.IsVertical = stream.ReadInt() == 1;
4,956✔
696
                text.IsUnderlined = stream.ReadInt() == 1;
4,956✔
697
                text.IsOverlined = stream.ReadInt() == 1;
4,956✔
698

699
                TrueTypeFontDescriptor fontDescriptor = new TrueTypeFontDescriptor();
4,956✔
700
                fontDescriptor.IsBold = stream.ReadInt() == 1;
4,956✔
701
                fontDescriptor.IsItalic = stream.ReadInt() == 1;
4,956✔
702
                fontDescriptor.Charset = (byte)stream.ReadInt();
4,956✔
703
                fontDescriptor.PitchAndFamily = (byte)stream.ReadInt();
4,956✔
704
                fontDescriptor.Typeface = readPaddedUnicodeString(stream);
4,956✔
705

706
                // Padding to align the text to the next 4-byte boundary
707
                if (fontDescriptor.Typeface.Length % 2 == 0)
4,956!
NEW
708
                {
×
NEW
709
                        stream.ReadShort();
×
NEW
710
                }
×
711

712
                fontDescriptor.FontFilename = readPaddedUnicodeString(stream);
4,956✔
713

714
                // Padding to align the text to the next 4-byte boundary
715
                if (fontDescriptor.FontFilename.Length % 2 == 0)
4,956✔
716
                {
4,956✔
717
                        stream.ReadShort();
4,956✔
718
                }
4,956✔
719

720
                text.FontDescriptor = fontDescriptor;
4,956✔
721
                text.BigFontFilename = readPaddedUnicodeString(stream);
4,956✔
722

723
                // Padding to align the text to the next 4-byte boundary
724
                if (fontDescriptor.FontFilename.Length % 2 == 0)
4,956✔
725
                {
4,956✔
726
                        stream.ReadShort();
4,956✔
727
                }
4,956✔
728

729
                return text;
4,956✔
730
        }
4,956✔
731

732
        private static IProxyGeometry readUnknown37(StreamIO stream)
NEW
733
        {
×
NEW
734
                Debugger.Break();    // TODO: VALIDATE
×
NEW
735
                return new ProxyUnknown37();
×
NEW
736
        }
×
737

738
        private static IProxyGeometry readXLine(StreamIO stream)
NEW
739
        {
×
NEW
740
                ProxyXLine xline = new ProxyXLine();
×
741

NEW
742
                xline.Point1 = readPoint(stream);
×
NEW
743
                xline.Point2 = readPoint(stream);
×
744

NEW
745
                return xline;
×
NEW
746
        }
×
747

748
        private static XYZ readPoint(StreamIO stream)
749
        {
138,483✔
750
                var x = stream.ReadDouble();
138,483✔
751
                var y = stream.ReadDouble();
138,483✔
752
                var z = stream.ReadDouble();
138,483✔
753
                return new XYZ(x, y, z);
138,483✔
754
        }
138,483✔
755

756
        private static Matrix4 readMatrix(StreamIO stream)
757
        {
840✔
758
                Matrix4 matrix = Matrix4.Identity;
840✔
759
                matrix.M00 = stream.ReadDouble();
840✔
760
                matrix.M01 = stream.ReadDouble();
840✔
761
                matrix.M02 = stream.ReadDouble();
840✔
762
                matrix.M03 = stream.ReadDouble();
840✔
763
                matrix.M10 = stream.ReadDouble();
840✔
764
                matrix.M11 = stream.ReadDouble();
840✔
765
                matrix.M12 = stream.ReadDouble();
840✔
766
                matrix.M13 = stream.ReadDouble();
840✔
767
                matrix.M20 = stream.ReadDouble();
840✔
768
                matrix.M21 = stream.ReadDouble();
840✔
769
                matrix.M22 = stream.ReadDouble();
840✔
770
                matrix.M23 = stream.ReadDouble();
840✔
771
                matrix.M30 = stream.ReadDouble();
840✔
772
                matrix.M31 = stream.ReadDouble();
840✔
773
                matrix.M32 = stream.ReadDouble();
840✔
774
                matrix.M33 = stream.ReadDouble();
840✔
775
                return matrix;
840✔
776
        }
840✔
777

778
        /// <summary>
779
        /// PUS : Padded Unicode string, The bytes are encoded using Unicode encoding. 
780
        /// The bytes consist of byte pairs and the string is terminated by 2 zero bytes.
781
        /// </summary>
782
        /// <returns></returns>
783
        private static string readPaddedUnicodeString(StreamIO stream)
784
        {
19,836✔
785
                byte[] nullTerminator = new byte[] { 0, 0 };
19,836✔
786

787
                List<byte> stringBytes = new List<byte>();
19,836✔
788
                byte[] character;
789
                while (!(character = stream.ReadBytes(2)).AsSpan().SequenceEqual(nullTerminator))
86,676✔
790
                {
66,840✔
791
                        stringBytes.AddRange(character);
66,840✔
792
                }
66,840✔
793
                return Encoding.Unicode.GetString(stringBytes.ToArray());
19,836✔
794
        }
19,836✔
795

796
        /// <summary>
797
        /// PS : Padded string. This is a string, terminated with a zero byte.
798
        /// The file’s text encoding (code page) is used to encode / decode 
799
        /// the bytes into a string
800
        /// </summary>
801
        /// <returns></returns>
802
        private static string readPaddedString(StreamIO stream)
803
        {
11,151✔
804
                List<byte> stringBytes = new List<byte>();
11,151✔
805
                byte character;
806
                while ((character = stream.ReadByte()) != 0)
61,047✔
807
                {
49,896✔
808
                        stringBytes.Add(character);
49,896✔
809
                }
49,896✔
810
                return stream.Encoding.GetString(stringBytes.ToArray());
11,151✔
811
        }
11,151✔
812

813
        public enum ProxyColorMethod : byte
814
        {
815
                ByLayer = 0xC0,
816
                ByBlock = 0xC1,
817
                ByColor = 0xC2,
818
                ByACI = 0xC3,
819
                Foreground = 0xC5,
820
                None = 0xC8
821
        }
822
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc