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

DomCR / ACadSharp / 14734578702

29 Apr 2025 03:02PM UTC coverage: 75.022% (-0.004%) from 75.026%
14734578702

Pull #648

github

web-flow
Merge a6bbe69a7 into 12bc8deed
Pull Request #648: MText rotation fix

5716 of 8383 branches covered (68.19%)

Branch coverage included in aggregate %.

25 of 28 new or added lines in 1 file covered. (89.29%)

2 existing lines in 1 file now uncovered.

22805 of 29634 relevant lines covered (76.96%)

82140.59 hits per line

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

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

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

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

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

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

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

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

57
                public TextColumn Column { get; set; } = new TextColumn();
15,494✔
58

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

65
                /// <inheritdoc/>
66
                [DxfCodeValue(40)]
67
                public double Height
68
                {
69
                        get => this._height;
789✔
70
                        set
71
                        {
12,898✔
72
                                if (value < 0)
12,898!
73
                                        throw new ArgumentOutOfRangeException("Height value cannot be negative.");
×
74
                                else
75
                                        this._height = value;
12,898✔
76
                        }
12,898✔
77
                }
78

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

89
                /// <summary>
90
                /// A 3D WCS coordinate representing the insertion or origin point.
91
                /// </summary>
92
                [DxfCodeValue(10, 20, 30)]
93
                public XYZ InsertPoint { get; set; } = XYZ.Zero;
66,749✔
94

95
                public bool IsAnnotative { get; set; } = false;
14,206✔
96

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

106
                /// <summary>
107
                /// Mtext line spacing style.
108
                /// </summary>
109
                [DxfCodeValue(73)]
110
                public LineSpacingStyleType LineSpacingStyle { get; set; }
12,996✔
111

112
                /// <summary>
113
                /// Specifies the three-dimensional normal unit vector for the object.
114
                /// </summary>
115
                [DxfCodeValue(210, 220, 230)]
116
                public XYZ Normal { get; set; } = XYZ.AxisZ;
18,370✔
117

118
                /// <inheritdoc/>
119
                public override string ObjectName => DxfFileToken.EntityMText;
1,410✔
120

121
                /// <inheritdoc/>
122
                public override ObjectType ObjectType => ObjectType.MTEXT;
1✔
123

124
                /// <summary>
125
                /// Reference rectangle height.
126
                /// </summary>
127
                [DxfCodeValue(46)]
128
                public double RectangleHeight { get; set; }
8,754✔
129

130
                /// <summary>
131
                /// Reference rectangle width.
132
                /// </summary>
133
                [DxfCodeValue(41)]
134
                public double RectangleWidth { get; set; }
13,685✔
135

136
                /// <summary>
137
                /// Specifies the rotation angle for the object.
138
                /// </summary>
139
                /// <remarks>
140
                /// The rotation is only valid if the <see cref="Normal"/> is set to the Z axis.
141
                /// </remarks>
142
                /// <value>
143
                /// The rotation angle in radians.
144
                /// </value>
145
                [DxfCodeValue(DxfReferenceType.IsAngle | DxfReferenceType.Ignored, 50)]
146
                public double Rotation
147
                {
148
                        get
NEW
149
                        {
×
NEW
150
                                return new XY(this.AlignmentPoint.X, this.AlignmentPoint.Y).GetAngle();
×
NEW
151
                        }
×
152
                }
153

154
                /// <inheritdoc/>
155
                [DxfCodeValue(DxfReferenceType.Name | DxfReferenceType.Optional, 7)]
156
                public TextStyle Style
157
                {
158
                        get { return this._style; }
43,026✔
159
                        set
160
                        {
5,324✔
161
                                if (value == null)
5,324!
162
                                {
×
163
                                        throw new ArgumentNullException(nameof(value));
×
164
                                }
165

166
                                if (this.Document != null)
5,324✔
167
                                {
4,793✔
168
                                        this._style = this.updateTable(value, this.Document.TextStyles);
4,793✔
169
                                }
4,793✔
170
                                else
171
                                {
531✔
172
                                        this._style = value;
531✔
173
                                }
531✔
174
                        }
5,324✔
175
                }
176

177
                /// <inheritdoc/>
178
                public override string SubclassMarker => DxfSubclassMarker.MText;
150,518✔
179

180
                /// <inheritdoc/>
181
                [DxfCodeValue(1)]
182
                public string Value { get; set; } = string.Empty;
40,115✔
183

184
                /// <summary>
185
                /// Vertical height of the mtext entity
186
                /// </summary>
187
                /// <remarks>
188
                /// read-only, ignored if supplied
189
                /// </remarks>
190
                [DxfCodeValue(DxfReferenceType.Ignored, 43)]
191
                public double VerticalHeight { get; set; } = 0.2;
12,904✔
192

193
                private double _height = 1.0;
12,747✔
194

195
                private TextStyle _style = TextStyle.Default;
12,747✔
196

197
                /// <inheritdoc/>
198
                public MText() : base() { }
38,241✔
199

200
                /// <inheritdoc/>
201
                public override void ApplyTransform(Transform transform)
202
                {
×
203
                        XYZ newInsert = transform.ApplyTransform(this.InsertPoint);
×
204
                        XYZ newNormal = this.transformNormal(transform, this.Normal);
×
205

206
                        var transformation = this.getWorldMatrix(transform, Normal, newNormal, out Matrix3 transOW, out Matrix3 transWO);
×
207

208
                        transWO = transWO.Transpose();
×
209

210
                        List<XY> uv = applyRotation(
×
211
                                new[]
×
212
                                {
×
213
                                        XY.AxisX, XY.AxisY
×
214
                                },
×
215
                                this.Rotation);
×
216

217
                        XYZ v;
218
                        v = transOW * new XYZ(uv[0].X, uv[0].Y, 0.0);
×
219
                        v = transformation * v;
×
220
                        v = transWO * v;
×
221
                        XY newUvector = new XY(v.X, v.Y);
×
222

223
                        // the MText entity does not support non-uniform scaling
224
                        double scale = newUvector.GetLength();
×
225

226
                        v = transOW * new XYZ(uv[1].X, uv[1].Y, 0.0);
×
227
                        v = transformation * v;
×
228
                        v = transWO * v;
×
229
                        XY newVvector = new XY(v.X, v.Y);
×
230

231
                        double newRotation = newUvector.GetAngle();
×
232

233
                        if (XY.Cross(newUvector, newVvector) < 0.0)
×
234
                        {
×
235
                                if (newUvector.Dot(uv[0]) < 0.0)
×
236
                                {
×
237
                                        newRotation += 180;
×
238

239
                                        switch (this.AttachmentPoint)
×
240
                                        {
241
                                                case AttachmentPointType.TopLeft:
242
                                                        this.AttachmentPoint = AttachmentPointType.TopRight;
×
243
                                                        break;
×
244
                                                case AttachmentPointType.TopRight:
245
                                                        this.AttachmentPoint = AttachmentPointType.TopLeft;
×
246
                                                        break;
×
247
                                                case AttachmentPointType.MiddleLeft:
248
                                                        this.AttachmentPoint = AttachmentPointType.MiddleRight;
×
249
                                                        break;
×
250
                                                case AttachmentPointType.MiddleRight:
251
                                                        this.AttachmentPoint = AttachmentPointType.MiddleLeft;
×
252
                                                        break;
×
253
                                                case AttachmentPointType.BottomLeft:
254
                                                        this.AttachmentPoint = AttachmentPointType.BottomRight;
×
255
                                                        break;
×
256
                                                case AttachmentPointType.BottomRight:
257
                                                        this.AttachmentPoint = AttachmentPointType.BottomLeft;
×
258
                                                        break;
×
259
                                        }
260
                                }
×
261
                                else
262
                                {
×
263
                                        switch (this.AttachmentPoint)
×
264
                                        {
265
                                                case AttachmentPointType.TopLeft:
266
                                                        this.AttachmentPoint = AttachmentPointType.BottomLeft;
×
267
                                                        break;
×
268
                                                case AttachmentPointType.TopCenter:
269
                                                        this.AttachmentPoint = AttachmentPointType.BottomCenter;
×
270
                                                        break;
×
271
                                                case AttachmentPointType.TopRight:
272
                                                        this.AttachmentPoint = AttachmentPointType.BottomRight;
×
273
                                                        break;
×
274
                                                case AttachmentPointType.BottomLeft:
275
                                                        this.AttachmentPoint = AttachmentPointType.TopLeft;
×
276
                                                        break;
×
277
                                                case AttachmentPointType.BottomCenter:
278
                                                        this.AttachmentPoint = AttachmentPointType.TopCenter;
×
279
                                                        break;
×
280
                                                case AttachmentPointType.BottomRight:
281
                                                        this.AttachmentPoint = AttachmentPointType.TopRight;
×
282
                                                        break;
×
283
                                        }
284
                                }
×
285
                        }
×
286

287
                        double newHeight = this.Height * scale;
×
288
                        newHeight = MathHelper.IsZero(newHeight) ? MathHelper.Epsilon : newHeight;
×
289

290
                        this.InsertPoint = newInsert;
×
291
                        this.Normal = newNormal;
×
292
                        this.Height = newHeight;
×
293
                        this.RectangleWidth *= scale;
×
294
                }
×
295

296
                /// <inheritdoc/>
297
                public override CadObject Clone()
298
                {
363✔
299
                        MText clone = (MText)base.Clone();
363✔
300

301
                        clone.Style = (TextStyle)(this.Style?.Clone());
363!
302
                        clone.Column = this.Column?.Clone();
363!
303

304
                        return clone;
363✔
305
                }
363✔
306

307
                /// <inheritdoc/>
308
                public override BoundingBox GetBoundingBox()
309
                {
5✔
310
                        return new BoundingBox(this.InsertPoint);
5✔
311
                }
5✔
312

313
                /// <summary>
314
                /// Get the text value separated in lines.
315
                /// </summary>
316
                /// <returns></returns>
317
                public string[] GetTextLines()
318
                {
2✔
319
                        return this.Value.Split(
2✔
320
                                new string[] { "\r\n", "\r", "\n", "\\P" },
2✔
321
                                StringSplitOptions.None
2✔
322
                        );
2✔
323
                }
2✔
324

325
                internal override void AssignDocument(CadDocument doc)
326
                {
13,060✔
327
                        base.AssignDocument(doc);
13,060✔
328

329
                        this._style = this.updateTable(this.Style, doc.TextStyles);
13,060✔
330

331
                        doc.DimensionStyles.OnRemove += this.tableOnRemove;
13,060✔
332
                }
13,060✔
333

334
                internal override void UnassignDocument()
335
                {
130✔
336
                        this.Document.DimensionStyles.OnRemove -= this.tableOnRemove;
130✔
337

338
                        base.UnassignDocument();
130✔
339

340
                        this.Style = (TextStyle)this.Style.Clone();
130✔
341
                }
130✔
342

343
                protected override void tableOnRemove(object sender, CollectionChangedEventArgs e)
344
                {
×
345
                        base.tableOnRemove(sender, e);
×
346

347
                        if (e.Item.Equals(this.Style))
×
348
                        {
×
349
                                this.Style = this.Document.TextStyles[TextStyle.DefaultName];
×
350
                        }
×
351
                }
×
352
        }
353
}
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