• 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

58.03
/src/ACadSharp/Entities/MText.cs
1
using ACadSharp.Attributes;
2
using ACadSharp.Tables;
3
using ACadSharp.Text;
4
using CSMath;
5
using System;
6
using System.Collections.Generic;
7

8
namespace ACadSharp.Entities
9
{
10
        /// <summary>
11
        /// Represents a <see cref="MText"/> entity.
12
        /// </summary>
13
        /// <remarks>
14
        /// Object name <see cref="DxfFileToken.EntityMText"/> <br/>
15
        /// Dxf class name <see cref="DxfSubclassMarker.MText"/>
16
        /// </remarks>
17
        [DxfName(DxfFileToken.EntityMText)]
18
        [DxfSubClass(DxfSubclassMarker.MText)]
19
        public partial class MText : Entity, IText
20
        {
21
                /// <inheritdoc/>
22
                [DxfCodeValue(11, 21, 31)]
23
                public XYZ AlignmentPoint { get; set; } = XYZ.AxisX;
28,499✔
24

25
                /// <summary>
26
                /// Attachment point
27
                /// </summary>
28
                [DxfCodeValue(71)]
29
                public AttachmentPointType AttachmentPoint { get; set; } = AttachmentPointType.TopLeft;
27,942✔
30

31
                /// <summary>
32
                /// Background fill color
33
                /// </summary>
34
                /// <remarks>
35
                /// Color to use for background fill when group code 90 is 1.
36
                /// </remarks>
37
                [DxfCodeValue(63, 421, 430)]
38
                public Color BackgroundColor { get; set; }
196✔
39

40
                /// <summary>
41
                /// Background fill setting
42
                /// </summary>
43
                [DxfCodeValue(90)]
44
                public BackgroundFillFlags BackgroundFillFlags { get; set; } = BackgroundFillFlags.None;
21,537✔
45

46
                /// <summary>
47
                /// Determines how much border there is around the text.
48
                /// </summary>
49
                [DxfCodeValue(45)]
50
                public double BackgroundScale { get; set; } = 1.5;
14,116✔
51

52
                /// <summary>
53
                /// Transparency of background fill color
54
                /// </summary>
55
                [DxfCodeValue(441)]
56
                public Transparency BackgroundTransparency { get; set; }
576✔
57

58
                public TextColumn Column { get; set; } = new TextColumn();
16,735✔
59

60
                /// <summary>
61
                /// Drawing direction
62
                /// </summary>
63
                [DxfCodeValue(72)]
64
                public DrawingDirectionType DrawingDirection { get; set; } = DrawingDirectionType.LeftToRight;
27,761✔
65

66
                /// <inheritdoc/>
67
                [DxfCodeValue(40)]
68
                public double Height
69
                {
70
                        get => this._height;
1,059✔
71
                        set
72
                        {
13,468✔
73
                                if (value <= 0)
13,468!
NEW
74
                                {
×
NEW
75
                                        throw new ArgumentOutOfRangeException(nameof(value), value, "The MText height must be greater than zero.");
×
76
                                }
77
                                else
78
                                        this._height = value;
13,468✔
79
                        }
13,468✔
80
                }
81

82
                /// <summary>
83
                /// Horizontal width of the characters that make up the mtext entity.
84
                /// This value will always be equal to or less than the value of group code 41
85
                /// </summary>
86
                /// <remarks>
87
                /// read-only, ignored if supplied
88
                /// </remarks>
89
                [DxfCodeValue(DxfReferenceType.Ignored, 42)]
90
                public double HorizontalWidth { get; set; } = 0.9;
13,564✔
91

92
                /// <summary>
93
                /// A 3D WCS coordinate representing the insertion or origin point.
94
                /// </summary>
95
                [DxfCodeValue(10, 20, 30)]
96
                public XYZ InsertPoint { get; set; } = XYZ.Zero;
70,461✔
97

98
                public bool IsAnnotative { get; set; } = false;
14,876✔
99

100
                /// <summary>
101
                /// Mtext line spacing factor.
102
                /// </summary>
103
                /// <remarks>
104
                /// Percentage of default (3-on-5) line spacing to be applied.Valid values range from 0.25 to 4.00
105
                /// </remarks>
106
                [DxfCodeValue(44)]
107
                public double LineSpacing { get; set; } = 1.0;
27,083✔
108

109
                /// <summary>
110
                /// Mtext line spacing style.
111
                /// </summary>
112
                [DxfCodeValue(73)]
113
                public LineSpacingStyleType LineSpacingStyle { get; set; }
13,697✔
114

115
                /// <summary>
116
                /// Specifies the three-dimensional normal unit vector for the object.
117
                /// </summary>
118
                [DxfCodeValue(210, 220, 230)]
119
                public XYZ Normal { get; set; } = XYZ.AxisZ;
19,301✔
120

121
                /// <inheritdoc/>
122
                public override string ObjectName => DxfFileToken.EntityMText;
39,915✔
123

124
                /// <inheritdoc/>
125
                public override ObjectType ObjectType => ObjectType.MTEXT;
182✔
126

127
                /// <summary>
128
                /// Gets the plain text representation of the processed value.
129
                /// </summary>
130
                /// <remarks>This property processes the underlying value and returns its plain text equivalent. The parsing
131
                /// operation may involve removing formatting or extracting meaningful content.</remarks>
132
                public string PlainText
133
                {
134
                        get
135
                        {
7✔
136
                                return TextProcessor.Parse(this.Value, out _);
7✔
137
                        }
7✔
138
                }
139

140
                /// <summary>
141
                /// Reference rectangle height.
142
                /// </summary>
143
                [DxfCodeValue(46)]
144
                public double RectangleHeight { get; set; }
9,243✔
145

146
                /// <summary>
147
                /// Reference rectangle width.
148
                /// </summary>
149
                [DxfCodeValue(41)]
150
                public double RectangleWidth { get; set; }
14,425✔
151

152
                /// <inheritdoc/>
153
                /// <remarks>
154
                /// The rotation is only valid if the <see cref="Normal"/> is set to the Z axis.
155
                /// </remarks>
156
                [DxfCodeValue(DxfReferenceType.IsAngle | DxfReferenceType.Ignored, 50)]
157
                public double Rotation
158
                {
159
                        get
160
                        {
16✔
161
                                return new XY(this.AlignmentPoint.X, this.AlignmentPoint.Y).GetAngle();
16✔
162
                        }
16✔
163
                }
164

165
                /// <inheritdoc/>
166
                [DxfCodeValue(DxfReferenceType.Name | DxfReferenceType.Optional, 7)]
167
                public TextStyle Style
168
                {
169
                        get { return this._style; }
47,388✔
170
                        set
171
                        {
5,620✔
172
                                if (value == null)
5,620!
173
                                {
×
174
                                        throw new ArgumentNullException(nameof(value));
×
175
                                }
176

177
                                if (this.Document != null)
5,620✔
178
                                {
4,793✔
179
                                        this._style = CadObject.updateCollection(value, this.Document.TextStyles);
4,793✔
180
                                }
4,793✔
181
                                else
182
                                {
827✔
183
                                        this._style = value;
827✔
184
                                }
827✔
185
                        }
5,620✔
186
                }
187

188
                /// <inheritdoc/>
189
                public override string SubclassMarker => DxfSubclassMarker.MText;
158,427✔
190

191
                /// <inheritdoc/>
192
                [DxfCodeValue(1)]
193
                public string Value { get; set; } = string.Empty;
42,391✔
194

195
                /// <summary>
196
                /// Vertical height of the mtext entity
197
                /// </summary>
198
                /// <remarks>
199
                /// read-only, ignored if supplied
200
                /// </remarks>
201
                [DxfCodeValue(DxfReferenceType.Ignored, 43)]
202
                public double VerticalHeight { get; set; } = 0.2;
13,564✔
203

204
                private double _height = 1.0d;
13,380✔
205

206
                private TextStyle _style = TextStyle.Default;
13,380✔
207

208
                /// <inheritdoc/>
209
                public MText() : base() { }
40,119✔
210

211
                /// <summary>
212
                /// Initializes a new instance of the <see cref="MText"/> class with the specified text value.
213
                /// </summary>
214
                /// <param name="value">The text value to initialize the instance with. Cannot be <see langword="null"/>.</param>
215
                public MText(string value) : base()
7✔
216
                {
7✔
217
                        this.Value = value;
7✔
218
                }
7✔
219

220
                /// <inheritdoc/>
221
                public override void ApplyTransform(Transform transform)
222
                {
10✔
223
                        XYZ newInsert = transform.ApplyTransform(this.InsertPoint);
10✔
224
                        XYZ newNormal = this.transformNormal(transform, this.Normal);
10✔
225

226
                        var transformation = this.getWorldMatrix(transform, Normal, newNormal, out Matrix3 transOW, out Matrix3 transWO);
10✔
227

228
                        transWO = transWO.Transpose();
10✔
229

230
                        List<XY> uv = applyRotation(
10✔
231
                                new[]
10✔
232
                                {
10✔
233
                                        XY.AxisX, XY.AxisY
10✔
234
                                },
10✔
235
                                this.Rotation);
10✔
236

237
                        XYZ v;
238
                        v = transOW * new XYZ(uv[0].X, uv[0].Y, 0.0);
10✔
239
                        v = transformation * v;
10✔
240
                        v = transWO * v;
10✔
241
                        XY newUvector = new XY(v.X, v.Y);
10✔
242

243
                        // the MText entity does not support non-uniform scaling
244
                        double scale = newUvector.GetLength();
10✔
245

246
                        v = transOW * new XYZ(uv[1].X, uv[1].Y, 0.0);
10✔
247
                        v = transformation * v;
10✔
248
                        v = transWO * v;
10✔
249
                        XY newVvector = new XY(v.X, v.Y);
10✔
250

251
                        double newRotation = newUvector.GetAngle();
10✔
252

253
                        if (XY.Cross(newUvector, newVvector) < 0.0)
10!
254
                        {
×
255
                                if (newUvector.Dot(uv[0]) < 0.0)
×
256
                                {
×
257
                                        newRotation += 180;
×
258

259
                                        switch (this.AttachmentPoint)
×
260
                                        {
261
                                                case AttachmentPointType.TopLeft:
262
                                                        this.AttachmentPoint = AttachmentPointType.TopRight;
×
263
                                                        break;
×
264
                                                case AttachmentPointType.TopRight:
265
                                                        this.AttachmentPoint = AttachmentPointType.TopLeft;
×
266
                                                        break;
×
267
                                                case AttachmentPointType.MiddleLeft:
268
                                                        this.AttachmentPoint = AttachmentPointType.MiddleRight;
×
269
                                                        break;
×
270
                                                case AttachmentPointType.MiddleRight:
271
                                                        this.AttachmentPoint = AttachmentPointType.MiddleLeft;
×
272
                                                        break;
×
273
                                                case AttachmentPointType.BottomLeft:
274
                                                        this.AttachmentPoint = AttachmentPointType.BottomRight;
×
275
                                                        break;
×
276
                                                case AttachmentPointType.BottomRight:
277
                                                        this.AttachmentPoint = AttachmentPointType.BottomLeft;
×
278
                                                        break;
×
279
                                        }
280
                                }
×
281
                                else
282
                                {
×
283
                                        switch (this.AttachmentPoint)
×
284
                                        {
285
                                                case AttachmentPointType.TopLeft:
286
                                                        this.AttachmentPoint = AttachmentPointType.BottomLeft;
×
287
                                                        break;
×
288
                                                case AttachmentPointType.TopCenter:
289
                                                        this.AttachmentPoint = AttachmentPointType.BottomCenter;
×
290
                                                        break;
×
291
                                                case AttachmentPointType.TopRight:
292
                                                        this.AttachmentPoint = AttachmentPointType.BottomRight;
×
293
                                                        break;
×
294
                                                case AttachmentPointType.BottomLeft:
295
                                                        this.AttachmentPoint = AttachmentPointType.TopLeft;
×
296
                                                        break;
×
297
                                                case AttachmentPointType.BottomCenter:
298
                                                        this.AttachmentPoint = AttachmentPointType.TopCenter;
×
299
                                                        break;
×
300
                                                case AttachmentPointType.BottomRight:
301
                                                        this.AttachmentPoint = AttachmentPointType.TopRight;
×
302
                                                        break;
×
303
                                        }
304
                                }
×
305
                        }
×
306

307
                        double newHeight = this.Height * scale;
10✔
308
                        newHeight = MathHelper.IsZero(newHeight) ? MathHelper.Epsilon : newHeight;
10!
309

310
                        this.InsertPoint = newInsert;
10✔
311
                        this.Normal = newNormal;
10✔
312
                        this.Height = newHeight;
10✔
313
                        this.RectangleWidth *= scale;
10✔
314
                }
10✔
315

316
                /// <inheritdoc/>
317
                public override CadObject Clone()
318
                {
649✔
319
                        MText clone = (MText)base.Clone();
649✔
320

321
                        clone.Style = (TextStyle)(this.Style?.Clone());
649!
322
                        clone.Column = this.Column?.Clone();
649!
323

324
                        return clone;
649✔
325
                }
649✔
326

327
                /// <inheritdoc/>
328
                public override BoundingBox GetBoundingBox()
329
                {
6✔
330
                        return new BoundingBox(this.InsertPoint);
6✔
331
                }
6✔
332

333
                /// <summary>
334
                /// Splits the plain text into an array of lines based on common line break sequences.
335
                /// </summary>
336
                /// <remarks>The method splits the text using the following line break sequences:  carriage return and line feed
337
                /// ("\r\n"), carriage return ("\r"), line feed ("\n"), and the Unicode paragraph separator ("\P").
338
                /// The resulting array includes all lines, including empty ones.
339
                /// </remarks>
340
                /// <returns>An array of strings, where each string represents a line of text. The array may contain empty strings if the plain
341
                /// text includes consecutive line break sequences.</returns>
342
                public string[] GetPlainTextLines()
343
                {
×
344
                        return this.PlainText.Split(
×
345
                                new string[] { "\r\n", "\r", "\n", "\\P" },
×
346
                                StringSplitOptions.None
×
347
                        );
×
348
                }
×
349

350
                /// <summary>
351
                /// Splits the text into an array of lines based on common line break sequences.
352
                /// </summary>
353
                /// <remarks>The method splits the text using the following line break sequences: carriage return and line feed
354
                /// ("\r\n"), carriage return ("\r"),  line feed ("\n"), and the Unicode paragraph separator ("\P").
355
                /// The resulting array includes all lines, including empty ones.
356
                /// </remarks>
357
                /// <returns>
358
                /// An array of strings, where each string represents a line of text. The array may contain empty strings if the
359
                /// text includes consecutive line break sequences.
360
                /// </returns>
361
                public string[] GetTextLines()
362
                {
5✔
363
                        return this.Value.Split(
5✔
364
                                new string[] { "\r\n", "\r", "\n", "\\P" },
5✔
365
                                StringSplitOptions.None
5✔
366
                        );
5✔
367
                }
5✔
368

369
                internal override void AssignDocument(CadDocument doc)
370
                {
13,958✔
371
                        base.AssignDocument(doc);
13,958✔
372

373
                        this._style = CadObject.updateCollection(this.Style, doc.TextStyles);
13,958✔
374

375
                        doc.DimensionStyles.OnRemove += this.tableOnRemove;
13,958✔
376
                }
13,958✔
377

378
                internal override void UnassignDocument()
379
                {
130✔
380
                        this.Document.DimensionStyles.OnRemove -= this.tableOnRemove;
130✔
381

382
                        base.UnassignDocument();
130✔
383

384
                        this.Style = (TextStyle)this.Style.Clone();
130✔
385
                }
130✔
386

387
                protected override void tableOnRemove(object sender, CollectionChangedEventArgs e)
388
                {
×
389
                        base.tableOnRemove(sender, e);
×
390

391
                        if (e.Item.Equals(this.Style))
×
392
                        {
×
393
                                this.Style = this.Document.TextStyles[TextStyle.DefaultName];
×
394
                        }
×
395
                }
×
396
        }
397
}
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