relative path support (#81)
* relative path support * add test for path.d(rel=True) * add path test to test_path.pypull/114/head
parent
8457dc01ee
commit
c7b6c030a6
|
@ -2265,13 +2265,13 @@ class Path(MutableSequence):
|
||||||
self._end = pt
|
self._end = pt
|
||||||
self._segments[-1].end = pt
|
self._segments[-1].end = pt
|
||||||
|
|
||||||
def d(self, useSandT=False, use_closed_attrib=False):
|
def d(self, useSandT=False, use_closed_attrib=False, rel=False):
|
||||||
"""Returns a path d-string for the path object.
|
"""Returns a path d-string for the path object.
|
||||||
For an explanation of useSandT and use_closed_attrib, see the
|
For an explanation of useSandT and use_closed_attrib, see the
|
||||||
compatibility notes in the README."""
|
compatibility notes in the README."""
|
||||||
|
|
||||||
if use_closed_attrib:
|
if use_closed_attrib:
|
||||||
self_closed = self.closed(warning_on=False)
|
self_closed = self.iscontinuous() and self.isclosed()
|
||||||
if self_closed:
|
if self_closed:
|
||||||
segments = self[:-1]
|
segments = self[:-1]
|
||||||
else:
|
else:
|
||||||
|
@ -2292,36 +2292,71 @@ class Path(MutableSequence):
|
||||||
# of a closed path, then we should start a new subpath here.
|
# of a closed path, then we should start a new subpath here.
|
||||||
if current_pos != seg_start or \
|
if current_pos != seg_start or \
|
||||||
(self_closed and seg_start == end and use_closed_attrib):
|
(self_closed and seg_start == end and use_closed_attrib):
|
||||||
parts.append('M {},{}'.format(seg_start.real, seg_start.imag))
|
if rel:
|
||||||
|
_seg_start = seg_start - current_pos if current_pos is not None else seg_start
|
||||||
|
else:
|
||||||
|
_seg_start = seg_start
|
||||||
|
parts.append('M {},{}'.format(_seg_start.real, _seg_start.imag))
|
||||||
|
|
||||||
if isinstance(segment, Line):
|
if isinstance(segment, Line):
|
||||||
args = segment.end.real, segment.end.imag
|
if rel:
|
||||||
parts.append('L {},{}'.format(*args))
|
_seg_end = segment.end - seg_start
|
||||||
|
else:
|
||||||
|
_seg_end = segment.end
|
||||||
|
parts.append('L {},{}'.format(_seg_end.real, _seg_end.imag))
|
||||||
elif isinstance(segment, CubicBezier):
|
elif isinstance(segment, CubicBezier):
|
||||||
if useSandT and segment.is_smooth_from(previous_segment,
|
if useSandT and segment.is_smooth_from(previous_segment,
|
||||||
warning_on=False):
|
warning_on=False):
|
||||||
args = (segment.control2.real, segment.control2.imag,
|
if rel:
|
||||||
segment.end.real, segment.end.imag)
|
_seg_control2 = segment.control2 - seg_start
|
||||||
|
_seg_end = segment.end - seg_start
|
||||||
|
else:
|
||||||
|
_seg_control2 = segment.control2
|
||||||
|
_seg_end = segment.end
|
||||||
|
args = (_seg_control2.real, _seg_control2.imag,
|
||||||
|
_seg_end.real, _seg_end.imag)
|
||||||
parts.append('S {},{} {},{}'.format(*args))
|
parts.append('S {},{} {},{}'.format(*args))
|
||||||
else:
|
else:
|
||||||
args = (segment.control1.real, segment.control1.imag,
|
if rel:
|
||||||
segment.control2.real, segment.control2.imag,
|
_seg_control1 = segment.control1 - seg_start
|
||||||
segment.end.real, segment.end.imag)
|
_seg_control2 = segment.control2 - seg_start
|
||||||
|
_seg_end = segment.end - seg_start
|
||||||
|
else:
|
||||||
|
_seg_control1 = segment.control1
|
||||||
|
_seg_control2 = segment.control2
|
||||||
|
_seg_end = segment.end
|
||||||
|
args = (_seg_control1.real, _seg_control1.imag,
|
||||||
|
_seg_control2.real, _seg_control2.imag,
|
||||||
|
_seg_end.real, _seg_end.imag)
|
||||||
parts.append('C {},{} {},{} {},{}'.format(*args))
|
parts.append('C {},{} {},{} {},{}'.format(*args))
|
||||||
elif isinstance(segment, QuadraticBezier):
|
elif isinstance(segment, QuadraticBezier):
|
||||||
if useSandT and segment.is_smooth_from(previous_segment,
|
if useSandT and segment.is_smooth_from(previous_segment,
|
||||||
warning_on=False):
|
warning_on=False):
|
||||||
args = segment.end.real, segment.end.imag
|
if rel:
|
||||||
|
_seg_end = segment.end - seg_start
|
||||||
|
else:
|
||||||
|
_seg_end = segment.end
|
||||||
|
args = _seg_end.real, _seg_end.imag
|
||||||
parts.append('T {},{}'.format(*args))
|
parts.append('T {},{}'.format(*args))
|
||||||
else:
|
else:
|
||||||
args = (segment.control.real, segment.control.imag,
|
if rel:
|
||||||
segment.end.real, segment.end.imag)
|
_seg_control = segment.control - seg_start
|
||||||
|
_seg_end = segment.end - seg_start
|
||||||
|
else:
|
||||||
|
_seg_control = segment.control
|
||||||
|
_seg_end = segment.end
|
||||||
|
args = (_seg_control.real, _seg_control.imag,
|
||||||
|
_seg_end.real, _seg_end.imag)
|
||||||
parts.append('Q {},{} {},{}'.format(*args))
|
parts.append('Q {},{} {},{}'.format(*args))
|
||||||
|
|
||||||
elif isinstance(segment, Arc):
|
elif isinstance(segment, Arc):
|
||||||
|
if rel:
|
||||||
|
_seg_end = segment.end - seg_start
|
||||||
|
else:
|
||||||
|
_seg_end = segment.end
|
||||||
args = (segment.radius.real, segment.radius.imag,
|
args = (segment.radius.real, segment.radius.imag,
|
||||||
segment.rotation,int(segment.large_arc),
|
segment.rotation,int(segment.large_arc),
|
||||||
int(segment.sweep),segment.end.real, segment.end.imag)
|
int(segment.sweep),_seg_end.real, _seg_end.imag)
|
||||||
parts.append('A {},{} {} {:d},{:d} {},{}'.format(*args))
|
parts.append('A {},{} {} {:d},{:d} {},{}'.format(*args))
|
||||||
current_pos = segment.end
|
current_pos = segment.end
|
||||||
previous_segment = segment
|
previous_segment = segment
|
||||||
|
@ -2329,7 +2364,8 @@ class Path(MutableSequence):
|
||||||
if self_closed:
|
if self_closed:
|
||||||
parts.append('Z')
|
parts.append('Z')
|
||||||
|
|
||||||
return ' '.join(parts)
|
s = ' '.join(parts)
|
||||||
|
return s if not rel else s.lower()
|
||||||
|
|
||||||
def joins_smoothly_with(self, previous, wrt_parameterization=False):
|
def joins_smoothly_with(self, previous, wrt_parameterization=False):
|
||||||
"""Checks if this Path object joins smoothly with previous
|
"""Checks if this Path object joins smoothly with previous
|
||||||
|
|
|
@ -1052,7 +1052,16 @@ class TestPath(unittest.TestCase):
|
||||||
pt_xpct = (pt_orig - complex(0, -100)) * 0.3 + complex(0, -100)
|
pt_xpct = (pt_orig - complex(0, -100)) * 0.3 + complex(0, -100)
|
||||||
self.assertAlmostEqual(pt_xpct, pt_trns, delta=0.000001)
|
self.assertAlmostEqual(pt_xpct, pt_trns, delta=0.000001)
|
||||||
|
|
||||||
|
def test_d(self):
|
||||||
|
# the following two path represent the same path but in absolute and relative forms
|
||||||
|
abs_s = 'M 38.0,130.0 C 37.0,132.0 38.0,136.0 40.0,137.0 L 85.0,161.0 C 87.0,162.0 91.0,162.0 93.0,160.0 L 127.0,133.0 C 129.0,131.0 129.0,128.0 127.0,126.0 L 80.0,70.0 C 78.0,67.0 75.0,68.0 74.0,70.0 Z'
|
||||||
|
rel_s = 'm 38.0,130.0 c -1.0,2.0 0.0,6.0 2.0,7.0 l 45.0,24.0 c 2.0,1.0 6.0,1.0 8.0,-1.0 l 34.0,-27.0 c 2.0,-2.0 2.0,-5.0 0.0,-7.0 l -47.0,-56.0 c -2.0,-3.0 -5.0,-2.0 -6.0,0.0 z'
|
||||||
|
path1 = parse_path(abs_s)
|
||||||
|
path2 = parse_path(rel_s)
|
||||||
|
self.assertEqual(path1.d(use_closed_attrib=True), abs_s)
|
||||||
|
self.assertEqual(path2.d(use_closed_attrib=True), abs_s)
|
||||||
|
self.assertEqual(path1.d(use_closed_attrib=True, rel=True), rel_s)
|
||||||
|
self.assertEqual(path2.d(use_closed_attrib=True, rel=True), rel_s)
|
||||||
|
|
||||||
|
|
||||||
class Test_ilength(unittest.TestCase):
|
class Test_ilength(unittest.TestCase):
|
||||||
|
|
Loading…
Reference in New Issue