1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2009 Lode Leroy
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
# Inkscape uses a fixed resolution of 90 dpi
SVG_OUTPUT_DPI = 90
class SVGExporter(object):
def __init__(self, output, unit="mm", maxx=None, maxy=None):
if isinstance(output, basestring):
# a filename was given
self.output = file(output,"w")
else:
# a stream was given
self.output = output
if unit == "mm":
dots_per_px = SVG_OUTPUT_DPI / 25.4
else:
dots_per_px = SVG_OUTPUT_DPI
if maxx is None:
width = 640
else:
width = dots_per_px * maxx
if width <= 0:
width = 640
if maxy is None:
height = 800
else:
height = dots_per_px * maxy
if height <= 0:
height = 800
self.output.write("""<?xml version='1.0'?>
<svg xmlns='http://www.w3.org/2000/svg' width='%f' height='%f'>
<g transform='translate(0,%f) scale(%.10f)' stroke-width='0.05' font-size='0.2'>
""" % (width, height, height, dots_per_px))
self._fill = 'none'
self._stroke = 'black'
def close(self, close_stream=True):
self.output.write("""</g>
</svg>
""")
if close_stream:
self.output.close()
def stroke(self, stroke):
self._stroke = stroke
def fill(self, fill):
self._fill = fill
def AddDot(self, x, y):
l = "<circle fill='" + self._fill +"'" + (" cx='%g'" % x) \
+ (" cy='%g'" % -y) + " r='0.04'/>\n"
self.output.write(l)
def AddText(self, x, y, text):
l = "<text fill='" + self._fill +"'" + (" x='%g'" % x) \
+ (" y='%g'" % -y) + " dx='0.07'>" + text + "</text>\n"
self.output.write(l)
def AddLine(self, x1, y1, x2, y2):
l = "<line fill='" + self._fill +"' stroke='" + self._stroke + "'" \
+ (" x1='%.8f'" % x1) + (" y1='%.8f'" % -y1) + (" x2='%.8f'" % x2) \
+ (" y2='%.8f'" % -y2) + " />\n"
self.output.write(l)
def AddPoint(self, p):
self.AddDot(p.x, p.y)
def AddPath(self, path):
self.AddLines(path.points)
def AddLines(self, points):
l = "<path fill='" + self._fill +"' stroke='" + self._stroke + "' d='"
for i in range(0, len(points)):
p = points[i]
if i == 0:
l += "M "
else:
l += " L "
l += "%.8f %.8f" % (p.x, -p.y)
l += "'/>\n"
self.output.write(l)
def AddPathList(self, pathlist):
for path in pathlist:
self.AddPath(path)
#TODO: we need to create a unified "Exporter" interface and base class
class SVGExporterContourModel(object):
def __init__(self, model, unit="mm", **kwargs):
self.model = model
self.unit = unit
def write(self, stream):
writer = SVGExporter(stream, unit=self.unit, maxx=self.model.maxx,
maxy=self.model.maxy)
for polygon in self.model.get_polygons():
points = polygon.get_points()
if polygon.is_closed:
points.append(points[0])
writer.AddLines(points)
writer.close(close_stream=False)