Skip to content

Commit 2c6c3b7

Browse files
authored
Merge pull request #236 from nxp-mcuxpresso/release/vglite-tools-2.1
Upstream svgpathtools improvement - v2.1
2 parents 10ee33f + aeb799b commit 2c6c3b7

File tree

4 files changed

+83
-8
lines changed

4 files changed

+83
-8
lines changed

svgpathtools/svg_to_paths.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def path2pathd(path):
2727
return path.get('d', '')
2828

2929

30-
def ellipse2pathd(ellipse):
30+
def ellipse2pathd(ellipse, use_cubics=False):
3131
"""converts the parameters from an ellipse or a circle to a string for a
3232
Path object d-attribute"""
3333

@@ -46,10 +46,32 @@ def ellipse2pathd(ellipse):
4646
cx = float(cx)
4747
cy = float(cy)
4848

49-
d = ''
50-
d += 'M' + str(cx - rx) + ',' + str(cy)
51-
d += 'a' + str(rx) + ',' + str(ry) + ' 0 1,0 ' + str(2 * rx) + ',0'
52-
d += 'a' + str(rx) + ',' + str(ry) + ' 0 1,0 ' + str(-2 * rx) + ',0'
49+
if use_cubics:
50+
# Modified by NXP 2024, 2025
51+
PATH_KAPPA = 0.552284
52+
rxKappa = rx * PATH_KAPPA;
53+
ryKappa = ry * PATH_KAPPA;
54+
55+
#According to the SVG specification (https://lists.w3.org/Archives/Public/www-archive/2005May/att-0005/SVGT12_Main.pdf),
56+
#Section 9.4, "The 'ellipse' element": "The arc of an 'ellipse' element begins at the "3 o'clock" point on
57+
#the radius and progresses towards the "9 o'clock". Therefore, the ellipse begins at the rightmost point
58+
#and progresses clockwise.
59+
d = ''
60+
# Move to the rightmost point
61+
d += 'M' + str(cx + rx) + ' ' + str(cy)
62+
# Draw bottom-right quadrant
63+
d += 'C' + str(cx + rx) + ' ' + str(cy + ryKappa) + ' ' + str(cx + rxKappa) + ' ' + str(cy + ry) + ' ' + str(cx) + ' ' + str(cy + ry)
64+
# Draw bottom-left quadrant
65+
d += 'C' + str(cx - rxKappa) + ' ' + str(cy + ry) + ' ' + str(cx - rx) + ' ' + str(cy + ryKappa) + ' ' + str(cx - rx) + ' ' + str(cy)
66+
# Draw top-left quadrant
67+
d += 'C' + str(cx - rx) + ' ' + str(cy - ryKappa) + ' ' + str(cx - rxKappa) + ' ' + str(cy - ry) + ' ' + str(cx) + ' ' + str(cy - ry)
68+
# Draw top-right quadrant
69+
d += 'C' + str(cx + rxKappa) + ' ' + str(cy - ry) + ' ' + str(cx + rx) + ' ' + str(cy - ryKappa) + ' ' + str(cx + rx) + ' ' + str(cy)
70+
else:
71+
d = ''
72+
d += 'M' + str(cx - rx) + ',' + str(cy)
73+
d += 'a' + str(rx) + ',' + str(ry) + ' 0 1,0 ' + str(2 * rx) + ',0'
74+
d += 'a' + str(rx) + ',' + str(ry) + ' 0 1,0 ' + str(-2 * rx) + ',0'
5375

5476
return d + 'z'
5577

@@ -62,6 +84,9 @@ def polyline2pathd(polyline, is_polygon=False):
6284
else:
6385
points = COORD_PAIR_TMPLT.findall(polyline.get('points', ''))
6486

87+
if len(points) == 0:
88+
return ''
89+
6590
closed = (float(points[0][0]) == float(points[-1][0]) and
6691
float(points[0][1]) == float(points[-1][1]))
6792

@@ -77,13 +102,13 @@ def polyline2pathd(polyline, is_polygon=False):
77102
return d
78103

79104

80-
def polygon2pathd(polyline):
105+
def polygon2pathd(polyline, is_polygon=True):
81106
"""converts the string from a polygon points-attribute to a string
82107
for a Path object d-attribute.
83108
Note: For a polygon made from n points, the resulting path will be
84109
composed of n lines (even if some of these lines have length zero).
85110
"""
86-
return polyline2pathd(polyline, True)
111+
return polyline2pathd(polyline, is_polygon)
87112

88113

89114
def rect2pathd(rect):
@@ -205,7 +230,7 @@ def dom2dict(element):
205230
# path strings, add to list
206231
if convert_polygons_to_paths:
207232
pgons = [dom2dict(el) for el in doc.getElementsByTagName('polygon')]
208-
d_strings += [polygon2pathd(pg) for pg in pgons]
233+
d_strings += [polygon2pathd(pg, True) for pg in pgons]
209234
attribute_dictionary_list += pgons
210235

211236
if convert_lines_to_paths:

test/polygons_no_points.svg

Lines changed: 5 additions & 0 deletions
Loading

test/polyline.svg

Lines changed: 7 additions & 0 deletions
Loading

test/test_svg2paths.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,44 @@ def test_from_string(self):
168168

169169
self.assertEqual(len(paths), 2)
170170

171+
def test_svg2paths_polygon_no_points(self):
172+
173+
paths, _ = svg2paths(join(dirname(__file__), 'polygons_no_points.svg'))
174+
175+
path = paths[0]
176+
path_correct = Path()
177+
self.assertTrue(len(path)==0)
178+
self.assertTrue(path==path_correct)
179+
180+
path = paths[1]
181+
self.assertTrue(len(path)==0)
182+
self.assertTrue(path==path_correct)
183+
184+
def test_svg2paths_polyline_tests(self):
185+
186+
paths, _ = svg2paths(join(dirname(__file__), 'polyline.svg'))
187+
188+
path = paths[0]
189+
path_correct = Path(Line(59+185j, 98+203j),
190+
Line(98+203j, 108+245j),
191+
Line(108+245j, 82+279j),
192+
Line(82+279j, 39+280j),
193+
Line(39+280j, 11+247j),
194+
Line(11+247j, 19+205j))
195+
self.assertFalse(path.isclosed())
196+
self.assertTrue(len(path)==6)
197+
self.assertTrue(path==path_correct)
198+
199+
path = paths[1]
200+
path_correct = Path(Line(220+50j, 267+84j),
201+
Line(267+84j, 249+140j),
202+
Line(249+140j, 190+140j),
203+
Line(190+140j, 172+84j),
204+
Line(172+84j, 220+50j))
205+
self.assertTrue(path.isclosed())
206+
self.assertTrue(len(path)==5)
207+
self.assertTrue(path==path_correct)
208+
171209

172210
if __name__ == '__main__':
173211
unittest.main()

0 commit comments

Comments
 (0)