@@ -263,44 +263,49 @@ def ellipse_params_via_border_pca_from(border_grid, xp=np, eps=1e-12):
263263 return origin , a , b , phi
264264
265265
266- def relocated_grid_via_ellipse_border_from (
267- grid , origin , a , b , phi , xp = np , eps = 1e-12 , border_frac = 1e-2
268- ):
266+ def relocated_grid_via_ellipse_border_from (grid , origin , a , b , phi , xp = np , eps = 1e-12 ):
269267 """
270- Move points outside the ellipse to a contour slightly *outside* the border
271- to avoid geometric degeneracy in Voronoi/Delaunay .
268+ Rotated ellipse centered at origin with semi-axes a (major, x'), b (minor, y'),
269+ rotated by phi radians (counterclockwise) .
272270
273- border_frac: fractional expansion of ellipse radius
274- (e.g. 1e-3 = +0.1% outside).
271+ Parameters
272+ ----------
273+ grid : (N,2)
274+ Coordinates in (y, x) order.
275+ origin : (2,)
276+ Ellipse center (y0, x0).
277+ a, b : float
278+ Semi-major and semi-minor axes.
279+ phi : float
280+ Rotation angle in radians.
281+ xp : module
282+ numpy-like module (np, jnp, cupy, etc.).
283+ eps : float
284+ Numerical safety epsilon.
275285 """
276286
287+ # shift to origin
277288 dy = grid [:, 0 ] - origin [0 ]
278289 dx = grid [:, 1 ] - origin [1 ]
279290
280291 c = xp .cos (phi )
281292 s = xp .sin (phi )
282293
283- # Rotate into ellipse-aligned frame
294+ # rotate into ellipse-aligned frame
284295 xprime = c * dx + s * dy
285296 yprime = - s * dx + c * dy
286297
287- # Normalized ellipse radius
298+ # ellipse radius in normalized coords
288299 q = (xprime / a ) ** 2 + (yprime / b ) ** 2
289300
290301 outside = q > 1.0
302+ scale = 1.0 / xp .sqrt (xp .maximum (q , 1.0 + eps ))
291303
292- # Target radius slightly OUTSIDE ellipse
293- expand = xp .asarray (1.0 + border_frac , dtype = q .dtype )
294- q_target = expand * expand # (1 + border_frac)^2
295-
296- # Project only outside points
297- safe_q = xp .maximum (q , xp .asarray (1.0 , dtype = q .dtype ))
298- scale = xp .sqrt (q_target / safe_q )
299-
304+ # scale back to boundary
300305 xprime2 = xprime * scale
301306 yprime2 = yprime * scale
302307
303- # Rotate back
308+ # rotate back to original frame
304309 dx2 = c * xprime2 - s * yprime2
305310 dy2 = s * xprime2 + c * yprime2
306311
@@ -309,7 +314,6 @@ def relocated_grid_via_ellipse_border_from(
309314 return xp .where (outside [:, None ], moved , grid )
310315
311316
312-
313317class BorderRelocator :
314318 def __init__ (
315319 self ,
0 commit comments