Skip to content

Commit

Permalink
Merge pull request #4173 from nortikin/nurbs_birail_auto_rotate
Browse files Browse the repository at this point in the history
Nurbs Birail: "auto rotate" flag
  • Loading branch information
portnov authored Jun 19, 2021
2 parents ed7c93b + 79de7ca commit 4083422
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
10 changes: 9 additions & 1 deletion docs/nodes/surface/nurbs_birail.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ path's curve T parameter, at which profile curves must be placed; otherwise,
the node will place them automatically evenly along T parameter of the path
curve.

It is supposed that initially th eprovided profile curve(s) lie in XOY plane.
By default it is supposed that initially the provided profile curve(s) lie in
XOY plane. However, there is an option to instruct the node to try to figure
out correct rotation of profile curve(s). Note that this option may result in
precision loss in some cases.

The node works by placing several copies of profile curve along the path
curves, and then lofting (skinning) between them. If several profile curves
Expand Down Expand Up @@ -99,6 +102,11 @@ This node has the following parameters:
* **Scale all axes**. If not checked, profile curves will be scaled along one
axis only, in order to fill the space between two paths. If checked, profile
curves will be scaled along all axes uniformly. Checked by default.
* **Auto rotate profiles**. If not checked, the node will assume that all
profile curves lie in the XOY plane. If checked, the node will work with
arbitrarily rotated profile curves. Enabled option requires more
computations, and so, may make the node slower and less precise. Unchecked by
default.
* **Explicit V Values**. If checked, then the user has the ability to provide
values of path curves parameter values, at which the provided path curves
must be placed; otherwise, the node will calculate these parameters
Expand Down
8 changes: 8 additions & 0 deletions nodes/surface/nurbs_birail.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,16 @@ def update_sockets(self, context):
default = True,
update = updateNode)

auto_rotate_profiles : BoolProperty(
name = "Auto rotate profiles",
description = "If checked, then the node will try to rotate provided profile curves appropriately. Otherwise, the node expects provided profile curves to lie in XOY plane.",
default = False,
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.prop(self, "explicit_v")

def draw_buttons_ext(self, context, layout):
Expand Down Expand Up @@ -179,6 +186,7 @@ def process(self):
degree_v = degree_v,
metric = self.metric,
scale_uniform = self.scale_uniform,
auto_rotate = self.auto_rotate_profiles,
implementation = self.nurbs_implementation
)
new_surfaces.append(surface)
Expand Down
20 changes: 19 additions & 1 deletion utils/curve/nurbs_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import numpy as np
from collections import defaultdict

from sverchok.utils.geom import Spline
from sverchok.utils.geom import Spline, linear_approximation
from sverchok.utils.nurbs_common import SvNurbsBasisFunctions, SvNurbsMaths, from_homogenous
from sverchok.utils.curve import knotvector as sv_knotvector
from sverchok.utils.curve.algorithms import unify_curves_degree
Expand Down Expand Up @@ -122,3 +122,21 @@ def concatenate_nurbs_curves(curves):
raise Exception(f"Can't append curve #{i+1}: {e}")
return result

def nurbs_curve_to_xoy(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
matrix = np.linalg.inv(matrix)
center = approx.center
new_cpts = np.array([matrix @ (cpt - center) for cpt in cpts])
return curve.copy(control_points = new_cpts)

2 changes: 1 addition & 1 deletion utils/geom.py
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ def two_vectors(self, normalize=False):
def get_matrix(self, invert_y=False):
x = self.second_vector().normalized()
z = self.normal.normalized()
y = z.cross(x)
y = z.cross(x).normalized()
if invert_y:
y = - y
return Matrix([x, y, z]).transposed()
Expand Down
18 changes: 15 additions & 3 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
from sverchok.utils.curve.nurbs_algorithms import interpolate_nurbs_curve, unify_curves, nurbs_curve_to_xoy
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 @@ -903,7 +903,14 @@ def nurbs_sweep(path, profiles, ts, min_profiles, algorithm, knots_u = 'UNIFY',
knots_u=knots_u, metric=metric,
implementation=implementation)

def nurbs_birail(path1, path2, profiles, ts1 = None, ts2 = None, min_profiles = 10, knots_u = 'UNIFY', degree_v = None, metric = 'DISTANCE', scale_uniform = True, implementation = SvNurbsSurface.NATIVE):
def nurbs_birail(path1, path2, profiles,
ts1 = None, ts2 = None,
min_profiles = 10,
knots_u = 'UNIFY',
degree_v = None, metric = 'DISTANCE',
scale_uniform = True,
auto_rotate = False,
implementation = SvNurbsSurface.NATIVE):
"""
NURBS BiRail.
Expand Down Expand Up @@ -1007,7 +1014,10 @@ def nurbs_birail(path1, path2, profiles, ts1 = None, ts2 = None, min_profiles =

scales = scales.flatten()
placed_profiles = []
for pt1, profile, scale, matrix in zip(points1, profiles, scales, matrices):
for pt1, pt2, profile, scale, matrix in zip(points1, points2, profiles, scales, matrices):
if auto_rotate:
profile = nurbs_curve_to_xoy(profile)

t_min, t_max = profile.get_u_bounds()
pr_start = profile.evaluate(t_min)
pr_end = profile.evaluate(t_max)
Expand All @@ -1024,6 +1034,7 @@ def nurbs_birail(path1, path2, profiles, ts1 = None, ts2 = None, min_profiles =
(0, 0, 1)
])

src_scale = scale
scale /= pr_length
if scale_uniform:
scale_m = np.array([
Expand All @@ -1039,6 +1050,7 @@ def nurbs_birail(path1, path2, profiles, ts1 = None, ts2 = None, min_profiles =
])
cpts = [matrix @ scale_m @ rotation @ (pt - pr_start) + pt1 for pt in profile.get_control_points()]
cpts = np.array(cpts)

profile = profile.copy(control_points = cpts)
placed_profiles.append(profile)

Expand Down

0 comments on commit 4083422

Please sign in to comment.