-
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 #4623 from nortikin/nurbs_move_point
"Move NURBS Curve Point" node
- Loading branch information
Showing
10 changed files
with
943 additions
and
6 deletions.
There are no files selected for viewing
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,137 @@ | ||
Move NURBS Curve Point | ||
====================== | ||
|
||
Functionality | ||
------------- | ||
|
||
This node suggests several ways of adjusting a NURBS curve so that it would go | ||
through another point at specified position, while keeping most of the curve | ||
more or less in place. | ||
|
||
Different methods of curve adjustment allow different degrees of freedom in | ||
specifying what do you want to move and where to. | ||
|
||
Inputs | ||
------ | ||
|
||
This node has the following inputs: | ||
|
||
* **Curve**. The NURBS Curve object to be adjusted. This input is mandatory. | ||
* **T**. The value of curve parameter, point at which is to be moved. The default value is 0.5. | ||
* **Index**. This input has different meaning for different curve adjustment methods being used: | ||
|
||
* For **Move one control point** method, this is the index of curve control point to be moved. | ||
* For **Adjust one weight** method, this is the index of curve weight to be adjusted. | ||
* For **Adjust two weights** method, this is the index of first of two curve | ||
weights to be adjusted. The second weight adjusted will be the following one. | ||
* For other methods, this input is not available. | ||
|
||
The default value is 1. | ||
|
||
* **Distance**. The distance for which curve point at **T** parameter is to be moved. | ||
|
||
* For **Adjust one weight** method, positive values mean move the point | ||
toward corresponding control point (index of which is defined in **Index** | ||
input). Negative values mean movement in the oppposite direction. | ||
* For **Adjust two weight** method, positive values mean move the span of | ||
curve towards the corresponding curve control polygon leg (the one between | ||
control points **Index** and **Index+1**). Negative values mean movement in | ||
the opposite direction. | ||
* For other methods, this input is not available. | ||
|
||
The default value is 1.0. | ||
|
||
* **Vector**. The vector for which the curve point at **T** parameter is to be | ||
moved. This input is available only when **Method** is set to **Move one | ||
control point**, **Move control points**, or **Insert knot**. The default | ||
value is ``(1.0, 0.0, 0.0)``. | ||
|
||
Parameters | ||
---------- | ||
|
||
This node has the following parameters: | ||
|
||
* **Method**. The method to be used to adjust the curve. The following methods are available: | ||
|
||
* **Move one control point**. The node will move exactly one control point of | ||
the curve, to move curve point at **T** parameter by **Vector**. The index | ||
of control point being moved is specified in the **Index** input. Note that | ||
it is not always possible to move arbitrary curve point by arbitrary vector | ||
by moving specified control point. In intuitive terms, the point to be | ||
moved has to be near control point being moved. | ||
* **Adjust one weight**. The node will adjust one weight of the curve, to | ||
move curve point at **T** parameter directly towards corresponding control | ||
point, or in the opposite direction. The index of the weight being adjusted | ||
(and the index of corresponding control point) is specified in the | ||
**Index** input. Movement distance is specified in the **Distance** input. | ||
Note that it is not always possible to move arbitrary curve point by | ||
adjusting the specified curve weight. Also, if you try to move the point | ||
too far with this method, you will probably get unexpected curve shapes. | ||
* **Adjust two weights**. The node will adjust two weights of the curve, to | ||
move curve point at **T** parameter, together with neighbouring curve span, | ||
towards the corresponding control polygon leg, or in the opposite | ||
direction. The index of the first weight to be adjusted (and corresponding | ||
control point index) is specified in the **Index** input. Note that it is | ||
not always possible to move an arbitrary curve point by adjusting the | ||
specified weights. Also, if you try to move the point too far with this | ||
method, you will probably get unexpected curve shapes. | ||
* **Move control points**. The node will move several control points of the | ||
curve (approximately ``p`` of them, where ``p`` is the degree of the | ||
curve), to move curve point at **T** parameter by the specified vector. The | ||
node will automatically figure out which control points have to be moved. | ||
This algorithms gives most smooth results, but it requires more | ||
computations, so it is probably less performant. | ||
* **Insert knot**. The node will insert additional knot into curve's | ||
knotvector, and then move three control points, in order to move curve | ||
point at **T** parameter by specified vector. The node will automatically | ||
figure out which control points have to be moved. | ||
|
||
The default option is **Move one control point**. | ||
|
||
* **Preserve tangent**. This parameter is available only when **Method** is set | ||
to **Move control points**. If checked, the node will try to preserve the | ||
direction of curve tangent at the point being moved. In many cases, this | ||
gives only a slight difference; but sometimes this will make the result | ||
smoother. Unchecked by default. | ||
|
||
Outputs | ||
------- | ||
|
||
This node has the following output: | ||
|
||
* **Curve**. The adjusted curve. | ||
|
||
Examples of Usage | ||
----------------- | ||
|
||
An illustration of **Move one control point** method. Here, black is the | ||
original curve; dark blue is it's control polygon; light blue point is the | ||
point at T parameter on the original curve. Green is the resulting curve, and | ||
big green point is the resulting point. In this case, only control point number | ||
7 is moved. | ||
|
||
.. image:: https://user-images.githubusercontent.com/284644/186957079-ceee637d-be54-4d26-8474-04dd4543a011.png | ||
|
||
An example of **Adjust one weight** method. Here, the blue point is moved | ||
towards the control point number 8. Curve control points are not moved, only | ||
one curve weight is changed. | ||
|
||
.. image:: https://user-images.githubusercontent.com/284644/186957074-4f520bad-ff48-48d1-a3b4-ebe2fec1d270.png | ||
|
||
An example of **Adjust two weights** method. Here, the blue point is pushed | ||
away from control polygon leg between control points 4 and 5 (note the negative | ||
value of Distance parameter). Again, control points are not moved, only weights | ||
are changed. | ||
|
||
.. image:: https://user-images.githubusercontent.com/284644/186957069-2bb35686-1d3b-4abb-94cb-fb0fc03a338d.png | ||
|
||
An example of **Move control points** method. Here, the blue point is moved by | ||
specified vector by moving of three control points (6, 7 and 8). | ||
|
||
.. image:: https://user-images.githubusercontent.com/284644/186957065-2b465e62-82f7-48ce-a38a-402580dcd7e7.png | ||
|
||
An example of **Insert knot** method. The point is moved by inserting a knot, | ||
thus creating additional control points, and moving three control points. | ||
|
||
.. image:: https://user-images.githubusercontent.com/284644/186957056-66fb3952-664a-4368-92e3-ab48487d51b6.png | ||
|
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,154 @@ | ||
# 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, repeat_last_for_length | ||
from sverchok.utils.curve import SvCurve | ||
from sverchok.utils.curve.nurbs import SvNurbsCurve | ||
from sverchok.utils.curve.nurbs_algorithms import ( | ||
move_curve_point_by_moving_control_point, | ||
move_curve_point_by_adjusting_one_weight, | ||
move_curve_point_by_adjusting_two_weights, | ||
move_curve_point_by_moving_control_points, TANGENT_PRESERVE, | ||
move_curve_point_by_inserting_knot) | ||
|
||
class SvNurbsCurveMovePointNode(bpy.types.Node, SverchCustomTreeNode): | ||
""" | ||
Triggers: Move NURBS curve point | ||
Tooltip: Adjust NURBS curve to move it's point to another location | ||
""" | ||
bl_idname = 'SvNurbsCurveMovePointNode' | ||
bl_label = 'Move NURBS Curve Point' | ||
bl_icon = 'OUTLINER_OB_EMPTY' | ||
sv_icon = 'SV_MOVE_CURVE_POINT' | ||
|
||
methods = [ | ||
('ONE_CPT', "Move one control point", "Move single control point", 0), | ||
('ONE_WEIGHT', "Adjust one weight", "Change single weight", 1), | ||
('TWO_WEIGHTS', "Adjust two weights", "Change two weights", 2), | ||
('MOVE_CPTS', "Move control points", "Move several control points", 3), | ||
('INSERT_KNOT', "Insert knot", "Insert additional knot and move several control points", 4) | ||
] | ||
|
||
def update_sockets(self, context): | ||
self.inputs['Index'].hide_safe = self.method not in ['ONE_CPT', 'ONE_WEIGHT', 'TWO_WEIGHTS'] | ||
self.inputs['Distance'].hide_safe = self.method not in ['ONE_WEIGHT', 'TWO_WEIGHTS'] | ||
self.inputs['Vector'].hide_safe = self.method not in ['ONE_CPT', 'MOVE_CPTS', 'INSERT_KNOT'] | ||
updateNode(self, context) | ||
|
||
method : EnumProperty( | ||
name = "Method", | ||
description = "How should we modify the curve control points or weights", | ||
items = methods, | ||
default = 'ONE_CPT', | ||
update = update_sockets) | ||
|
||
t_value : FloatProperty( | ||
name = "T", | ||
description = "Curve parameter value", | ||
default = 0.5, | ||
update = updateNode) | ||
|
||
idx : IntProperty( | ||
name = "Index", | ||
description = "Control point or weight index to be adjusted", | ||
default = 1, | ||
min = 0, | ||
update = updateNode) | ||
|
||
distance : FloatProperty( | ||
name = "Distance", | ||
description = "How far to move the point; negative value mean move in the opposite direction", | ||
default = 1.0, | ||
update = updateNode) | ||
|
||
preserve_tangent : BoolProperty( | ||
name = "Preserve tangent", | ||
default = False, | ||
update = updateNode) | ||
|
||
def draw_buttons(self, context, layout): | ||
layout.prop(self, 'method') | ||
if self.method == 'MOVE_CPTS': | ||
layout.prop(self, 'preserve_tangent') | ||
|
||
def sv_init(self, context): | ||
self.inputs.new('SvCurveSocket', "Curve") | ||
self.inputs.new('SvStringsSocket', "T").prop_name = 't_value' | ||
self.inputs.new('SvStringsSocket', "Index").prop_name = 'idx' | ||
self.inputs.new('SvStringsSocket', "Distance").prop_name = 'distance' | ||
p = self.inputs.new('SvVerticesSocket', "Vector") | ||
p.use_prop = True | ||
p.default_property = (1.0, 0.0, 0.0) | ||
self.outputs.new('SvCurveSocket', "Curve") | ||
self.update_sockets(context) | ||
|
||
def process(self): | ||
if not any(socket.is_linked for socket in self.outputs): | ||
return | ||
|
||
curve_s = self.inputs['Curve'].sv_get() | ||
t_value_s = self.inputs['T'].sv_get() | ||
index_s = self.inputs['Index'].sv_get() | ||
distance_s = self.inputs['Distance'].sv_get() | ||
vector_s = self.inputs['Vector'].sv_get() | ||
|
||
input_level = get_data_nesting_level(curve_s, data_types=(SvCurve,)) | ||
flat_output = input_level < 2 | ||
|
||
curve_s = ensure_nesting_level(curve_s, 2, data_types=(SvCurve,)) | ||
t_value_s = ensure_nesting_level(t_value_s, 2) | ||
index_s = ensure_nesting_level(index_s, 2) | ||
distance_s = ensure_nesting_level(distance_s, 2) | ||
vector_s = ensure_nesting_level(vector_s, 3) | ||
|
||
curves_out = [] | ||
for params in zip_long_repeat(curve_s, t_value_s, index_s, distance_s, vector_s): | ||
new_curves = [] | ||
for curve, t_value, index, distance, vector in zip_long_repeat(*params): | ||
curve = SvNurbsCurve.to_nurbs(curve) | ||
if curve is None: | ||
raise Exception("One of curves is not NURBS") | ||
|
||
vector = np.array(vector) | ||
if self.method == 'ONE_CPT': | ||
curve = move_curve_point_by_moving_control_point(curve, t_value, index, vector) | ||
elif self.method == 'ONE_WEIGHT': | ||
curve = move_curve_point_by_adjusting_one_weight(curve, t_value, index, distance) | ||
elif self.method == 'TWO_WEIGHTS': | ||
curve = move_curve_point_by_adjusting_two_weights(curve, t_value, index, distance=distance) | ||
elif self.method == 'MOVE_CPTS': | ||
if self.preserve_tangent: | ||
tangent = TANGENT_PRESERVE | ||
else: | ||
tangent = None | ||
curve = move_curve_point_by_moving_control_points(curve, t_value, vector, tangent=tangent) | ||
elif self.method == 'INSERT_KNOT': | ||
curve = move_curve_point_by_inserting_knot(curve, t_value, vector) | ||
else: | ||
raise Exception("Unsupported method") | ||
|
||
new_curves.append(curve) | ||
|
||
if flat_output: | ||
curves_out.extend(new_curves) | ||
else: | ||
curves_out.append(new_curves) | ||
|
||
self.outputs['Curve'].sv_set(curves_out) | ||
|
||
def register(): | ||
bpy.utils.register_class(SvNurbsCurveMovePointNode) | ||
|
||
def unregister(): | ||
bpy.utils.unregister_class(SNurbsCurveMovePointNodevCurveInsertKnotNode) | ||
|
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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.