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

DomCR / ACadSharp / 14101911880

27 Mar 2025 08:19AM UTC coverage: 76.335% (-3.4%) from 79.72%
14101911880

Pull #211

github

web-flow
Merge 5b1fbf460 into c902191a1
Pull Request #211: Cad to svg

5559 of 7990 branches covered (69.57%)

Branch coverage included in aggregate %.

322 of 394 new or added lines in 9 files covered. (81.73%)

24 existing lines in 2 files now uncovered.

21991 of 28101 relevant lines covered (78.26%)

74709.86 hits per line

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

86.44
/src/ACadSharp/IO/SVG/SvgXmlWriter.cs
1
using ACadSharp.Entities;
2
using ACadSharp.Tables;
3
using CSMath;
4
using System;
5
using System.Collections.Generic;
6
using System.Globalization;
7
using System.IO;
8
using System.Linq;
9
using System.Text;
10
using System.Xml;
11

12
namespace ACadSharp.IO.SVG
13
{
14
        internal class SvgXmlWriter : XmlTextWriter
15
        {
16
                public event NotificationEventHandler OnNotification;
17

18
                public SvgConfiguration Configuration { get; } = new();
19✔
19

20
                public SvgXmlWriter(Stream w, Encoding encoding, SvgConfiguration configuration) : base(w, encoding)
1✔
21
                {
1✔
22
                        this.Configuration = configuration;
1✔
23
                }
1✔
24

25
                public void WriteAttributeString(string localName, double value)
26
                {
64✔
27
                        this.WriteAttributeString(localName, value.ToString(CultureInfo.InvariantCulture));
64✔
28
                }
64✔
29

30
                public void WriteBlock(BlockRecord record)
31
                {
1✔
32
                        BoundingBox box = record.GetBoundingBox();
1✔
33
                        this.startDocument(box);
1✔
34

35
                        Transform transform = new Transform(-box.Min, new XYZ(1), XYZ.Zero);
1✔
36
                        foreach (var e in record.Entities)
47✔
37
                        {
22✔
38
                                this.writeEntity(e);
22✔
39
                        }
22✔
40

41
                        this.endDocument();
1✔
42
                }
1✔
43

44
                private string colorSvg(Color color)
45
                {
22✔
46
                        return $"rgb({color.R},{color.G},{color.B})";
22✔
47
                }
22✔
48

49
                private void endDocument()
50
                {
1✔
51
                        this.WriteEndElement();
1✔
52
                        this.WriteEndDocument();
1✔
53
                        this.Close();
1✔
54
                }
1✔
55

56
                private void notify(string message, NotificationType type, Exception ex = null)
57
                {
1✔
58
                        this.OnNotification?.Invoke(this, new NotificationEventArgs(message, type, ex));
1!
59
                }
1✔
60

61
                private void startDocument(BoundingBox box)
62
                {
1✔
63
                        this.WriteStartDocument();
1✔
64

65
                        this.WriteStartElement("svg");
1✔
66
                        this.WriteAttributeString("xmlns", "http://www.w3.org/2000/svg");
1✔
67

68
                        this.WriteAttributeString("width", box.Max.X - box.Min.X);
1✔
69
                        this.WriteAttributeString("height", box.Max.Y - box.Min.Y);
1✔
70

71
                        this.WriteStartAttribute("viewBox");
1✔
72
                        this.WriteValue(box.Min.X);
1✔
73
                        this.WriteValue(" ");
1✔
74
                        this.WriteValue(box.Min.Y);
1✔
75
                        this.WriteValue(" ");
1✔
76
                        this.WriteValue(box.Max.X - box.Min.X);
1✔
77
                        this.WriteValue(" ");
1✔
78
                        this.WriteValue(box.Max.Y - box.Min.Y);
1✔
79
                        this.WriteEndAttribute();
1✔
80

81
                        this.WriteAttributeString("transform", $"scale(1,-1)");
1✔
82
                }
1✔
83

84
                private string svgPoints(IEnumerable<IVector> points, Transform transform)
85
                {
7✔
86
                        if (!points.Any())
7!
NEW
87
                        {
×
NEW
88
                                return string.Empty;
×
89
                        }
90

91
                        StringBuilder sb = new StringBuilder();
7✔
92
                        sb.Append(transform.ApplyTransform(points.First().Convert<XYZ>()).SvgPoint());
7✔
93
                        foreach (IVector point in points.Skip(1))
2,079✔
94
                        {
1,029✔
95
                                sb.Append(' ');
1,029✔
96
                                sb.Append(transform.ApplyTransform(point.Convert<XYZ>()).SvgPoint());
1,029✔
97
                        }
1,029✔
98

99
                        return sb.ToString();
7✔
100
                }
7✔
101

102
                private void writeArc(Arc arc, Transform transform)
103
                {
3✔
104
                        //A rx ry rotation large-arc-flag sweep-flag x y
105

106
                        this.WriteStartElement("polyline");
3✔
107

108
                        this.writeEntityStyle(arc);
3✔
109

110
                        IEnumerable<IVector> vertices = arc.PolygonalVertexes(256).OfType<IVector>();
3✔
111
                        string pts = this.svgPoints(vertices, transform);
3✔
112
                        this.WriteAttributeString("points", pts);
3✔
113
                        this.WriteAttributeString("fill", "none");
3✔
114

115
                        this.WriteEndElement();
3✔
116
                }
3✔
117

118
                private void writeCircle(Circle circle, Transform transform)
119
                {
2✔
120
                        var loc = transform.ApplyTransform(circle.Center);
2✔
121

122
                        this.WriteStartElement("circle");
2✔
123

124
                        this.writeEntityStyle(circle);
2✔
125

126
                        this.WriteAttributeString("r", circle.Radius);
2✔
127
                        this.WriteAttributeString("cx", loc.X);
2✔
128
                        this.WriteAttributeString("cy", loc.Y);
2✔
129

130
                        this.WriteAttributeString("fill", "none");
2✔
131

132
                        this.WriteEndElement();
2✔
133
                }
2✔
134

135
                private void writeEllipse(Ellipse ellipse, Transform transform)
136
                {
1✔
137
                        this.WriteStartElement("polygon");
1✔
138

139
                        this.writeEntityStyle(ellipse);
1✔
140

141
                        IEnumerable<IVector> vertices = ellipse.PolygonalVertexes(256).OfType<IVector>();
1✔
142
                        string pts = this.svgPoints(vertices, transform);
1✔
143
                        this.WriteAttributeString("points", pts);
1✔
144
                        this.WriteAttributeString("fill", "none");
1✔
145

146
                        this.WriteEndElement();
1✔
147
                }
1✔
148

149
                private void writeInsert(Insert insert, Transform transform)
150
                {
1✔
151
                        var insertTransform = insert.GetTransform();
1✔
152
                        var merged = new Transform(transform.Matrix * insertTransform.Matrix);
1✔
153

154
                        StringBuilder sb = new StringBuilder();
1✔
155
                        sb.Append($"translate(");
1✔
156
                        sb.Append($"{insert.InsertPoint.X.ToString(CultureInfo.InvariantCulture)},");
1✔
157
                        sb.Append($"{insert.InsertPoint.Y.ToString(CultureInfo.InvariantCulture)})");
1✔
158
                        sb.Append(' ');
1✔
159
                        sb.Append($"scale(");
1✔
160
                        sb.Append($"{insert.XScale.ToString(CultureInfo.InvariantCulture)},");
1✔
161
                        sb.Append($"{insert.YScale.ToString(CultureInfo.InvariantCulture)})");
1✔
162
                        sb.Append(' ');
1✔
163
                        sb.Append($"rotate(");
1✔
164
                        sb.Append($"{insert.Rotation.ToString(CultureInfo.InvariantCulture)})");
1✔
165

166
                        this.WriteStartElement("g");
1✔
167
                        this.WriteAttributeString("transform", sb.ToString());
1✔
168

169
                        foreach (var e in insert.Block.Entities)
5✔
170
                        {
1✔
171
                                this.writeEntity(e);
1✔
172
                        }
1✔
173

174
                        this.WriteEndElement();
1✔
175
                }
1✔
176

177
                private void writeEntity(Entity entity)
178
                {
23✔
179
                        this.writeEntity(entity, new Transform());
23✔
180
                }
23✔
181

182
                private void writeEntity(Entity entity, Transform transform)
183
                {
23✔
184
                        switch (entity)
23✔
185
                        {
186
                                case Arc arc:
187
                                        this.writeArc(arc, transform);
3✔
188
                                        break;
3✔
189
                                case Line line:
190
                                        this.writeLine(line, transform);
7✔
191
                                        break;
7✔
192
                                case Point point:
193
                                        this.writePoint(point, transform);
1✔
194
                                        break;
1✔
195
                                case Circle circle:
196
                                        this.writeCircle(circle, transform);
2✔
197
                                        break;
2✔
198
                                case Ellipse ellipse:
199
                                        this.writeEllipse(ellipse, transform);
1✔
200
                                        break;
1✔
201
                                case Insert insert:
202
                                        this.writeInsert(insert, transform);
1✔
203
                                        break;
1✔
204
                                case IPolyline polyline:
205
                                        this.writePolyline(polyline, transform);
3✔
206
                                        break;
3✔
207
                                case IText text:
208
                                        this.writeText(text, transform);
4✔
209
                                        break;
4✔
210
                                default:
211
                                        this.notify($"[{entity.ObjectName}] Entity not implemented.", NotificationType.NotImplemented);
1✔
212
                                        break;
1✔
213
                        }
214
                }
23✔
215

216
                private void writeEntityStyle(IEntity entity)
217
                {
17✔
218
                        Color color = entity.GetActiveColor();
17✔
219

220
                        this.WriteAttributeString("stroke", this.colorSvg(color));
17✔
221

222
                        var lineWeight = entity.LineWeight;
17✔
223
                        switch (lineWeight)
17✔
224
                        {
225
                                case LineweightType.ByLayer:
226
                                        lineWeight = entity.Layer.LineWeight;
17✔
227
                                        break;
17✔
228
                        }
229

230
                        this.WriteAttributeString("stroke-width", Configuration.GetLineWeightValue(lineWeight));
17✔
231
                }
17✔
232

233
                private void writeLine(Line line, Transform transform)
234
                {
7✔
235
                        var start = transform.ApplyTransform(line.StartPoint);
7✔
236
                        var end = transform.ApplyTransform(line.EndPoint);
7✔
237

238
                        this.WriteStartElement("line");
7✔
239

240
                        this.writeEntityStyle(line);
7✔
241

242
                        this.WriteAttributeString("x1", start.X);
7✔
243
                        this.WriteAttributeString("y1", start.Y);
7✔
244
                        this.WriteAttributeString("x2", end.X);
7✔
245
                        this.WriteAttributeString("y2", end.Y);
7✔
246

247
                        this.WriteEndElement();
7✔
248
                }
7✔
249

250
                private void writePoint(Point point, Transform transform)
251
                {
1✔
252
                        var loc = transform.ApplyTransform(point.Location);
1✔
253

254
                        this.WriteStartElement("circle");
1✔
255

256
                        this.writeEntityStyle(point);
1✔
257

258
                        this.WriteAttributeString("r", this.Configuration.PointRadius);
1✔
259
                        this.WriteAttributeString("cx", loc.X);
1✔
260
                        this.WriteAttributeString("cy", loc.Y);
1✔
261

262
                        this.WriteAttributeString("fill", this.colorSvg(point.GetActiveColor()));
1✔
263

264
                        this.WriteEndElement();
1✔
265
                }
1✔
266

267
                private void writePolyline(IPolyline polyline, Transform transform)
268
                {
3✔
269
                        if (polyline.IsClosed)
3✔
270
                        {
2✔
271
                                this.WriteStartElement("polygon");
2✔
272
                        }
2✔
273
                        else
274
                        {
1✔
275
                                this.WriteStartElement("polyline");
1✔
276
                        }
1✔
277

278
                        this.writeEntityStyle(polyline);
3✔
279

280
                        var vertices = polyline.Vertices.Select(v => v.Location).ToList();
15✔
281

282
                        string pts = this.svgPoints(polyline.Vertices.Select(v => v.Location), transform);
21✔
283
                        this.WriteAttributeString("points", pts);
3✔
284
                        this.WriteAttributeString("fill", "none");
3✔
285

286
                        this.WriteEndElement();
3✔
287
                }
3✔
288

289
                private void writeText(IText text, Transform transform)
290
                {
4✔
291
                        var insert = transform.ApplyTransform(text.InsertPoint);
4✔
292

293
                        this.WriteStartElement("g");
4✔
294
                        this.WriteAttributeString("transform", $"translate({insert.X.ToString(CultureInfo.InvariantCulture)},{insert.Y.ToString(CultureInfo.InvariantCulture)})");
4✔
295

296
                        this.WriteStartElement("text");
4✔
297
                        this.WriteAttributeString("transform", "scale(1,-1)");
4✔
298

299
                        this.WriteAttributeString("fill", this.colorSvg(text.GetActiveColor()));
4✔
300

301
                        //<text x="20" y="35" class="small">My</text>
302
                        this.WriteStartAttribute("style");
4✔
303
                        this.WriteValue("font:");
4✔
304
                        this.WriteValue(text.Height);
4✔
305
                        this.WriteValue("px");
4✔
306
                        this.WriteValue(" ");
4✔
307
                        this.WriteValue(Path.GetFileNameWithoutExtension(text.Style.Filename));
4✔
308
                        this.WriteEndAttribute();
4✔
309

310
                        switch (text)
4✔
311
                        {
312
                                case MText mtext:
313
                                        switch (mtext.AttachmentPoint)
2!
314
                                        {
315
                                                case AttachmentPointType.TopLeft:
316
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
1✔
317
                                                        this.WriteAttributeString("text-anchor", "start");
1✔
318
                                                        break;
1✔
319
                                                case AttachmentPointType.TopCenter:
NEW
320
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
×
NEW
321
                                                        this.WriteAttributeString("text-anchor", "middle");
×
NEW
322
                                                        break;
×
323
                                                case AttachmentPointType.TopRight:
324
                                                        this.WriteAttributeString("alignment-baseline", "hanging");
1✔
325
                                                        this.WriteAttributeString("text-anchor", "end");
1✔
326
                                                        break;
1✔
327
                                                case AttachmentPointType.MiddleLeft:
NEW
328
                                                        this.WriteAttributeString("alignment-baseline", "middle");
×
NEW
329
                                                        this.WriteAttributeString("text-anchor", "start");
×
NEW
330
                                                        break;
×
331
                                                case AttachmentPointType.MiddleCenter:
NEW
332
                                                        this.WriteAttributeString("alignment-baseline", "middle");
×
NEW
333
                                                        this.WriteAttributeString("text-anchor", "middle");
×
NEW
334
                                                        break;
×
335
                                                case AttachmentPointType.MiddleRight:
NEW
336
                                                        this.WriteAttributeString("alignment-baseline", "middle");
×
NEW
337
                                                        this.WriteAttributeString("text-anchor", "end");
×
NEW
338
                                                        break;
×
339
                                                case AttachmentPointType.BottomLeft:
NEW
340
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
×
NEW
341
                                                        this.WriteAttributeString("text-anchor", "start");
×
NEW
342
                                                        break;
×
343
                                                case AttachmentPointType.BottomCenter:
NEW
344
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
×
NEW
345
                                                        this.WriteAttributeString("text-anchor", "middle");
×
NEW
346
                                                        break;
×
347
                                                case AttachmentPointType.BottomRight:
NEW
348
                                                        this.WriteAttributeString("alignment-baseline", "baseline");
×
NEW
349
                                                        this.WriteAttributeString("text-anchor", "end");
×
NEW
350
                                                        break;
×
351
                                                default:
NEW
352
                                                        break;
×
353
                                        }
354

355
                                        foreach (var item in mtext.GetTextLines())
22✔
356
                                        {
8✔
357
                                                this.WriteStartElement("tspan");
8✔
358
                                                this.WriteAttributeString("x", 0);
8✔
359
                                                this.WriteAttributeString("dy", "1em");
8✔
360
                                                this.WriteRaw(item);
8✔
361
                                                this.WriteEndElement();
8✔
362
                                        }
8✔
363
                                        break;
2✔
364
                                case TextEntity textEntity:
365

366
                                        switch (textEntity.HorizontalAlignment)
2!
367
                                        {
368
                                                case TextHorizontalAlignment.Left:
369
                                                        this.WriteAttributeString("text-anchor", "start");
2✔
370
                                                        break;
2✔
371
                                                case TextHorizontalAlignment.Middle:
372
                                                case TextHorizontalAlignment.Center:
NEW
373
                                                        this.WriteAttributeString("text-anchor", "middle");
×
NEW
374
                                                        break;
×
375
                                                case TextHorizontalAlignment.Right:
NEW
376
                                                        this.WriteAttributeString("text-anchor", "end");
×
NEW
377
                                                        break;
×
378
                                        }
379

380
                                        this.WriteRaw(text.Value);
2✔
381
                                        break;
2✔
382
                        }
383

384
                        this.WriteEndElement();
4✔
385
                        this.WriteEndElement();
4✔
386
                }
4✔
387
        }
388
}
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