@@ -1963,6 +1963,9 @@ def __init__(self, xy, width, height, angle=0.0,
1963
1963
1964
1964
self .theta1 = theta1
1965
1965
self .theta2 = theta2
1966
+ self ._theta1 , self ._theta2 , self ._width , self ._height = \
1967
+ self ._theta_stretch ()
1968
+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
1966
1969
1967
1970
@artist .allow_rasterization
1968
1971
def draw (self , renderer ):
@@ -2015,36 +2018,7 @@ def draw(self, renderer):
2015
2018
2016
2019
self ._recompute_transform ()
2017
2020
2018
- width = self .convert_xunits (self .width )
2019
- height = self .convert_yunits (self .height )
2020
-
2021
- # If the width and height of ellipse are not equal, take into account
2022
- # stretching when calculating angles to draw between
2023
- def theta_stretch (theta , scale ):
2024
- theta = np .deg2rad (theta )
2025
- x = np .cos (theta )
2026
- y = np .sin (theta )
2027
- stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2028
- # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2029
- return (stheta + 360 ) % 360
2030
-
2031
- theta1 = self .theta1
2032
- theta2 = self .theta2
2033
-
2034
- if (
2035
- # if we need to stretch the angles because we are distorted
2036
- width != height
2037
- # and we are not doing a full circle.
2038
- #
2039
- # 0 and 360 do not exactly round-trip through the angle
2040
- # stretching (due to both float precision limitations and
2041
- # the difference between the range of arctan2 [-pi, pi] and
2042
- # this method [0, 360]) so avoid doing it if we don't have to.
2043
- and not (theta1 != theta2 and theta1 % 360 == theta2 % 360 )
2044
- ):
2045
- theta1 = theta_stretch (self .theta1 , width / height )
2046
- theta2 = theta_stretch (self .theta2 , width / height )
2047
-
2021
+ self ._update_path ()
2048
2022
# Get width and height in pixels we need to use
2049
2023
# `self.get_data_transform` rather than `self.get_transform`
2050
2024
# because we want the transform from dataspace to the
@@ -2053,12 +2027,12 @@ def theta_stretch(theta, scale):
2053
2027
# `self.get_transform()` goes from an idealized unit-radius
2054
2028
# space to screen space).
2055
2029
data_to_screen_trans = self .get_data_transform ()
2056
- pwidth , pheight = (data_to_screen_trans .transform ((width , height )) -
2057
- data_to_screen_trans .transform ((0 , 0 )))
2030
+ pwidth , pheight = (
2031
+ data_to_screen_trans .transform ((self ._width , self ._height )) -
2032
+ data_to_screen_trans .transform ((0 , 0 )))
2058
2033
inv_error = (1.0 / 1.89818e-6 ) * 0.5
2059
2034
2060
2035
if pwidth < inv_error and pheight < inv_error :
2061
- self ._path = Path .arc (theta1 , theta2 )
2062
2036
return Patch .draw (self , renderer )
2063
2037
2064
2038
def line_circle_intersect (x0 , y0 , x1 , y1 ):
@@ -2112,10 +2086,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
2112
2086
# arctan2 return [-pi, pi), the rest of our angles are in
2113
2087
# [0, 360], adjust as needed.
2114
2088
theta = (np .rad2deg (np .arctan2 (y , x )) + 360 ) % 360
2115
- thetas .update (theta [(theta1 < theta ) & (theta < theta2 )])
2116
- thetas = sorted (thetas ) + [theta2 ]
2117
- last_theta = theta1
2118
- theta1_rad = np .deg2rad (theta1 )
2089
+ thetas .update (
2090
+ theta [(self ._theta1 < theta ) & (theta < self ._theta2 )])
2091
+ thetas = sorted (thetas ) + [self ._theta2 ]
2092
+ last_theta = self ._theta1
2093
+ theta1_rad = np .deg2rad (self ._theta1 )
2119
2094
inside = box_path .contains_point (
2120
2095
(np .cos (theta1_rad ), np .sin (theta1_rad ))
2121
2096
)
@@ -2134,6 +2109,44 @@ def segment_circle_intersect(x0, y0, x1, y1):
2134
2109
# restore original path
2135
2110
self ._path = path_original
2136
2111
2112
+ def _update_path (self ):
2113
+ # Compute new values and update and set new _path if any value changed
2114
+ stretched = self ._theta_stretch ()
2115
+ if any (a != b for a , b in zip (stretched , (self ._theta1 , self ._theta2 ,
2116
+ self ._width , self ._height ))):
2117
+ self ._theta1 , self ._theta2 , self ._width , self ._height = stretched
2118
+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
2119
+
2120
+ def _theta_stretch (self ):
2121
+ # If the width and height of ellipse are not equal, take into account
2122
+ # stretching when calculating angles to draw between
2123
+ def theta_stretch (theta , scale ):
2124
+ theta = np .deg2rad (theta )
2125
+ x = np .cos (theta )
2126
+ y = np .sin (theta )
2127
+ stheta = np .rad2deg (np .arctan2 (scale * y , x ))
2128
+ # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2129
+ return (stheta + 360 ) % 360
2130
+
2131
+ width = self .convert_xunits (self .width )
2132
+ height = self .convert_yunits (self .height )
2133
+ if (
2134
+ # if we need to stretch the angles because we are distorted
2135
+ width != height
2136
+ # and we are not doing a full circle.
2137
+ #
2138
+ # 0 and 360 do not exactly round-trip through the angle
2139
+ # stretching (due to both float precision limitations and
2140
+ # the difference between the range of arctan2 [-pi, pi] and
2141
+ # this method [0, 360]) so avoid doing it if we don't have to.
2142
+ and not (self .theta1 != self .theta2 and
2143
+ self .theta1 % 360 == self .theta2 % 360 )
2144
+ ):
2145
+ theta1 = theta_stretch (self .theta1 , width / height )
2146
+ theta2 = theta_stretch (self .theta2 , width / height )
2147
+ return theta1 , theta2 , width , height
2148
+ return self .theta1 , self .theta2 , width , height
2149
+
2137
2150
2138
2151
def bbox_artist (artist , renderer , props = None , fill = True ):
2139
2152
"""
0 commit comments