@@ -1561,14 +1561,12 @@ def draw(self, renderer):
15611561 calculation much easier than doing rotated ellipse
15621562 intersection directly).
15631563
1564- This uses the "line intersecting a circle" algorithm
1565- from:
1564+ This uses the "line intersecting a circle" algorithm from:
15661565
15671566 Vince, John. *Geometry for Computer Graphics: Formulae,
15681567 Examples & Proofs.* London: Springer-Verlag, 2005.
15691568
1570- 2. The angles of each of the intersection points are
1571- calculated.
1569+ 2. The angles of each of the intersection points are calculated.
15721570
15731571 3. Proceeding counterclockwise starting in the positive
15741572 x-direction, each of the visible arc-segments between the
@@ -1601,33 +1599,25 @@ def theta_stretch(theta, scale):
16011599 self ._path = Path .arc (theta1 , theta2 )
16021600 return Patch .draw (self , renderer )
16031601
1604- def iter_circle_intersect_on_line (x0 , y0 , x1 , y1 ):
1602+ def line_circle_intersect (x0 , y0 , x1 , y1 ):
16051603 dx = x1 - x0
16061604 dy = y1 - y0
16071605 dr2 = dx * dx + dy * dy
16081606 D = x0 * y1 - x1 * y0
16091607 D2 = D * D
16101608 discrim = dr2 - D2
1611-
1612- # Single (tangential) intersection
1613- if discrim == 0.0 :
1614- x = (D * dy ) / dr2
1615- y = (- D * dx ) / dr2
1616- yield x , y
1617- elif discrim > 0.0 :
1618- # The definition of "sign" here is different from
1619- # np.sign: we never want to get 0.0
1620- if dy < 0.0 :
1621- sign_dy = - 1.0
1622- else :
1623- sign_dy = 1.0
1609+ if discrim >= 0.0 :
1610+ sign_dy = np .copysign (1 , dy ) # +/-1, never 0.
16241611 sqrt_discrim = np .sqrt (discrim )
1625- for sign in (1. , - 1. ):
1626- x = (D * dy + sign * sign_dy * dx * sqrt_discrim ) / dr2
1627- y = (- D * dx + sign * np .abs (dy ) * sqrt_discrim ) / dr2
1628- yield x , y
1612+ return np .array (
1613+ [[(D * dy + sign_dy * dx * sqrt_discrim ) / dr2 ,
1614+ (- D * dx + abs (dy ) * sqrt_discrim ) / dr2 ],
1615+ [(D * dy - sign_dy * dx * sqrt_discrim ) / dr2 ,
1616+ (- D * dx - abs (dy ) * sqrt_discrim ) / dr2 ]])
1617+ else :
1618+ return np .empty ((0 , 2 ))
16291619
1630- def iter_circle_intersect_on_line_seg (x0 , y0 , x1 , y1 ):
1620+ def segment_circle_intersect (x0 , y0 , x1 , y1 ):
16311621 epsilon = 1e-9
16321622 if x1 < x0 :
16331623 x0e , x1e = x1 , x0
@@ -1637,17 +1627,13 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
16371627 y0e , y1e = y1 , y0
16381628 else :
16391629 y0e , y1e = y0 , y1
1640- x0e -= epsilon
1641- y0e -= epsilon
1642- x1e += epsilon
1643- y1e += epsilon
1644- for x , y in iter_circle_intersect_on_line (x0 , y0 , x1 , y1 ):
1645- if x0e <= x <= x1e and y0e <= y <= y1e :
1646- yield x , y
1630+ xys = line_circle_intersect (x0 , y0 , x1 , y1 )
1631+ xs , ys = xys .T
1632+ return xys [(x0e - epsilon < xs ) & (xs < x1e + epsilon )
1633+ & (y0e - epsilon < ys ) & (ys < y1e + epsilon )]
16471634
16481635 # Transforms the axes box_path so that it is relative to the unit
1649- # circle in the same way that it is relative to the desired
1650- # ellipse.
1636+ # circle in the same way that it is relative to the desired ellipse.
16511637 box_path = Path .unit_rectangle ()
16521638 box_path_transform = transforms .BboxTransformTo (self .axes .bbox ) + \
16531639 self .get_transform ().inverted ()
@@ -1656,16 +1642,10 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
16561642 thetas = set ()
16571643 # For each of the point pairs, there is a line segment
16581644 for p0 , p1 in zip (box_path .vertices [:- 1 ], box_path .vertices [1 :]):
1659- x0 , y0 = p0
1660- x1 , y1 = p1
1661- for x , y in iter_circle_intersect_on_line_seg (x0 , y0 , x1 , y1 ):
1662- theta = np .arccos (x )
1663- if y < 0 :
1664- theta = 2 * np .pi - theta
1665- # Convert radians to angles
1666- theta = np .rad2deg (theta )
1667- if theta1 < theta < theta2 :
1668- thetas .add (theta )
1645+ xy = segment_circle_intersect (* p0 , * p1 )
1646+ x , y = xy .T
1647+ theta = np .rad2deg (np .arctan2 (y , x ))
1648+ thetas .update (theta [(theta1 < theta ) & (theta < theta2 )])
16691649 thetas = sorted (thetas ) + [theta2 ]
16701650
16711651 last_theta = theta1
0 commit comments