-
Notifications
You must be signed in to change notification settings - Fork 233
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5162 from nortikin/snap_curves
"Snap curves" node
- Loading branch information
Showing
9 changed files
with
520 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
Snap Curves | ||
=========== | ||
|
||
Functionality | ||
------------- | ||
|
||
This node takes two or more NURBS curve objects, and modifies them in such a | ||
way that they become connected: end point of first curve coincides with start | ||
point of the second curve, and so on. It is possible to define, which curve | ||
must become "main" , and which curve should be adjusted in order to match the | ||
"main" curve. | ||
|
||
Optionally, this node can also adjust directions of curves at their start and | ||
end points. | ||
|
||
For this node, direction and order of curves are important. If you have several | ||
curves with arbitrary directions, you may want to use "Sort Curves" node first, | ||
to ensure that the end of each curve is near the beginning of the next curve. | ||
|
||
This node can work with NURBS and NURBS-like curves only. It adjusts curves by | ||
moving their control points, while trying to move all points as less as | ||
possible. This means that curve structure is important for this node. For | ||
example, | ||
|
||
* If the curve has a lot of control points, the node will have to move only one | ||
or two of it's control points near the end, so that most of the curve will be | ||
left unchanged. | ||
* If the curve has only a few of control points, for example 3 or 4, then | ||
movement of 1 or 2 control points can move almost whole curve. | ||
* For curves with higher degree, each control point controls wider span of the | ||
curve. So when adjusting curves with higher degree, wider span of the curve | ||
will be moved. | ||
|
||
Inputs | ||
------ | ||
|
||
This node has the following inputs: | ||
|
||
* **Curve1**. First curve to process. This input is available and mandatory | ||
only if **Input Mode** parameter is set to **Two Curves**. | ||
* **Curve2**. Second curve to process. This input is available and mandatory | ||
only if **Input Mode** parameter is set to **Two Curves**. | ||
* **Curves**. List of curves to be processed. This input is available and mandatory | ||
only if **Input Mode** parameter is set to **List of Curves**. | ||
|
||
Parameters | ||
---------- | ||
|
||
This node has the following parameters: | ||
|
||
* **Input Mode**. The available options are **Two Curves** and **List of | ||
Curves**. The default option is **Two Curves**. | ||
* **Bias**. This defines where two curves should meet. The available options are: | ||
|
||
* **Middle**. The meeting point will be defined as middle between end of | ||
first curve and start of second curve. | ||
* **Curve 1**. First curve will be considered "main", so it's end point will | ||
not be moved; start point of the second curve will be moved to end point of | ||
the first curve. | ||
* **Curve 2**. Second curve will be considered "main", so it's start point | ||
will not be moved; end point fo the first curve will be moved to start | ||
point of the second curve. | ||
|
||
The default option is **Middle**. | ||
* **Tangents**. This defines whether the node should adjust directions of | ||
curves at their ends, and how exactly. The available options are: | ||
|
||
* **No matter**. The node will not bother about curve directions, and try to | ||
move curve ends properly while moving control points as less as possible. | ||
* **Preserve**. The node will try to preserve directions of the curves at their ends. | ||
* **Medium**. The node will adjust the directions of curves at their ends in | ||
such a way, that their tangent vectors will be equal to average between | ||
tangent vector of the first curve at it's end and tangent vector of the | ||
second curve at it's beginning. | ||
* **Curve 1**. The node will preserve the direction of the first curve at | ||
it's end, and adjust the direction of the second curve at it's beginning to | ||
match the first curve. | ||
* **Curve 2**. The node will preserve the direction of the second curve at | ||
it's beginning, and adjust the direction of the first curve at it's end to | ||
match the second curve. | ||
|
||
The default option is **No matter**. | ||
|
||
* **Cyclic**. If checked, the node will also try to connect the end point of | ||
last curve to the start point of the first curve, in order to create a closed | ||
loop. Unchecked by default. | ||
|
||
Outputs | ||
------- | ||
|
||
This node has the following output: | ||
|
||
* **Curves**. The resulting curves. | ||
|
||
Example of Usage | ||
---------------- | ||
|
||
.. image:: ../../../docs/assets/nodes/curve/snap_curves.gif | ||
:target: ../../../docs/assets/nodes/curve/snap_curves.gif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
# 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 | ||
|
||
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, get_data_nesting_level | ||
from sverchok.utils.curve import SvCurve | ||
from sverchok.utils.curve.nurbs import SvNurbsCurve | ||
from sverchok.utils.curve.nurbs_solver_applications import ( | ||
snap_curves, | ||
BIAS_CURVE1, BIAS_CURVE2, BIAS_MID, | ||
TANGENT_ANY, TANGENT_PRESERVE, TANGENT_MATCH, | ||
TANGENT_CURVE1, TANGENT_CURVE2 | ||
) | ||
|
||
class SvSnapCurvesNode(SverchCustomTreeNode, bpy.types.Node): | ||
""" | ||
Triggers: Snap Curves | ||
Tooltip: Snap ends of curves to common point, optionally controlling curve tangents. | ||
""" | ||
bl_idname = 'SvSnapCurvesNode' | ||
bl_label = 'Snap NURBS Curves' | ||
bl_icon = 'OUTLINER_OB_EMPTY' | ||
sv_icon = 'SV_SNAP_CURVES' | ||
|
||
bias_modes = [ | ||
(BIAS_MID, "Middle point", "Snap to middle point between end of first curve and start of second curve", 0), | ||
(BIAS_CURVE1, "Curve 1", "Snap start of second curve to the end of the first curve", 1), | ||
(BIAS_CURVE2, "Curve 2", "Snap end of first curve to the start of the second curve", | ||
2) | ||
] | ||
|
||
tangent_modes = [ | ||
(TANGENT_ANY, "No matter", "Tangents will probably change", 0), | ||
(TANGENT_PRESERVE, "Preserve", "Preserve tangent vectors of all curves at both ends", 1), | ||
(TANGENT_MATCH, "Medium", "Adjust tangent vectors of curves so that they will be average between end tangent of the first curve and start tangent of the second curve", 2), | ||
(TANGENT_CURVE1, "Curve 1", "Preserve tangent vector of the first curve at it's end, and adjust the tangent vector of the second curve to match", 3), | ||
(TANGENT_CURVE2, "Curve 2", "Preserve tangent vector of the second curve at it'send, and adjust the tangent vector of the first curve to match", 4) | ||
] | ||
|
||
input_modes = [ | ||
('TWO', "Two curves", "Process two curves", 0), | ||
('N', "List of curves", "Process several curves", 1) | ||
] | ||
|
||
def update_sockets(self, context): | ||
self.inputs['Curve1'].hide_safe = self.input_mode != 'TWO' | ||
self.inputs['Curve2'].hide_safe = self.input_mode != 'TWO' | ||
self.inputs['Curves'].hide_safe = self.input_mode != 'N' | ||
updateNode(self, context) | ||
|
||
input_mode : EnumProperty( | ||
name = "Input mode", | ||
items = input_modes, | ||
default = 'TWO', | ||
update = update_sockets) | ||
|
||
bias : EnumProperty( | ||
name = "Bias", | ||
items = bias_modes, | ||
update = updateNode) | ||
|
||
tangent : EnumProperty( | ||
name = "Tangents", | ||
items = tangent_modes, | ||
update = updateNode) | ||
|
||
cyclic : BoolProperty( | ||
name = "Cyclic", | ||
default = False, | ||
update = updateNode) | ||
|
||
def sv_init(self, context): | ||
self.inputs.new('SvCurveSocket', "Curves") | ||
self.inputs.new('SvCurveSocket', "Curve1") | ||
self.inputs.new('SvCurveSocket', "Curve2") | ||
self.outputs.new('SvCurveSocket', "Curves") | ||
self.update_sockets(context) | ||
|
||
def draw_buttons(self, context, layout): | ||
layout.prop(self, 'input_mode', text='') | ||
layout.prop(self, 'bias') | ||
layout.prop(self, 'tangent') | ||
layout.prop(self, 'cyclic') | ||
|
||
def get_inputs(self): | ||
curves_s = [] | ||
if self.input_mode == 'TWO': | ||
curve1_s = self.inputs['Curve1'].sv_get() | ||
curve2_s = self.inputs['Curve2'].sv_get() | ||
level1 = get_data_nesting_level(curve1_s, data_types=(SvCurve,)) | ||
level2 = get_data_nesting_level(curve2_s, data_types=(SvCurve,)) | ||
nested_input = level1 > 1 or level2 > 1 | ||
curve1_s = ensure_nesting_level(curve1_s, 2, data_types=(SvCurve,)) | ||
curve2_s = ensure_nesting_level(curve2_s, 2, data_types=(SvCurve,)) | ||
for inputs in zip_long_repeat(curve1_s, curve2_s): | ||
curves_s.append( list( *zip_long_repeat(*inputs) ) ) | ||
else: | ||
curves_s = self.inputs['Curves'].sv_get() | ||
level = get_data_nesting_level(curves_s, data_types=(SvCurve,)) | ||
nested_input = level > 1 | ||
curves_s = ensure_nesting_level(curves_s, 2, data_types=(SvCurve,)) | ||
return nested_input, curves_s | ||
|
||
def process(self): | ||
if not any(socket.is_linked for socket in self.outputs): | ||
return | ||
|
||
curves_out = [] | ||
nested_input, curves_s = self.get_inputs() | ||
for curves in curves_s: | ||
curves = [SvNurbsCurve.to_nurbs(c) for c in curves] | ||
if any(c is None for c in curves): | ||
raise Exception("Some of curves are not NURBS!") | ||
new_curves = snap_curves(curves, | ||
bias = self.bias, | ||
tangent = self.tangent, | ||
cyclic = self.cyclic) | ||
if nested_input: | ||
curves_out.append(new_curves) | ||
else: | ||
curves_out.extend(new_curves) | ||
|
||
self.outputs['Curves'].sv_set(curves_out) | ||
|
||
def register(): | ||
bpy.utils.register_class(SvSnapCurvesNode) | ||
|
||
def unregister(): | ||
bpy.utils.unregister_class(SvSnapCurvesNode) | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
61dc7b1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sweet!