|
@@ -9,6 +9,10 @@
|
|
|
# * Groups #
|
|
# * Groups #
|
|
|
# * Rectangles #
|
|
# * Rectangles #
|
|
|
# * Circles #
|
|
# * Circles #
|
|
|
|
|
+# * Ellipses #
|
|
|
|
|
+# * Polygons #
|
|
|
|
|
+# * Polylines #
|
|
|
|
|
+# * Lines #
|
|
|
# * Paths #
|
|
# * Paths #
|
|
|
# * All transformations #
|
|
# * All transformations #
|
|
|
# #
|
|
# #
|
|
@@ -22,6 +26,9 @@ from svg.path import Path, Line, Arc, CubicBezier, QuadraticBezier, parse_path
|
|
|
from shapely.geometry import LinearRing, LineString, Point
|
|
from shapely.geometry import LinearRing, LineString, Point
|
|
|
from shapely.affinity import translate, rotate, scale, skew, affine_transform
|
|
from shapely.affinity import translate, rotate, scale, skew, affine_transform
|
|
|
import numpy as np
|
|
import numpy as np
|
|
|
|
|
+import logging
|
|
|
|
|
+
|
|
|
|
|
+log = logging.getLogger('base2')
|
|
|
|
|
|
|
|
|
|
|
|
|
def svgparselength(lengthstr):
|
|
def svgparselength(lengthstr):
|
|
@@ -83,7 +90,7 @@ def path2shapely(path, res=1.0):
|
|
|
points.append((end.real, end.imag))
|
|
points.append((end.real, end.imag))
|
|
|
continue
|
|
continue
|
|
|
|
|
|
|
|
- print "I don't know what this is:", component
|
|
|
|
|
|
|
+ log.warning("I don't know what this is:", component)
|
|
|
continue
|
|
continue
|
|
|
|
|
|
|
|
if path.closed:
|
|
if path.closed:
|
|
@@ -156,6 +163,32 @@ def svgellipse2shapely(ellipse, n_points=32):
|
|
|
return LinearRing(pts)
|
|
return LinearRing(pts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def svgline2shapely(line):
|
|
|
|
|
+
|
|
|
|
|
+ x1 = svgparselength(line.get('x1'))
|
|
|
|
|
+ y1 = svgparselength(line.get('y1'))
|
|
|
|
|
+ x2 = svgparselength(line.get('x2'))
|
|
|
|
|
+ y2 = svgparselength(line.get('y2'))
|
|
|
|
|
+
|
|
|
|
|
+ return LineString([(x1, y1), (x2, y2)])
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def svgpolyline2shapely(polyline):
|
|
|
|
|
+
|
|
|
|
|
+ ptliststr = polyline.get('points')
|
|
|
|
|
+ points = parse_svg_point_list(ptliststr)
|
|
|
|
|
+
|
|
|
|
|
+ return LineString(points)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def svgpolygon2shapely(polygon):
|
|
|
|
|
+
|
|
|
|
|
+ ptliststr = polygon.get('points')
|
|
|
|
|
+ points = parse_svg_point_list(ptliststr)
|
|
|
|
|
+
|
|
|
|
|
+ return LinearRing(points)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def getsvggeo(node):
|
|
def getsvggeo(node):
|
|
|
"""
|
|
"""
|
|
|
Extracts and flattens all geometry from an SVG node
|
|
Extracts and flattens all geometry from an SVG node
|
|
@@ -176,35 +209,50 @@ def getsvggeo(node):
|
|
|
|
|
|
|
|
# Parse
|
|
# Parse
|
|
|
elif kind == 'path':
|
|
elif kind == 'path':
|
|
|
- print "***PATH***"
|
|
|
|
|
|
|
+ log.debug("***PATH***")
|
|
|
P = parse_path(node.get('d'))
|
|
P = parse_path(node.get('d'))
|
|
|
P = path2shapely(P)
|
|
P = path2shapely(P)
|
|
|
geo = [P]
|
|
geo = [P]
|
|
|
|
|
|
|
|
elif kind == 'rect':
|
|
elif kind == 'rect':
|
|
|
- print "***RECT***"
|
|
|
|
|
|
|
+ log.debug("***RECT***")
|
|
|
R = svgrect2shapely(node)
|
|
R = svgrect2shapely(node)
|
|
|
geo = [R]
|
|
geo = [R]
|
|
|
|
|
|
|
|
elif kind == 'circle':
|
|
elif kind == 'circle':
|
|
|
- print "***CIRCLE***"
|
|
|
|
|
|
|
+ log.debug("***CIRCLE***")
|
|
|
C = svgcircle2shapely(node)
|
|
C = svgcircle2shapely(node)
|
|
|
geo = [C]
|
|
geo = [C]
|
|
|
|
|
|
|
|
elif kind == 'ellipse':
|
|
elif kind == 'ellipse':
|
|
|
- print "***ELLIPSE***"
|
|
|
|
|
|
|
+ log.debug("***ELLIPSE***")
|
|
|
E = svgellipse2shapely(node)
|
|
E = svgellipse2shapely(node)
|
|
|
geo = [E]
|
|
geo = [E]
|
|
|
|
|
|
|
|
|
|
+ elif kind == 'polygon':
|
|
|
|
|
+ log.debug("***POLYGON***")
|
|
|
|
|
+ poly = svgpolygon2shapely(node)
|
|
|
|
|
+ geo = [poly]
|
|
|
|
|
+
|
|
|
|
|
+ elif kind == 'line':
|
|
|
|
|
+ log.debug("***LINE***")
|
|
|
|
|
+ line = svgline2shapely(node)
|
|
|
|
|
+ geo = [line]
|
|
|
|
|
+
|
|
|
|
|
+ elif kind == 'polyline':
|
|
|
|
|
+ log.debug("***POLYLINE***")
|
|
|
|
|
+ pline = svgpolyline2shapely(node)
|
|
|
|
|
+ geo = [pline]
|
|
|
|
|
+
|
|
|
else:
|
|
else:
|
|
|
- print "Unknown kind:", kind
|
|
|
|
|
|
|
+ log.warning("Unknown kind: " + kind)
|
|
|
geo = None
|
|
geo = None
|
|
|
|
|
|
|
|
# Transformations
|
|
# Transformations
|
|
|
if 'transform' in node.attrib:
|
|
if 'transform' in node.attrib:
|
|
|
trstr = node.get('transform')
|
|
trstr = node.get('transform')
|
|
|
trlist = parse_svg_transform(trstr)
|
|
trlist = parse_svg_transform(trstr)
|
|
|
- print trlist
|
|
|
|
|
|
|
+ #log.debug(trlist)
|
|
|
|
|
|
|
|
# Transformations are applied in reverse order
|
|
# Transformations are applied in reverse order
|
|
|
for tr in trlist[::-1]:
|
|
for tr in trlist[::-1]:
|
|
@@ -227,6 +275,42 @@ def getsvggeo(node):
|
|
|
return geo
|
|
return geo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def parse_svg_point_list(ptliststr):
|
|
|
|
|
+ """
|
|
|
|
|
+ Returns a list of coordinate pairs extracted from the "points"
|
|
|
|
|
+ attribute in SVG polygons and polylines.
|
|
|
|
|
+
|
|
|
|
|
+ :param ptliststr: "points" attribute string in polygon or polyline.
|
|
|
|
|
+ :return: List of tuples with coordinates.
|
|
|
|
|
+ """
|
|
|
|
|
+
|
|
|
|
|
+ pairs = []
|
|
|
|
|
+ last = None
|
|
|
|
|
+ pos = 0
|
|
|
|
|
+ i = 0
|
|
|
|
|
+
|
|
|
|
|
+ for match in re.finditer(r'(\s*,\s*)|(\s+)', ptliststr):
|
|
|
|
|
+
|
|
|
|
|
+ val = float(ptliststr[pos:match.start()])
|
|
|
|
|
+
|
|
|
|
|
+ if i % 2 == 1:
|
|
|
|
|
+ pairs.append((last, val))
|
|
|
|
|
+ else:
|
|
|
|
|
+ last = val
|
|
|
|
|
+
|
|
|
|
|
+ pos = match.end()
|
|
|
|
|
+ i += 1
|
|
|
|
|
+
|
|
|
|
|
+ # Check for last element
|
|
|
|
|
+ val = float(ptliststr[pos:])
|
|
|
|
|
+ if i % 2 == 1:
|
|
|
|
|
+ pairs.append((last, val))
|
|
|
|
|
+ else:
|
|
|
|
|
+ log.warning("Incomplete coordinates.")
|
|
|
|
|
+
|
|
|
|
|
+ return pairs
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def parse_svg_transform(trstr):
|
|
def parse_svg_transform(trstr):
|
|
|
"""
|
|
"""
|
|
|
Parses an SVG transform string into a list
|
|
Parses an SVG transform string into a list
|