Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d9855d3

Browse files
committed
Vectorize Arc.draw.
... by replacing generators into functions working on numpy arrays. All modified functions are nested and thus not publically accessible.
1 parent 59b5e0e commit d9855d3

File tree

1 file changed

+21
-30
lines changed

1 file changed

+21
-30
lines changed

lib/matplotlib/patches.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,14 +1558,12 @@ def draw(self, renderer):
15581558
calculation much easier than doing rotated ellipse
15591559
intersection directly).
15601560
1561-
This uses the "line intersecting a circle" algorithm
1562-
from:
1561+
This uses the "line intersecting a circle" algorithm from:
15631562
15641563
Vince, John. *Geometry for Computer Graphics: Formulae,
15651564
Examples & Proofs.* London: Springer-Verlag, 2005.
15661565
1567-
2. The angles of each of the intersection points are
1568-
calculated.
1566+
2. The angles of each of the intersection points are calculated.
15691567
15701568
3. Proceeding counterclockwise starting in the positive
15711569
x-direction, each of the visible arc-segments between the
@@ -1598,7 +1596,7 @@ def theta_stretch(theta, scale):
15981596
self._path = Path.arc(theta1, theta2)
15991597
return Patch.draw(self, renderer)
16001598

1601-
def iter_circle_intersect_on_line(x0, y0, x1, y1):
1599+
def line_circle_intersect(x0, y0, x1, y1):
16021600
dx = x1 - x0
16031601
dy = y1 - y0
16041602
dr2 = dx * dx + dy * dy
@@ -1610,7 +1608,7 @@ def iter_circle_intersect_on_line(x0, y0, x1, y1):
16101608
if discrim == 0.0:
16111609
x = (D * dy) / dr2
16121610
y = (-D * dx) / dr2
1613-
yield x, y
1611+
return np.array([[x, y]])
16141612
elif discrim > 0.0:
16151613
# The definition of "sign" here is different from
16161614
# np.sign: we never want to get 0.0
@@ -1619,12 +1617,15 @@ def iter_circle_intersect_on_line(x0, y0, x1, y1):
16191617
else:
16201618
sign_dy = 1.0
16211619
sqrt_discrim = np.sqrt(discrim)
1622-
for sign in (1., -1.):
1623-
x = (D * dy + sign * sign_dy * dx * sqrt_discrim) / dr2
1624-
y = (-D * dx + sign * np.abs(dy) * sqrt_discrim) / dr2
1625-
yield x, y
1620+
return np.array(
1621+
[[(D * dy + sign_dy * dx * sqrt_discrim) / dr2,
1622+
(-D * dx + abs(dy) * sqrt_discrim) / dr2],
1623+
[(D * dy - sign_dy * dx * sqrt_discrim) / dr2,
1624+
(-D * dx - abs(dy) * sqrt_discrim) / dr2]])
1625+
else:
1626+
return np.empty((0, 2))
16261627

1627-
def iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
1628+
def segment_circle_intersect(x0, y0, x1, y1):
16281629
epsilon = 1e-9
16291630
if x1 < x0:
16301631
x0e, x1e = x1, x0
@@ -1634,17 +1635,13 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
16341635
y0e, y1e = y1, y0
16351636
else:
16361637
y0e, y1e = y0, y1
1637-
x0e -= epsilon
1638-
y0e -= epsilon
1639-
x1e += epsilon
1640-
y1e += epsilon
1641-
for x, y in iter_circle_intersect_on_line(x0, y0, x1, y1):
1642-
if x0e <= x <= x1e and y0e <= y <= y1e:
1643-
yield x, y
1638+
xys = line_circle_intersect(x0, y0, x1, y1)
1639+
xs, ys = xys.T
1640+
return xys[(x0e - epsilon < xs) & (xs < x1e + epsilon)
1641+
& (y0e - epsilon < ys) & (ys < y1e + epsilon)]
16441642

16451643
# Transforms the axes box_path so that it is relative to the unit
1646-
# circle in the same way that it is relative to the desired
1647-
# ellipse.
1644+
# circle in the same way that it is relative to the desired ellipse.
16481645
box_path = Path.unit_rectangle()
16491646
box_path_transform = transforms.BboxTransformTo(self.axes.bbox) + \
16501647
self.get_transform().inverted()
@@ -1653,16 +1650,10 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
16531650
thetas = set()
16541651
# For each of the point pairs, there is a line segment
16551652
for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]):
1656-
x0, y0 = p0
1657-
x1, y1 = p1
1658-
for x, y in iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
1659-
theta = np.arccos(x)
1660-
if y < 0:
1661-
theta = 2 * np.pi - theta
1662-
# Convert radians to angles
1663-
theta = np.rad2deg(theta)
1664-
if theta1 < theta < theta2:
1665-
thetas.add(theta)
1653+
xy = segment_circle_intersect(*p0, *p1)
1654+
x, y = xy.T
1655+
theta = np.rad2deg(np.arctan2(y, x))
1656+
thetas.update(theta[(theta1 < theta) & (theta < theta2)])
16661657
thetas = sorted(thetas) + [theta2]
16671658

16681659
last_theta = theta1

0 commit comments

Comments
 (0)