From 2dcfa88cf2acceb4702eb295c46203f554d0a201 Mon Sep 17 00:00:00 2001 From: Dmitry_Milk Date: Sun, 27 May 2018 11:47:44 +0300 Subject: [PATCH] Adjust polyline/polygon parsing to W3C specification https://www.w3.org/TR/SVG11/shapes.html#PointsBNF --- svgpathtools/svg2paths.py | 44 ++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/svgpathtools/svg2paths.py b/svgpathtools/svg2paths.py index 8f62932..7c9285a 100644 --- a/svgpathtools/svg2paths.py +++ b/svgpathtools/svg2paths.py @@ -5,10 +5,16 @@ The main tool being the svg2paths() function.""" from __future__ import division, absolute_import, print_function from xml.dom.minidom import parse from os import path as os_path, getcwd +import re # Internal dependencies from .parser import parse_path +COORD_PAIR_TMPLT = re.compile( + r'([\+-]?\d*[\.\d]\d*[eE][\+-]?\d+|[\+-]?\d*[\.\d]\d*)' + + r'(?:\s*,\s*|\s+|(?=-))' + + r'([\+-]?\d*[\.\d]\d*[eE][\+-]?\d+|[\+-]?\d*[\.\d]\d*)' +) def ellipse2pathd(ellipse): """converts the parameters from an ellipse or a circle to a string for a @@ -37,19 +43,21 @@ def ellipse2pathd(ellipse): return d -def polyline2pathd(polyline_d): +def polyline2pathd(polyline_d, is_polygon=False): """converts the string from a polyline points-attribute to a string for a Path object d-attribute""" - points = polyline_d.replace(', ', ',') - points = points.replace(' ,', ',') - points = points.split() + points = COORD_PAIR_TMPLT.findall(polyline_d) + closed = (float(points[0][0]) == float(points[-1][0]) and + float(points[0][1]) == float(points[-1][1])) - closed = points[0] == points[-1] + # The `parse_path` call ignores redundant 'z' (closure) commands + # e.g. `parse_path('M0 0L100 100Z') == parse_path('M0 0L100 100L0 0Z')` + # This check ensures that an n-point polygon is converted to an n-Line path. + if is_polygon and closed: + points.append(points[0]) - d = 'M' + points.pop(0).replace(',', ' ') - for p in points: - d += 'L' + p.replace(',', ' ') - if closed: + d = 'M' + 'L'.join('{0} {1}'.format(x,y) for x,y in points) + if is_polygon or closed: d += 'z' return d @@ -59,23 +67,7 @@ def polygon2pathd(polyline_d): Path object d-attribute. Note: For a polygon made from n points, the resulting path will be composed of n lines (even if some of these lines have length zero).""" - points = polyline_d.replace(', ', ',') - points = points.replace(' ,', ',') - points = points.split() - - reduntantly_closed = points[0] == points[-1] - - d = 'M' + points[0].replace(',', ' ') - for p in points[1:]: - d += 'L' + p.replace(',', ' ') - - # The `parse_path` call ignores redundant 'z' (closure) commands - # e.g. `parse_path('M0 0L100 100Z') == parse_path('M0 0L100 100L0 0Z')` - # This check ensures that an n-point polygon is converted to an n-Line path. - if reduntantly_closed: - d += 'L' + points[0].replace(',', ' ') - - return d + 'z' + return polyline2pathd(polyline_d, True) def rect2pathd(rect):