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