@@ -97,6 +97,33 @@ def _viewlim_mask(xs, ys, zs, axes):
9797 return mask
9898
9999
100+ def _clip_to_axes_bbox (axes , paths ):
101+ """
102+ Return an Axes-clipped copy of paths.
103+
104+ Parameters
105+ ----------
106+ axes : Axes3D
107+ The axes to clip the paths against.
108+ paths : array-like
109+ A list of polygons, each comprised of a path of vertices. May also be a 3D NumPy
110+ array, if all polygons contain paths of the same length.
111+
112+ Returns
113+ -------
114+ list of np.ndarray
115+ A copy of *paths* with each polygon clipped to the *axes*.
116+ """
117+ result = mpath ._path .clip_paths_to_box (
118+ paths ,
119+ [axes .xy_viewLim .intervalx ,
120+ axes .xy_viewLim .intervaly ,
121+ axes .zz_viewLim .intervalx ],
122+ True ) # TODO: Pass in mask?
123+
124+ return result
125+
126+
100127class Text3D (mtext .Text ):
101128 """
102129 Text object with 3D position and direction.
@@ -1339,22 +1366,28 @@ def do_3d_projection(self):
13391366 if self ._edge_is_mapped :
13401367 self ._edgecolor3d = self ._edgecolors
13411368
1342- needs_masking = np .any (self ._invalid_vertices )
1343- num_faces = len (self ._faces )
1344- mask = self ._invalid_vertices
1369+ if self ._axlim_clip :
1370+ # TODO: Apply `self._invalid_vertices` for proper masking.
1371+ pfaces = _clip_to_axes_bbox (self .axes , self ._faces )
1372+ num_faces = len (pfaces )
1373+ num_verts = np .fromiter (map (len , pfaces ), dtype = np .intp )
1374+ max_verts = num_verts .max (initial = 0 )
1375+ segments = np .empty ((num_faces , max_verts , 3 ))
1376+ for i , face in enumerate (pfaces ):
1377+ segments [i , :len (face )] = face
1378+ pfaces = segments
1379+ mask = np .arange (max_verts ) >= num_verts [:, None ]
1380+ needs_masking = np .any (mask )
1381+ else :
1382+ pfaces = self ._faces
1383+ needs_masking = np .any (self ._invalid_vertices )
1384+ num_faces = len (self ._faces )
1385+ mask = self ._invalid_vertices
13451386
13461387 # Some faces might contain masked vertices, so we want to ignore any
13471388 # errors that those might cause
13481389 with np .errstate (invalid = 'ignore' , divide = 'ignore' ):
1349- pfaces = proj3d ._proj_transform_vectors (self ._faces , self .axes .M )
1350-
1351- if self ._axlim_clip :
1352- viewlim_mask = _viewlim_mask (self ._faces [..., 0 ], self ._faces [..., 1 ],
1353- self ._faces [..., 2 ], self .axes )
1354- if np .any (viewlim_mask ):
1355- needs_masking = True
1356- mask = mask | viewlim_mask
1357-
1390+ pfaces = proj3d ._proj_transform_vectors (pfaces , self .axes .M )
13581391 pzs = pfaces [..., 2 ]
13591392 if needs_masking :
13601393 pzs = np .ma .MaskedArray (pzs , mask = mask )
@@ -1385,8 +1418,7 @@ def do_3d_projection(self):
13851418 if self ._codes3d is not None and len (self ._codes3d ) > 0 :
13861419 if needs_masking :
13871420 segment_mask = ~ mask [face_order , :]
1388- faces_2d = [face [mask , :] for face , mask
1389- in zip (faces_2d , segment_mask )]
1421+ faces_2d = [face [mask , :] for face , mask in zip (faces_2d , segment_mask )]
13901422 codes = [self ._codes3d [idx ] for idx in face_order ]
13911423 PolyCollection .set_verts_and_codes (self , faces_2d , codes )
13921424 else :
0 commit comments