Коммит e4a9d3ba создал по автору Ilya Portnov's avatar Ilya Portnov
Просмотр файлов

Simple reparametrization option.

владелец b5c7a40c
......@@ -22,6 +22,9 @@ from sverchok.dependencies import FreeCAD, scipy
if FreeCAD is None and scipy is None:
add_dummy('SvIntersectNurbsCurvesNode', "Intersect Curves", 'FreeCAD or scipy')
if FreeCAD is not None:
from FreeCAD import Base
class SvIntersectNurbsCurvesNode(bpy.types.Node, SverchCustomTreeNode):
"""
Triggers: Intersect Curves
......@@ -107,25 +110,31 @@ class SvIntersectNurbsCurvesNode(bpy.types.Node, SverchCustomTreeNode):
self.inputs.new('SvCurveSocket', "Curve1")
self.inputs.new('SvCurveSocket', "Curve2")
self.outputs.new('SvVerticesSocket', "Intersections")
self.outputs.new('SvStringsSocket', "T1")
self.outputs.new('SvStringsSocket', "T2")
def _filter(self, points):
if not points:
return points
return [], [], []
prev = points[0]
result = [prev]
for p in points[1:]:
t1, t2, prev = points[0]
out_t1 = [t1]
out_t2 = [t2]
out_points = [prev]
for t1, t2, p in points[1:]:
r = (Vector(p) - Vector(prev)).length
if r > 1e-4:
result.append(p)
out_t1.append(t1)
out_t2.append(t2)
out_points.append(p)
prev = p
return result
return out_t1, out_t2, out_points
def process_native(self, curve1, curve2):
res = intersect_nurbs_curves(curve1, curve2,
method = self.method,
numeric_precision = self.precision)
points = [r[2].tolist() for r in res]
points = [(r[0], r[1], r[2].tolist()) for r in res]
return self._filter(points)
def process_freecad(self, sv_curve1, sv_curve2):
......@@ -133,6 +142,12 @@ class SvIntersectNurbsCurvesNode(bpy.types.Node, SverchCustomTreeNode):
fc_curve2 = curve_to_freecad(sv_curve2)[0]
points = fc_curve1.curve.intersectCC(fc_curve2.curve)
points = [(p.X, p.Y, p.Z) for p in points]
pts = []
for p in points:
t1 = fc_curve1.curve.parameter(Base.Vector(*p))
t2 = fc_curve2.curve.parameter(Base.Vector(*p))
pts.append((t1, t2, p))
return self._filter(points)
def match(self, curves1, curves2):
......@@ -152,9 +167,13 @@ class SvIntersectNurbsCurvesNode(bpy.types.Node, SverchCustomTreeNode):
curve2_s = ensure_nesting_level(curve2_s, 2, data_types=(SvCurve,))
points_out = []
t1_out = []
t2_out = []
for curve1s, curve2s in zip_long_repeat(curve1_s, curve2_s):
new_points = []
new_t1 = []
new_t2 = []
for curve1, curve2 in self.match(curve1s, curve2s):
curve1 = SvNurbsCurve.to_nurbs(curve1)
if curve1 is None:
......@@ -164,23 +183,33 @@ class SvIntersectNurbsCurvesNode(bpy.types.Node, SverchCustomTreeNode):
raise Exception("Curve2 is not a NURBS")
if self.implementation == 'SCIPY':
ps = self.process_native(curve1, curve2)
t1s, t2s, ps = self.process_native(curve1, curve2)
else:
ps = self.process_freecad(curve1, curve2)
t1s, t2s, ps = self.process_freecad(curve1, curve2)
if self.single:
if len(ps) >= 1:
ps = ps[0]
t1s = t1s[0]
t2s = t2s[0]
new_points.append(ps)
new_t1.append(t1s)
new_t2.append(t2s)
if self.split:
n = len(curve1s)
new_points = split_by_count(new_points, n)
new_t1 = split_by_count(new_t1, n)
new_t2 = split_by_count(new_t2, n)
points_out.append(new_points)
t1_out.append(new_t1)
t2_out.append(new_t2)
self.outputs['Intersections'].sv_set(points_out)
self.outputs['T1'].sv_set(t1_out)
self.outputs['T2'].sv_set(t2_out)
def register():
if FreeCAD is not None or scipy is not None:
......
......@@ -10,7 +10,7 @@ import bpy
from bpy.props import FloatProperty, EnumProperty, BoolProperty, IntProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, zip_long_repeat, ensure_nesting_level
from sverchok.data_structure import updateNode, zip_long_repeat, ensure_nesting_level, throttle_and_update_node
from sverchok.utils.math import supported_metrics
from sverchok.utils.nurbs_common import SvNurbsMaths
from sverchok.utils.curve.core import SvCurve
......@@ -31,6 +31,19 @@ class SvGordonSurfaceNode(bpy.types.Node, SverchCustomTreeNode):
description = "Knot mode",
default="POINTS", items=supported_metrics,
update=updateNode)
@throttle_and_update_node
def update_sockets(self, context):
self.inputs['T1'].hide_safe = self.explicit_t_values != True
self.inputs['T2'].hide_safe = self.explicit_t_values != True
explicit_t_values : BoolProperty(
name = "Explicit T values",
default = False,
update = update_sockets)
def draw_buttons(self, context, layout):
layout.prop(self, 'explicit_t_values')
def draw_buttons_ext(self, context, layout):
layout.prop(self, 'metric')
......@@ -38,8 +51,11 @@ class SvGordonSurfaceNode(bpy.types.Node, SverchCustomTreeNode):
def sv_init(self, context):
self.inputs.new('SvCurveSocket', "CurvesU")
self.inputs.new('SvCurveSocket', "CurvesV")
self.inputs.new('SvStringsSocket', "T1")
self.inputs.new('SvStringsSocket', "T2")
self.inputs.new('SvVerticesSocket', "Intersections")
self.outputs.new('SvSurfaceSocket', "Surface")
self.update_sockets(context)
def process(self):
if not any(socket.is_linked for socket in self.outputs):
......@@ -49,12 +65,21 @@ class SvGordonSurfaceNode(bpy.types.Node, SverchCustomTreeNode):
v_curves_s = self.inputs['CurvesV'].sv_get()
intersections_s = self.inputs['Intersections'].sv_get()
if self.explicit_t_values:
t1_s = self.inputs['T1'].sv_get()
t2_s = self.inputs['T2'].sv_get()
else:
t1_s = [[[0]]]
t2_s = [[[0]]]
u_curves_s = ensure_nesting_level(u_curves_s, 2, data_types=(SvCurve,))
v_curves_s = ensure_nesting_level(v_curves_s, 2, data_types=(SvCurve,))
t1_s = ensure_nesting_level(t1_s, 3)
t2_s = ensure_nesting_level(t2_s, 3)
intersections_s = ensure_nesting_level(intersections_s, 4)
surface_out = []
for u_curves, v_curves, intersections in zip_long_repeat(u_curves_s, v_curves_s, intersections_s):
for u_curves, v_curves, t1s, t2s, intersections in zip_long_repeat(u_curves_s, v_curves_s, t1_s, t2_s, intersections_s):
u_curves = [SvNurbsCurve.to_nurbs(c) for c in u_curves]
if any(c is None for c in u_curves):
raise Exception("Some of U curves are not NURBS!")
......@@ -62,7 +87,11 @@ class SvGordonSurfaceNode(bpy.types.Node, SverchCustomTreeNode):
if any(c is None for c in v_curves):
raise Exception("Some of V curves are not NURBS!")
_, _, _, surface = gordon_surface(u_curves, v_curves, intersections, metric=self.metric)
if self.explicit_t_values:
kwargs = {'u_knots': np.array(t1s), 'v_knots': np.array(t2s)}
else:
kwargs = dict()
_, _, _, surface = gordon_surface(u_curves, v_curves, intersections, metric=self.metric, **kwargs)
surface_out.append(surface)
self.outputs['Surface'].sv_set(surface_out)
......
......@@ -367,6 +367,15 @@ class SvNurbsCurve(SvCurve):
# on the other hand, we may not care about it
# if we are throwing away that small segment and
# going to use only the bigger one.
t_min, t_max = self.get_u_bounds()
# corner cases
if t <= t_min:
return None, (self.get_knotvector(), self.get_control_points(), self.get_weights())
if t >= t_max:
return (self.get_knotvector(), self.get_control_points(), self.get_weights()), None
current_multiplicity = sv_knotvector.find_multiplicity(self.get_knotvector(), t)
to_add = self.get_degree() - current_multiplicity # + 1
curve = self.insert_knot(t, count=to_add)
......@@ -417,12 +426,16 @@ class SvNurbsCurve(SvCurve):
params = (self.get_knotvector(), self.get_control_points(), self.get_weights())
if new_t_min > t_min:
_, params = curve._split_at(new_t_min)
if params is None:
print(f"Cut 1: {new_t_min} - {new_t_max} from {t_min} - {t_max}")
knotvector, control_points, weights = params
curve = SvNurbsCurve.build(implementation,
degree, knotvector,
control_points, weights)
if new_t_max < t_max:
params, _ = curve._split_at(new_t_max)
if params is None:
print(f"Cut 2: {new_t_min} - {new_t_max} from {t_min} - {t_max}")
knotvector, control_points, weights = params
curve = SvNurbsCurve.build(implementation,
degree, knotvector,
......
......@@ -209,22 +209,27 @@ def _intersect_curves_equation(curve1, curve2, method='SLSQP', precision=0.001):
lower = np.array([t1_min, t2_min])
upper = np.array([t1_max, t2_max])
line1 = _check_is_line(curve1)
line2 = _check_is_line(curve2)
if line1 and line2:
v1, v2 = line1
v3, v4 = line2
#print(f"Call L: [{t1_min} - {t1_max}] x [{t2_min} - {t2_max}]")
r = intersect_segment_segment(v1, v2, v3, v4)
if not r:
#print(f"({v1} - {v2}) x ({v3} - {v4}): no intersection")
return []
else:
u, v, pt = r
t1 = (1-u)*t1_min + u*t1_max
t2 = (1-v)*t2_min + v*t2_max
return [(t1, t2, pt)]
def linear_intersection():
line1 = _check_is_line(curve1)
line2 = _check_is_line(curve2)
if line1 and line2:
v1, v2 = line1
v3, v4 = line2
print(f"Call L: [{t1_min} - {t1_max}] x [{t2_min} - {t2_max}]")
r = intersect_segment_segment(v1, v2, v3, v4)
if not r:
print(f"({v1} - {v2}) x ({v3} - {v4}): no intersection")
return None
else:
u, v, pt = r
t1 = (1-u)*t1_min + u*t1_max
t2 = (1-v)*t2_min + v*t2_max
return [(t1, t2, pt)]
r = linear_intersection()
if r is not None:
return r
def goal(ts):
p1 = curve1.evaluate(ts[0])
......
......@@ -15,7 +15,36 @@ from sverchok.utils.surface.nurbs import SvNurbsSurface, simple_loft, interpolat
from sverchok.utils.surface.algorithms import unify_nurbs_surfaces
from sverchok.data_structure import repeat_last_for_length
def gordon_surface(u_curves, v_curves, intersections, metric='POINTS'):
def reparametrize_by_segments(curve, t_values):
t_min, t_max = curve.get_u_bounds()
print(f"Reparametrize: {t_min} - {t_max}: {t_values}")
#t_values = [t_min] + t_values + [t_max]
segments = []
for t1, t2 in zip(t_values, t_values[1:]):
segment = curve.cut_segment(t1, t2, rescale=True)
segments.append(segment)
result = segments[0]
for segment in segments[1:]:
result = result.concatenate(segment)
return result
def gordon_surface(u_curves, v_curves, intersections, metric='POINTS', u_knots=None, v_knots=None):
if (u_knots is None) != (v_knots is None):
raise Exception("u_knots and v_knots must be either both provided or both omited")
intersections = np.array(intersections)
if u_knots is not None:
loft_u_kwargs = loft_v_kwargs = interpolate_kwargs = {'metric': 'POINTS'}
u_curves = [reparametrize_by_segments(c, knots) for c, knots in zip(u_curves, u_knots)]
v_curves = [reparametrize_by_segments(c, knots) for c, knots in zip(v_curves, v_knots)]
else:
loft_u_kwargs = loft_v_kwargs = interpolate_kwargs = {'metric': metric}
u_curves = unify_curves_degree(u_curves)
u_curves = unify_curves(u_curves)#, method='AVERAGE')
......@@ -24,27 +53,19 @@ def gordon_surface(u_curves, v_curves, intersections, metric='POINTS'):
u_curves_degree = u_curves[0].get_degree()
v_curves_degree = v_curves[0].get_degree()
intersections = np.array(intersections)
n = len(intersections)
m = len(intersections[0])
knots = np.array([Spline.create_knots(intersections[i,:], metric=metric) for i in range(n)])
u_knots = knots.mean(axis=0)
knots = np.array([Spline.create_knots(intersections[:,j], metric=metric) for j in range(m)])
v_knots = knots.mean(axis=0)
loft_v_degree = min(len(u_curves)-1, v_curves_degree)
loft_u_degree = min(len(v_curves)-1, u_curves_degree)
_,_,lofted_v = simple_loft(u_curves, degree_v=loft_v_degree, metric=metric)# tknots=u_knots)
_,_,lofted_u = simple_loft(v_curves, degree_v=loft_u_degree, metric=metric)# tknots=v_knots)
_,_,lofted_v = simple_loft(u_curves, degree_v=loft_v_degree, **loft_v_kwargs)
_,_,lofted_u = simple_loft(v_curves, degree_v=loft_u_degree, **loft_u_kwargs)
lofted_u = lofted_u.swap_uv()
int_degree_u = min(m-1, u_curves_degree)
int_degree_v = min(n-1, v_curves_degree)
interpolated = interpolate_nurbs_surface(int_degree_u, int_degree_v, intersections, metric=metric)# uknots=u_knots, vknots=v_knots)
interpolated = interpolate_nurbs_surface(int_degree_u, int_degree_v, intersections, **interpolate_kwargs)
interpolated = interpolated.swap_uv()
#print(f"Loft.U: {lofted_u}")
#print(f"Loft.V: {lofted_v}")
......
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать