@@ -1961,6 +1961,9 @@ def __init__(self, xy, width, height, angle=0.0,
19611961
19621962 self .theta1 = theta1
19631963 self .theta2 = theta2
1964+ (self ._theta1 , self ._theta2 , self ._stretched_width ,
1965+ self ._stretched_height ) = self ._theta_stretch ()
1966+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
19641967
19651968 @artist .allow_rasterization
19661969 def draw (self , renderer ):
@@ -2013,36 +2016,7 @@ def draw(self, renderer):
20132016
20142017 self ._recompute_transform ()
20152018
2016- width = self .convert_xunits (self .width )
2017- height = self .convert_yunits (self .height )
2018-
2019- # If the width and height of ellipse are not equal, take into account
2020- # stretching when calculating angles to draw between
2021- def theta_stretch (theta , scale ):
2022- theta = np .deg2rad (theta )
2023- x = np .cos (theta )
2024- y = np .sin (theta )
2025- stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2026- # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2027- return (stheta + 360 ) % 360
2028-
2029- theta1 = self .theta1
2030- theta2 = self .theta2
2031-
2032- if (
2033- # if we need to stretch the angles because we are distorted
2034- width != height
2035- # and we are not doing a full circle.
2036- #
2037- # 0 and 360 do not exactly round-trip through the angle
2038- # stretching (due to both float precision limitations and
2039- # the difference between the range of arctan2 [-pi, pi] and
2040- # this method [0, 360]) so avoid doing it if we don't have to.
2041- and not (theta1 != theta2 and theta1 % 360 == theta2 % 360 )
2042- ):
2043- theta1 = theta_stretch (self .theta1 , width / height )
2044- theta2 = theta_stretch (self .theta2 , width / height )
2045-
2019+ self ._update_path ()
20462020 # Get width and height in pixels we need to use
20472021 # `self.get_data_transform` rather than `self.get_transform`
20482022 # because we want the transform from dataspace to the
@@ -2051,12 +2025,13 @@ def theta_stretch(theta, scale):
20512025 # `self.get_transform()` goes from an idealized unit-radius
20522026 # space to screen space).
20532027 data_to_screen_trans = self .get_data_transform ()
2054- pwidth , pheight = (data_to_screen_trans .transform ((width , height )) -
2055- data_to_screen_trans .transform ((0 , 0 )))
2028+ pwidth , pheight = (
2029+ data_to_screen_trans .transform ((self ._stretched_width ,
2030+ self ._stretched_height )) -
2031+ data_to_screen_trans .transform ((0 , 0 )))
20562032 inv_error = (1.0 / 1.89818e-6 ) * 0.5
20572033
20582034 if pwidth < inv_error and pheight < inv_error :
2059- self ._path = Path .arc (theta1 , theta2 )
20602035 return Patch .draw (self , renderer )
20612036
20622037 def line_circle_intersect (x0 , y0 , x1 , y1 ):
@@ -2110,10 +2085,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
21102085 # arctan2 return [-pi, pi), the rest of our angles are in
21112086 # [0, 360], adjust as needed.
21122087 theta = (np .rad2deg (np .arctan2 (y , x )) + 360 ) % 360
2113- thetas .update (theta [(theta1 < theta ) & (theta < theta2 )])
2114- thetas = sorted (thetas ) + [theta2 ]
2115- last_theta = theta1
2116- theta1_rad = np .deg2rad (theta1 )
2088+ thetas .update (
2089+ theta [(self ._theta1 < theta ) & (theta < self ._theta2 )])
2090+ thetas = sorted (thetas ) + [self ._theta2 ]
2091+ last_theta = self ._theta1
2092+ theta1_rad = np .deg2rad (self ._theta1 )
21172093 inside = box_path .contains_point (
21182094 (np .cos (theta1_rad ), np .sin (theta1_rad ))
21192095 )
@@ -2132,6 +2108,46 @@ def segment_circle_intersect(x0, y0, x1, y1):
21322108 # restore original path
21332109 self ._path = path_original
21342110
2111+ def _update_path (self ):
2112+ # Compute new values and update and set new _path if any value changed
2113+ stretched = self ._theta_stretch ()
2114+ if any (a != b for a , b in zip (
2115+ stretched , (self ._theta1 , self ._theta2 , self ._stretched_width ,
2116+ self ._stretched_height ))):
2117+ (self ._theta1 , self ._theta2 , self ._stretched_width ,
2118+ self ._stretched_height ) = stretched
2119+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
2120+
2121+ def _theta_stretch (self ):
2122+ # If the width and height of ellipse are not equal, take into account
2123+ # stretching when calculating angles to draw between
2124+ def theta_stretch (theta , scale ):
2125+ theta = np .deg2rad (theta )
2126+ x = np .cos (theta )
2127+ y = np .sin (theta )
2128+ stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2129+ # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2130+ return (stheta + 360 ) % 360
2131+
2132+ width = self .convert_xunits (self .width )
2133+ height = self .convert_yunits (self .height )
2134+ if (
2135+ # if we need to stretch the angles because we are distorted
2136+ width != height
2137+ # and we are not doing a full circle.
2138+ #
2139+ # 0 and 360 do not exactly round-trip through the angle
2140+ # stretching (due to both float precision limitations and
2141+ # the difference between the range of arctan2 [-pi, pi] and
2142+ # this method [0, 360]) so avoid doing it if we don't have to.
2143+ and not (self .theta1 != self .theta2 and
2144+ self .theta1 % 360 == self .theta2 % 360 )
2145+ ):
2146+ theta1 = theta_stretch (self .theta1 , width / height )
2147+ theta2 = theta_stretch (self .theta2 , width / height )
2148+ return theta1 , theta2 , width , height
2149+ return self .theta1 , self .theta2 , width , height
2150+
21352151
21362152def bbox_artist (artist , renderer , props = None , fill = True ):
21372153 """
0 commit comments