Skip to content

Commit 7b47c4d

Browse files
committed
Refactor NURBS intersection logic: enhance interpolation with interpolate_nurbs_curve, fix camera initialization in viewer, and improve SSX result handling with new example script.
1 parent 1a7ac47 commit 7b47c4d

5 files changed

Lines changed: 139 additions & 9 deletions

File tree

examples/ssx/common_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def draw_ssx(
125125

126126
bb = AABB.from_points(s1.control_points.reshape(-1, 3)).merge(AABB.from_points(s2.control_points.reshape(-1, 3)))
127127
if viewer is None:
128-
viewer = Viewer(camera=OrbitCamera(target=bb.centroid(), distance=np.linalg.norm(bb.diag())*2, near=1.0))
128+
viewer = Viewer(camera=OrbitCamera(target=bb.centroid(), distance=np.linalg.norm(bb.diag())**2, near=1.0))
129129

130130
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,)
131131
viewer.add_nurbs_surface(
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""
2+
3+
This example demonstrates the intersection of two NURBS spheres.
4+
"""
5+
import time
6+
7+
from mmcore.construction import cylinder_surface_2pt
8+
from mmcore.geom._nurbs_eval import _tuple_to_nurbs, NURBSSurfaceTuple
9+
from mmcore.geom._nurbs_transform import transform_nurbs
10+
from mmcore.geom.bvh.lbvh import AABB
11+
from mmcore.geom.nurbs import NURBSSurface
12+
from mmcore.construction import nurbs_surface
13+
from mmcore.numeric.intersection.ssx import ssx
14+
15+
# Creating intersection objects
16+
import numpy as np
17+
18+
import numpy as np
19+
from mmcore.geom._nurbs_eval import NURBSSurfaceTuple
20+
21+
22+
s1 = NURBSSurfaceTuple(
23+
order_u=4,
24+
order_v=4,
25+
knot_u=np.array([ 0.00000000, 0.00000000, 0.00000000, 0.00000000,
26+
584.56714755, 1169.13429511, 1169.13429511, 1169.13429511,
27+
1169.13429511]),
28+
knot_v=np.array([ 0.00000000, 0.00000000, 0.00000000, 0.00000000,
29+
675.00000000, 675.00000000, 675.00000000, 675.00000000]),
30+
control_points=np.array([[[2488.56941006, 1499.08843254, 0.00000000],
31+
[2394.60779838, 1603.70965174, 0.00000000],
32+
[2394.60779838, 1675.09483487, 0.00000000],
33+
[2488.56941006, 1779.71605406, 0.00000000]],
34+
35+
[[2582.53102174, 1394.46721335, 0.00000000],
36+
[2550.34379877, 1515.98031620, 152.12435146],
37+
[2550.34379877, 1762.82417041, 152.12435146],
38+
[2582.53102174, 1884.33727326, 0.00000000]],
39+
40+
[[2754.10779838, 1284.40224330, 0.00000000],
41+
[2754.10779838, 1466.26757810, 257.50000000],
42+
[2754.10779838, 1812.53690851, 257.50000000],
43+
[2754.10779838, 1994.40224330, 0.00000000]],
44+
45+
[[2925.68457502, 1394.46721335, 0.00000000],
46+
[2957.87179798, 1515.98031620, 152.12435146],
47+
[2957.87179798, 1762.82417041, 152.12435146],
48+
[2925.68457502, 1884.33727326, 0.00000000]],
49+
50+
[[3019.64618670, 1499.08843254, 0.00000000],
51+
[3113.60779838, 1603.70965174, 0.00000000],
52+
[3113.60779838, 1675.09483487, 0.00000000],
53+
[3019.64618670, 1779.71605406, 0.00000000]]]),
54+
weights=np.array([[1.00000000, 1.00000000, 1.00000000, 1.00000000],
55+
[1.00000000, 1.00000000, 1.00000000, 1.00000000],
56+
[1.00000000, 1.00000000, 1.00000000, 1.00000000],
57+
[1.00000000, 1.00000000, 1.00000000, 1.00000000],
58+
[1.00000000, 1.00000000, 1.00000000, 1.00000000]])
59+
)
60+
import numpy as np
61+
from mmcore.geom._nurbs_eval import NURBSSurfaceTuple
62+
63+
64+
s2 = NURBSSurfaceTuple(
65+
order_u=2,
66+
order_v=2,
67+
knot_u=np.array([ 0.00000000, 0.00000000, 854.10934693, 854.10934693]),
68+
knot_v=np.array([ 0.00000000, 0.00000000, 1119.84031048, 1119.84031048]),
69+
control_points=np.array([[[2372.10906381, 1470.47565841, 170.90189109],
70+
[2614.15055984, 2054.83790061, 228.66096126]],
71+
72+
[[2953.02855072, 1248.46099847, -17.28737813],
73+
[3195.07004676, 1832.82324067, 40.47169204]]]),
74+
weights=np.array([[1.00000000, 1.00000000],
75+
[1.00000000, 1.00000000]])
76+
)
77+
78+
79+
s1,s2=s2,s1
80+
import logging
81+
from examples.ssx.common_helpers import parse_args, save_pkl, draw_ssx, VIEWER_INSTALLED, CurveMaterial, ControlNetMaterial, PointMaterial
82+
args = parse_args()
83+
logging.basicConfig(level=getattr(logging, args.loglevel, logging.INFO))
84+
from mmcore.numeric.intersection.ssx import nurbs_ssx
85+
86+
s = time.time()
87+
result = nurbs_ssx(s1, s2, atol=0.001, angle_tol=0.052)
88+
89+
print(f"intersection computed at: {time.time() - s} sec.")
90+
print(len(result[0]), "branch(s)")
91+
print(len(result[1]), "pts(s)")
92+
93+
if args.save_pkl or args.pkl_path is not None:
94+
path = save_pkl(s1, s2, result, fp=args.pkl_path)
95+
print(path.absolute().as_posix())
96+
97+
RENDER = args.viewer
98+
99+
if RENDER:
100+
inter_curves_mat = CurveMaterial(
101+
(0.0, 1.0, 0.5, 1.0),
102+
show_control_net=args.show_inter_cpts,
103+
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)),
104+
)
105+
106+
viewer = draw_ssx(s1, s2, result, intersection_curves_material=inter_curves_mat)
107+
108+
viewer.run()

mmcore/geom/_nurbs_interp.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,18 @@ def fair_interpolate_curve(points, degree, lambda_reg=1e-3)->tuple[NDArray[float
310310
control_points = np.vstack([d0, x, d_end])
311311

312312
return control_points, knot_vector
313+
def interpolate_nurbs_curve(points, degree, use_centripetal=False,rational=False,**kwargs):
313314

315+
cp,kv=interpolate_curve(points, degree, use_centripetal=use_centripetal,**kwargs)
316+
cp=np.array(cp)
317+
if rational:
318+
cp,w=from_homogeneous_1d(cp)
319+
else:
320+
w=np.ones_like(cp[:,0])
321+
return NURBSCurveTuple(order=degree+1, knot=np.array(kv), control_points=cp, weights=w)
314322
from mmcore.geom.nurbs import ders_basis_funs as _ders_basis_funs
315323
from mmcore.geom.nurbs import find_span as _find_span
324+
from mmcore.geom._nurbs_eval import from_homogeneous_1d,to_homogeneous_1d
316325
import numpy as np
317326
from scipy.special import comb, factorial
318327
from typing import NamedTuple, List, Optional

mmcore/numeric/intersection/ssx/_ssx4.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from mmcore.construction import nurbs_curve
1212
from mmcore.geom._nurbs_eval import evaluate_nurbs_curve, evaluate_nurbs_surface, NURBSSurfaceTuple
13-
from mmcore.geom._nurbs_interp import interpolate_curve
13+
from mmcore.geom._nurbs_interp import interpolate_curve, interpolate_nurbs_curve
1414

1515
import functools
1616
import pickle
@@ -1822,7 +1822,7 @@ def _eval_curve(t):
18221822
#
18231823
#
18241824
# crvs.append(bern_to_nurbs_bezier(np.array([ps,ps+ds*h,pe-ds*h,pe]),interval=(ts,te),rational=False))
1825-
branch.curve_xyz=nurbs_curve(np.array(_points),degree=1)
1825+
branch.curve_xyz=interpolate_nurbs_curve(np.array(_points),branch.curve.degree)
18261826
#branch.curve_xyz=remove_knots_after_merge(crv,interior,atol)
18271827

18281828
def compute_branch_curves(branch: SSXBranch, surface1:NURBSSurfaceTuple, surface2:NURBSSurfaceTuple,**kwargs):

mmcore/numeric/intersection/ssx/trace_inter_segm.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import numpy as np
2020
from numpy.typing import NDArray
2121

22+
from mmcore.geom._nurbs_interp import interpolate_curve
2223
from mmcore.geom._nurbs_knots import link_curves,remove_knot,remove_knot_curve_max
24+
from mmcore.geom._nurbs_interp import interpolate_nurbs_curve
2325
from mmcore.numeric.intersection.ssx.refine import refine_intersection_point
2426
from mmcore.numeric.sbern import bern_to_nurbs_bezier
2527

@@ -518,10 +520,10 @@ def compute(self):
518520

519521
def compute_normals_tangent_and_curvature(self):
520522
if self.s_eval['s1'].get('N') is None:
521-
self.s_eval['s1']['N']=evaluate_normal2( self.s_eval['s1']['Su'],self.s_eval['s1']['Sv'],self.s_eval['s1']['Suu'],self.s_eval['s1']['Suv'],self.s_eval['s1']['Svv'],self.s_eval['s1']['Svv'])
523+
self.s_eval['s1']['N']=evaluate_normal2( self.s_eval['s1']['Su'],self.s_eval['s1']['Sv'],self.s_eval['s1']['Suu'],self.s_eval['s1']['Suv'],self.s_eval['s1']['Svv'])
522524
self.s_eval['s1']['N']/=np.linalg.norm(self.s_eval['s1']['N'])
523525
if self.s_eval['s2'].get('N') is None:
524-
self.s_eval['s2']['N']=evaluate_normal2( self.s_eval['s2']['Su'],self.s_eval['s2']['Sv'],self.s_eval['s2']['Suu'],self.s_eval['s2']['Suv'],self.s_eval['s2']['Svv'],self.s_eval['s2']['Svv'])
526+
self.s_eval['s2']['N']=evaluate_normal2( self.s_eval['s2']['Su'],self.s_eval['s2']['Sv'],self.s_eval['s2']['Suu'],self.s_eval['s2']['Suv'],self.s_eval['s2']['Svv'])
525527
self.s_eval['s2']['N']/=np.linalg.norm(self.s_eval['s2']['N'])
526528

527529
self.s_eval['T']=np.cross(self.s_eval['s1']['N'],
@@ -573,12 +575,16 @@ def __init__(self,start:InterpNode,end:InterpNode):
573575
end: InterpNode
574576
start.curve_stuv: NDArray = None
575577
end.curve_xyz: NDArray = None
578+
self._curve=None
576579

577580
def stuv_mid(self) -> NDArray[np.float64]: ...
578581

579582
def xyz_mid(self)->NDArray[np.float64]:...
580583

581-
def build_curves(self):...
584+
def build_curves(self):
585+
586+
self._curve=hinterp(np.array((self.start.s_eval['s1']['S'],self.end.s_eval['s1']['S'])),np.array((self.start.s_eval['T'],self.end.s_eval['T'])))
587+
582588

583589
@property
584590
def next_segm(self):
@@ -649,11 +655,13 @@ def adaptive_refine_bruteforce(
649655

650656
node_a = InterpNode( {'stuv':stuv_a,'s1':xyz_s,'s2':xyz_s2,"T":None,"pN":None,"K":None},prev=None, next=None)
651657
node_b = InterpNode({'stuv':stuv_b,'s1':xyz_e,'s2':xyz_e2,"T":None,"pN":None,"K":None}, prev=node_a, next=None)
658+
#max_h=np.linalg.norm(stuv_a-stuv_b)/8
652659

653660
node_a.next = node_b
654661
node_a.compute()
655662
node_b.compute()
656663
stack = [(node_a, node_b, depth, np.inf)]
664+
657665
while stack:
658666
stuv_start, stuv_end, cur_depth,delta = stack.pop()
659667
if cur_depth >= fit_max_depth:
@@ -685,9 +693,13 @@ def adaptive_refine_bruteforce(
685693
new_node.compute_normals_tangent_and_curvature()
686694
T = (new_node.s_eval['s1']["S"] - stuv_start.s_eval['s1']["S"]) / 2
687695
dT=np.linalg.norm(T)
696+
688697
s = np.sqrt(8.0 * spt / np.linalg.norm(new_node.s_eval['K']))
698+
699+
700+
print(s,dT)
689701
if dT<=s:
690-
continue
702+
continue
691703
delta=np.linalg.norm(p_eval['S']-xyz1)
692704

693705

@@ -698,8 +710,9 @@ def adaptive_refine_bruteforce(
698710
stack.append((new_node,stuv_end,cur_depth+1,delta))
699711
else:
700712
continue
701-
702-
return nurbs_curve(np.array(list(node_a)),1)
713+
ll=list(node_a)
714+
print(len(ll))
715+
return interpolate_nurbs_curve(np.array(ll),degree=min(len(ll)-1,3))
703716

704717

705718
def _from_homogeneous(H: NDArray[np.float64]) -> tuple[NDArray[np.float64], NDArray[np.float64]]:

0 commit comments

Comments
 (0)