fixed bug in new Arc-friendly Path.area() method

pull/76/head
Andy Port 2018-11-04 22:22:20 -08:00
parent b37e74f5f3
commit 58d48029ac
1 changed files with 20 additions and 17 deletions

View File

@ -2445,12 +2445,13 @@ class Path(MutableSequence):
Approximates any Arc segments in the Path with lines Approximates any Arc segments in the Path with lines
approximately `chord_length` long, and returns the area enclosed approximately `chord_length` long, and returns the area enclosed
by the approximated Path. Default chord length is 0.01. To by the approximated Path. Default chord length is 0.01. If Arc
ensure accurate results, make sure this `chord_length` is set to segments are included in path, to ensure accurate results, make
a reasonable value (e.g. by checking curvature). sure this `chord_length` is set to a reasonable value (e.g. by
checking curvature).
Notes Notes
---- -----
* Negative area results from clockwise (as opposed to * Negative area results from clockwise (as opposed to
counter-clockwise) parameterization of the input Path. counter-clockwise) parameterization of the input Path.
@ -2458,13 +2459,13 @@ class Path(MutableSequence):
--------------- ---------------
This is one of many parts of `svgpathtools` that could be This is one of many parts of `svgpathtools` that could be
improved by a noble soul implementing a piecewise-linear improved by a noble soul implementing a piecewise-linear
approximation scheme for paths (one with controls to approximation scheme for paths (one with controls to guarantee a
guarantee a desired accuracies). desired accuracy).
""" """
def area_without_arcs(self): def area_without_arcs(path):
area_enclosed = 0 area_enclosed = 0
for seg in self: for seg in path:
x = real(seg.poly()) x = real(seg.poly())
dy = imag(seg.poly()).deriv() dy = imag(seg.poly()).deriv()
integrand = x*dy integrand = x*dy
@ -2472,20 +2473,22 @@ class Path(MutableSequence):
area_enclosed += integral(1) - integral(0) area_enclosed += integral(1) - integral(0)
return area_enclosed return area_enclosed
def seg2lines(seg):
"""Find piecewise-linear approximation of `seg`."""
num_lines = ceil(seg.length() / chord_length)
tvals = np.linspace(0, seg.length(), num_lines)
return [Line(seg.point(tvals[i]), seg.point(tvals[i+1]))
for i in range(len(tvals)-1)]
assert self.isclosed() assert self.isclosed()
bezier_path_approximation = Path() bezier_path_approximation = []
for seg in self: for seg in self:
if isinstance(seg, Arc): if isinstance(seg, Arc):
num_lines = ceil(seg.length() / chord_length) # check curvature to improve bezier_path_approximation += seg2lines(seg)
bezier_path_approximation = \
[Line(seg.point(i/num_lines), seg.point((i+1)/num_lines))
for i in range(int(num_lines))]
else: else:
approximated_path.append(seg) bezier_path_approximation.append(seg)
return area_without_arcs(Path(*bezier_path_approximation))
return area_without_arcs(approximated_path)
def intersect(self, other_curve, justonemode=False, tol=1e-12): def intersect(self, other_curve, justonemode=False, tol=1e-12):
"""returns list of pairs of pairs ((T1, seg1, t1), (T2, seg2, t2)) """returns list of pairs of pairs ((T1, seg1, t1), (T2, seg2, t2))