8000 Merge pull request #27385 from scottshambaugh/3d_culling · matplotlib/matplotlib@bdbbb2d · GitHub
[go: up one dir, main page]

Skip to content

Commit bdbbb2d

Browse files
authored
Merge pull request #27385 from scottshambaugh/3d_culling
Fix 3D lines being visible when behind camera
2 parents c51103a + 11855d1 commit bdbbb2d

File tree

5 files changed

+48
-17
lines changed

5 files changed

+48
-17
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``proj3d.proj_transform_clip``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
... is deprecated with no replacement.

lib/matplotlib/path.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1,
129129
vertices = _to_unmasked_float_array(vertices)
130130
_api.check_shape((None, 2), vertices=vertices)
131131

132-
if codes is not None:
132+
if codes is not None and len(vertices):
133133
codes = np.asarray(codes, self.code_type)
134134
if codes.ndim != 1 or len(codes) != len(vertices):
135135
raise ValueError("'codes' must be a 1D list or array with the "

lib/mpl_toolkits/mplot3d/art3d.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,9 @@ def get_data_3d(self):
267267
@artist.allow_rasterization
268268
def draw(self, renderer):
269269
xs3d, ys3d, zs3d = self._verts3d
270-
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
270+
xs, ys, zs, tis = proj3d._proj_transform_clip(xs3d, ys3d, zs3d,
271+
self.axes.M,
272+
self.axes._focal_length)
271273
self.set_data(xs, ys)
272274
super().draw(renderer)
273275
self.stale = False
@@ -458,8 +460,9 @@ def get_path(self):
458460
def do_3d_projection(self):
459461
s = self._segment3d
460462
xs, ys, zs = zip(*s)
461-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
462-
self.axes.M)
463+
vxs, vys, vzs, vis = proj3d._proj_transform_clip(xs, ys, zs,
464+
self.axes.M,
465+
self.axes._focal_length)
463466
self._path2d = mpath.Path(np.column_stack([vxs, vys]))
464467
return min(vzs)
465468

@@ -505,8 +508,9 @@ def set_3d_properties(self, path, zs=0, zdir='z'):
505508
def do_3d_projection(self):
506509
s = self._segment3d
507510
xs, ys, zs = zip(*s)
508-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
509-
self.axes.M)
511+
vxs, vys, vzs, vis = proj3d._proj_transform_clip(xs, ys, zs,
512+
self.axes.M,
513+
self.axes._focal_length)
510514
self._path2d = mpath.Path(np.column_stack([vxs, vys]), self._code3d)
511515
return min(vzs)
512516

@@ -611,8 +615,9 @@ def set_3d_properties(self, zs, zdir):
611615

612616
def do_3d_projection(self):
613617
xs, ys, zs = self._offsets3d
614-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
615-
self.axes.M)
618+
vxs, vys, vzs, vis = proj3d._proj_transform_clip(xs, ys, zs,
619+
self.axes.M,
620+
self.axes._focal_length)
616621
self._vzs = vzs
617622
super().set_offsets(np.column_stack([vxs, vys]))
618623

@@ -752,8 +757,9 @@ def set_depthshade(self, depthshade):
752757

753758
def do_3d_projection(self):
754759
xs, ys, zs = self._offsets3d
755-
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
756-
self.axes.M)
760+
vxs, vys, vzs, vis = proj3d._proj_transform_clip(xs, ys, zs,
761+
self.axes.M,
762+
self.axes._focal_length)
757763
# Sort the points based on z coordinates
758764
# Performance optimization: Create a sorted index array and reorder
759765
# points and point properties according to the index array

lib/mpl_toolkits/mplot3d/proj3d.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,21 @@ def _ortho_transformation(zfront, zback):
173173
def _proj_transform_vec(vec, M):
174174
vecw = np.dot(M, vec)
175175
w = vecw[3]
176-
# clip here..
177176
txs, tys, tzs = vecw[0]/w, vecw[1]/w, vecw[2]/w
178177
return txs, tys, tzs
179178

180179

181-
def _proj_transform_vec_clip(vec, M):
180+
def _proj_transform_vec_clip(vec, M, focal_length):
182181
vecw = np.dot(M, vec)
183182
w = vecw[3]
184-
# clip here.
185183
txs, tys, tzs = vecw[0] / w, vecw[1] / w, vecw[2] / w
186-
tis = (0 <= vecw[0]) & (vecw[0] <= 1) & (0 <= vecw[1]) & (vecw[1] <= 1)
187-
if np.any(tis):
188-
tis = vecw[1] < 1
184+
if np.isinf(focal_length): # don't clip orthographic projection
185+
tis = np.ones(txs.shape, dtype=bool)
186+
else:
187+
tis = (-1 <= txs) & (txs <= 1) & (-1 <= tys) & (tys <= 1) & (tzs <= 0)
188+
txs = np.ma.masked_array(txs, ~tis)
189+
tys = np.ma.masked_array(tys, ~tis)
190+
tzs = np.ma.masked_array(tzs, ~tis)
189191
return txs, tys, tzs, tis
190192

191193

@@ -220,14 +222,19 @@ def proj_transform(xs, ys, zs, M):
220222
alternative="proj_transform")(proj_transform)
221223

222224

225+
@_api.deprecated("3.10")
223226
def proj_transform_clip(xs, ys, zs, M):
227+
return _proj_transform_clip(xs, ys, zs, M, focal_length=np.inf)
228+
229+
230+
def _proj_transform_clip(xs, ys, zs, M, focal_length):
224231
"""
225232
Transform the points by the projection matrix
226233
and return the clipping result
227234
returns txs, tys, tzs, tis
228235
"""
229236
vec = _vec_pad_ones(xs, ys, zs)
230-
return _proj_transform_vec_clip(vec, M)
237+
return _proj_transform_vec_clip(vec, M, focal_length)
231238

232239

233240
@_api.deprecated("3.8")

lib/mpl_toolkits/mplot3d/tests/test_axes3d.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,21 @@ def test_unautoscale(axis, auto):
13251325
np.testing.assert_array_equal(get_lim(), (-0.5, 0.5))
13261326

13271327

1328+
@check_figures_equal(extensions=["png"])
1329+
def test_culling(fig_test, fig_ref):
1330+
xmins = (-100, -50)
1331+
for fig, xmin in zip((fig_test, fig_ref), xmins):
1332+
ax = fig.add_subplot(projection='3d')
1333+
n = abs(xmin) + 1
1334+
xs = np.linspace(0, xmin, n)
1335+
ys = np.ones(n)
1336+
zs = np.zeros(n)
1337+
ax.plot(xs, ys, zs, 'k')
1338+
1339+
ax.set(xlim=(-5, 5), ylim=(-5, 5), zlim=(-5, 5))
1340+
ax.view_init(5, 180, 0)
1341+
1342+
13281343
def test_axes3d_focal_length_checks():
13291344
fig = plt.figure()
13301345
ax = fig.add_subplot(projection='3d')

0 commit comments

Comments
 (0)
0