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

DomCR / ACadSharp / 20092767827

10 Dec 2025 08:52AM UTC coverage: 77.865% (-0.02%) from 77.88%
20092767827

push

github

web-flow
Merge pull request #913 from DomCR/issue-912_AC1015-dwgwriter

Issue 912 AC1015 dwgwriter

7574 of 10565 branches covered (71.69%)

Branch coverage included in aggregate %.

37 of 43 new or added lines in 7 files covered. (86.05%)

20 existing lines in 3 files now uncovered.

28139 of 35300 relevant lines covered (79.71%)

162340.96 hits per line

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

57.42
/src/ACadSharp/Entities/TextEntity.cs
1
using ACadSharp.Attributes;
2
using ACadSharp.Tables;
3
using CSMath;
4
using CSUtilities.Extensions;
5
using System;
6
using System.Collections.Generic;
7

8
namespace ACadSharp.Entities
9
{
10
        /// <summary>
11
        /// Represents a <see cref="TextEntity"/>
12
        /// </summary>
13
        /// <remarks>
14
        /// Object name <see cref="DxfFileToken.EntityText"/> <br/>
15
        /// Dxf class name <see cref="DxfSubclassMarker.Text"/>
16
        /// </remarks>
17
        [DxfName(DxfFileToken.EntityText)]
18
        [DxfSubClass(DxfSubclassMarker.Text)]
19
        public class TextEntity : Entity, IText
20
        {
21
                /// <summary>
22
                /// Second alignment point (in OCS)
23
                /// </summary>
24
                /// <remarks>
25
                /// This value is meaningful only if the value of a 72 or 73 group is nonzero (if the justification is anything other than baseline/left)
26
                /// </remarks>
27
                [DxfCodeValue(DxfReferenceType.Optional, 11, 21, 31)]
28
                public XYZ AlignmentPoint { get; set; }
7,940✔
29

30
                /// <inheritdoc/>
31
                [DxfCodeValue(40)]
32
                public double Height
33
                {
34
                        get => this._height;
1,192✔
35
                        set
36
                        {
24,419✔
37
                                if (value <= 0)
24,419!
NEW
38
                                        throw new ArgumentOutOfRangeException(nameof(value), value, "The Text height must be greater than zero.");
×
39
                                else
40
                                        this._height = value;
24,419✔
41
                        }
24,419✔
42
                }
43

44
                /// <summary>
45
                /// Horizontal text justification type.
46
                /// </summary>
47
                [DxfCodeValue(72)]
48
                public TextHorizontalAlignment HorizontalAlignment { get; set; } = TextHorizontalAlignment.Left;
26,803✔
49

50
                /// <summary>
51
                /// First alignment point(in OCS)
52
                /// </summary>
53
                [DxfCodeValue(10, 20, 30)]
54
                public XYZ InsertPoint { get; set; } = XYZ.Zero;
146,988✔
55

56
                /// <summary>
57
                /// Mirror flags.
58
                /// </summary>
59
                [DxfCodeValue(71)]
60
                public TextMirrorFlag Mirror { get => this._mirror; set => this._mirror = value; }
2,031✔
61

62
                /// <summary>
63
                /// Specifies the three-dimensional normal unit vector for the object.
64
                /// </summary>
65
                [DxfCodeValue(210, 220, 230)]
66
                public XYZ Normal { get; set; } = XYZ.AxisZ;
30,775✔
67

68
                /// <inheritdoc/>
69
                public override string ObjectName => DxfFileToken.EntityText;
32,023✔
70

71
                /// <inheritdoc/>
72
                public override ObjectType ObjectType => ObjectType.TEXT;
98✔
73

74
                /// <summary>
75
                /// Specifies the oblique angle of the object.
76
                /// </summary>
77
                /// <value>
78
                /// The angle in radians within the range of -85 to +85 degrees. A positive angle denotes a lean to the right; a negative value will have 2*PI added to it to convert it to its positive equivalent.
79
                /// </value>
80
                [DxfCodeValue(DxfReferenceType.IsAngle, 51)]
81
                public double ObliqueAngle { get; set; } = 0.0;
26,411✔
82

83
                /// <inheritdoc/>
84
                [DxfCodeValue(DxfReferenceType.IsAngle, 50)]
85
                public double Rotation { get; set; }
2,548✔
86

87
                /// <inheritdoc/>
88
                [DxfCodeValue(DxfReferenceType.Name | DxfReferenceType.Optional, 7)]
89
                public TextStyle Style
90
                {
91
                        get { return this._style; }
84,699✔
92
                        set
93
                        {
9,907✔
94
                                if (value == null)
9,907!
95
                                {
×
96
                                        throw new ArgumentNullException(nameof(value));
×
97
                                }
98

99
                                if (this.Document != null)
9,907✔
100
                                {
8,267✔
101
                                        this._style = CadObject.updateCollection(value, this.Document.TextStyles);
8,267✔
102
                                }
8,267✔
103
                                else
104
                                {
1,640✔
105
                                        this._style = value;
1,640✔
106
                                }
1,640✔
107
                        }
9,907✔
108
                }
109

110
                /// <inheritdoc/>
111
                public override string SubclassMarker => DxfSubclassMarker.Text;
156,539✔
112

113
                /// <summary>
114
                /// Specifies the distance a 2D object is extruded above or below its elevation.
115
                /// </summary>
116
                [DxfCodeValue(39)]
117
                public double Thickness { get; set; } = 0.0;
29,702✔
118

119
                /// <inheritdoc/>
120
                /// <value>
121
                /// The maximum length is 256 characters.
122
                /// </value>
123
                [DxfCodeValue(1)]
124
                public string Value
125
                {
126
                        get
127
                        {
1,189✔
128
                                return this._value;
1,189✔
129
                        }
1,189✔
130
                        set
131
                        {
24,413✔
132
                                if (value.Length > 256)
24,413!
133
                                        throw new ArgumentException($"Text length cannot be supiror than 256, current: {value.Length}");
×
134
                                else
135
                                        this._value = value;
24,413✔
136
                        }
24,413✔
137
                }
138

139
                /// <summary>
140
                /// Vertical text justification type.
141
                /// </summary>
142
                [DxfCodeValue(DxfReferenceType.Optional, 73)]
143
                public virtual TextVerticalAlignmentType VerticalAlignment { get; set; } = TextVerticalAlignmentType.Baseline;
25,926✔
144

145
                /// <summary>
146
                /// Relative X scale factor—widt
147
                /// </summary>
148
                /// <remarks>
149
                /// This value is also adjusted when fit-type text is used
150
                /// </remarks>
151
                [DxfCodeValue(DxfReferenceType.Optional, 41)]
152
                public double WidthFactor { get; set; } = 1.0;
26,412✔
153

154
                private double _height = 1.0d;
24,455✔
155

156
                private TextMirrorFlag _mirror = TextMirrorFlag.None;
24,455✔
157

158
                private TextStyle _style = TextStyle.Default;
24,455✔
159

160
                private string _value = string.Empty;
24,455✔
161

162
                public TextEntity() : base()
24,455✔
163
                {
24,455✔
164
                }
24,455✔
165

166
                /// <inheritdoc/>
167
                public override void ApplyTransform(Transform transform)
168
                {
1✔
169
                        bool mirrText = this.Mirror.HasFlag(TextMirrorFlag.Backward);
1✔
170

171
                        XYZ newInsert = transform.ApplyTransform(this.InsertPoint);
1✔
172
                        XYZ newNormal = this.transformNormal(transform, this.Normal);
1✔
173

174
                        var transformation = this.getWorldMatrix(transform, this.Normal, newNormal, out Matrix3 transOW, out Matrix3 transWO);
1✔
175

176
                        List<XY> uv = this.applyRotation(
1✔
177
                                new[]
1✔
178
                                {
1✔
179
                                        this.WidthFactor * this.Height * XY.AxisX,
1✔
180
                                        new XY(this.Height * Math.Tan(this.ObliqueAngle), this.Height)
1✔
181
                                },
1✔
182
                                this.Rotation);
1✔
183

184
                        XYZ v;
185
                        v = transOW * new XYZ(uv[0].X, uv[0].Y, 0.0);
1✔
186
                        v = transformation * v;
1✔
187
                        v = transWO * v;
1✔
188
                        XY newUvector = new XY(v.X, v.Y);
1✔
189

190
                        v = transOW * new XYZ(uv[1].X, uv[1].Y, 0.0);
1✔
191
                        v = transformation * v;
1✔
192
                        v = transWO * v;
1✔
193
                        XY newVvector = new XY(v.X, v.Y);
1✔
194

195
                        double newRotation = newUvector.GetAngle();
1✔
196
                        double newObliqueAngle = newVvector.GetAngle();
1✔
197

198
                        if (mirrText)
1!
199
                        {
×
200
                                if (XY.Cross(newUvector, newVvector) < 0)
×
201
                                {
×
202
                                        newObliqueAngle = MathHelper.HalfPI - (newRotation - newObliqueAngle);
×
203
                                        if (!(this.HorizontalAlignment.HasFlag(TextHorizontalAlignment.Fit)
×
204
                                                || this.HorizontalAlignment.HasFlag(TextHorizontalAlignment.Aligned)))
×
205
                                        {
×
206
                                                newRotation += Math.PI;
×
207
                                        }
×
208

209
                                        this._mirror.RemoveFlag(TextMirrorFlag.Backward);
×
210
                                }
×
211
                                else
212
                                {
×
213
                                        newObliqueAngle = MathHelper.HalfPI + (newRotation - newObliqueAngle);
×
214
                                }
×
215
                        }
×
216
                        else
217
                        {
1✔
218
                                if (XY.Cross(newUvector, newVvector) < 0.0)
1!
219
                                {
×
220
                                        newObliqueAngle = MathHelper.HalfPI - (newRotation - newObliqueAngle);
×
221

222
                                        if (newUvector.Dot(uv[0]) < 0.0)
×
223
                                        {
×
224
                                                newRotation += Math.PI;
×
225

226
                                                switch (this.HorizontalAlignment)
×
227
                                                {
228
                                                        case TextHorizontalAlignment.Left:
229
                                                                this.HorizontalAlignment = TextHorizontalAlignment.Right;
×
230
                                                                break;
×
231
                                                        case TextHorizontalAlignment.Right:
232
                                                                this.HorizontalAlignment = TextHorizontalAlignment.Left;
×
233
                                                                break;
×
234
                                                }
235
                                        }
×
236
                                        else
237
                                        {
×
238
                                                switch (this.VerticalAlignment)
×
239
                                                {
240
                                                        case TextVerticalAlignmentType.Top:
241
                                                                this.VerticalAlignment = TextVerticalAlignmentType.Bottom;
×
242
                                                                break;
×
243
                                                        case TextVerticalAlignmentType.Bottom:
244
                                                                this.VerticalAlignment = TextVerticalAlignmentType.Top;
×
245
                                                                break;
×
246
                                                }
247
                                        }
×
248
                                }
×
249
                                else
250
                                {
1✔
251
                                        newObliqueAngle = MathHelper.HalfPI + (newRotation - newObliqueAngle);
1✔
252
                                }
1✔
253
                        }
1✔
254

255
                        // the oblique angle is defined between -85 and 85 degrees
256
                        double maxOblique = MathHelper.DegToRad(85);
1✔
257
                        double minOblique = -maxOblique;
1✔
258
                        if (newObliqueAngle > Math.PI)
1!
259
                        {
×
260
                                newObliqueAngle = Math.PI - newObliqueAngle;
×
261
                        }
×
262

263
                        if (newObliqueAngle < minOblique)
1!
264
                        {
×
265
                                newObliqueAngle = minOblique;
×
266
                        }
×
267
                        else if (newObliqueAngle > maxOblique)
1!
UNCOV
268
                        {
×
UNCOV
269
                                newObliqueAngle = maxOblique;
×
UNCOV
270
                        }
×
271

272
                        // the height must be greater than zero, the cos is always positive between -85 and 85
273
                        double newHeight = newVvector.GetLength() * Math.Cos(newObliqueAngle);
1✔
274
                        newHeight = MathHelper.IsZero(newHeight) ? MathHelper.Epsilon : newHeight;
1!
275

276
                        // the width factor is defined between 0.01 and 100
277
                        double newWidthFactor = newUvector.GetLength() / newHeight;
1✔
278
                        if (newWidthFactor < 0.01)
1!
UNCOV
279
                        {
×
UNCOV
280
                                newWidthFactor = 0.01;
×
UNCOV
281
                        }
×
282
                        else if (newWidthFactor > 100)
1!
283
                        {
×
284
                                newWidthFactor = 100;
×
285
                        }
×
286

287
                        this.InsertPoint = newInsert;
1✔
288
                        this.Normal = newNormal;
1✔
289
                        this.Rotation = newRotation;
1✔
290
                        this.Height = newHeight;
1✔
291
                        this.WidthFactor = newWidthFactor;
1✔
292
                        this.ObliqueAngle = newObliqueAngle;
1✔
293
                }
1✔
294

295
                /// <inheritdoc/>
296
                public override CadObject Clone()
297
                {
682✔
298
                        TextEntity clone = (TextEntity)base.Clone();
682✔
299
                        clone.Style = (TextStyle)this.Style.Clone();
682✔
300
                        return clone;
682✔
301
                }
682✔
302

303
                /// <inheritdoc/>
304
                public override BoundingBox GetBoundingBox()
305
                {
9✔
306
                        return new BoundingBox(this.InsertPoint);
9✔
307
                }
9✔
308

309
                internal override void AssignDocument(CadDocument doc)
310
                {
25,414✔
311
                        base.AssignDocument(doc);
25,414✔
312

313
                        this._style = CadObject.updateCollection(this.Style, doc.TextStyles);
25,414✔
314

315
                        doc.DimensionStyles.OnRemove += this.tableOnRemove;
25,414✔
316
                }
25,414✔
317

318
                internal override void UnassignDocument()
319
                {
924✔
320
                        this.Document.DimensionStyles.OnRemove -= this.tableOnRemove;
924✔
321

322
                        base.UnassignDocument();
924✔
323

324
                        this.Style = (TextStyle)this.Style.Clone();
924✔
325
                }
924✔
326

327
                protected override void tableOnRemove(object sender, CollectionChangedEventArgs e)
328
                {
×
329
                        base.tableOnRemove(sender, e);
×
330

331
                        if (e.Item.Equals(this.Style))
×
332
                        {
×
333
                                this.Style = this.Document.TextStyles[TextStyle.DefaultName];
×
334
                        }
×
335
                }
×
336
        }
337
}
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