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._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.
|
||||
For an explanation of useSandT and use_closed_attrib, see the
|
||||
compatibility notes in the README."""
|
||||
|
||||
|
||||
if use_closed_attrib:
|
||||
self_closed = self.closed(warning_on=False)
|
||||
self_closed = self.iscontinuous() and self.isclosed()
|
||||
if self_closed:
|
||||
segments = self[:-1]
|
||||
else:
|
||||
|
@ -2279,12 +2279,12 @@ class Path(MutableSequence):
|
|||
else:
|
||||
self_closed = False
|
||||
segments = self[:]
|
||||
|
||||
|
||||
current_pos = None
|
||||
parts = []
|
||||
previous_segment = None
|
||||
end = self[-1].end
|
||||
|
||||
|
||||
for segment in segments:
|
||||
seg_start = segment.start
|
||||
# If the start of this segment does not coincide with the end of
|
||||
|
@ -2292,44 +2292,80 @@ class Path(MutableSequence):
|
|||
# of a closed path, then we should start a new subpath here.
|
||||
if current_pos != seg_start or \
|
||||
(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):
|
||||
args = segment.end.real, segment.end.imag
|
||||
parts.append('L {},{}'.format(*args))
|
||||
if rel:
|
||||
_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):
|
||||
if useSandT and segment.is_smooth_from(previous_segment,
|
||||
warning_on=False):
|
||||
args = (segment.control2.real, segment.control2.imag,
|
||||
segment.end.real, segment.end.imag)
|
||||
if rel:
|
||||
_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))
|
||||
else:
|
||||
args = (segment.control1.real, segment.control1.imag,
|
||||
segment.control2.real, segment.control2.imag,
|
||||
segment.end.real, segment.end.imag)
|
||||
if rel:
|
||||
_seg_control1 = segment.control1 - seg_start
|
||||
_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))
|
||||
elif isinstance(segment, QuadraticBezier):
|
||||
if useSandT and segment.is_smooth_from(previous_segment,
|
||||
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))
|
||||
else:
|
||||
args = (segment.control.real, segment.control.imag,
|
||||
segment.end.real, segment.end.imag)
|
||||
if rel:
|
||||
_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))
|
||||
|
||||
|
||||
elif isinstance(segment, Arc):
|
||||
if rel:
|
||||
_seg_end = segment.end - seg_start
|
||||
else:
|
||||
_seg_end = segment.end
|
||||
args = (segment.radius.real, segment.radius.imag,
|
||||
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))
|
||||
current_pos = segment.end
|
||||
previous_segment = segment
|
||||
|
||||
|
||||
if self_closed:
|
||||
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):
|
||||
"""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)
|
||||
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):
|
||||
|
|
Loading…
Reference in New Issue