svg2gcode/svg/svg.py

Sat, 07 Nov 2015 18:45:17 +0100

author
mbayer
date
Sat, 07 Nov 2015 18:45:17 +0100
changeset 7
421aae29d9d9
parent 3
a519e3ac3849
child 12
a90b8113be25
permissions
-rw-r--r--

finished poly infill

2
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
1 # SVG parser in Python
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
2
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
3 # Copyright (C) 2013 -- CJlano < cjlano @ free.fr >
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
4
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
5 # This program is free software; you can redistribute it and/or modify
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
6 # it under the terms of the GNU General Public License as published by
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
7 # the Free Software Foundation; either version 2 of the License, or
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
8 # (at your option) any later version.
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
9 #
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
10 # This program is distributed in the hope that it will be useful,
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
13 # GNU General Public License for more details.
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
14 #
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
15 # You should have received a copy of the GNU General Public License along
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
16 # with this program; if not, write to the Free Software Foundation, Inc.,
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
18
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
19 from __future__ import absolute_import
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
20 import sys
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
21 import os
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
22 import copy
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
23 import re
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
24 import xml.etree.ElementTree as etree
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
25 import itertools
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
26 import operator
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
27 import json
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
28 from .geometry import *
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
29
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
30 svg_ns = '{http://www.w3.org/2000/svg}'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
31
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
32 # Regex commonly used
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
33 number_re = r'[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
34 unit_re = r'em|ex|px|in|cm|mm|pt|pc|%'
3
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
35 point_re = r'(?:\d+(?:\.\d*)?|\.\d+),(?:\d+(?:\.\d*)?|\.\d+)'
2
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
36
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
37 # Unit converter
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
38 unit_convert = {
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
39 None: 1, # Default unit (same as pixel)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
40 'px': 1, # px: pixel. Default SVG unit
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
41 'em': 10, # 1 em = 10 px FIXME
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
42 'ex': 5, # 1 ex = 5 px FIXME
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
43 'in': 96, # 1 in = 96 px
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
44 'cm': 96 / 2.54, # 1 cm = 1/2.54 in
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
45 'mm': 96 / 25.4, # 1 mm = 1/25.4 in
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
46 'pt': 96 / 72.0, # 1 pt = 1/72 in
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
47 'pc': 96 / 6.0, # 1 pc = 1/6 in
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
48 '%' : 1 / 100.0 # 1 percent
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
49 }
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
50
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
51 class Transformable:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
52 '''Abstract class for objects that can be geometrically drawn & transformed'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
53 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
54 # a 'Transformable' is represented as a list of Transformable items
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
55 self.items = []
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
56 self.id = hex(id(self))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
57 # Unit transformation matrix on init
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
58 self.matrix = Matrix()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
59 self.viewport = Point(800, 600) # default viewport is 800x600
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
60 if elt is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
61 self.id = elt.get('id', self.id)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
62 # Parse transform attibute to update self.matrix
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
63 self.getTransformations(elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
64
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
65 def bbox(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
66 '''Bounding box'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
67 bboxes = [x.bbox() for x in self.items]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
68 xmin = min([b[0].x for b in bboxes])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
69 xmax = max([b[1].x for b in bboxes])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
70 ymin = min([b[0].y for b in bboxes])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
71 ymax = max([b[1].y for b in bboxes])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
72
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
73 return (Point(xmin,ymin), Point(xmax,ymax))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
74
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
75 # Parse transform field
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
76 def getTransformations(self, elt):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
77 t = elt.get('transform')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
78 if t is None: return
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
79
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
80 svg_transforms = [
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
81 'matrix', 'translate', 'scale', 'rotate', 'skewX', 'skewY']
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
82
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
83 # match any SVG transformation with its parameter (until final parenthese)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
84 # [^)]* == anything but a closing parenthese
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
85 # '|'.join == OR-list of SVG transformations
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
86 transforms = re.findall(
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
87 '|'.join([x + '[^)]*\)' for x in svg_transforms]), t)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
88
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
89 for t in transforms:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
90 op, arg = t.split('(')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
91 op = op.strip()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
92 # Keep only numbers
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
93 arg = [float(x) for x in re.findall(number_re, arg)]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
94 print('transform: ' + op + ' '+ str(arg))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
95
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
96 if op == 'matrix':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
97 self.matrix *= Matrix(arg)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
98
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
99 if op == 'translate':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
100 tx = arg[0]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
101 if len(arg) == 1: ty = 0
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
102 else: ty = arg[1]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
103 self.matrix *= Matrix([1, 0, 0, 1, tx, ty])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
104
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
105 if op == 'scale':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
106 sx = arg[0]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
107 if len(arg) == 1: sy = sx
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
108 else: sy = arg[1]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
109 self.matrix *= Matrix([sx, 0, 0, sy, 0, 0])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
110
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
111 if op == 'rotate':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
112 cosa = math.cos(math.radians(arg[0]))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
113 sina = math.sin(math.radians(arg[0]))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
114 if len(arg) != 1:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
115 tx, ty = arg[1:3]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
116 self.matrix *= Matrix([1, 0, 0, 1, tx, ty])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
117 self.matrix *= Matrix([cosa, sina, -sina, cosa, 0, 0])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
118 if len(arg) != 1:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
119 self.matrix *= Matrix([1, 0, 0, 1, -tx, -ty])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
120
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
121 if op == 'skewX':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
122 tana = math.tan(math.radians(arg[0]))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
123 self.matrix *= Matrix([1, 0, tana, 1, 0, 0])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
124
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
125 if op == 'skewY':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
126 tana = math.tan(math.radians(arg[0]))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
127 self.matrix *= Matrix([1, tana, 0, 1, 0, 0])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
128
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
129 def transform(self, matrix=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
130 for x in self.items:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
131 x.transform(self.matrix)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
132
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
133 def length(self, v, mode='xy'):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
134 # Handle empty (non-existing) length element
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
135 if v is None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
136 return 0
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
137
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
138 # Get length value
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
139 m = re.search(number_re, v)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
140 if m: value = m.group(0)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
141 else: raise TypeError(v + 'is not a valid length')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
142
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
143 # Get length unit
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
144 m = re.search(unit_re, v)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
145 if m: unit = m.group(0)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
146 else: unit = None
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
147
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
148 if unit == '%':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
149 if mode == 'x':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
150 return float(value) * unit_convert[unit] * self.viewport.x
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
151 if mode == 'y':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
152 return float(value) * unit_convert[unit] * self.viewport.y
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
153 if mode == 'xy':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
154 return float(value) * unit_convert[unit] * self.viewport.x # FIXME
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
155
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
156 return float(value) * unit_convert[unit]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
157
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
158 def xlength(self, x):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
159 return self.length(x, 'x')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
160 def ylength(self, y):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
161 return self.length(y, 'y')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
162
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
163 def flatten(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
164 '''Flatten the SVG objects nested list into a flat (1-D) list,
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
165 removing Groups'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
166 # http://rightfootin.blogspot.fr/2006/09/more-on-python-flatten.html
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
167 # Assigning a slice a[i:i+1] with a list actually replaces the a[i]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
168 # element with the content of the assigned list
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
169 i = 0
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
170 flat = copy.deepcopy(self.items)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
171 while i < len(flat):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
172 while isinstance(flat[i], Group):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
173 flat[i:i+1] = flat[i].items
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
174 i += 1
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
175 return flat
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
176
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
177 def scale(self, ratio):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
178 for x in self.items:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
179 x.scale(ratio)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
180 return self
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
181
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
182 def translate(self, offset):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
183 for x in self.items:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
184 x.translate(offset)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
185 return self
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
186
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
187 def rotate(self, angle):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
188 for x in self.items:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
189 x.rotate(angle)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
190 return self
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
191
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
192 class Svg(Transformable):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
193 '''SVG class: use parse to parse a file'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
194 # class Svg handles the <svg> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
195 # tag = 'svg'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
196
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
197 def __init__(self, filename=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
198 Transformable.__init__(self)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
199 if filename:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
200 self.parse(filename)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
201
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
202 def parse(self, filename):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
203 self.filename = filename
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
204 tree = etree.parse(filename)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
205 self.root = tree.getroot()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
206 if self.root.tag != svg_ns + 'svg':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
207 raise TypeError('file %s does not seem to be a valid SVG file', filename)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
208
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
209 # Create a top Group to group all other items (useful for viewBox elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
210 top_group = Group()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
211 self.items.append(top_group)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
212
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
213 # SVG dimension
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
214 width = self.xlength(self.root.get('width'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
215 height = self.ylength(self.root.get('height'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
216 # update viewport
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
217 top_group.viewport = Point(width, height)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
218
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
219 # viewBox
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
220 if self.root.get('viewBox') is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
221 viewBox = re.findall(number_re, self.root.get('viewBox'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
222 sx = width / float(viewBox[2])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
223 sy = height / float(viewBox[3])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
224 tx = -float(viewBox[0])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
225 ty = -float(viewBox[1])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
226 top_group.matrix = Matrix([sx, 0, 0, sy, tx, ty])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
227
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
228 # Parse XML elements hierarchically with groups <g>
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
229 top_group.append(self.root)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
230
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
231 self.transform()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
232
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
233 def title(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
234 t = self.root.find(svg_ns + 'title')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
235 if t is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
236 return t
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
237 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
238 return os.path.splitext(os.path.basename(self.filename))[0]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
239
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
240 def json(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
241 return self.items
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
242
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
243
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
244 class Group(Transformable):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
245 '''Handle svg <g> elements'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
246 # class Group handles the <g> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
247 tag = 'g'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
248
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
249 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
250 Transformable.__init__(self, elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
251
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
252 def append(self, element):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
253 for elt in element:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
254 elt_class = svgClass.get(elt.tag, None)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
255 if elt_class is None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
256 print('No handler for element %s' % elt.tag)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
257 continue
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
258 # instanciate elt associated class (e.g. <path>: item = Path(elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
259 item = elt_class(elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
260 # Apply group matrix to the newly created object
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
261 item.matrix = self.matrix * item.matrix
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
262 item.viewport = self.viewport
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
263
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
264 self.items.append(item)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
265 # Recursively append if elt is a <g> (group)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
266 if elt.tag == svg_ns + 'g':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
267 item.append(elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
268
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
269 def __repr__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
270 return '<Group ' + self.id + '>: ' + repr(self.items)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
271
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
272 def json(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
273 return {'Group ' + self.id : self.items}
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
274
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
275 class Matrix:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
276 ''' SVG transformation matrix and its operations
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
277 a SVG matrix is represented as a list of 6 values [a, b, c, d, e, f]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
278 (named vect hereafter) which represent the 3x3 matrix
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
279 ((a, c, e)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
280 (b, d, f)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
281 (0, 0, 1))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
282 see http://www.w3.org/TR/SVG/coords.html#EstablishingANewUserSpace '''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
283
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
284 def __init__(self, vect=[1, 0, 0, 1, 0, 0]):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
285 # Unit transformation vect by default
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
286 if len(vect) != 6:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
287 raise ValueError("Bad vect size %d" % len(vect))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
288 self.vect = list(vect)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
289
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
290 def __mul__(self, other):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
291 '''Matrix multiplication'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
292 if isinstance(other, Matrix):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
293 a = self.vect[0] * other.vect[0] + self.vect[2] * other.vect[1]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
294 b = self.vect[1] * other.vect[0] + self.vect[3] * other.vect[1]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
295 c = self.vect[0] * other.vect[2] + self.vect[2] * other.vect[3]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
296 d = self.vect[1] * other.vect[2] + self.vect[3] * other.vect[3]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
297 e = self.vect[0] * other.vect[4] + self.vect[2] * other.vect[5] \
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
298 + self.vect[4]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
299 f = self.vect[1] * other.vect[4] + self.vect[3] * other.vect[5] \
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
300 + self.vect[5]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
301 return Matrix([a, b, c, d, e, f])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
302
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
303 elif isinstance(other, Point):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
304 x = other.x * self.vect[0] + other.y * self.vect[2] + self.vect[4]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
305 y = other.x * self.vect[1] + other.y * self.vect[3] + self.vect[5]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
306 return Point(x,y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
307
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
308 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
309 return NotImplemented
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
310
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
311 def __str__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
312 return str(self.vect)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
313
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
314 def xlength(self, x):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
315 return x * self.vect[0]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
316 def ylength(self, y):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
317 return y * self.vect[3]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
318
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
319
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
320 COMMANDS = 'MmZzLlHhVvCcSsQqTtAa'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
321
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
322 class Path(Transformable):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
323 '''SVG <path>'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
324 # class Path handles the <path> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
325 tag = 'path'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
326
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
327 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
328 Transformable.__init__(self, elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
329 if elt is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
330 self.style = elt.get('style')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
331 self.parse(elt.get('d'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
332
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
333 def parse(self, pathstr):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
334 """Parse path string and build elements list"""
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
335
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
336 pathlst = re.findall(number_re + r"|\ *[%s]\ *" % COMMANDS, pathstr)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
337
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
338 pathlst.reverse()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
339
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
340 command = None
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
341 current_pt = Point(0,0)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
342 start_pt = None
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
343
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
344 while pathlst:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
345 if pathlst[-1].strip() in COMMANDS:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
346 last_command = command
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
347 command = pathlst.pop().strip()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
348 absolute = (command == command.upper())
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
349 command = command.upper()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
350 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
351 if command is None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
352 raise ValueError("No command found at %d" % len(pathlst))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
353
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
354 if command == 'M':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
355 # MoveTo
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
356 x = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
357 y = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
358 pt = Point(x, y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
359 if absolute:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
360 current_pt = pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
361 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
362 current_pt += pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
363 start_pt = current_pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
364
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
365 self.items.append(MoveTo(current_pt))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
366
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
367 # MoveTo with multiple coordinates means LineTo
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
368 command = 'L'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
369
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
370 elif command == 'Z':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
371 # Close Path
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
372 l = Segment(current_pt, start_pt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
373 self.items.append(l)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
374
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
375
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
376 elif command in 'LHV':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
377 # LineTo, Horizontal & Vertical line
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
378 # extra coord for H,V
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
379 if absolute:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
380 x,y = current_pt.coord()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
381 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
382 x,y = (0,0)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
383
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
384 if command in 'LH':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
385 x = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
386 if command in 'LV':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
387 y = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
388
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
389 pt = Point(x, y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
390 if not absolute:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
391 pt += current_pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
392
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
393 self.items.append(Segment(current_pt, pt))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
394 current_pt = pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
395
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
396 elif command in 'CQ':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
397 dimension = {'Q':3, 'C':4}
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
398 bezier_pts = []
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
399 bezier_pts.append(current_pt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
400 for i in range(1,dimension[command]):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
401 x = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
402 y = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
403 pt = Point(x, y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
404 if not absolute:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
405 pt += current_pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
406 bezier_pts.append(pt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
407
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
408 self.items.append(Bezier(bezier_pts))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
409 current_pt = pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
410
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
411 elif command in 'TS':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
412 # number of points to read
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
413 nbpts = {'T':1, 'S':2}
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
414 # the control point, from previous Bezier to mirror
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
415 ctrlpt = {'T':1, 'S':2}
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
416 # last command control
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
417 last = {'T': 'QT', 'S':'CS'}
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
418
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
419 bezier_pts = []
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
420 bezier_pts.append(current_pt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
421
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
422 if last_command in last[command]:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
423 pt0 = self.items[-1].control_point(ctrlpt[command])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
424 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
425 pt0 = current_pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
426 pt1 = current_pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
427 # Symetrical of pt1 against pt0
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
428 bezier_pts.append(pt1 + pt1 - pt0)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
429
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
430 for i in range(0,nbpts[command]):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
431 x = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
432 y = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
433 pt = Point(x, y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
434 if not absolute:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
435 pt += current_pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
436 bezier_pts.append(pt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
437
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
438 self.items.append(Bezier(bezier_pts))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
439 current_pt = pt
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
440
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
441 elif command == 'A':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
442 rx = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
443 ry = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
444 xrot = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
445 # Arc flags are not necesarily sepatated numbers
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
446 flags = pathlst.pop().strip()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
447 large_arc_flag = flags[0]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
448 if large_arc_flag not in '01':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
449 print('Arc parsing failure')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
450 break
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
451
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
452 if len(flags) > 1: flags = flags[1:].strip()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
453 else: flags = pathlst.pop().strip()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
454 sweep_flag = flags[0]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
455 if sweep_flag not in '01':
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
456 print('Arc parsing failure')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
457 break
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
458
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
459 if len(flags) > 1: x = flags[1:]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
460 else: x = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
461 y = pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
462 # TODO
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
463 print('ARC: ' +
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
464 ', '.join([rx, ry, xrot, large_arc_flag, sweep_flag, x, y]))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
465 # self.items.append(
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
466 # Arc(rx, ry, xrot, large_arc_flag, sweep_flag, Point(x, y)))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
467
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
468 else:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
469 pathlst.pop()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
470
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
471 def __str__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
472 return '\n'.join(str(x) for x in self.items)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
473
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
474 def __repr__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
475 return '<Path ' + self.id + '>'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
476
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
477 def segments(self, precision=0):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
478 '''Return a list of segments, each segment is ended by a MoveTo.
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
479 A segment is a list of Points'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
480 ret = []
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
481 # group items separated by MoveTo
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
482 for moveTo, group in itertools.groupby(self.items,
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
483 lambda x: isinstance(x, MoveTo)):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
484 # Use only non MoveTo item
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
485 if not moveTo:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
486 # Generate segments for each relevant item
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
487 seg = [x.segments(precision) for x in group]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
488 # Merge all segments into one
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
489 ret.append(list(itertools.chain.from_iterable(seg)))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
490
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
491 return ret
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
492
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
493 def simplify(self, precision):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
494 '''Simplify segment with precision:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
495 Remove any point which are ~aligned'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
496 ret = []
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
497 for seg in self.segments(precision):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
498 ret.append(simplify_segment(seg, precision))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
499
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
500 return ret
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
501
3
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
502
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
503 class Polygon(Transformable):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
504 '''SVG <polygon>'''
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
505 # class Path handles the <polygon> tag
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
506 tag = 'polygon'
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
507
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
508 def __init__(self, elt=None):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
509 Transformable.__init__(self, elt)
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
510 if elt is not None:
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
511 self.style = elt.get('style')
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
512 self.parse(elt.get('points'))
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
513
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
514 def parse(self, pathstr):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
515 """Parse path string and build elements list"""
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
516
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
517 pathlst = re.findall(point_re, pathstr)
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
518
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
519 #pathlst.reverse()
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
520
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
521 current_pt = None
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
522 start_pt = None
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
523 while pathlst:
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
524 coord = pathlst.pop().split(",")
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
525 pt = Point(coord[0], coord[1])
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
526
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
527 if start_pt:
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
528 current_pt = pt
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
529 l = Segment(start_pt, current_pt)
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
530 self.items.append(l)
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
531 start_pt = current_pt
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
532 else:
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
533 start_pt = pt
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
534 self.items.append(MoveTo(pt))
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
535
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
536 def __str__(self):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
537 return '\n'.join(str(x) for x in self.items)
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
538
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
539 def __repr__(self):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
540 return '<Polygon ' + self.id + '>'
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
541
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
542 def segments(self, precision=0):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
543 '''Return a list of segments, each segment is ended by a MoveTo.
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
544 A segment is a list of Points'''
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
545 ret = []
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
546 # group items separated by MoveTo
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
547 for moveTo, group in itertools.groupby(self.items,
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
548 lambda x: isinstance(x, MoveTo)):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
549 # Use only non MoveTo item
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
550 if not moveTo:
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
551 # Generate segments for each relevant item
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
552 seg = [x.segments(precision) for x in group]
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
553 # Merge all segments into one
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
554 ret.append(list(itertools.chain.from_iterable(seg)))
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
555
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
556 return ret
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
557
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
558 def simplify(self, precision):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
559 '''Simplify segment with precision:
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
560 Remove any point which are ~aligned'''
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
561 ret = []
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
562 for seg in self.segments(precision):
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
563 ret.append(simplify_segment(seg, precision))
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
564
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
565 return ret
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
566
a519e3ac3849 added parser for polygon elements
mbayer
parents: 2
diff changeset
567
2
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
568 class Ellipse(Transformable):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
569 '''SVG <ellipse>'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
570 # class Ellipse handles the <ellipse> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
571 tag = 'ellipse'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
572
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
573 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
574 Transformable.__init__(self, elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
575 if elt is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
576 self.center = Point(self.xlength(elt.get('cx')),
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
577 self.ylength(elt.get('cy')))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
578 self.rx = self.length(elt.get('rx'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
579 self.ry = self.length(elt.get('ry'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
580 self.style = elt.get('style')
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
581
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
582 def __repr__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
583 return '<Ellipse ' + self.id + '>'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
584
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
585 def bbox(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
586 '''Bounding box'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
587 pmin = self.center - Point(self.rx, self.ry)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
588 pmax = self.center + Point(self.rx, self.ry)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
589 return (pmin, pmax)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
590
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
591 def transform(self, matrix):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
592 self.center = self.matrix * self.center
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
593 self.rx = self.matrix.xlength(self.rx)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
594 self.ry = self.matrix.ylength(self.ry)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
595
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
596 def scale(self, ratio):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
597 self.center *= ratio
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
598 self.rx *= ratio
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
599 self.ry *= ratio
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
600 def translate(self, offset):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
601 self.center += offset
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
602 def rotate(self, angle):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
603 self.center = self.center.rot(angle)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
604
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
605 def P(self, t):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
606 '''Return a Point on the Ellipse for t in [0..1]'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
607 x = self.center.x + self.rx * math.cos(2 * math.pi * t)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
608 y = self.center.y + self.ry * math.sin(2 * math.pi * t)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
609 return Point(x,y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
610
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
611 def segments(self, precision=0):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
612 if max(self.rx, self.ry) < precision:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
613 return [[self.center]]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
614
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
615 p = [(0,self.P(0)), (1, self.P(1))]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
616 d = 2 * max(self.rx, self.ry)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
617
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
618 while d > precision:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
619 for (t1,p1),(t2,p2) in zip(p[:-1],p[1:]):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
620 t = t1 + (t2 - t1)/2.
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
621 d = Segment(p1, p2).pdistance(self.P(t))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
622 p.append((t, self.P(t)))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
623 p.sort(key=operator.itemgetter(0))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
624
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
625 ret = [x for t,x in p]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
626 return [ret]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
627
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
628 def simplify(self, precision):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
629 return self
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
630
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
631 # A circle is a special type of ellipse where rx = ry = radius
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
632 class Circle(Ellipse):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
633 '''SVG <circle>'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
634 # class Circle handles the <circle> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
635 tag = 'circle'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
636
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
637 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
638 if elt is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
639 elt.set('rx', elt.get('r'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
640 elt.set('ry', elt.get('r'))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
641 Ellipse.__init__(self, elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
642
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
643 def __repr__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
644 return '<Circle ' + self.id + '>'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
645
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
646 class Rect(Transformable):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
647 '''SVG <rect>'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
648 # class Rect handles the <rect> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
649 tag = 'rect'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
650
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
651 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
652 Transformable.__init__(self, elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
653 if elt is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
654 self.P1 = Point(self.xlength(elt.get('x')),
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
655 self.ylength(elt.get('y')))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
656
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
657 self.P2 = Point(self.P1.x + self.xlength(elt.get('width')),
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
658 self.P1.y + self.ylength(elt.get('height')))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
659
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
660 def __repr__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
661 return '<Rect ' + self.id + '>'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
662
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
663 def bbox(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
664 '''Bounding box'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
665 xmin = min([p.x for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
666 xmax = max([p.x for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
667 ymin = min([p.y for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
668 ymax = max([p.y for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
669
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
670 return (Point(xmin,ymin), Point(xmax,ymax))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
671
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
672 def transform(self, matrix):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
673 self.P1 = self.matrix * self.P1
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
674 self.P2 = self.matrix * self.P2
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
675
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
676 def segments(self, precision=0):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
677 # A rectangle is built with a segment going thru 4 points
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
678 ret = []
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
679 Pa = Point(self.P1.x, self.P2.y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
680 Pb = Point(self.P2.x, self.P1.y)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
681
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
682 ret.append([self.P1, Pa, self.P2, Pb, self.P1])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
683 return ret
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
684
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
685 def simplify(self, precision):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
686 return self.segments(precision)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
687
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
688 class Line(Transformable):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
689 '''SVG <line>'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
690 # class Line handles the <line> tag
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
691 tag = 'line'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
692
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
693 def __init__(self, elt=None):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
694 Transformable.__init__(self, elt)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
695 if elt is not None:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
696 self.P1 = Point(self.xlength(elt.get('x1')),
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
697 self.ylength(elt.get('y1')))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
698 self.P2 = Point(self.xlength(elt.get('x2')),
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
699 self.ylength(elt.get('y2')))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
700 self.segment = Segment(self.P1, self.P2)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
701
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
702 def __repr__(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
703 return '<Line ' + self.id + '>'
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
704
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
705 def bbox(self):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
706 '''Bounding box'''
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
707 xmin = min([p.x for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
708 xmax = max([p.x for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
709 ymin = min([p.y for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
710 ymax = max([p.y for p in (self.P1, self.P2)])
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
711
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
712 return (Point(xmin,ymin), Point(xmax,ymax))
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
713
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
714 def transform(self, matrix):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
715 self.P1 = self.matrix * self.P1
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
716 self.P2 = self.matrix * self.P2
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
717 self.segment = Segment(self.P1, self.P2)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
718
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
719 def segments(self, precision=0):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
720 return [self.segment.segments()]
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
721
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
722 def simplify(self, precision):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
723 return self.segments(precision)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
724
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
725 # overwrite JSONEncoder for svg classes which have defined a .json() method
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
726 class JSONEncoder(json.JSONEncoder):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
727 def default(self, obj):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
728 if not isinstance(obj, tuple(svgClass.values() + [Svg])):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
729 return json.JSONEncoder.default(self, obj)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
730
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
731 if not hasattr(obj, 'json'):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
732 return repr(obj)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
733
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
734 return obj.json()
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
735
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
736 ## Code executed on module load ##
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
737
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
738 # SVG tag handler classes are initialized here
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
739 # (classes must be defined before)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
740 import inspect
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
741 svgClass = {}
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
742 # Register all classes with attribute 'tag' in svgClass dict
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
743 for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
744 tag = getattr(cls, 'tag', None)
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
745 if tag:
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
746 svgClass[svg_ns + tag] = cls
660ce16822a9 added basic svg parser library
mbayer
parents:
diff changeset
747

mercurial