@@ -1958,6 +1958,9 @@ def __init__(self, xy, width, height, angle=0.0,
19581958
19591959 self .theta1 = theta1
19601960 self .theta2 = theta2
1961+ (self ._theta1 , self ._theta2 , self ._stretched_width ,
1962+ self ._stretched_height ) = self ._theta_stretch ()
1963+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
19611964
19621965 @artist .allow_rasterization
19631966 def draw (self , renderer ):
@@ -2010,36 +2013,7 @@ def draw(self, renderer):
20102013
20112014 self ._recompute_transform ()
20122015
2013- width = self .convert_xunits (self .width )
2014- height = self .convert_yunits (self .height )
2015-
2016- # If the width and height of ellipse are not equal, take into account
2017- # stretching when calculating angles to draw between
2018- def theta_stretch (theta , scale ):
2019- theta = np .deg2rad (theta )
2020- x = np .cos (theta )
2021- y = np .sin (theta )
2022- stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2023- # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2024- return (stheta + 360 ) % 360
2025-
2026- theta1 = self .theta1
2027- theta2 = self .theta2
2028-
2029- if (
2030- # if we need to stretch the angles because we are distorted
2031- width != height
2032- # and we are not doing a full circle.
2033- #
2034- # 0 and 360 do not exactly round-trip through the angle
2035- # stretching (due to both float precision limitations and
2036- # the difference between the range of arctan2 [-pi, pi] and
2037- # this method [0, 360]) so avoid doing it if we don't have to.
2038- and not (theta1 != theta2 and theta1 % 360 == theta2 % 360 )
2039- ):
2040- theta1 = theta_stretch (self .theta1 , width / height )
2041- theta2 = theta_stretch (self .theta2 , width / height )
2042-
2016+ self ._update_path ()
20432017 # Get width and height in pixels we need to use
20442018 # `self.get_data_transform` rather than `self.get_transform`
20452019 # because we want the transform from dataspace to the
@@ -2048,12 +2022,13 @@ def theta_stretch(theta, scale):
20482022 # `self.get_transform()` goes from an idealized unit-radius
20492023 # space to screen space).
20502024 data_to_screen_trans = self .get_data_transform ()
2051- pwidth , pheight = (data_to_screen_trans .transform ((width , height )) -
2052- data_to_screen_trans .transform ((0 , 0 )))
2025+ pwidth , pheight = (
2026+ data_to_screen_trans .transform ((self ._stretched_width ,
2027+ self ._stretched_height )) -
2028+ data_to_screen_trans .transform ((0 , 0 )))
20532029 inv_error = (1.0 / 1.89818e-6 ) * 0.5
20542030
20552031 if pwidth < inv_error and pheight < inv_error :
2056- self ._path = Path .arc (theta1 , theta2 )
20572032 return Patch .draw (self , renderer )
20582033
20592034 def line_circle_intersect (x0 , y0 , x1 , y1 ):
@@ -2107,10 +2082,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
21072082 # arctan2 return [-pi, pi), the rest of our angles are in
21082083 # [0, 360], adjust as needed.
21092084 theta = (np .rad2deg (np .arctan2 (y , x )) + 360 ) % 360
2110- thetas .update (theta [(theta1 < theta ) & (theta < theta2 )])
2111- thetas = sorted (thetas ) + [theta2 ]
2112- last_theta = theta1
2113- theta1_rad = np .deg2rad (theta1 )
2085+ thetas .update (
2086+ theta [(self ._theta1 < theta ) & (theta < self ._theta2 )])
2087+ thetas = sorted (thetas ) + [self ._theta2 ]
2088+ last_theta = self ._theta1
2089+ theta1_rad = np .deg2rad (self ._theta1 )
21142090 inside = box_path .contains_point (
21152091 (np .cos (theta1_rad ), np .sin (theta1_rad ))
21162092 )
@@ -2129,6 +2105,46 @@ def segment_circle_intersect(x0, y0, x1, y1):
21292105 # restore original path
21302106 self ._path = path_original
21312107
2108+ def _update_path (self ):
2109+ # Compute new values and update and set new _path if any value changed
2110+ stretched = self ._theta_stretch ()
2111+ if any (a != b for a , b in zip (
2112+ stretched , (self ._theta1 , self ._theta2 , self ._stretched_width ,
2113+ self ._stretched_height ))):
2114+ (self ._theta1 , self ._theta2 , self ._stretched_width ,
2115+ self ._stretched_height ) = stretched
2116+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
2117+
2118+ def _theta_stretch (self ):
2119+ # If the width and height of ellipse are not equal, take into account
2120+ # stretching when calculating angles to draw between
2121+ def theta_stretch (theta , scale ):
2122+ theta = np .deg2rad (theta )
2123+ x = np .cos (theta )
2124+ y = np .sin (theta )
2125+ stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2126+ # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2127+ return (stheta + 360 ) % 360
2128+
2129+ width = self .convert_xunits (self .width )
2130+ height = self .convert_yunits (self .height )
2131+ if (
2132+ # if we need to stretch the angles because we are distorted
2133+ width != height
2134+ # and we are not doing a full circle.
2135+ #
2136+ # 0 and 360 do not exactly round-trip through the angle
2137+ # stretching (due to both float precision limitations and
2138+ # the difference between the range of arctan2 [-pi, pi] and
2139+ # this method [0, 360]) so avoid doing it if we don't have to.
2140+ and not (self .theta1 != self .theta2 and
2141+ self .theta1 % 360 == self .theta2 % 360 )
2142+ ):
2143+ theta1 = theta_stretch (self .theta1 , width / height )
2144+ theta2 = theta_stretch (self .theta2 , width / height )
2145+ return theta1 , theta2 , width , height
2146+ return self .theta1 , self .theta2 , width , height
2147+
21322148
21332149def bbox_artist (artist , renderer , props = None , fill = True ):
21342150 """
0 commit comments