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

DomCR / ACadSharp / 18093480635

29 Sep 2025 10:12AM UTC coverage: 77.923% (-0.4%) from 78.349%
18093480635

push

github

web-flow
Merge pull request #776 from DomCR/svg-linetypes

Svg linetypes

6787 of 9447 branches covered (71.84%)

Branch coverage included in aggregate %.

112 of 319 new or added lines in 10 files covered. (35.11%)

11 existing lines in 3 files now uncovered.

26081 of 32733 relevant lines covered (79.68%)

109509.64 hits per line

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

80.34
/src/ACadSharp/IO/SVG/SvgXmlWriter.cs
1
using ACadSharp.Entities;
2
using ACadSharp.Extensions;
3
using ACadSharp.Objects;
4
using ACadSharp.Tables;
5
using ACadSharp.Types.Units;
6
using CSMath;
7
using CSUtilities.Extensions;
8
using System;
9
using System.Collections.Generic;
10
using System.Globalization;
11
using System.IO;
12
using System.Linq;
13
using System.Text;
14
using System.Xml;
15

16
namespace ACadSharp.IO.SVG
17
{
18
        internal class SvgXmlWriter : XmlTextWriter
19
        {
20
                public event NotificationEventHandler OnNotification;
21

22
                public SvgConfiguration Configuration { get; } = new();
128✔
23

24
                public Layout Layout { get; set; }
159✔
25

26
                public UnitsType Units { get; protected set; }
8,145✔
27

NEW
28
                public SvgXmlWriter(Stream stream, SvgConfiguration configuration) : this(stream, null, configuration)
×
NEW
29
                {
×
NEW
30
                }
×
31

32
                public SvgXmlWriter(Stream stream, Encoding? encoding, SvgConfiguration configuration) : base(stream, encoding)
7✔
33
                {
7✔
34
                        this.Configuration = configuration;
7✔
35
                }
7✔
36

37
                public void WriteAttributeString(string localName, double value)
38
                {
53✔
39
                        this.WriteAttributeString(localName, value.ToSvg(this.Units));
53✔
40
                }
53✔
41

42
                public void WriteBlock(BlockRecord record)
43
                {
1✔
44
                        this.Units = record.Units;
1✔
45

46
                        BoundingBox box = record.GetBoundingBox();
1✔
47

48
                        this.startDocument(box);
1✔
49

50
                        foreach (var e in record.Entities)
47✔
51
                        {
22✔
52
                                this.writeEntity(e);
22✔
53
                        }
22✔
54

55
                        this.endDocument();
1✔
56
                }
1✔
57

58
                public void WriteLayout(Layout layout)
59
                {
6✔
60
                        this.Layout = layout;
6✔
61
                        this.Units = layout.PaperUnits.ToUnits();
6✔
62

63
                        double paperWidth = layout.PaperWidth;
6✔
64
                        double paperHeight = layout.PaperHeight;
6✔
65

66
                        switch (layout.PaperRotation)
6✔
67
                        {
68
                                case PlotRotation.Degrees90:
69
                                case PlotRotation.Degrees270:
70
                                        paperWidth = layout.PaperHeight;
4✔
71
                                        paperHeight = layout.PaperWidth;
4✔
72
                                        break;
4✔
73
                        }
74

75
                        XYZ lowerCorner = XYZ.Zero;
6✔
76
                        XYZ upperCorner = new XYZ(paperWidth, paperHeight, 0.0);
6✔
77
                        BoundingBox paper = new BoundingBox(lowerCorner, upperCorner);
6✔
78

79
                        XYZ lowerMargin = this.Layout.UnprintableMargin.BottomLeftCorner.Convert<XYZ>();
6✔
80
                        BoundingBox margins = new BoundingBox(
6✔
81
                                lowerMargin,
6✔
82
                                this.Layout.UnprintableMargin.TopCorner.Convert<XYZ>());
6✔
83

84
                        this.startDocument(paper);
6✔
85

86
                        Transform transform = new Transform(
6✔
87
                                lowerMargin.ToPixelSize(this.Units),
6✔
88
                                new XYZ(layout.PrintScale),
6✔
89
                                XYZ.Zero);
6✔
90

91
                        foreach (var e in layout.AssociatedBlock.Entities)
258✔
92
                        {
120✔
93
                                this.writeEntity(e, transform);
120✔
94
                        }
120✔
95

96
                        this.endDocument();
6✔
97
                }
6✔
98

99
                protected void notify(string message, NotificationType type, Exception ex = null)
100
                {
9✔
101
                        this.OnNotification?.Invoke(this, new NotificationEventArgs(message, type, ex));
9!
102
                }
9✔
103

104
                protected void triggerNotification(object sender, NotificationEventArgs e)
NEW
105
                {
×
NEW
106
                        this.OnNotification?.Invoke(sender, e);
×
NEW
107
                }
×
108

109
                protected void writeEntity(Entity entity, Transform transform)
110
                {
143✔
111
                        this.WriteComment($"{entity.ObjectName} | {entity.Handle}");
143✔
112

113
                        switch (entity)
143✔
114
                        {
115
                                case Arc arc:
116
                                        this.writeArc(arc, transform);
9✔
117
                                        break;
9✔
118
                                case Line line:
119
                                        this.writeLine(line, transform);
78✔
120
                                        break;
78✔
121
                                case Point point:
122
                                        this.writePoint(point, transform);
1✔
123
                                        break;
1✔
124
                                case Circle circle:
125
                                        this.writeCircle(circle, transform);
4✔
126
                                        break;
4✔
127
                                case Ellipse ellipse:
128
                                        this.writeEllipse(ellipse, transform);
2✔
129
                                        break;
2✔
130
                                //case Hatch hatch:
131
                                //        this.writeHatch(hatch, transform);
132
                                //        break;
133
                                case Insert insert:
134
                                        this.writeInsert(insert, transform);
1✔
135
                                        break;
1✔
136
                                case IPolyline polyline:
137
                                        this.writePolyline(polyline, transform);
13✔
138
                                        break;
13✔
139
                                case IText text:
140
                                        this.writeText(text, transform);
26✔
141
                                        break;
26✔
142
                                default:
143
                                        this.notify($"[{entity.ObjectName}] Entity not implemented.", NotificationType.NotImplemented);
9✔
144
                                        break;
9✔
145
                        }
146
                }
143✔
147

148
                private string colorSvg(Color color)
149
                {
134✔
150
                        if (this.Layout != null && color.Equals(Color.Default))
134✔
151
                        {
92✔
152
                                color = Color.Black;
92✔
153
                        }
92✔
154

155
                        return $"rgb({color.R},{color.G},{color.B})";
134✔
156
                }
134✔
157

158
                private string createPath(IEnumerable<IPolyline> polylines)
NEW
159
                {
×
NEW
160
                        StringBuilder sb = new StringBuilder();
×
161

NEW
162
                        foreach (var item in polylines)
×
NEW
163
                        {
×
NEW
164
                                var pts = item.GetPoints<XY>().ToArray();
×
NEW
165
                                if (!pts.Any())
×
NEW
166
                                {
×
NEW
167
                                        continue;
×
168
                                }
169

NEW
170
                                var pt = pts[0];
×
NEW
171
                                sb.Append($"M {pt.ToPixelSize(this.Units).ToSvg()} ");
×
NEW
172
                                for (int i = 1; i < pts.Length; i++)
×
NEW
173
                                {
×
NEW
174
                                        pt = pts[i];
×
NEW
175
                                        sb.Append($"L {pt.ToPixelSize(this.Units).ToSvg()} ");
×
NEW
176
                                }
×
177

NEW
178
                                if (item.IsClosed)
×
NEW
179
                                {
×
NEW
180
                                        sb.Append("Z");
×
NEW
181
                                }
×
NEW
182
                        }
×
183

NEW
184
                        return sb.ToString();
×
NEW
185
                }
×
186

187
                private bool drawableLineType(IEntity entity)
188
                {
107✔
189
                        var lineType = entity.GetActiveLineType();
107✔
190
                        return lineType.IsComplex && !lineType.Segments.Any(s => s.IsShape);
205✔
191
                }
107✔
192

193
                private void endDocument()
194
                {
7✔
195
                        this.WriteEndElement();
7✔
196
                        this.WriteEndDocument();
7✔
197
                        this.Close();
7✔
198
                }
7✔
199

200
                private double getPointSize(IEntity entity)
201
                {
20✔
202
                        return entity.GetActiveLineWeightType().GetLineWeightValue().ToPixelSize(this.Units);
20✔
203
                }
20✔
204

205
                private void startDocument(BoundingBox box)
206
                {
7✔
207
                        this.WriteStartDocument();
7✔
208

209
                        this.WriteStartElement("svg");
7✔
210
                        this.WriteAttributeString("xmlns", "http://www.w3.org/2000/svg");
7✔
211

212
                        this.WriteAttributeString("width", box.Max.X - box.Min.X);
7✔
213
                        this.WriteAttributeString("height", box.Max.Y - box.Min.Y);
7✔
214

215
                        this.WriteStartAttribute("viewBox");
7✔
216
                        this.WriteValue(box.Min.X.ToSvg(this.Units));
7✔
217
                        this.WriteValue(" ");
7✔
218
                        this.WriteValue(box.Min.Y.ToSvg(this.Units));
7✔
219
                        this.WriteValue(" ");
7✔
220
                        this.WriteValue((box.Max.X - box.Min.X).ToSvg(this.Units));
7✔
221
                        this.WriteValue(" ");
7✔
222
                        this.WriteValue((box.Max.Y - box.Min.Y).ToSvg(this.Units));
7✔
223
                        this.WriteEndAttribute();
7✔
224

225
                        this.WriteAttributeString("transform", $"scale(1,-1)");
7✔
226

227
                        if (this.Layout != null)
7✔
228
                        {
6✔
229
                                this.WriteAttributeString("style", "background-color:white");
6✔
230
                        }
6✔
231
                }
7✔
232

233
                private string svgPoints<T>(IEnumerable<T> points, Transform transform)
234
                        where T : IVector, new()
235
                {
24✔
236
                        if (!points.Any())
24!
237
                        {
×
238
                                return string.Empty;
×
239
                        }
240

241
                        StringBuilder sb = new StringBuilder();
24✔
242
                        sb.Append(points.First().ToPixelSize(this.Units).ToSvg());
24✔
243
                        foreach (T point in points.Skip(1))
14,928✔
244
                        {
7,428✔
245
                                sb.Append(' ');
7,428✔
246
                                sb.Append(point.ToPixelSize(this.Units).ToSvg());
7,428✔
247
                        }
7,428✔
248

249
                        return sb.ToString();
24✔
250
                }
24✔
251

252
                private void writeArc(Arc arc, Transform transform)
253
                {
9✔
254
                        //A rx ry rotation large-arc-flag sweep-flag x y
255

256
                        this.WriteStartElement("polyline");
9✔
257

258
                        this.writeEntityHeader(arc, transform);
9✔
259

260
                        var vertices = arc.PolygonalVertexes(256);
9✔
261
                        string pts = this.svgPoints(vertices, transform);
9✔
262
                        this.WriteAttributeString("points", pts);
9✔
263
                        this.WriteAttributeString("fill", "none");
9✔
264

265
                        this.WriteEndElement();
9✔
266
                }
9✔
267

268
                private void writeCircle(Circle circle, Transform transform)
269
                {
4✔
270
                        var loc = transform.ApplyTransform(circle.Center);
4✔
271

272
                        this.WriteStartElement("circle");
4✔
273

274
                        this.writeEntityHeader(circle, transform);
4✔
275

276
                        this.WriteAttributeString("r", circle.Radius);
4✔
277
                        this.WriteAttributeString("cx", loc.X);
4✔
278
                        this.WriteAttributeString("cy", loc.Y);
4✔
279

280
                        this.WriteAttributeString("fill", "none");
4✔
281

282
                        this.WriteEndElement();
4✔
283
                }
4✔
284

285
                private void writeDashes(LineType lineType, double pointSize)
286
                {
20✔
287
                        StringBuilder str = new StringBuilder();
20✔
288
                        foreach (LineType.Segment segment in lineType.Segments)
224✔
289
                        {
82✔
290
                                if (segment.IsPoint)
82✔
291
                                {
13✔
292
                                        str.Append(pointSize.ToPixelSize(this.Units));
13✔
293
                                }
13✔
294
                                else
295
                                {
69✔
296
                                        str.Append(Math.Abs(segment.Length.ToPixelSize(this.Units)));
69✔
297
                                }
69✔
298

299
                                str.Append(' ');
82✔
300
                        }
82✔
301

302
                        this.WriteAttributeString("stroke-dasharray", str.ToString().Trim());
20✔
303
                }
20✔
304

305
                private void writeEllipse(Ellipse ellipse, Transform transform)
306
                {
2✔
307
                        this.WriteStartElement("polygon");
2✔
308

309
                        this.writeEntityHeader(ellipse, transform);
2✔
310

311
                        var vertices = ellipse.PolygonalVertexes(256);
2✔
312
                        string pts = this.svgPoints(vertices, transform);
2✔
313
                        this.WriteAttributeString("points", pts);
2✔
314
                        this.WriteAttributeString("fill", "none");
2✔
315

316
                        this.WriteEndElement();
2✔
317
                }
2✔
318

319
                private void writeEntity(Entity entity)
320
                {
23✔
321
                        this.writeEntity(entity, new Transform());
23✔
322
                }
23✔
323

324
                private void writeEntityAsPath<T>(Entity entity, Transform transform, params IEnumerable<T> points)
325
                        where T : IVector
UNCOV
326
                {
×
327
                        //Will be needed to write the linetypes that use shapes
NEW
328
                        double pointSize = this.getPointSize(entity);
×
NEW
329
                        var lines = entity.GetActiveLineType().CreateLineTypeShape(pointSize, points);
×
330

NEW
331
                        this.WriteStartElement("path");
×
332

NEW
333
                        this.writeEntityHeader(entity, transform);
×
334

NEW
335
                        this.WriteAttributeString("d", this.createPath(lines));
×
336

NEW
337
                        this.WriteEndElement();
×
UNCOV
338
                }
×
339

340
                private void writeEntityHeader(IEntity entity, Transform transform)
341
                {
107✔
342
                        Color color = entity.GetActiveColor();
107✔
343

344
                        this.WriteAttributeString("vector-effect", "non-scaling-stroke");
107✔
345
                        this.WriteAttributeString("stroke", this.colorSvg(color));
107✔
346

347
                        var lineWeight = entity.LineWeight;
107✔
348
                        switch (lineWeight)
107✔
349
                        {
350
                                case LineWeightType.ByLayer:
351
                                        lineWeight = entity.Layer.LineWeight;
92✔
352
                                        break;
92✔
353
                        }
354

355
                        this.WriteAttributeString("stroke-width", $"{this.Configuration.GetLineWeightValue(lineWeight, this.Units).ToSvg(UnitsType.Millimeters)}");
107!
356

357
                        this.writeTransform(transform);
107✔
358

359
                        if (this.drawableLineType(entity))
107✔
360
                        {
20✔
361
                                this.writeDashes(entity.GetActiveLineType(), this.getPointSize(entity));
20✔
362
                        }
20✔
363
                }
107✔
364

365
                private void writeHatch(Hatch hatch, Transform transform)
366
                {
×
367
                        this.WriteStartElement("g");
×
368

369
                        this.writePattern(hatch.Pattern);
×
370

371
                        foreach (Hatch.BoundaryPath path in hatch.Paths)
×
372
                        {
×
373
                                this.WriteStartElement("polyline");
×
374

375
                                this.writeEntityHeader(hatch, transform);
×
376

377
                                foreach (var item in path.Edges)
×
378
                                {
×
379
                                        //TODO: svg edges for hatch drawing
380
                                }
×
381

382
                                //this.WriteAttributeString("points", pts);
383

384
                                this.WriteAttributeString("fill", "none");
×
385

386
                                this.WriteEndElement();
×
387
                        }
×
388

389
                        this.WriteEndElement();
×
390
                }
×
391

392
                private void writeInsert(Insert insert, Transform transform)
393
                {
1✔
394
                        var insertTransform = insert.GetTransform();
1✔
395
                        var merged = new Transform(transform.Matrix * insertTransform.Matrix);
1✔
396

397
                        this.WriteStartElement("g");
1✔
398
                        this.writeTransform(merged);
1✔
399

400
                        foreach (var e in insert.Block.Entities)
5✔
401
                        {
1✔
402
                                this.writeEntity(e);
1✔
403
                        }
1✔
404

405
                        this.WriteEndElement();
1✔
406
                }
1✔
407

408
                private void writeLine(Line line, Transform transform)
409
                {
78✔
410
                        this.WriteStartElement("line");
78✔
411

412
                        this.writeEntityHeader(line, transform);
78✔
413

414
                        this.WriteAttributeString("x1", line.StartPoint.X.ToSvg(this.Units));
78✔
415
                        this.WriteAttributeString("y1", line.StartPoint.Y.ToSvg(this.Units));
78✔
416
                        this.WriteAttributeString("x2", line.EndPoint.X.ToSvg(this.Units));
78✔
417
                        this.WriteAttributeString("y2", line.EndPoint.Y.ToSvg(this.Units));
78✔
418

419
                        this.WriteEndElement();
78✔
420
                }
78✔
421

422
                private void writePattern(HatchPattern pattern)
423
                {
×
424
                        this.WriteStartElement("pattern");
×
425

426
                        this.WriteEndElement();
×
427
                }
×
428

429
                private void writePoint(Point point, Transform transform)
430
                {
1✔
431
                        this.WriteStartElement("circle");
1✔
432

433
                        this.writeEntityHeader(point, transform);
1✔
434

435
                        this.WriteAttributeString("r", this.Configuration.PointRadius);
1✔
436
                        this.WriteAttributeString("cx", point.Location.X);
1✔
437
                        this.WriteAttributeString("cy", point.Location.Y);
1✔
438

439
                        this.WriteAttributeString("fill", this.colorSvg(point.GetActiveColor()));
1✔
440

441
                        this.WriteEndElement();
1✔
442
                }
1✔
443

444
                private void writePolyline(IPolyline polyline, Transform transform)
445
                {
13✔
446
                        if (polyline.IsClosed)
13✔
447
                        {
6✔
448
                                this.WriteStartElement("polygon");
6✔
449
                        }
6✔
450
                        else
451
                        {
7✔
452
                                this.WriteStartElement("polyline");
7✔
453
                        }
7✔
454

455
                        this.writeEntityHeader(polyline, transform);
13✔
456

457
                        string pts = this.svgPoints(polyline.GetPoints<XY>(this.Configuration.ArcPoints), transform);
13✔
458

459
                        this.WriteAttributeString("points", pts);
13✔
460
                        this.WriteAttributeString("fill", "none");
13✔
461

462
                        this.WriteEndElement();
13✔
463
                }
13✔
464

465
                private void writeText(IText text, Transform transform)
466
                {
26✔
467
                        XYZ insert;
468

469
                        if (text is TextEntity lineText
26✔
470
                                && (lineText.HorizontalAlignment != TextHorizontalAlignment.Left
26✔
471
                                || lineText.VerticalAlignment != TextVerticalAlignmentType.Baseline)
26✔
472
                                && !(lineText.HorizontalAlignment == TextHorizontalAlignment.Fit
26✔
473
                                || lineText.HorizontalAlignment == TextHorizontalAlignment.Aligned))
26✔
474
                        {
12✔
475
                                insert = lineText.AlignmentPoint;
12✔
476
                        }
12✔
477
                        else
478
                        {
14✔
479
                                insert = text.InsertPoint;
14✔
480
                        }
14✔
481

482
                        this.WriteStartElement("g");
26✔
483
                        this.writeTransform(transform);
26✔
484

485
                        this.WriteStartElement("text");
26✔
486

487
                        this.writeTransform(translation: insert.ToPixelSize(this.Units), scale: new XYZ(1, -1, 0), rotation: text.Rotation != 0 ? text.Rotation : null);
26✔
488

489
                        this.WriteAttributeString("fill", this.colorSvg(text.GetActiveColor()));
26✔
490

491
                        //<text x="20" y="35" class="small">My</text>
492
                        this.WriteStartAttribute("style");
26✔
493
                        this.WriteValue("font:");
26✔
494
                        this.WriteValue(text.Height.ToSvg(this.Units));
26✔
495
                        if (this.Units == UnitsType.Unitless)
26✔
496
                        {
4✔
497
                                this.WriteValue("px");
4✔
498
                        }
4✔
499
                        this.WriteValue(" ");
26✔
500
                        this.WriteValue(Path.GetFileNameWithoutExtension(text.Style.Filename));
26✔
501
                        this.WriteEndAttribute();
26✔
502

503
                        switch (text)
26✔
504
                        {
505
                                case MText mtext:
506
                                        switch (mtext.AttachmentPoint)
5!
507
                                        {
508
                                                case AttachmentPointType.TopLeft:
509
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
4✔
510
                                                        this.WriteAttributeString("text-anchor", "start");
4✔
511
                                                        break;
4✔
512
                                                case AttachmentPointType.TopCenter:
513
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
×
514
                                                        this.WriteAttributeString("text-anchor", "middle");
×
515
                                                        break;
×
516
                                                case AttachmentPointType.TopRight:
517
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
1✔
518
                                                        this.WriteAttributeString("text-anchor", "end");
1✔
519
                                                        break;
1✔
520
                                                case AttachmentPointType.MiddleLeft:
521
                                                        this.WriteAttributeString("alignment-baseline", "middle");
×
522
                                                        this.WriteAttributeString("text-anchor", "start");
×
523
                                                        break;
×
524
                                                case AttachmentPointType.MiddleCenter:
525
                                                        this.WriteAttributeString("alignment-baseline", "middle");
×
526
                                                        this.WriteAttributeString("text-anchor", "middle");
×
527
                                                        break;
×
528
                                                case AttachmentPointType.MiddleRight:
529
                                                        this.WriteAttributeString("alignment-baseline", "middle");
×
530
                                                        this.WriteAttributeString("text-anchor", "end");
×
531
                                                        break;
×
532
                                                case AttachmentPointType.BottomLeft:
533
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
×
534
                                                        this.WriteAttributeString("text-anchor", "start");
×
535
                                                        break;
×
536
                                                case AttachmentPointType.BottomCenter:
537
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
×
538
                                                        this.WriteAttributeString("text-anchor", "middle");
×
539
                                                        break;
×
540
                                                case AttachmentPointType.BottomRight:
541
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
×
542
                                                        this.WriteAttributeString("text-anchor", "end");
×
543
                                                        break;
×
544
                                                default:
545
                                                        break;
×
546
                                        }
547

548
                                        foreach (var item in mtext.GetTextLines())
53✔
549
                                        {
19✔
550
                                                this.WriteStartElement("tspan");
19✔
551
                                                this.WriteAttributeString("x", 0);
19✔
552
                                                this.WriteAttributeString("dy", "1em");
19✔
553
                                                this.WriteString(item);
19✔
554
                                                this.WriteEndElement();
19✔
555
                                        }
19✔
556

557
                                        //Line to avoid the strange offset at the end
558
                                        this.WriteStartElement("tspan");
5✔
559
                                        this.WriteAttributeString("x", 0);
5✔
560
                                        this.WriteAttributeString("dy", "1em");
5✔
561
                                        this.WriteAttributeString("visibility", "hidden");
5✔
562
                                        this.WriteString(".");
5✔
563
                                        this.WriteEndElement();
5✔
564
                                        break;
5✔
565
                                case TextEntity textEntity:
566

567
                                        switch (textEntity.HorizontalAlignment)
21✔
568
                                        {
569
                                                case TextHorizontalAlignment.Left:
570
                                                        this.WriteAttributeString("text-anchor", "start");
10✔
571
                                                        break;
10✔
572
                                                case TextHorizontalAlignment.Middle:
573
                                                case TextHorizontalAlignment.Center:
574
                                                        this.WriteAttributeString("text-anchor", "middle");
5✔
575
                                                        break;
5✔
576
                                                case TextHorizontalAlignment.Right:
577
                                                        this.WriteAttributeString("text-anchor", "end");
4✔
578
                                                        break;
4✔
579
                                        }
580

581
                                        switch (textEntity.VerticalAlignment)
21✔
582
                                        {
583
                                                case TextVerticalAlignmentType.Baseline:
584
                                                case TextVerticalAlignmentType.Bottom:
585
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
15✔
586
                                                        break;
15✔
587
                                                case TextVerticalAlignmentType.Middle:
588
                                                        this.WriteAttributeString("alignment-baseline", "middle");
3✔
589
                                                        break;
3✔
590
                                                case TextVerticalAlignmentType.Top:
591
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
3✔
592
                                                        break;
3✔
593
                                        }
594

595
                                        this.WriteString(text.Value);
21✔
596
                                        break;
21✔
597
                        }
598

599
                        this.WriteEndElement();
26✔
600
                        this.WriteEndElement();
26✔
601
                }
26✔
602

603
                private void writeTransform(Transform transform)
604
                {
134✔
605
                        XYZ? translation = transform.Translation != XYZ.Zero ? transform.Translation : null;
134✔
606
                        XYZ? scale = transform.Scale != new XYZ(1) ? transform.Scale : null;
134✔
607
                        double? rotation = transform.EulerRotation.Z != 0 ? transform.EulerRotation.Z : null;
134!
608

609
                        this.writeTransform(translation, scale, rotation);
134✔
610
                }
134✔
611

612
                private void writeTransform(XYZ? translation = null, XYZ? scale = null, double? rotation = null)
613
                {
160✔
614
                        StringBuilder sb = new StringBuilder();
160✔
615

616
                        if (translation.HasValue)
160✔
617
                        {
88✔
618
                                var t = translation.Value;
88✔
619

620
                                sb.Append($"translate(");
88✔
621
                                sb.Append($"{t.X.ToString(CultureInfo.InvariantCulture)},");
88✔
622
                                sb.Append($"{t.Y.ToString(CultureInfo.InvariantCulture)})");
88✔
623
                        }
88✔
624

625
                        if (scale.HasValue)
160✔
626
                        {
83✔
627
                                var s = scale.Value;
83✔
628

629
                                sb.Append($"scale(");
83✔
630
                                sb.Append($"{s.X.ToString(CultureInfo.InvariantCulture)},");
83✔
631
                                sb.Append($"{s.Y.ToString(CultureInfo.InvariantCulture)})");
83✔
632
                        }
83✔
633

634
                        if (rotation.HasValue)
160✔
635
                        {
2✔
636
                                var r = -MathHelper.RadToDeg(rotation.Value);
2✔
637

638
                                sb.Append($"rotate(");
2✔
639
                                sb.Append($"{r.ToString(CultureInfo.InvariantCulture)})");
2✔
640
                        }
2✔
641

642
                        if (sb.ToString().IsNullOrEmpty())
160✔
643
                        {
66✔
644
                                return;
66✔
645
                        }
646

647
                        this.WriteAttributeString("transform", sb.ToString());
94✔
648
                }
160✔
649
        }
650
}
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