@@ -1968,6 +1968,9 @@ def __init__(self, xy, width, height, angle=0.0,
19681968
19691969 self .theta1 = theta1
19701970 self .theta2 = theta2
1971+ self ._theta1 , self ._theta2 , self ._width , self ._height = \
1972+ self ._theta_stretch ()
1973+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
19711974
19721975 @artist .allow_rasterization
19731976 def draw (self , renderer ):
@@ -2023,36 +2026,7 @@ def draw(self, renderer):
20232026
20242027 self ._recompute_transform ()
20252028
2026- width = self .convert_xunits (self .width )
2027- height = self .convert_yunits (self .height )
2028-
2029- # If the width and height of ellipse are not equal, take into account
2030- # stretching when calculating angles to draw between
2031- def theta_stretch (theta , scale ):
2032- theta = np .deg2rad (theta )
2033- x = np .cos (theta )
2034- y = np .sin (theta )
2035- stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2036- # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2037- return (stheta + 360 ) % 360
2038-
2039- theta1 = self .theta1
2040- theta2 = self .theta2
2041-
2042- if (
2043- # if we need to stretch the angles because we are distorted
2044- width != height
2045- # and we are not doing a full circle.
2046- #
2047- # 0 and 360 do not exactly round-trip through the angle
2048- # stretching (due to both float precision limitations and
2049- # the difference between the range of arctan2 [-pi, pi] and
2050- # this method [0, 360]) so avoid doing it if we don't have to.
2051- and not (theta1 != theta2 and theta1 % 360 == theta2 % 360 )
2052- ):
2053- theta1 = theta_stretch (self .theta1 , width / height )
2054- theta2 = theta_stretch (self .theta2 , width / height )
2055-
2029+ self ._update_path ()
20562030 # Get width and height in pixels we need to use
20572031 # `self.get_data_transform` rather than `self.get_transform`
20582032 # because we want the transform from dataspace to the
@@ -2061,12 +2035,12 @@ def theta_stretch(theta, scale):
20612035 # `self.get_transform()` goes from an idealized unit-radius
20622036 # space to screen space).
20632037 data_to_screen_trans = self .get_data_transform ()
2064- pwidth , pheight = (data_to_screen_trans .transform ((width , height )) -
2065- data_to_screen_trans .transform ((0 , 0 )))
2038+ pwidth , pheight = (
2039+ data_to_screen_trans .transform ((self ._width , self ._height )) -
2040+ data_to_screen_trans .transform ((0 , 0 )))
20662041 inv_error = (1.0 / 1.89818e-6 ) * 0.5
20672042
20682043 if pwidth < inv_error and pheight < inv_error :
2069- self ._path = Path .arc (theta1 , theta2 )
20702044 return Patch .draw (self , renderer )
20712045
20722046 def line_circle_intersect (x0 , y0 , x1 , y1 ):
@@ -2118,10 +2092,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
21182092 # arctan2 return [-pi, pi), the rest of our angles are in
21192093 # [0, 360], adjust as needed.
21202094 theta = (np .rad2deg (np .arctan2 (y , x )) + 360 ) % 360
2121- thetas .update (theta [(theta1 < theta ) & (theta < theta2 )])
2122- thetas = sorted (thetas ) + [theta2 ]
2123- last_theta = theta1
2124- theta1_rad = np .deg2rad (theta1 )
2095+ thetas .update (
2096+ theta [(self ._theta1 < theta ) & (theta < self ._theta2 )])
2097+ thetas = sorted (thetas ) + [self ._theta2 ]
2098+ last_theta = self ._theta1
2099+ theta1_rad = np .deg2rad (self ._theta1 )
21252100 inside = box_path .contains_point (
21262101 (np .cos (theta1_rad ), np .sin (theta1_rad ))
21272102 )
@@ -2140,6 +2115,47 @@ def segment_circle_intersect(x0, y0, x1, y1):
21402115 # restore original path
21412116 self ._path = path_original
21422117
2118+ def _convert_xy_units (self ):
2119+ # Return converted width and height
2120+ return (self .convert_xunits (self .width ),
2121+ self .convert_yunits (self .height ))
2122+
2123+ def _update_path (self ):
2124+ stretched = self ._theta_stretch ()
2125+ if any (a != b for a , b in zip (stretched , (self ._theta1 , self ._theta2 ,
2126+ self ._width , self ._height ))):
2127+ self ._theta1 , self ._theta2 , self ._width , self ._height = stretched
2128+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
2129+
2130+ def _theta_stretch (self ):
2131+ # If the width and height of ellipse are not equal, take into account
2132+ # stretching when calculating angles to draw between
2133+ def theta_stretch (theta , scale ):
2134+ theta = np .deg2rad (theta )
2135+ x = np .cos (theta )
2136+ y = np .sin (theta )
2137+ stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2138+ # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2139+ return (stheta + 360 ) % 360
2140+
2141+ width , height = self ._convert_xy_units ()
2142+ if (
2143+ # if we need to stretch the angles because we are distorted
2144+ width != height
2145+ # and we are not doing a full circle.
2146+ #
2147+ # 0 and 360 do not exactly round-trip through the angle
2148+ # stretching (due to both float precision limitations and
2149+ # the difference between the range of arctan2 [-pi, pi] and
2150+ # this method [0, 360]) so avoid doing it if we don't have to.
2151+ and not (self .theta1 != self .theta2 and
2152+ self .theta1 % 360 == self .theta2 % 360 )
2153+ ):
2154+ theta1 = theta_stretch (self .theta1 , width / height )
2155+ theta2 = theta_stretch (self .theta2 , width / height )
2156+ return theta1 , theta2 , width , height
2157+ return self .theta1 , self .theta2 , width , height
2158+
21432159
21442160def bbox_artist (artist , renderer , props = None , fill = True ):
21452161 """
0 commit comments