-
-
Notifications
You must be signed in to change notification settings - Fork 8k
Implement full 3D box clipping #30553
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
... by replacing double pointers by fixed-size `std::array`, or a return `tuple`. With gcc (and optimization enabled?), this has no effect on code size, but gives compile-time (and better runtime) checks that there are no out-of-bounds access.
... by avoiding double pointers.
It is `bool` for the Python wrapper, while internally `int`, but can be `bool` consistently. Also mark it as `inline` since it's used in a template and the compiler warns about a possible ODR violation (which isn't a problem since it's only used in one file.)
By using the existing `XY` type to replace x/y pairs, and taking advantage of struct methods.
Use `XY` type to shorten internals, and `agg::rect_d::normalize` to shorten initialization.
I'll wait for this to come out of draft to do a thorough review, but I played around with the poly clipping and it works really well - pretty excited to see this go in! A somewhat pathological "C" shaped polygon didn't show any issues.
import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d.art3d import Poly3DCollection fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) ys = [0, 2, 2, 0, 0, 1, 1, 0, 0] zs = [0, 0, 3, 3, 2, 2, 1, 1, 0] xs = np.ones(len(ys)) verts = np.array(list(zip(xs, ys, zs))) poly1 = Poly3DCollection([verts], alpha=.5, color='C1', axlim_clip=True) poly2 = Poly3DCollection([verts], alpha=.5, color='C2', axlim_clip=False) ax.add_collection3d(poly1) ax.add_collection3d(poly2) plt.show()
Would it be difficult to extend this to Line3D as well?
This is still under the axlim_clip flag; I don't know if we just want to enable this all the time and/or deprecate that option.
I think "show all the data you can" is probably a better maxim for the default, but could be convinced otherwise.
Probably could warrant an API/what's new note.
Yeah, I think this is a pretty decently large change in behavior that should be highlighted.
Would it be difficult to extend this to Line3D as well?
If I'm not mistaken, 2D line clipping uses a different algorithm:
matplotlib/src/path_converters.h
Lines 322 to 520 in 5b38f50
This makes some sense as it doesn't need to preserve polygon fills, but I'm not sure if the one implemented here can be "downgraded" to simple lines or whether I'd have to implement that one as well.
PR summary
Based on @scottshambaugh's comment, I took the existing 2D clipping algorithm and extended it to 3D. That turned out to be quite straightforward as it already worked on each direction independently. Most of the work was actually with regards to the plumbing to get things in and out. Then I implemented it for
Poly3DCollection
andPatch3D
.There are still a few things to finish this:
Poly3DCollection
supports masking on the input, both from the original input and also to allow combining ragged input into a single array for quicker processing. I have not tested either, and don't expect them to work properly.axlim_clip
flag; I don't know if we just want to enable this all the time and/or deprecate that option.Using the example from #8902 without clipping, the bars are quite misleading, as it seems like they are in a completely different spot initially compared to when looking at them edgewise.
Screencast.From.2025年09月12日.05-24-46.mp4
whereas with clipping here, we get something that isn't so weird:
Screencast.From.2025年09月12日.05-25-33.mp4
This is based on #30208.
PR checklist