-
Notifications
You must be signed in to change notification settings - Fork 154
Upstream svgpathtools improvement #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
f058038
4c4cb51
405baa9
0ec4f99
302071a
d7927a7
833a0a6
a70e494
c71b257
1396f99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| # | ||
| # Modified by NXP 2024 | ||
| # | ||
| """This submodule contains tools for creating path objects from SVG files. | ||
| The main tool being the svg2paths() function.""" | ||
|
|
||
|
|
@@ -31,27 +34,42 @@ def ellipse2pathd(ellipse): | |
| """converts the parameters from an ellipse or a circle to a string for a | ||
| Path object d-attribute""" | ||
|
|
||
| cx = ellipse.get('cx', 0) | ||
| cy = ellipse.get('cy', 0) | ||
| cx = (ellipse.get('cx', 0) or 0) | ||
| cy = (ellipse.get('cy', 0) or 0) | ||
| rx = ellipse.get('rx', None) | ||
| ry = ellipse.get('ry', None) | ||
| r = ellipse.get('r', None) | ||
|
|
||
| if r is not None: | ||
| rx = ry = float(r) | ||
| else: | ||
| rx = float(rx) | ||
| ry = float(ry) | ||
| rx = float(rx or 0) | ||
| ry = float(ry or 0) | ||
|
|
||
| cx = float(cx) | ||
| cy = float(cy) | ||
|
|
||
| d = '' | ||
| d += 'M' + str(cx - rx) + ',' + str(cy) | ||
| d += 'a' + str(rx) + ',' + str(ry) + ' 0 1,0 ' + str(2 * rx) + ',0' | ||
| d += 'a' + str(rx) + ',' + str(ry) + ' 0 1,0 ' + str(-2 * rx) + ',0' | ||
| PATH_KAPPA = 0.552284 | ||
| rxKappa = rx * PATH_KAPPA; | ||
| ryKappa = ry * PATH_KAPPA; | ||
|
|
||
| return d + 'z' | ||
| #According to the SVG specification (https://lists.w3.org/Archives/Public/www-archive/2005May/att-0005/SVGT12_Main.pdf), | ||
| #Section 9.4, "The 'ellipse' element": "The arc of an 'ellipse' element begins at the "3 o'clock" point on | ||
| #the radius and progresses towards the "9 o'clock". Therefore, the ellipse begins at the rightmost point | ||
| #and progresses clockwise. | ||
| d = '' | ||
| # Move to the rightmost point | ||
| d += 'M ' + str(cx + rx) + ' ' + str(cy) | ||
| # Draw bottom-right quadrant | ||
| d += ' C ' + str(cx + rx) + ' ' + str(cy + ryKappa) + ' ' + str(cx + rxKappa) + ' ' + str(cy + ry) + ' ' + str(cx) + ' ' + str(cy + ry) | ||
| # Draw bottom-left quadrant | ||
| d += ' C ' + str(cx - rxKappa) + ' ' + str(cy + ry) + ' ' + str(cx - rx) + ' ' + str(cy + ryKappa) + ' ' + str(cx - rx) + ' ' + str(cy) | ||
| # Draw top-left quadrant | ||
| d += ' C ' + str(cx - rx) + ' ' + str(cy - ryKappa) + ' ' + str(cx - rxKappa) + ' ' + str(cy - ry) + ' ' + str(cx) + ' ' + str(cy - ry) | ||
| # Draw top-right quadrant | ||
| d += ' C ' + str(cx + rxKappa) + ' ' + str(cy - ry) + ' ' + str(cx + rx) + ' ' + str(cy - ryKappa) + ' ' + str(cx + rx) + ' ' + str(cy) | ||
|
|
||
| return d + ' Z' | ||
|
|
||
|
|
||
| def polyline2pathd(polyline, is_polygon=False): | ||
|
|
@@ -60,39 +78,43 @@ def polyline2pathd(polyline, is_polygon=False): | |
| if isinstance(polyline, str): | ||
| points = polyline | ||
| else: | ||
| points = COORD_PAIR_TMPLT.findall(polyline.get('points', '')) | ||
| raw_points = polyline.get('points', '') | ||
| if not raw_points: | ||
| points = [(0,0)] | ||
|
||
| else: | ||
| points = COORD_PAIR_TMPLT.findall(raw_points) | ||
|
|
||
| closed = (float(points[0][0]) == float(points[-1][0]) and | ||
| float(points[0][1]) == float(points[-1][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: | ||
| if is_polygon or closed: | ||
| points.append(points[0]) | ||
|
|
||
| d = 'M' + 'L'.join('{0} {1}'.format(x,y) for x,y in points) | ||
| d = 'M ' + ' L '.join('{0} {1}'.format(x,y) for x,y in points) | ||
| if is_polygon or closed: | ||
| d += 'z' | ||
| d += ' z' | ||
| return d | ||
|
|
||
|
|
||
| def polygon2pathd(polyline): | ||
| def polygon2pathd(polyline, is_polygon): | ||
NGExplorer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| """converts the string from a polygon points-attribute to a string | ||
| for a 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). | ||
| """ | ||
| return polyline2pathd(polyline, True) | ||
| return polyline2pathd(polyline, is_polygon) | ||
|
|
||
|
|
||
| def rect2pathd(rect): | ||
| """Converts an SVG-rect element to a Path d-string. | ||
|
|
||
| The rectangle will start at the (x,y) coordinate specified by the | ||
| rectangle object and proceed counter-clockwise.""" | ||
| x, y = float(rect.get('x', 0)), float(rect.get('y', 0)) | ||
| w, h = float(rect.get('width', 0)), float(rect.get('height', 0)) | ||
| x, y = float(rect.get('x', 0) or 0), float(rect.get('y', 0) or 0) | ||
| w, h = float(rect.get('width', 0) or 0), float(rect.get('height', 0) or 0) | ||
| if 'rx' in rect or 'ry' in rect: | ||
|
|
||
| # if only one, rx or ry, is present, use that value for both | ||
|
|
@@ -121,7 +143,7 @@ def rect2pathd(rect): | |
| x2, y2 = x + w, y + h | ||
| x3, y3 = x, y + h | ||
|
|
||
| d = ("M{} {} L {} {} L {} {} L {} {} z" | ||
| d = ("M {} {} L {} {} L {} {} L {} {} z" | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this change have an effect? |
||
| "".format(x0, y0, x1, y1, x2, y2, x3, y3)) | ||
|
|
||
| return d | ||
|
|
@@ -204,7 +226,7 @@ def dom2dict(element): | |
| # path strings, add to list | ||
| if convert_polygons_to_paths: | ||
| pgons = [dom2dict(el) for el in doc.getElementsByTagName('polygon')] | ||
| d_strings += [polygon2pathd(pg) for pg in pgons] | ||
| d_strings += [polygon2pathd(pg, True) for pg in pgons] | ||
| attribute_dictionary_list += pgons | ||
|
|
||
| if convert_lines_to_paths: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be an option, we should let users continue using arcs if they want, and for now at least.
Let's make that the default unless there is a very good reason this new behavior should be the default.
We could
use_cubics=FalseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @mathandy , We have incorporated this suggestion. We'll upstream our changes in this PR in 1-2 days.