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

Extend curve - technical refactoring.

владелец 76ce02de
......@@ -9,6 +9,7 @@ from sverchok.data_structure import updateNode, zip_long_repeat, ensure_nesting_
from sverchok.utils.curve import SvCurve, SvTaylorCurve, SvLine, SvCircle, SvCurveLengthSolver
from sverchok.utils.curve.algorithms import concatenate_curves, reverse_curve
from sverchok.utils.curve.nurbs import SvNurbsCurve
from sverchok.utils.curve.extend import extend_curve
from sverchok.utils.geom import circle_by_two_derivatives
class SvExtendCurveNode(bpy.types.Node, SverchCustomTreeNode):
......@@ -81,139 +82,6 @@ class SvExtendCurveNode(bpy.types.Node, SverchCustomTreeNode):
if self.len_mode == 'L':
layout.prop(self, 'len_resolution')
def make_line(self, point, tangent, t_ext, sign):
if sign < 0:
before_start = point - t_ext*tangent # / np.linalg.norm(tangent_start)
return SvLine.from_two_points(before_start, point)
else:
after_end = point + t_ext*tangent # / np.linalg.norm(tangent_end)
return SvLine.from_two_points(point, after_end)
def set_length(self, base_curve, curve, t_ext, sign=1):
if curve is None:
return None
if self.len_mode == 'T':
curve.u_bounds = (0, t_ext)
if isinstance(curve, SvLine) and sign < 0:
unit = curve.direction / np.linalg.norm(curve.direction)
t_target = t_ext / np.linalg.norm(curve.direction)
start = curve.point + curve.direction - t_ext*unit
curve.point = start
curve.u_bounds = (0, t_target)
elif self.len_mode == 'L':
if isinstance(curve, SvLine):
if sign > 0:
curve.direction = curve.direction
t_ext = t_ext / np.linalg.norm(curve.direction)
curve.u_bounds = (0, t_ext)
else:
unit = curve.direction / np.linalg.norm(curve.direction)
t_target = t_ext / np.linalg.norm(curve.direction)
start = curve.point + curve.direction - t_ext*unit
curve.point = start
curve.u_bounds = (0, t_target)
else:
u_min, u_max = base_curve.get_u_bounds()
base_length = base_curve.calc_length(u_min, u_max, self.len_resolution)
# base_length / (u_max - u_min) ~= t_ext / (t_target - 0)
t_mid = t_ext * (u_max - u_min) / base_length
#self.debug(f"Base curve len: {base_length}, range: {u_max - u_min}, T_ext {t_ext} => T_mid {t_mid}")
curve.u_bounds = (0, t_mid)
solver = SvCurveLengthSolver(curve)
solver.prepare('SPL', self.len_resolution)
t_target = solver.solve(np.array([t_ext]))[0]
#self.debug(f"C: {type(curve)}: L = {t_mid} => T = {t_target}")
curve.u_bounds = (0, t_target)
return curve
def extend_curve(self, curve, t_before, t_after):
u_min, u_max = curve.get_u_bounds()
start, end = curve.evaluate(u_min), curve.evaluate(u_max)
start_extent, end_extent = None, None
is_nurbs = isinstance(curve, SvNurbsCurve)
if self.mode == 'LINE':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
if t_before > 0:
start_extent = self.make_line(start, tangent_start, t_before, -1)
start_extent = self.set_length(curve, start_extent, t_before, -1)
if t_after > 0:
end_extent = self.make_line(end, tangent_end, t_after, +1)
end_extent = self.set_length(curve, end_extent, t_after, +1)
elif self.mode == 'ARC':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
second_start = curve.second_derivative(u_min)
second_end = curve.second_derivative(u_max)
if t_before > 0:
if np.linalg.norm(second_start) > 1e-6:
eq1 = circle_by_two_derivatives(start, -tangent_start, second_start)
start_extent = SvCircle.from_equation(eq1)
start_extent = self.set_length(curve, start_extent, t_before, -1)
if is_nurbs:
start_extent = start_extent.to_nurbs()
start_extent = reverse_curve(start_extent)
else:
start_extent = self.make_line(start, tangent_start, t_before, -1)
start_extent = self.set_length(curve, start_extent, t_before, -1)
if t_after > 0:
if np.linalg.norm(second_end) > 1e-6:
eq2 = circle_by_two_derivatives(end, tangent_end, second_end)
end_extent = SvCircle.from_equation(eq2)
else:
end_extent = self.make_line(end, tangent_end, t_after, +1)
end_extent = self.set_length(curve, end_extent, t_after, +1)
elif self.mode == 'QUAD':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
second_start = curve.second_derivative(u_min)
second_end = curve.second_derivative(u_max)
if t_before > 0:
start_extent = SvTaylorCurve(start, [-tangent_start, second_start])
start_extent = self.set_length(curve, start_extent, t_before)
if is_nurbs:
start_extent = start_extent.to_nurbs()
start_extent = reverse_curve(start_extent)
if t_after > 0:
end_extent = SvTaylorCurve(end, [tangent_end, second_end])
end_extent = self.set_length(curve, end_extent, t_after)
elif self.mode == 'CUBIC':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
second_start = curve.second_derivative(u_min)
second_end = curve.second_derivative(u_max)
third_start, third_end = curve.third_derivative_array(np.array([u_min, u_max]))
if t_before > 0:
start_extent = SvTaylorCurve(start, [-tangent_start, second_start, -third_start])
start_extent = self.set_length(curve, start_extent, t_before)
if is_nurbs:
start_extent = start_extent.to_nurbs()
start_extent = reverse_curve(start_extent)
if t_after > 0:
end_extent = SvTaylorCurve(end, [tangent_end, second_end, third_end])
end_extent = self.set_length(curve, end_extent, t_after)
else:
raise Exception("Unsupported mode")
if is_nurbs:
if start_extent is not None and not isinstance(start_extent, SvNurbsCurve):
start_extent = start_extent.to_nurbs(implementation=curve.get_nurbs_implementation())
if end_extent is not None and not isinstance(end_extent, SvNurbsCurve):
end_extent = end_extent.to_nurbs(implementation=curve.get_nurbs_implementation())
return start_extent, end_extent
def process(self):
if not any(socket.is_linked for socket in self.outputs):
return
......@@ -231,7 +99,10 @@ class SvExtendCurveNode(bpy.types.Node, SverchCustomTreeNode):
curve_out = []
for curves, t_before_i, t_after_i in zip_long_repeat(curve_s, t_before_s, t_after_s):
for curve, t_before, t_after in zip_long_repeat(curves, t_before_i, t_after_i):
start_extent, end_extent = self.extend_curve(curve, t_before, t_after)
start_extent, end_extent = extend_curve(curve, t_before, t_after,
mode = self.mode,
len_mode = self.len_mode,
len_resolution = self.len_resolution)
start_out.append(start_extent)
end_out.append(end_extent)
curves = []
......
# This file is part of project Sverchok. It's copyrighted by the contributors
# recorded in the version control history of the file, available from
# its original location https://github.com/nortikin/sverchok/commit/master
#
# SPDX-License-Identifier: GPL3
# License-Filename: LICENSE
import numpy as np
from sverchok.utils.curve.core import SvTaylorCurve
from sverchok.utils.curve.primitives import SvLine, SvCircle
from sverchok.utils.curve.nurbs import SvNurbsCurve
from sverchok.utils.curve.algorithms import SvCurveLengthSolver, reverse_curve
from sverchok.utils.geom import circle_by_two_derivatives
def set_length(base_curve, curve, t_ext, sign=1, len_mode='T', len_resolution=50):
if curve is None:
return None
if len_mode == 'T':
curve.u_bounds = (0, t_ext)
if isinstance(curve, SvLine) and sign < 0:
unit = curve.direction / np.linalg.norm(curve.direction)
t_target = t_ext / np.linalg.norm(curve.direction)
start = curve.point + curve.direction - t_ext*unit
curve.point = start
curve.u_bounds = (0, t_target)
elif len_mode == 'L':
if isinstance(curve, SvLine):
if sign > 0:
curve.direction = curve.direction
t_ext = t_ext / np.linalg.norm(curve.direction)
curve.u_bounds = (0, t_ext)
else:
unit = curve.direction / np.linalg.norm(curve.direction)
t_target = t_ext / np.linalg.norm(curve.direction)
start = curve.point + curve.direction - t_ext*unit
curve.point = start
curve.u_bounds = (0, t_target)
else:
u_min, u_max = base_curve.get_u_bounds()
base_length = base_curve.calc_length(u_min, u_max, len_resolution)
# base_length / (u_max - u_min) ~= t_ext / (t_target - 0)
t_mid = t_ext * (u_max - u_min) / base_length
curve.u_bounds = (0, t_mid)
solver = SvCurveLengthSolver(curve)
solver.prepare('SPL', len_resolution)
t_target = solver.solve(np.array([t_ext]))[0]
curve.u_bounds = (0, t_target)
return curve
def extend_curve(curve, t_before, t_after, mode = 'LINE', len_mode='T', len_resolution=50):
def make_line(point, tangent, t_ext, sign):
if sign < 0:
before_start = point - t_ext*tangent # / np.linalg.norm(tangent_start)
return SvLine.from_two_points(before_start, point)
else:
after_end = point + t_ext*tangent # / np.linalg.norm(tangent_end)
return SvLine.from_two_points(point, after_end)
u_min, u_max = curve.get_u_bounds()
start, end = curve.evaluate(u_min), curve.evaluate(u_max)
start_extent, end_extent = None, None
is_nurbs = isinstance(curve, SvNurbsCurve)
if mode == 'LINE':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
if t_before > 0:
start_extent = make_line(start, tangent_start, t_before, -1)
start_extent = set_length(curve, start_extent, t_before, -1, len_mode=len_mode, len_resolution=len_resolution)
if t_after > 0:
end_extent = make_line(end, tangent_end, t_after, +1)
end_extent = set_length(curve, end_extent, t_after, +1, len_mode=len_mode, len_resolution=len_resolution)
elif mode == 'ARC':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
second_start = curve.second_derivative(u_min)
second_end = curve.second_derivative(u_max)
if t_before > 0:
if np.linalg.norm(second_start) > 1e-6:
eq1 = circle_by_two_derivatives(start, -tangent_start, second_start)
start_extent = SvCircle.from_equation(eq1)
start_extent = set_length(curve, start_extent, t_before, -1, len_mode=len_mode, len_resolution=len_resolution)
if is_nurbs:
start_extent = start_extent.to_nurbs()
start_extent = reverse_curve(start_extent)
else:
start_extent = make_line(start, tangent_start, t_before, -1)
start_extent = set_length(curve, start_extent, t_before, -1, len_mode=len_mode, len_resolution=len_resolution)
if t_after > 0:
if np.linalg.norm(second_end) > 1e-6:
eq2 = circle_by_two_derivatives(end, tangent_end, second_end)
end_extent = SvCircle.from_equation(eq2)
else:
end_extent = make_line(end, tangent_end, t_after, +1)
end_extent = set_length(curve, end_extent, t_after, +1, len_mode=len_mode, len_resolution=len_resolution)
elif mode == 'QUAD':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
second_start = curve.second_derivative(u_min)
second_end = curve.second_derivative(u_max)
if t_before > 0:
start_extent = SvTaylorCurve(start, [-tangent_start, second_start])
start_extent = set_length(curve, start_extent, t_before, len_mode=len_mode, len_resolution=len_resolution)
if is_nurbs:
start_extent = start_extent.to_nurbs()
start_extent = reverse_curve(start_extent)
if t_after > 0:
end_extent = SvTaylorCurve(end, [tangent_end, second_end])
end_extent = set_length(curve, end_extent, t_after, len_mode=len_mode, len_resolution=len_resolution)
elif mode == 'CUBIC':
tangent_start = curve.tangent(u_min)
tangent_end = curve.tangent(u_max)
second_start = curve.second_derivative(u_min)
second_end = curve.second_derivative(u_max)
third_start, third_end = curve.third_derivative_array(np.array([u_min, u_max]))
if t_before > 0:
start_extent = SvTaylorCurve(start, [-tangent_start, second_start, -third_start])
start_extent = set_length(curve, start_extent, t_before, len_mode=len_mode, len_resolution=len_resolution)
if is_nurbs:
start_extent = start_extent.to_nurbs()
start_extent = reverse_curve(start_extent)
if t_after > 0:
end_extent = SvTaylorCurve(end, [tangent_end, second_end, third_end])
end_extent = set_length(curve, end_extent, t_after, len_mode=len_mode, len_resolution=len_resolution)
else:
raise Exception("Unsupported mode")
if is_nurbs:
if start_extent is not None and not isinstance(start_extent, SvNurbsCurve):
start_extent = start_extent.to_nurbs(implementation=curve.get_nurbs_implementation())
if end_extent is not None and not isinstance(end_extent, SvNurbsCurve):
end_extent = end_extent.to_nurbs(implementation=curve.get_nurbs_implementation())
return start_extent, end_extent
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать