Skip to content

Commit

Permalink
Nurbs Birail update 2.
Browse files Browse the repository at this point in the history
refs #3884.
  • Loading branch information
portnov committed Jun 20, 2021
1 parent 4083422 commit 454c245
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 9 deletions.
17 changes: 17 additions & 0 deletions nodes/surface/nurbs_birail.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,26 @@ def update_sockets(self, context):
default = False,
update = updateNode)

rotate_options = [
('PATHS_AVG', "Paths average", "Rotate profile(s), trying to make it perpendicular to both paths", 0),
('FROM_PATH1', "Perpendicular to Path 1", "Rotate profile(s), trying to make it perpendicular to the first path", 1),
('FROM_PATH2', "Perpendicular to Path 2", "Rotate profile(s), trying to make it perpendicular to the second path", 2),
('FROM_PROFILE', "By profile", "Try to use initial rotation of profile curve(s)", 3)
]

profile_rotation : EnumProperty(
name = "Profile rotation",
description = "Defines how profile curves should be rotated",
items = rotate_options,
default = 'PATHS_AVG',
update = updateNode)

def draw_buttons(self, context, layout):
layout.prop(self, 'nurbs_implementation', text='')
layout.prop(self, "scale_uniform")
layout.prop(self, "auto_rotate_profiles")
layout.label(text="Profile rotation:")
layout.prop(self, "profile_rotation", text='')
layout.prop(self, "explicit_v")

def draw_buttons_ext(self, context, layout):
Expand Down Expand Up @@ -187,6 +203,7 @@ def process(self):
metric = self.metric,
scale_uniform = self.scale_uniform,
auto_rotate = self.auto_rotate_profiles,
use_tangents = self.profile_rotation,
implementation = self.nurbs_implementation
)
new_surfaces.append(surface)
Expand Down
24 changes: 22 additions & 2 deletions utils/curve/nurbs_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,18 @@ def concatenate_nurbs_curves(curves):
raise Exception(f"Can't append curve #{i+1}: {e}")
return result

def nurbs_curve_to_xoy(curve):
def nurbs_curve_to_xoy(curve, target_normal=None):
cpts = curve.get_control_points()

approx = linear_approximation(cpts)
plane = approx.most_similar_plane()
normal = plane.normal

if target_normal is not None:
a = np.dot(normal, target_normal)
if a > 0:
normal = -normal

xx = cpts[-1] - cpts[0]
xx /= np.linalg.norm(xx)

Expand All @@ -139,4 +144,19 @@ def nurbs_curve_to_xoy(curve):
center = approx.center
new_cpts = np.array([matrix @ (cpt - center) for cpt in cpts])
return curve.copy(control_points = new_cpts)


def nurbs_curve_matrix(curve):
cpts = curve.get_control_points()

approx = linear_approximation(cpts)
plane = approx.most_similar_plane()
normal = plane.normal

xx = cpts[-1] - cpts[0]
xx /= np.linalg.norm(xx)

yy = np.cross(normal, xx)

matrix = np.stack((xx, yy, normal)).T
return matrix

37 changes: 30 additions & 7 deletions utils/surface/nurbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
nurbs_divide, from_homogenous
)
from sverchok.utils.curve import knotvector as sv_knotvector
from sverchok.utils.curve.nurbs_algorithms import interpolate_nurbs_curve, unify_curves, nurbs_curve_to_xoy
from sverchok.utils.curve.nurbs_algorithms import interpolate_nurbs_curve, unify_curves, nurbs_curve_to_xoy, nurbs_curve_matrix
from sverchok.utils.curve.algorithms import unify_curves_degree, SvCurveFrameCalculator
from sverchok.utils.surface.core import UnsupportedSurfaceTypeException
from sverchok.utils.surface import SvSurface, SurfaceCurvatureCalculator, SurfaceDerivativesData
Expand Down Expand Up @@ -910,6 +910,7 @@ def nurbs_birail(path1, path2, profiles,
degree_v = None, metric = 'DISTANCE',
scale_uniform = True,
auto_rotate = False,
use_tangents = 'PATHS_AVG',
implementation = SvNurbsSurface.NATIVE):
"""
NURBS BiRail.
Expand All @@ -931,6 +932,8 @@ def nurbs_birail(path1, path2, profiles,
* scale_uniform: If True, profile curves will be scaled along all axes
uniformly; if False, they will be scaled only along one axis, in order to
fill space between two path curves.
* auto_rotate: if False, the profile curves are supposed to lie in XOY plane.
Otherwise, try to figure out their rotation automatically.
* implementation: surface implementation
output: tuple:
Expand Down Expand Up @@ -992,16 +995,34 @@ def nurbs_birail(path1, path2, profiles,
points1 = path1.evaluate_array(ts1)
points2 = path2.evaluate_array(ts2)

tangents1 = path1.tangent_array(ts1)
tangents2 = path2.tangent_array(ts2)
tangents = 0.5 * (tangents1 + tangents2)
tangents /= np.linalg.norm(tangents, axis=1, keepdims=True)
orig_profiles = profiles[:]

if use_tangents == 'PATHS_AVG':
tangents1 = path1.tangent_array(ts1)
tangents2 = path2.tangent_array(ts2)
tangents = 0.5 * (tangents1 + tangents2)
tangents /= np.linalg.norm(tangents, axis=1, keepdims=True)
elif use_tangents == 'FROM_PATH1':
tangents = path1.tangent_array(ts1)
tangents /= np.linalg.norm(tangents, axis=1, keepdims=True)
elif use_tangents == 'FROM_PATH2':
tangents = path2.tangent_array(ts2)
tangents /= np.linalg.norm(tangents, axis=1, keepdims=True)
elif use_tangents == 'FROM_PROFILE':
tangents = []
for profile in orig_profiles:
matrix = nurbs_curve_matrix(profile)
yy = matrix @ np.array([0, 0, -1])
yy /= np.linalg.norm(yy)
tangents.append(yy)
tangents = np.array(tangents)

binormals = points2 - points1
scales = np.linalg.norm(binormals, axis=1, keepdims=True)
if scales.min() < 1e-6:
raise Exception("Paths go too close")
binormals /= scales

normals = np.cross(tangents, binormals)
normals /= np.linalg.norm(normals, axis=1, keepdims=True)

Expand All @@ -1014,9 +1035,11 @@ def nurbs_birail(path1, path2, profiles,

scales = scales.flatten()
placed_profiles = []
for pt1, pt2, profile, scale, matrix in zip(points1, points2, profiles, scales, matrices):
prev_normal = None
for pt1, pt2, profile, tangent, scale, matrix in zip(points1, points2, profiles, tangents, scales, matrices):

if auto_rotate:
profile = nurbs_curve_to_xoy(profile)
profile = nurbs_curve_to_xoy(profile, tangent)

t_min, t_max = profile.get_u_bounds()
pr_start = profile.evaluate(t_min)
Expand Down

0 comments on commit 454c245

Please sign in to comment.