@@ -96,20 +96,27 @@ def scipy_delaunay_tri_only(points_np):
9696 coplanar/duplicate (the walk then starts from simplex 0 instead,
9797 which is equally valid — the walk converges from any start).
9898 """
99+ N = points_np .shape [0 ]
100+ simplices_padded = - np .ones ((2 * N , 3 ), dtype = np .int32 )
101+ simplex_neighbors = - np .ones ((2 * N , 3 ), dtype = np .int32 )
102+ vertex_simplex = - np .ones (N , dtype = np .int32 )
103+
104+ # This function is the body of a sequentially-vmapped host callback. A
105+ # qhull exception in one lane aborts the entire batch, so keep non-finite
106+ # input lane-local and encode it with the callback's existing padding
107+ # convention. The JAX-side walk and weights preserve the lane as NaN.
108+ if not np .isfinite (points_np ).all ():
109+ return simplices_padded , simplex_neighbors , vertex_simplex
110+
99111 from scipy .spatial import Delaunay
100112
101- N = points_np .shape [0 ]
102113 tri = Delaunay (points_np )
103114 simplices = tri .simplices .astype (np .int32 ) # (T, 3)
104115 T = simplices .shape [0 ]
105116
106- simplices_padded = - np .ones ((2 * N , 3 ), dtype = np .int32 )
107117 simplices_padded [:T ] = simplices
108-
109- simplex_neighbors = - np .ones ((2 * N , 3 ), dtype = np .int32 )
110118 simplex_neighbors [:T ] = tri .neighbors .astype (np .int32 )
111119
112- vertex_simplex = - np .ones (N , dtype = np .int32 )
113120 simplex_ids = np .arange (T , dtype = np .int32 )
114121 for k in range (3 ):
115122 vertex_simplex [simplices [:, k ]] = simplex_ids
@@ -185,9 +192,11 @@ def cross(u, v):
185192
186193 def weights_of (cur , q_chunk ):
187194 verts = simplices_padded [cur ] # (chunk, 3)
188- a = points [verts [:, 0 ]]
189- b = points [verts [:, 1 ]]
190- c = points [verts [:, 2 ]]
195+ valid_simplex = (verts >= 0 ).all (axis = 1 )
196+ safe_verts = verts .clip (min = 0 )
197+ a = points [safe_verts [:, 0 ]]
198+ b = points [safe_verts [:, 1 ]]
199+ c = points [safe_verts [:, 2 ]]
191200 den = cross (b - a , c - a )
192201 den = xp .where (den != 0.0 , den , 1.0 )
193202 w = (
@@ -201,13 +210,14 @@ def weights_of(cur, q_chunk):
201210 )
202211 / den [:, None ]
203212 )
204- return verts , w
213+ return verts , w , valid_simplex
205214
206215 def walk_step (carry , q_chunk ):
207216 cur , done , outside = carry
208- _ , w = weights_of (cur , q_chunk )
217+ _ , w , valid_simplex = weights_of (cur , q_chunk )
209218 minw = w .min (axis = 1 )
210219 opposite = w .argmin (axis = 1 )
220+ outside = outside | (~ done & ~ valid_simplex )
211221 done = done | (~ outside & (minw >= - 1.0e-12 ))
212222 nxt = simplex_neighbors [cur , opposite ]
213223 outside = outside | (~ done & (nxt < 0 ))
@@ -551,6 +561,10 @@ def pixel_weights_delaunay_from(
551561 # -----------------------------
552562 pixel_weights = xp .where (has_simplex [:, None ], weights_bary , weights_nn )
553563
564+ if xp is not np :
565+ mesh_is_finite = xp .isfinite (mesh_grid ).all ()
566+ pixel_weights = xp .where (mesh_is_finite , pixel_weights , xp .nan )
567+
554568 return pixel_weights
555569
556570
0 commit comments