Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
FIX: correctly handle large arcs#17564
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
98ab2a0
a302b5a
7ae0c34
d46c161
0dfdfd6
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1647,6 +1647,8 @@ def draw(self, renderer): | ||
""" | ||
if not hasattr(self, 'axes'): | ||
raise RuntimeError('Arcs can only be used in Axes instances') | ||
if not self.get_visible(): | ||
return | ||
self._recompute_transform() | ||
@@ -1659,14 +1661,40 @@ def theta_stretch(theta, scale): | ||
theta = np.deg2rad(theta) | ||
x = np.cos(theta) | ||
y = np.sin(theta) | ||
stheta = np.rad2deg(np.arctan2(scale * y, x)) | ||
# arctan2 has the range [-pi, pi], we expect [0, 2*pi] | ||
return (stheta + 360) % 360 | ||
theta1 = self.theta1 | ||
theta2 = self.theta2 | ||
if ( | ||
# if we need to stretch the angles because we are distorted | ||
width != height | ||
# and we are not doing a full circle. | ||
# | ||
# 0 and 360 do not exactly round-trip through the angle | ||
# stretching (due to both float precision limitations and | ||
# the difference between the range of arctan2 [-pi, pi] and | ||
# this method [0, 360]) so avoid doing it if we don't have to. | ||
and not (theta1 != theta2 and theta1 % 360 == theta2 % 360) | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. probably needs a comment, IIRC you do this because theta1 and theta2 may not match anymore after stretching? (i.e. why can't you just always stretch) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. can you instead first take everything mod 360 and then always stretch? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I tried that and it did not work, as | ||
): | ||
theta1 = theta_stretch(self.theta1, width / height) | ||
theta2 = theta_stretch(self.theta2, width / height) | ||
# Get width and height in pixels we need to use | ||
# `self.get_data_transform` rather than `self.get_transform` | ||
# because we want the transform from dataspace to the | ||
# screen space to estimate how big the arc will be in physical | ||
# units when rendered (the transform that we get via | ||
# `self.get_transform()` goes from an idealized unit-radius | ||
# space to screen space). | ||
data_to_screen_trans = self.get_data_transform() | ||
pwidth, pheight = (data_to_screen_trans.transform((width, height)) - | ||
data_to_screen_trans.transform((0, 0))) | ||
inv_error = (1.0 / 1.89818e-6) * 0.5 | ||
QuLogic marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
if pwidth < inv_error and pheight < inv_error: | ||
self._path = Path.arc(theta1, theta2) | ||
return Patch.draw(self, renderer) | ||
@@ -1700,29 +1728,32 @@ def segment_circle_intersect(x0, y0, x1, y1): | ||
y0e, y1e = y0, y1 | ||
xys = line_circle_intersect(x0, y0, x1, y1) | ||
xs, ys = xys.T | ||
return xys[ | ||
(x0e - epsilon < xs) & (xs < x1e + epsilon) | ||
& (y0e - epsilon < ys) & (ys < y1e + epsilon) | ||
] | ||
# Transforms the axes box_path so that it is relative to the unit | ||
# circle in the same way that it is relative to the desired ellipse. | ||
box_path_transform = (transforms.BboxTransformTo(self.axes.bbox) | ||
+ self.get_transform().inverted()) | ||
box_path =Path.unit_rectangle().transformed(box_path_transform) | ||
thetas = set() | ||
# For each of the point pairs, there is a line segment | ||
for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]): | ||
xy = segment_circle_intersect(*p0, *p1) | ||
x, y = xy.T | ||
# arctan2 return [-pi, pi), the rest of our angles are in | ||
# [0, 360], adjust as needed. | ||
theta = (np.rad2deg(np.arctan2(y, x)) + 360) % 360 | ||
thetas.update(theta[(theta1 < theta) & (theta < theta2)]) | ||
thetas = sorted(thetas) + [theta2] | ||
last_theta = theta1 | ||
theta1_rad = np.deg2rad(theta1) | ||
inside = box_path.contains_point( | ||
(np.cos(theta1_rad), np.sin(theta1_rad)) | ||
) | ||
# save original path | ||
path_original = self._path | ||
Uh oh!
There was an error while loading.Please reload this page.