Skip to content

Commit 9f6c73b

Browse files
committed
Improve NURBS and SSX intersection handling:
- Add `show_wires` property for better rendering control. - Extend `_try_deflated_hard_case` with recursion support for tangential cases. - Refactor `_leaf_boundary_test_and_march` and `_bez_ssx_recursive` with enhanced boundary logic and overlap deduplication. - Standardize parameter naming for clarity (`atol` over `spt`).
1 parent 961a217 commit 9f6c73b

7 files changed

Lines changed: 842 additions & 416 deletions

File tree

examples/ssx/common_helpers.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class WiresMaterial(CurveMaterial):
4444
class SurfaceMaterial:
4545

4646
color:tuple[float,float,float,float]=field(default=(0.5, 0.5, 0.9, 0.05))
47+
show_wires:bool=field(default=True)
4748
wires_material: WiresMaterial = field(
4849
default_factory=lambda: WiresMaterial((1.0, 1.0, 1.0, 1.0), show_control_net=False, u_count=1, v_count=1)
4950
)
@@ -98,7 +99,7 @@ def save_pkl(s1,s2,result,fp=None)->Path:
9899
fp=inspect.getfile(_find_root_frame(inspect.currentframe()))
99100
pth=Path(fp).with_suffix('.pkl')
100101
with open(pth, 'wb') as f:
101-
pickle.dump(((s1, s2), [r.curve_xyz for r in result[0]], [r.curve_st for r in result[0]], [r.curve_uv for r in result[0]]), f)
102+
pickle.dump(((s1, s2), [r.curve_xyz for r in result[0]], [r.curve_st for r in result[0]], [r.curve_uv for r in result[0]], [p.xyz for p in result[1]]), f)
102103
return pth
103104

104105

@@ -126,9 +127,9 @@ def draw_ssx(
126127
if viewer is None:
127128
viewer = Viewer(camera=OrbitCamera(target=bb.centroid(), distance=np.linalg.norm(bb.diag())*2, near=1.0))
128129

129-
viewer.add_nurbs_surface(s1, color=surf1_material.wires_material.color, surface_color=surf1_material.color, u_count=surf1_material.wires_material.u_count, v_count=surf1_material.wires_material.v_count)
130+
viewer.add_nurbs_surface(s1, color=surf1_material.wires_material.color, surface_color=surf1_material.color, u_count=surf1_material.wires_material.u_count, v_count=surf1_material.wires_material.v_count,show_edges=surf1_material.show_wires,show_isocurves=surf1_material.show_wires,)
130131
viewer.add_nurbs_surface(
131-
s2,color=surf2_material.wires_material.color,surface_color=surf2_material.color,u_count=surf2_material.wires_material.u_count,v_count=surf2_material.wires_material.v_count
132+
s2,color=surf2_material.wires_material.color,surface_color=surf2_material.color,u_count=surf2_material.wires_material.u_count,v_count=surf2_material.wires_material.v_count,show_edges=surf1_material.show_wires,show_isocurves=surf1_material.show_wires,
132133

133134
)
134135

examples/ssx/nurbs_nurbs_intersection_8.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545

4646
import logging
47-
from examples.ssx.common_helpers import parse_args, save_pkl, draw_ssx, VIEWER_INSTALLED, CurveMaterial, ControlNetMaterial, PointMaterial
47+
from examples.ssx.common_helpers import parse_args, save_pkl, draw_ssx, VIEWER_INSTALLED, CurveMaterial, ControlNetMaterial, PointMaterial,surface_material
4848
args = parse_args()
4949
logging.basicConfig(level=getattr(logging, args.loglevel, logging.INFO))
5050
from mmcore.numeric.intersection.ssx import nurbs_ssx
@@ -63,12 +63,13 @@
6363
RENDER = args.viewer and VIEWER_INSTALLED
6464

6565
if RENDER:
66+
surface_material.show_wires = False
6667
inter_curves_mat = CurveMaterial(
6768
(0.0, 1.0, 0.5, 1.0),
6869
show_control_net=args.show_inter_cpts,
6970
control_net_material=ControlNetMaterial((0.0, 1.0, 0.5, 0.7), control_point_material=PointMaterial((0.0, 1.0, 0.5, 0.4), size=8)),
7071
)
7172

72-
viewer = draw_ssx(s1, s2, result, intersection_curves_material=inter_curves_mat)
73+
viewer = draw_ssx(s1, s2, result, surf1_material=surface_material,surf2_material=surface_material,intersection_curves_material=inter_curves_mat)
7374

7475
viewer.run()

mmcore/extras/renderer/renderer3d.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -710,14 +710,15 @@ def _add_nurbs_curve(self, curve: NURBSCurveTuple, color=(1.0, 1.0, 1.0, 1.0),*a
710710
return tuple(self.add(to_homogeneous_1d(bezier.control_points, bezier.weights), rational=True, color=color,*args,**kwargs) for bezier in beziers)
711711
def add_nurbs_curve(self, curve: NURBSCurveTuple, color=(1.0, 1.0, 1.0, 1.0),*args,**kwargs):
712712
return self._add_nurbs_curve(curve, color, *args, **kwargs)
713-
def add_nurbs_surface(self, surface:NURBSSurfaceTuple, color=(1.0, 1.0, 1.0, 1.0),surface_color=(0.5, 0.5, 0.9, 0.05),u_count=1,v_count=1,*args,**kwargs):
713+
def add_nurbs_surface(self, surface:NURBSSurfaceTuple, color=(1.0, 1.0, 1.0, 1.0),surface_color=(0.5, 0.5, 0.9, 0.05),u_count=1,v_count=1,show_edges:bool=True,show_isocurves:bool=True,*args,**kwargs):
714714
shade = kwargs.pop("shade", True)
715715
surface_color = surface_color
716716

717717
surface_tol = kwargs.pop("surface_tol", 0.01)
718+
meshes=[]
718719
if shade:
719720

720-
self._add_surface_mesh(surface, color=surface_color, tol=surface_tol)
721+
meshes.append(self._add_surface_mesh(surface, color=surface_color, tol=surface_tol))
721722
(u0,u1),(v0,v1) = surface.interval()
722723
umid,vmid=(u1-u0)*0.5+u0, (v1-v0)*0.5+v0
723724
us=np.linspace(u0,u1,u_count+2)[1:][:-1]
@@ -727,13 +728,16 @@ def add_nurbs_surface(self, surface:NURBSSurfaceTuple, color=(1.0, 1.0, 1.0, 1.0
727728
color[2]*0.5,
728729
color[3])
729730
isolines=[]
730-
731-
for crv in [extract_isocurve(surface, u,'u') for u in us]+[extract_isocurve(surface, v,'v') for v in vs]:
732-
isolines.append(self._add_nurbs_curve(crv,iso_color,*args,**kwargs))
731+
if show_isocurves:
732+
for crv in [extract_isocurve(surface, u,'u') for u in us]+[extract_isocurve(surface, v,'v') for v in vs]:
733+
isolines.append(self._add_nurbs_curve(crv,iso_color,*args,**kwargs))
733734
bnds=[]
734-
for bnd in extract_surface_boundaries(surface):
735-
bnds.append(self._add_nurbs_curve(bnd,color,*args,**kwargs))
736-
return tuple(bnds)+tuple(isolines)
735+
if show_edges:
736+
for bnd in extract_surface_boundaries(surface):
737+
738+
bnds.append(self._add_nurbs_curve(bnd,color,*args,**kwargs))
739+
return tuple(meshes)+tuple(bnds)+tuple(isolines)
740+
737741

738742
def _upload_matrices(self, P_row: np.ndarray, V_row: np.ndarray, M_row: np.ndarray):
739743
"""

mmcore/numeric/bern.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ def bernstein_cutout_box_nd(control_grid: np.ndarray,
11961196
Notes
11971197
-----
11981198
• Per axis k we split into up to three slabs: L=[0,a_k], M=[a_k,b_k], H=[b_k,1], with matrices
1199-
T^L_k, T^M_k, T^H_k computed once from deCasteljau (matrix form).
1199+
T^L_k, T^M_k, T^H_k computed once from de Casteljau (matrix form).
12001200
• We enumerate the Cartesian product of available slabs across axes and exclude the all‑'M' box.
12011201
• Each sub‑patch is produced by a single `einsum` that applies all T_k at once.
12021202
"""

mmcore/numeric/intersection/_deflate.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,14 +1024,16 @@ def analyse_deflated_system(
10241024
lo, hi = Bf[axis]
10251025
if curve_mode != "krawczyk":
10261026
gamma_rows = choose_gamma_3eq(sys, xw)
1027-
curve_4d = trace_gamma(
1027+
curve_4d, curve_h_steps = trace_gamma(
10281028
sys, gamma_rows, xw, Bf,
10291029
h0=curve_trace_h0,
10301030
h_min=curve_trace_h_min,
10311031
h_max=curve_trace_h_max,
10321032
max_steps=curve_trace_max_steps,
10331033
tol=curve_trace_tol,
10341034
)
1035+
out["trace_points"] = curve_4d
1036+
out["trace_h_steps"] = curve_h_steps
10351037
samples = []
10361038
for xm in curve_4d:
10371039
fn = float(np.linalg.norm(sys.delta_point(xm)))
@@ -1343,12 +1345,13 @@ def newton_corrector_arclen(x_pred, t_pred, x_init=None, max_iter=12):
13431345

13441346
def trace_one_direction(sign):
13451347
pts = [x0.copy()]
1348+
h_steps = [0.0] # step size used to reach each point (0 for initial)
13461349
h = h0
13471350

13481351
J0 = sys.jac_rows_point(x0, gamma_rows)
13491352
t = nullspace_direction(J0)
13501353
if t is None:
1351-
return pts
1354+
return pts, h_steps
13521355
t *= sign
13531356

13541357
for _ in range(max_steps):
@@ -1367,6 +1370,7 @@ def trace_one_direction(sign):
13671370
axis_near, bound_near, B, tol=tol)
13681371
if ok and inside(x_end):
13691372
pts.append(x_end)
1373+
h_steps.append(h)
13701374
break
13711375

13721376
# Predict
@@ -1384,6 +1388,7 @@ def trace_one_direction(sign):
13841388
axis_hit, bound_hit, B, tol=tol)
13851389
if ok and inside(x_end) and np.linalg.norm(sys.delta_point(x_end)) < 1e-7:
13861390
pts.append(x_end)
1391+
h_steps.append(h)
13871392
solved = True
13881393
break
13891394
if solved:
@@ -1417,6 +1422,7 @@ def trace_one_direction(sign):
14171422
continue
14181423

14191424
pts.append(x_new)
1425+
h_steps.append(h)
14201426

14211427
# Update tangent
14221428
Jn = sys.jac_rows_point(x_new, gamma_rows)
@@ -1429,12 +1435,15 @@ def trace_one_direction(sign):
14291435

14301436
h = min(h_max, h * 1.2)
14311437

1432-
return pts
1438+
return pts, h_steps
14331439

1434-
fwd = trace_one_direction(+1)
1435-
bwd = trace_one_direction(-1)
1436-
bwd = bwd[::-1]
1437-
return bwd[:-1] + fwd
1440+
fwd_pts, fwd_h = trace_one_direction(+1)
1441+
bwd_pts, bwd_h = trace_one_direction(-1)
1442+
bwd_pts = bwd_pts[::-1]
1443+
bwd_h = bwd_h[::-1]
1444+
points = bwd_pts[:-1] + fwd_pts
1445+
h_steps = bwd_h[:-1] + fwd_h
1446+
return points, h_steps
14381447

14391448

14401449
if __name__ == "__main__":

0 commit comments

Comments
 (0)