Skip to content

Commit

Permalink
Bump Matrix Out node to MK2 .. adding same features in Quaternion Out…
Browse files Browse the repository at this point in the history
… node

- The new node now has modes that let you select the format of output the rotation component (Quaternion, Axis-Angle and Euler Angles).
- Also the node utilizes the Angle Units feature so the angle (by default set to DEGREES) can be changed to other units via Property Panel.
- Add documentation
  • Loading branch information
DolphinDream committed Mar 18, 2021
1 parent e6260de commit c49e7e9
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docs/nodes/matrix/matrix_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Matrix
input
interpolation
matrix_in_mk4
matrix_out
matrix_out_mk2
matrix_math
matrix_track_to
shear
Expand Down
2 changes: 0 additions & 2 deletions docs/nodes/matrix/matrix_out.rst

This file was deleted.

79 changes: 79 additions & 0 deletions docs/nodes/matrix/matrix_out_mk2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Matrix Out
==========

Functionality
-------------

Matrix Out node converts a 4x4 matrix into its location, rotation and scale components. The rotation component can be represented in various formats: quaternion, axis-angle or Euler angles.


Modes
-----

The available **Modes** are: EULER, AXIS-ANGLE & QUATERNION. These specify
how the output *rotation component* of the matrix is going to be represented.

Regardless of the selected mode the node always outputs the **Location** and the **Scale** components of the 4x4 matrix.

+------------+---------------------------------------------------------------------------------------+
| Mode | Description |
+============+=======================================================================================+
| EULER | Converts the rotation component of the matrix into X, Y, Z angles |
| | corresponding to the Euler rotation given an Euler rotation order. [1,2] |
+------------+---------------------------------------------------------------------------------------+
| AXIS-ANGLE | Converts the rotation component of the matrix into the Axis & Angle of rotation. [1] |
+------------+---------------------------------------------------------------------------------------+
| QUATERNION | Converts the rotation component of the matrix into a quaternion. |
+------------+---------------------------------------------------------------------------------------+

Notes:
[1] : For EULER and AXIS-ANGLE modes, which output angles, the node provides an angle unit conversion to let the angle output values be converted to Radians, Degrees or Unities (0-1 range).
[2] : For EULER mode the node provides the option to select the Euler rotation order: "XYZ", "XZY", "YXZ", "YZX", "ZXY" or "ZYX".


Inputs
------

**Matrix**
The node takes a list of (one or more) matrices and based on the selected mode
it converts the matrices into the corresponding components.


Extra Parameters
----------------
A set of extra parameters are available on the property panel.
These parameters do not receive external input.

+-----------------+----------+---------+--------------------------------------+
| Extra Param | Type | Default | Description |
+=================+==========+=========+======================================+
| **Angle Units** | Enum | DEGREES | Interprets the angle values based on |
| | RADIANS | | the selected angle units: |
| | DEGREES | | Radians = 0 - 2pi |
| | UNITIES | | Degrees = 0 - 360 |
| | | | Unities = 0 - 1 |
+-----------------+----------+---------+--------------------------------------+


Outputs
=======

Based on the selected **Mode** the node makes available the corresponding output sockets:

+------------+-----------------------------------------+
| Mode | Output Sockets (types) |
+============+=========================================+
| <any> | Location and Scale components (vectors) |
+------------+-----------------------------------------+
| EULER | X, Y, Z angles (floats) [1] |
+------------+-----------------------------------------+
| AXIS-ANGLE | Axis (vector) & Angle (float) [1] |
+------------+-----------------------------------------+
| QUATERNION | Quaternion |
+------------+-----------------------------------------+

Notes:
[1] : The angles are by default in DEGREES. The Property Panel has option to set angle units as: RADIANS, DEGREES or UNITIES.

The node only generates the conversion when the output sockets are connected.

4 changes: 2 additions & 2 deletions index.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@

## Matrix
SvMatrixInNodeMK4
MatrixOutNode
SvMatrixOutNodeMK2
SvMatrixApplyJoinNode
SvIterateNode
MatrixDeformNode
Expand Down Expand Up @@ -725,7 +725,7 @@
SvSelectMeshVerts
SvSetCustomMeshNormals
---
SvCombinatoricsNode
SvCombinatoricsNode

## Alpha Nodes
SvBManalyzinNode
Expand Down
8 changes: 4 additions & 4 deletions json_examples/Shapes/Donut.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"Matrix In": "Tangent Move",
"Matrix Math": "Tangent Move",
"Matrix Track To": "Tangent Move",
"Matrix out": "Tangent Move",
"Matrix Out": "Tangent Move",
"Mesh viewer": "Output",
"Move": "Bottom Flat",
"Move.002": "Tangent Move",
Expand Down Expand Up @@ -139,8 +139,8 @@
},
"width": 140.0
},
"Matrix out": {
"bl_idname": "MatrixOutNode",
"Matrix Out": {
"bl_idname": "SvMatrixOutNodeMK2",
"height": 100.0,
"hide": false,
"label": "",
Expand Down Expand Up @@ -860,7 +860,7 @@
[
"Matrix Math",
0,
"Matrix out",
"Matrix Out",
0
],
[
Expand Down
156 changes: 156 additions & 0 deletions nodes/matrix/matrix_out_mk2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

import bpy
from bpy.props import EnumProperty
from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode
from sverchok.utils.sv_transform_helper import AngleUnits, SvAngleHelper
from mathutils import Matrix


mode_items = [
("QUATERNION", "Quaternion", "Convert rotation component of the matrix into Quaternion", 0),
("EULER", "Euler Angles", "Convert rotation component of the matrix into Euler angles", 1),
("AXISANGLE", "Axis Angle", "Convert rotation component of the matrix into Axis & Angle", 2),
]

output_sockets = {
"QUATERNION": ["Quaternion"],
"EULER": ["Angle X", "Angle Y", "Angle Z"],
"AXISANGLE": ["Angle", "Axis"],
}


class SvMatrixOutNodeMK2(bpy.types.Node, SverchCustomTreeNode, SvAngleHelper):
"""
Triggers: Matrix, Out
Tooltip: Convert a matrix into its location, scale & rotation components
"""
bl_idname = 'SvMatrixOutNodeMK2'
bl_label = 'Matrix Out'
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_MATRIX_OUT'

def migrate_from(self, old_node):
''' Migration from old nodes (attributes mapping) '''
if old_node.bl_idname == "MatrixOutNode":
self.angle_units = AngleUnits.DEGREES
self.last_angle_units = AngleUnits.DEGREES

def migrate_props_pre_relink(self, old_node):
self.update_sockets()

def rclick_menu(self, context, layout):
layout.prop(self, "flat_output", text="Flat Output", expand=False)
self.node_replacement_menu(context, layout)

def update_sockets(self):
# hide all the mode related output sockets
for k, names in output_sockets.items():
for name in names:
self.outputs[name].hide_safe = True

# show the output sockets specific to the current mode
for name in output_sockets[self.mode]:
self.outputs[name].hide_safe = False

def update_mode(self, context):
self.update_sockets()
updateNode(self, context)

mode : EnumProperty(
name='Mode', description='The output component format of the Matrix',
items=mode_items, default="AXISANGLE", update=update_mode)

def sv_init(self, context):
self.inputs.new('SvMatrixSocket', "Matrix")
# translation and scale outputs
self.outputs.new('SvVerticesSocket', "Location")
self.outputs.new('SvVerticesSocket', "Scale")
# quaternion output
self.outputs.new('SvQuaternionSocket', "Quaternion")
# euler angles ouputs
self.outputs.new('SvStringsSocket', "Angle X")
self.outputs.new('SvStringsSocket', "Angle Y")
self.outputs.new('SvStringsSocket', "Angle Z")
# axis-angle output
self.outputs.new('SvVerticesSocket', "Axis")
self.outputs.new('SvStringsSocket', "Angle")

self.update_mode(context)

def draw_buttons(self, context, layout):
layout.prop(self, "mode", expand=False, text="")

if self.mode == "EULER":
self.draw_angle_euler_buttons(context, layout)

def draw_buttons_ext(self, context, layout):
if self.mode in {"EULER", "AXISANGLE"}:
self.draw_angle_units_buttons(context, layout)

def process(self):
outputs = self.outputs
if not any(s.is_linked for s in outputs):
return

input_M = self.inputs['Matrix'].sv_get()

# decompose matrices into: Translation, Rotation (quaternion) and Scale
location_list = []
quaternion_list = [] # rotations (as quaternions)
scale_list = []
for m in input_M:
T, R, S = m.decompose()
location_list.append(list(T))
quaternion_list.append(R)
scale_list.append(list(S))

outputs["Location"].sv_set(location_list)
outputs["Scale"].sv_set(scale_list)

if self.mode == "QUATERNION":
self.outputs['Quaternion'].sv_set(quaternion_list)

elif self.mode == "EULER":
# conversion factor from radians to the current angle units
au = self.angle_conversion_factor(AngleUnits.RADIANS, self.angle_units)
for i, name in enumerate("XYZ"):
if outputs["Angle " + name].is_linked:
angles = [q.to_euler(self.euler_order)[i] * au for q in quaternion_list]
outputs["Angle " + name].sv_set([angles])

elif self.mode == "AXISANGLE":
if outputs['Axis'].is_linked:
axis_list = [tuple(q.axis) for q in quaternion_list]
outputs['Axis'].sv_set([axis_list])

if outputs['Angle'].is_linked:
# conversion factor from radians to the current angle units
au = self.angle_conversion_factor(AngleUnits.RADIANS, self.angle_units)
angle_list = [q.angle * au for q in quaternion_list]
outputs['Angle'].sv_set([angle_list])


def register():
bpy.utils.register_class(SvMatrixOutNodeMK2)


def unregister():
bpy.utils.unregister_class(SvMatrixOutNodeMK2)
6 changes: 6 additions & 0 deletions nodes/matrix/matrix_out.py → old_nodes/matrix_out.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ class MatrixOutNode(bpy.types.Node, SverchCustomTreeNode):
bl_icon = 'OUTLINER_OB_EMPTY'
sv_icon = 'SV_MATRIX_OUT'

replacement_nodes = [('SvMatrixOutNodeMK2', None, dict(Rotation="Axis"))]

def rclick_menu(self, context, layout):
layout.prop(self, "flat_output", text="Flat Output", expand=False)
self.node_replacement_menu(context, layout)

def sv_init(self, context):
self.outputs.new('SvVerticesSocket', "Location")
self.outputs.new('SvVerticesSocket', "Scale")
Expand Down

0 comments on commit c49e7e9

Please sign in to comment.