@@ -1958,6 +1958,9 @@ def __init__(self, xy, width, height, angle=0.0,
1958
1958
1959
1959
self .theta1 = theta1
1960
1960
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 )
1961
1964
1962
1965
@artist .allow_rasterization
1963
1966
def draw (self , renderer ):
@@ -2010,36 +2013,7 @@ def draw(self, renderer):
2010
2013
2011
2014
self ._recompute_transform ()
2012
2015
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 ()
2043
2017
# Get width and height in pixels we need to use
2044
2018
# `self.get_data_transform` rather than `self.get_transform`
2045
2019
# because we want the transform from dataspace to the
@@ -2048,12 +2022,13 @@ def theta_stretch(theta, scale):
2048
2022
# `self.get_transform()` goes from an idealized unit-radius
2049
2023
# space to screen space).
2050
2024
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 )))
2053
2029
inv_error = (1.0 / 1.89818e-6 ) * 0.5
2054
2030
2055
2031
if pwidth < inv_error and pheight < inv_error :
2056
- self ._path = Path .arc (theta1 , theta2 )
2057
2032
return Patch .draw (self , renderer )
2058
2033
2059
2034
def line_circle_intersect (x0 , y0 , x1 , y1 ):
@@ -2107,10 +2082,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
2107
2082
# arctan2 return [-pi, pi), the rest of our angles are in
2108
2083
# [0, 360], adjust as needed.
2109
2084
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 )
2114
2090
inside = box_path .contains_point (
2115
2091
(np .cos (theta1_rad ), np .sin (theta1_rad ))
2116
2092
)
@@ -2129,6 +2105,46 @@ def segment_circle_intersect(x0, y0, x1, y1):
2129
2105
# restore original path
2130
2106
self ._path = path_original
2131
2107
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
+
2132
2148
2133
2149
def bbox_artist (artist , renderer , props = None , fill = True ):
2134
2150
"""
0 commit comments