Skip to content

Commit

Permalink
Merge pull request #223 from meerk40t/non-recursive_loop
Browse files Browse the repository at this point in the history
Correct Issue #222 Iterative Point Adding.
  • Loading branch information
tatarize authored Apr 17, 2023
2 parents 2832d96 + 22ab916 commit cd8cb41
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 122 deletions.
212 changes: 90 additions & 122 deletions svgelements/svgelements.py
Original file line number Diff line number Diff line change
Expand Up @@ -6053,154 +6053,122 @@ def start(self):
def end(self):
pass

def move(self, *points, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
def move(self, *points, relative=False, **kwargs):
start_pos = self.current_point
end_pos = points[0]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = Move(start_pos, end_pos)
segment.relative = relative
self.append(segment)
self.append(Move(start_pos, end_pos, relative=relative))
if len(points) > 1:
self.line(*points[1:], relative=relative)
return self

def line(self, *points, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
end_pos = points[0]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = Line(start_pos, end_pos)
segment.relative = relative
self.append(segment)
if len(points) > 1:
self.line(*points[1:])
def line(self, *points, relative=False, **kwargs):
for index in range(len(points)):
start_pos = self.current_point
end_pos = points[index]
if end_pos in ("z", "Z"):
end_pos = self.z_point
self.append(Line(start_pos, end_pos, relative=relative))
return self

def vertical(self, *y_points, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
if relative:
segment = Line(start_pos, Point(start_pos.x, start_pos.y + y_points[0]))
else:
segment = Line(start_pos, Point(start_pos.x, y_points[0]))
segment.relative = relative
self.append(segment)
if len(y_points) > 1:
self.vertical(*y_points[1:], relative=relative)
def vertical(self, *y_points, relative=False, **kwargs):
for index in range(len(y_points)):
start_pos = self.current_point
if relative:
self.append(Line(start_pos, Point(start_pos.x, start_pos.y + y_points[index]), relative=relative))
else:
self.append(Line(start_pos, Point(start_pos.x, y_points[index]), relative=relative))
return self

def horizontal(self, *x_points, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
if relative:
segment = Line(start_pos, Point(start_pos.x + x_points[0], start_pos.y))
segment.relative = relative
else:
segment = Line(start_pos, Point(x_points[0], start_pos.y))
segment.relative = relative
self.append(segment)
if len(x_points) > 1:
self.horizontal(*x_points[1:], relative=relative)
def horizontal(self, *x_points, relative=False, **kwargs):
for index in range(len(x_points)):
start_pos = self.current_point
if relative:
self.append(Line(start_pos, Point(start_pos.x + x_points[index], start_pos.y), relative=relative))
else:
self.append(Line(start_pos, Point(x_points[index], start_pos.y), relative=relative))
return self

def smooth_quad(self, *points, **kwargs):
def smooth_quad(self, *points, relative=False, **kwargs):
"""Smooth curve. First control point is the "reflection" of
the second control point in the previous path."""
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
control1 = self.smooth_point
end_pos = points[0]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = QuadraticBezier(start_pos, control1, end_pos)
segment.relative = relative
segment.smooth = True
self.append(segment)
if len(points) > 1:
self.smooth_quad(*points[1:])
for index in range(len(points)):
start_pos = self.current_point
control1 = self.smooth_point
end_pos = points[index]
if end_pos in ("z", "Z"):
end_pos = self.z_point
self.append(QuadraticBezier(start_pos, control1, end_pos, relative=relative, smooth=True))
return self

def quad(self, *points, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
control = points[0]
if control in ("z", "Z"):
control = self.z_point
end_pos = points[1]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = QuadraticBezier(start_pos, control, end_pos)
segment.relative = relative
segment.smooth = False
self.append(segment)
if len(points) > 2:
self.quad(*points[2:])
def quad(self, *points, relative=False, **kwargs):
for index in range(0, len(points), 2):
start_pos = self.current_point
control = points[index]
if control in ("z", "Z"):
control = self.z_point
self.append(QuadraticBezier(start_pos, control, control, relative=relative, smooth=False))
return self
end_pos = points[index + 1]
if end_pos in ("z", "Z"):
end_pos = self.z_point
self.append(QuadraticBezier(start_pos, control, end_pos, relative=relative, smooth=False))
return self

def smooth_cubic(self, *points, **kwargs):
def smooth_cubic(self, *points, relative=False, **kwargs):
"""Smooth curve. First control point is the "reflection" of
the second control point in the previous path."""
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
control1 = self.smooth_point
control2 = points[0]

if control2 in ("z", "Z"):
control2 = self.z_point
end_pos = points[1]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = CubicBezier(start_pos, control1, control2, end_pos)
segment.relative = relative
segment.smooth = True
self.append(segment)
if len(points) > 2:
self.smooth_cubic(*points[2:])
for index in range(0, len(points), 2):
start_pos = self.current_point
control1 = self.smooth_point
control2 = points[index]

if control2 in ("z", "Z"):
control2 = self.z_point
self.append(CubicBezier(start_pos, control1, control2, control2, relative=relative, smooth=True))
return self
end_pos = points[index + 1]
if end_pos in ("z", "Z"):
end_pos = self.z_point
self.append(CubicBezier(start_pos, control1, control2, end_pos, relative=relative, smooth=True))
return self

def cubic(self, *points, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
control1 = points[0]
if control1 in ("z", "Z"):
control1 = self.z_point
control2 = points[1]
if control2 in ("z", "Z"):
control2 = self.z_point
end_pos = points[2]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = CubicBezier(start_pos, control1, control2, end_pos)
segment.relative = relative
segment.smooth = False
self.append(segment)
if len(points) > 3:
self.cubic(*points[3:])
def cubic(self, *points, relative=False, **kwargs):
for index in range(0, len(points), 3):
start_pos = self.current_point
control1 = points[index]
if control1 in ("z", "Z"):
control1 = self.z_point
self.append(CubicBezier(start_pos, control1, control1, control1, relative=relative, smooth=True))
return self
control2 = points[index + 1]
if control2 in ("z", "Z"):
control2 = self.z_point
self.append(CubicBezier(start_pos, control1, control2, control2, relative=relative, smooth=True))
return self
end_pos = points[index + 2]
if end_pos in ("z", "Z"):
end_pos = self.z_point
self.append(CubicBezier(start_pos, control1, control2, end_pos, relative=relative, smooth=False))
return self

def arc(self, *arc_args, **kwargs):
relative = kwargs["relative"] if "relative" in kwargs else False
start_pos = self.current_point
rx = arc_args[0]
ry = arc_args[1]
if rx < 0:
rx = abs(rx)
if ry < 0:
ry = abs(ry)
rotation = arc_args[2]
arc = arc_args[3]
sweep = arc_args[4]
end_pos = arc_args[5]
if end_pos in ("z", "Z"):
end_pos = self.z_point
segment = Arc(start_pos, rx, ry, rotation, arc, sweep, end_pos)
segment.relative = relative
self.append(segment)
if len(arc_args) > 6:
self.arc(*arc_args[6:])
def arc(self, *arc_args, relative=False, **kwargs):
for index in range(0, len(arc_args), 6):
start_pos = self.current_point
rx = arc_args[index]
ry = arc_args[index + 1]
if rx < 0:
rx = abs(rx)
if ry < 0:
ry = abs(ry)
rotation = arc_args[index + 2]
arc = arc_args[index + 3]
sweep = arc_args[index + 4]
end_pos = arc_args[index + 5]
if end_pos in ("z", "Z"):
end_pos = self.z_point
self.append(Arc(start_pos, rx, ry, rotation, arc, sweep, end_pos, relative=relative))
return self

def closed(self, relative=False):
Expand Down
41 changes: 41 additions & 0 deletions test/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ def test_path_z_termination(self):
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 Q 20,33 4,4 Z")
m = Path("M 4,4 L 20,20 L 25,25 L 6,3 Q 20,33 100,100 T Z")
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 Q 20,33 100,100 T 4,4 Z")
m = Path("M 4,4 L 20,20 L 25,25 L 6,3 Q Z")
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 Q 4,4 4,4 Z")
m = Path("M 4,4 L 20,20 L 25,25 L 6,3 C Z")
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 C 4,4 4,4 4,4 Z")
m = Path("M 4,4 L 20,20 L 25,25 L 6,3 Q 20,33 100,100 T z")
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 Q 20,33 100,100 T 4,4 z")
m = Path("m 0,0 1,1 A 5.01,5.01 180 0,0 z")
Expand All @@ -244,6 +248,11 @@ def test_path_z_termination(self):
m = Path("M0,0Lz")
self.assertEqual(m.d(), "M 0,0 L 0,0 z")

m = Path("M 4,4 L 20,20 L 25,25 L 6,3").quad("Z").closed()
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 Q 4,4 4,4 Z")
m = Path("M 4,4 L 20,20 L 25,25 L 6,3").cubic("Z").closed()
self.assertEqual(m.d(), "M 4,4 L 20,20 L 25,25 L 6,3 C 4,4 4,4 4,4 Z")

def test_path_setitem_slice(self):
m = Path("M0,0 1,1 z")
m[1:] = 'L2,2z'
Expand Down Expand Up @@ -289,3 +298,35 @@ def test_path_setitem_slice(self):
def m_assign():
m[-1] = 'M5,5z'
self.assertRaises(ValueError, m_assign)

def test_iterative_loop_building_line(self):
path = Path()
path.move(0)
path.line(*([complex(1, 1)] * 2000))

def test_iterative_loop_building_vert(self):
path = Path()
path.move(0)
path.vertical(*([5.0] * 2000))

def test_iterative_loop_building_horiz(self):
path = Path()
path.move(0)
path.horizontal(*([5.0] * 2000))

def test_iterative_loop_building_quad(self):
path = Path()
path.move(0)
path.quad(*([complex(1, 1), complex(1, 1)] * 1000))

def test_iterative_loop_building_cubic(self):
path = Path()
path.move(0)
path.cubic(*([complex(1, 1), complex(1, 1), complex(1, 1)] * 1000))

def test_iterative_loop_building_arc(self):
path = Path()
path.move(0)
q = [0, 0, 0, 0, 0, complex(1, 1)] * 2000
path.arc(*q)

0 comments on commit cd8cb41

Please sign in to comment.