@@ -1961,6 +1961,9 @@ def __init__(self, xy, width, height, angle=0.0,
1961
1961
1962
1962
self .theta1 = theta1
1963
1963
self .theta2 = theta2
1964
+ self ._theta1 , self ._theta2 , self ._width , self ._height = \
1965
+ self ._theta_stretch ()
1966
+ self ._path = Path .arc (self ._theta1 , self ._theta2 )
1964
1967
1965
1968
@artist .allow_rasterization
1966
1969
def draw (self , renderer ):
@@ -2013,36 +2016,7 @@ def draw(self, renderer):
2013
2016
2014
2017
self ._recompute_transform ()
2015
2018
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 ()
2046
2020
# Get width and height in pixels we need to use
2047
2021
# `self.get_data_transform` rather than `self.get_transform`
2048
2022
# because we want the transform from dataspace to the
@@ -2051,12 +2025,12 @@ def theta_stretch(theta, scale):
2051
2025
# `self.get_transform()` goes from an idealized unit-radius
2052
2026
# space to screen space).
2053
2027
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 ._width , self ._height )) -
2030
+ data_to_screen_trans .transform ((0 , 0 )))
2056
2031
inv_error = (1.0 / 1.89818e-6 ) * 0.5
2057
2032
2058
2033
if pwidth < inv_error and pheight < inv_error :
2059
- self ._path = Path .arc (theta1 , theta2 )
2060
2034
return Patch .draw (self , renderer )
2061
2035
2062
2036
def line_circle_intersect (x0 , y0 , x1 , y1 ):
@@ -2110,10 +2084,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
2110
2084
# arctan2 return [-pi, pi), the rest of our angles are in
2111
2085
# [0, 360], adjust as needed.
2112
2086
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 )
2087
+ thetas .update (
2088
+ theta [(self ._theta1 < theta ) & (theta < self ._theta2 )])
2089
+ thetas = sorted (thetas ) + [self ._theta2 ]
2090
+ last_theta = self ._theta1
2091
+ theta1_rad = np .deg2rad (self ._theta1 )
2117
2092
inside = box_path .contains_point (
2118
2093
(np .cos (theta1_rad ), np .sin (theta1_rad ))
2119
2094
)
@@ -2132,6 +2107,44 @@ def segment_circle_intersect(x0, y0, x1, y1):
2132
2107
# restore original path
2133
2108
self ._path = path_original
2134
2109
2110
+ def _update_path (self ):
2111
+ # Compute new values and update and set new _path if any value changed
2112
+ stretched = self ._theta_stretch ()
2113
+ if any (a != b for a , b in zip (stretched , (self ._theta1 , self ._theta2 ,
2114
+ self ._width , self ._height ))):
2115
+ self ._theta1 , self ._theta2 , self ._width , self ._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
+
2135
2148
2136
2149
def bbox_artist (artist , renderer , props = None , fill = True ):
2137
2150
"""
0 commit comments