Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit eca26d0

Browse files
authored
Merge pull request #23340 from oscargus/arcfix
Set correct path for Arc
2 parents 1fd71a5 + a651e73 commit eca26d0

File tree

6 files changed

+395
-41
lines changed

6 files changed

+395
-41
lines changed

lib/matplotlib/patches.py

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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

21332149
def bbox_artist(artist, renderer, props=None, fill=True):
21342150
"""

0 commit comments

Comments
 (0)