Skip to content

Commit 82bc9d2

Browse files
committed
Add EulerND class and NodeND Euler angle rotation
1 parent 27b795c commit 82bc9d2

File tree

18 files changed

+1028
-36
lines changed

18 files changed

+1028
-36
lines changed

addons/nd/doc_classes/EulerND.xml

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="EulerND" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
3+
<brief_description>
4+
Represents a set of rotations in N-dimensional space using Euler angles.
5+
</brief_description>
6+
<description>
7+
EulerND contains a set of rotations in N-dimensional space, represented using a triplet of rotation from index, rotation to index, and rotation angle, which is usually in radians, but may be stored in degrees or other units if desired. The rotations may be composed together to form a single rotation matrix in a [BasisND] or [TransformND].
8+
The order of the rotations is significant, as they are applied in sequence from the first to the last. Therefore, unlike the Euler4D class in the 4D module, EulerND provides the user freedom to specify the order of rotations and which direction is positive. Users are recommended to use a consistent order and direction for all EulerND instances in a project to avoid confusion, but this is not enforced by the class. Consider using a superset of the rotations found in 2D, 3D, and 4D space as a starting point for defining a consistent order and direction for your project.
9+
</description>
10+
<tutorials>
11+
</tutorials>
12+
<methods>
13+
<method name="decompose_simple_rotations_from_basis" qualifiers="static">
14+
<return type="EulerND" />
15+
<param index="0" name="basis" type="BasisND" />
16+
<description>
17+
Given a [BasisND] rotation matrix, attempt to decompose it into a series of perpendicular simple rotations, and return them as an [EulerND]. If the basis cannot be decomposed into simple rotations, those axes will be skipped. For example, if the X basis vector is rotated in the XY plane, it must not have any non-zero values in the Z, W, etc directions, and the Y axis must also be in the XY plane, or else the decomposition will not show any rotation for those axes.
18+
</description>
19+
</method>
20+
<method name="decompose_simple_rotations_from_transform" qualifiers="static">
21+
<return type="EulerND" />
22+
<param index="0" name="transform" type="TransformND" />
23+
<description>
24+
Given a [TransformND] rotation matrix, attempt to decompose it into a series of perpendicular simple rotations, and return them as an [EulerND]. If the basis cannot be decomposed into simple rotations, those axes will be skipped. For example, if the X basis vector is rotated in the XY plane, it must not have any non-zero values in the Z, W, etc directions, and the Y axis must also be in the XY plane, or else the decomposition will not show any rotation for those axes.
25+
</description>
26+
</method>
27+
<method name="deg_to_rad" qualifiers="const">
28+
<return type="EulerND" />
29+
<description>
30+
Assuming this [EulerND] is in degrees, return a copy converted to radians.
31+
</description>
32+
</method>
33+
<method name="get_dimension" qualifiers="const">
34+
<return type="int" />
35+
<description>
36+
Returns the number of dimensions this [EulerND] is set to work in. This is equal to the highest index used in any rotation, plus one. For example, if the highest index used is 3, this will return 4, indicating it works in 4D space (which has axis indices 0 to 3).
37+
</description>
38+
</method>
39+
<method name="get_rotation_angle" qualifiers="const">
40+
<return type="float" />
41+
<param index="0" name="index" type="int" />
42+
<description>
43+
Returns the angle of the rotation at the given [param index]. The angle is usually in radians, but may be in degrees or other units if desired.
44+
</description>
45+
</method>
46+
<method name="get_rotation_from" qualifiers="const">
47+
<return type="int" />
48+
<param index="0" name="index" type="int" />
49+
<description>
50+
Returns the "from" index of the rotation at the given [param index]. This is the axis index that the rotation moves from. For example, a rotation from index 0 to index 1 rotates in the XY plane from X to Y.
51+
</description>
52+
</method>
53+
<method name="get_rotation_to" qualifiers="const">
54+
<return type="int" />
55+
<param index="0" name="index" type="int" />
56+
<description>
57+
Returns the "to" index of the rotation at the given [param index]. This is the axis index that the rotation moves towards. For example, a rotation from index 0 to index 1 rotates in the XY plane from X to Y.
58+
</description>
59+
</method>
60+
<method name="is_equal_approx" qualifiers="const">
61+
<return type="bool" />
62+
<param index="0" name="other" type="EulerND" />
63+
<description>
64+
Returns [code]true[/code] if this [EulerND] and [param other] are approximately equal, by comparing each rotation using [method @GlobalScope.is_equal_approx]. If the number of rotations differ, [code]false[/code] is returned. If a rotation's from index and to index are swapped, and the angles are negated, they are considered approximately equal by this function, even though the angle values on their own may not be.
65+
</description>
66+
</method>
67+
<method name="is_equal_exact" qualifiers="const">
68+
<return type="bool" />
69+
<param index="0" name="other" type="EulerND" />
70+
<description>
71+
Returns [code]true[/code] if this [EulerND] and [param other] are exactly equal, by comparing each rotation using [code]==[/code]. If the number of rotations differ, [code]false[/code] is returned. If a rotation's from index and to index are swapped, and the angles are negated, they are NOT considered exactly equal. This performs an exact value comparison, so floating point rounding errors may cause this to return [code]false[/code] unexpectedly.
72+
</description>
73+
</method>
74+
<method name="rad_to_deg" qualifiers="const">
75+
<return type="EulerND" />
76+
<description>
77+
Assuming this [EulerND] is in radians, return a copy converted to degrees.
78+
</description>
79+
</method>
80+
<method name="rotate_basis" qualifiers="const">
81+
<return type="BasisND" />
82+
<param index="0" name="basis" type="BasisND" />
83+
<description>
84+
Applies the rotations in this [EulerND] to the given [param basis] and returns the resulting rotated [BasisND].
85+
</description>
86+
</method>
87+
<method name="rotate_point" qualifiers="const">
88+
<return type="PackedFloat64Array" />
89+
<param index="0" name="point" type="PackedFloat64Array" />
90+
<description>
91+
Applies the rotations in this [EulerND] to the given [param point] VectorN ([PackedFloat64Array]) and returns the resulting rotated VectorN ([PackedFloat64Array]).
92+
</description>
93+
</method>
94+
<method name="set_rotation_angle">
95+
<return type="void" />
96+
<param index="0" name="index" type="int" />
97+
<param index="1" name="angle" type="float" />
98+
<description>
99+
Sets the angle of the rotation at the given [param index]. The angle is usually in radians, but may be in degrees or other units if desired.
100+
</description>
101+
</method>
102+
<method name="set_rotation_from">
103+
<return type="void" />
104+
<param index="0" name="index" type="int" />
105+
<param index="1" name="rot_from" type="int" />
106+
<description>
107+
Sets the "from" index of the rotation at the given [param index]. This is the axis index that the rotation moves from. For example, a rotation from index 0 to index 1 rotates in the XY plane from X to Y.
108+
</description>
109+
</method>
110+
<method name="set_rotation_of_basis">
111+
<return type="void" />
112+
<param index="0" name="basis" type="BasisND" />
113+
<description>
114+
Sets the rotation of the given [BasisND] to a rotation composed from the Euler angle rotations in this [EulerND], preserving the existing absolute scale of the basis.
115+
</description>
116+
</method>
117+
<method name="set_rotation_of_transform">
118+
<return type="void" />
119+
<param index="0" name="transform" type="TransformND" />
120+
<description>
121+
Sets the rotation of the given [TransformND] to a rotation composed from the Euler angle rotations in this [EulerND], preserving the existing absolute scale of the transform's basis, and leaving the origin unchanged.
122+
</description>
123+
</method>
124+
<method name="set_rotation_to">
125+
<return type="void" />
126+
<param index="0" name="index" type="int" />
127+
<param index="1" name="rot_to" type="int" />
128+
<description>
129+
Sets the "to" index of the rotation at the given [param index]. This is the axis index that the rotation moves towards. For example, a rotation from index 0 to index 1 rotates in the XY plane from X to Y.
130+
</description>
131+
</method>
132+
<method name="snapped" qualifiers="const">
133+
<return type="EulerND" />
134+
<param index="0" name="step" type="float" />
135+
<description>
136+
Returns a new [EulerND] where each rotation angle is snapped to the nearest multiple of [param step]. For example, if a rotation angle is 1.3 and the step is 0.5, the snapped angle will be 1.5.
137+
</description>
138+
</method>
139+
<method name="to_rotation_basis" qualifiers="const">
140+
<return type="BasisND" />
141+
<description>
142+
Composes the rotations in this [EulerND] into a single [BasisND] rotation matrix and returns it.
143+
</description>
144+
</method>
145+
<method name="to_rotation_transform" qualifiers="const">
146+
<return type="TransformND" />
147+
<description>
148+
Composes the rotations in this [EulerND] into a single [TransformND] rotation matrix and returns it.
149+
</description>
150+
</method>
151+
<method name="wrapped" qualifiers="const">
152+
<return type="EulerND" />
153+
<description>
154+
Returns a copy of this [EulerND] with all angles wrapped on the range [code]-PI[/code] to [code]PI[/code]. Note: This is not guaranteed to fully simplify the rotation in the case of multiple non-perpendicular simple rotations overlapping each other to form a complex rotation.
155+
</description>
156+
</method>
157+
</methods>
158+
<members>
159+
<member name="all_rotation_data" type="PackedFloat64Array" setter="set_all_rotation_data" getter="get_all_rotation_data" default="PackedFloat64Array()">
160+
A flat array containing all rotation data in the order of [from index, to index, angle, from index, to index, angle, ...]. This is useful for quickly getting or setting all rotation data at once, and is used for serializing the [EulerND] in a compact format. The from and to indices are stored as floats, but MUST be non-negative whole numbers. The length of the array MUST be a multiple of 3, or an error will occur when setting this property.
161+
</member>
162+
<member name="rotation_angle_array" type="PackedFloat64Array" setter="set_rotation_angle_array" getter="get_rotation_angle_array">
163+
The angles of all rotations stored in this [EulerND] as a [PackedFloat64Array]. The angles are usually in radians, but may be in degrees or other units if desired. This array always has the same length as [member rotation_count], which is the same as the length of [member rotation_from_array] and [member rotation_to_array].
164+
</member>
165+
<member name="rotation_count" type="int" setter="set_rotation_count" getter="get_rotation_count" default="0">
166+
The number of rotations stored in this [EulerND]. This can be changed to add or remove rotations. New rotations will default to a from index of 0, a to index of 1, and an angle of [code]0.0[/code]. If the count is reduced, excess rotations will be removed from the end of the list.
167+
</member>
168+
<member name="rotation_from_array" type="PackedInt32Array" setter="set_rotation_from_array" getter="get_rotation_from_array">
169+
The "from" indices of all rotations stored in this [EulerND] as a [PackedInt32Array]. These are the axis indices that each rotation moves from. This array always has the same length as [member rotation_count], which is the same as the length of [member rotation_angle_array] and [member rotation_to_array].
170+
</member>
171+
<member name="rotation_to_array" type="PackedInt32Array" setter="set_rotation_to_array" getter="get_rotation_to_array">
172+
The "to" indices of all rotations stored in this [EulerND] as a [PackedInt32Array]. These are the axis indices that each rotation moves towards. This array always has the same length as [member rotation_count], which is the same as the length of [member rotation_angle_array] and [member rotation_from_array].
173+
</member>
174+
</members>
175+
<signals>
176+
<signal name="rotation_changed">
177+
<description>
178+
Emitted whenever any rotation is changed, added, or removed, meaning that any data in this class changed.
179+
</description>
180+
</signal>
181+
</signals>
182+
</class>

addons/nd/doc_classes/NodeND.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
<member name="dimension_mode" type="int" setter="set_dimension_mode" getter="get_dimension_mode" enum="NodeND.DimensionMode" default="0">
5454
Controls whether this node's transform exists within a single dimension or converts between dimensions. See [enum NodeND.DimensionMode] for more information.
5555
</member>
56+
<member name="euler_rotation_count" type="int" setter="set_euler_rotation_count" getter="get_euler_rotation_count" default="0">
57+
The number of Euler rotations stored in this node's [Euler4D] rotation data. If [code]0[/code], the node may still be rotated, but the representation is not represented as Euler angles, only as basis vectors, such as stored in a [BasisND] or [TransformND].
58+
</member>
59+
<member name="euler_rotation_data" type="PackedFloat64Array" setter="set_euler_rotation_data" getter="get_euler_rotation_data">
60+
The local rotation data of the node's [EulerND] rotation, stored as a flat [PackedFloat64Array]. Each rotation is stored as three consecutive values: the "from" axis index, the "to" axis index, and the angle in radians. The size of this array is always [code]euler_rotation_count * 3[/code]. This is a low-level property used for serialization, consider using [member rotation_euler] for high-level access with helper functions.
61+
</member>
5662
<member name="global_position" type="PackedFloat64Array" setter="set_global_position" getter="get_global_position">
5763
The global position of the node. The size of this array depends on the output dimension after multiplying all ancestor transforms.
5864
</member>
@@ -71,6 +77,9 @@
7177
<member name="position" type="PackedFloat64Array" setter="set_position" getter="get_position" default="PackedFloat64Array()">
7278
The local position of the node. The size of this array is the same as [member output_dimension] which is the same as the number of rows in [member basis_columns] (unless the basis is a jagged array).
7379
</member>
80+
<member name="rotation_euler" type="EulerND" setter="set_rotation_euler" getter="get_rotation_euler">
81+
The local rotation data of the node's [EulerND] rotation, stored in a high-level [EulerND] resource with helper functions. See [EulerND] for more information.
82+
</member>
7483
<member name="scale_abs" type="PackedFloat64Array" setter="set_scale_abs" getter="get_scale_abs" default="PackedFloat64Array()">
7584
The local absolute scale of the node. This is the length of each basis vector. The size of this array is the same as [member input_dimension] which is the same as the number of columns in [member basis_columns].
7685
</member>

addons/nd/doc_classes/VectorND.xml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,17 +171,17 @@
171171
</method>
172172
<method name="fill" qualifiers="static">
173173
<return type="PackedFloat64Array" />
174-
<param index="0" name="value" type="float" />
175-
<param index="1" name="dimension" type="int" />
174+
<param index="0" name="dimension" type="int" />
175+
<param index="1" name="value" type="float" />
176176
<description>
177177
Returns a new VectorN ([PackedFloat64Array]) that is filled with the given [param value] for each component. The dimension of the vector is defined by [param dimension]. For example, [code]fill(1.0, 3)[/code] will return [code][1.0, 1.0, 1.0][/code].
178178
</description>
179179
</method>
180180
<method name="fill_array" qualifiers="static">
181181
<return type="PackedFloat64Array[]" />
182-
<param index="0" name="value" type="float" />
182+
<param index="0" name="dimension" type="int" />
183183
<param index="1" name="vector_amount" type="int" />
184-
<param index="2" name="dimension" type="int" />
184+
<param index="2" name="value" type="float" />
185185
<description>
186186
Returns an array of VectorN ([PackedFloat64Array]) that are filled with the given [param value] for each component in every vector. The amount of vectors is defined by [param vector_amount], and the dimension of each vector is defined by [param dimension]. For example, [code]fill_array(1.0, 3, 2)[/code] will return [code][[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]][/code].
187187
</description>
@@ -306,6 +306,13 @@
306306
Returns the index of the component with the smallest value in the input vector (most negative).
307307
</description>
308308
</method>
309+
<method name="multiply_components_together" qualifiers="static">
310+
<return type="float" />
311+
<param index="0" name="vector" type="PackedFloat64Array" />
312+
<description>
313+
Returns the product of all components in the input vector multiplied together. For example, [code]multiply_components_together([2.0, 3.0, 4.0, 5.0])[/code] will calculate [code]2.0 * 3.0 * 4.0 * 5.0[/code] and return [code]120.0[/code].
314+
</description>
315+
</method>
309316
<method name="multiply_scalar" qualifiers="static">
310317
<return type="PackedFloat64Array" />
311318
<param index="0" name="vector" type="PackedFloat64Array" />

addons/nd/godot_nd.gdextension

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ BoxWireMeshND = "icons/BoxWireMeshND.svg"
3333
CameraND = "icons/CameraND.svg"
3434
CellMaterialND = "icons/CellMaterialND.svg"
3535
CellMeshND = "icons/CellMeshND.svg"
36+
EulerND = "icons/EulerND.svg"
3637
GeometryND = "icons/GeometryND.svg"
3738
MarkerND = "icons/MarkerND.svg"
3839
MaterialND = "icons/MaterialND.svg"

0 commit comments

Comments
 (0)