Merge pull request #40581 from aaronfranke/3.2_docs

[3.2] Backport documentation for math types (core and C#)
This commit is contained in:
Rémi Verschelde 2020-07-22 09:29:18 +02:00 committed by GitHub
commit bdd1e74869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 2824 additions and 417 deletions

View File

@ -101,6 +101,10 @@ public:
_FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const; _FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const;
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */ _FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
return AABB(Vector3(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0), position.z + MIN(size.z, 0)), size.abs());
}
operator String() const; operator String() const;
_FORCE_INLINE_ AABB() {} _FORCE_INLINE_ AABB() {}

View File

@ -56,7 +56,6 @@ Plane Plane::normalized() const {
} }
Vector3 Plane::get_any_point() const { Vector3 Plane::get_any_point() const {
return get_normal() * d; return get_normal() * d;
} }

View File

@ -743,6 +743,7 @@ struct _VariantCall {
#define VCALL_PTR5R(m_type, m_method) \ #define VCALL_PTR5R(m_type, m_method) \
static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); } static void _call_##m_type##_##m_method(Variant &r_ret, Variant &p_self, const Variant **p_args) { r_ret = reinterpret_cast<m_type *>(p_self._data._ptr)->m_method(*p_args[0], *p_args[1], *p_args[2], *p_args[3], *p_args[4]); }
VCALL_PTR0R(AABB, abs);
VCALL_PTR0R(AABB, get_area); VCALL_PTR0R(AABB, get_area);
VCALL_PTR0R(AABB, has_no_area); VCALL_PTR0R(AABB, has_no_area);
VCALL_PTR0R(AABB, has_no_surface); VCALL_PTR0R(AABB, has_no_surface);
@ -1909,6 +1910,7 @@ void register_variant_methods() {
//pointerbased //pointerbased
ADDFUNC0R(AABB, AABB, AABB, abs, varray());
ADDFUNC0R(AABB, REAL, AABB, get_area, varray()); ADDFUNC0R(AABB, REAL, AABB, get_area, varray());
ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray()); ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray());
ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray()); ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray());

View File

@ -18,7 +18,14 @@
<argument index="1" name="size" type="Vector3"> <argument index="1" name="size" type="Vector3">
</argument> </argument>
<description> <description>
Optional constructor, accepts position and size. Constructs an [AABB] from a position and size.
</description>
</method>
<method name="abs">
<return type="AABB">
</return>
<description>
Returns an AABB with equivalent position and size, modified so that the most-negative corner is the origin and the size is positive.
</description> </description>
</method> </method>
<method name="encloses"> <method name="encloses">
@ -197,13 +204,14 @@
</methods> </methods>
<members> <members>
<member name="end" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> <member name="end" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
Ending corner. This is calculated as [code]position + size[/code]. Changing this property changes [member size] accordingly. Ending corner. This is calculated as [code]position + size[/code]. Setting this value will change the size.
</member> </member>
<member name="position" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> <member name="position" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
Beginning corner. Beginning corner. Typically has values lower than [member end].
</member> </member>
<member name="size" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> <member name="size" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
Size from position to end. Size from [member position] to [member end]. Typically all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member> </member>
</members> </members>
<constants> <constants>

View File

@ -4,10 +4,13 @@
3×3 matrix datatype. 3×3 matrix datatype.
</brief_description> </brief_description>
<description> <description>
3×3 matrix used for 3D rotation and scale. Contains 3 vector fields X, Y and Z as its columns, which can be interpreted as the local basis vectors of a transformation. Can also be accessed as array of 3D vectors. These vectors are orthogonal to each other, but are not necessarily normalized (due to scaling). Almost always used as an orthogonal basis for a [Transform]. 3×3 matrix used for 3D rotation and scale. Almost always used as an orthogonal basis for a Transform.
For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S). Contains 3 vector fields X, Y and Z as its columns, which are typically interpreted as the local basis vectors of a transformation. For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S).
Can also be accessed as array of 3D vectors. These vectors are normally orthogonal to each other, but are not necessarily normalized (due to scaling).
For more information, read the "Matrices and transforms" documentation article.
</description> </description>
<tutorials> <tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
<link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link> <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
</tutorials> </tutorials>
<methods> <methods>
@ -17,7 +20,7 @@
<argument index="0" name="from" type="Quat"> <argument index="0" name="from" type="Quat">
</argument> </argument>
<description> <description>
Create a rotation matrix from the given quaternion. Constructs a pure rotation basis matrix from the given quaternion.
</description> </description>
</method> </method>
<method name="Basis"> <method name="Basis">
@ -26,7 +29,8 @@
<argument index="0" name="from" type="Vector3"> <argument index="0" name="from" type="Vector3">
</argument> </argument>
<description> <description>
Create a rotation matrix (in the YXZ convention: first Z, then X, and Y last) from the specified Euler angles, given in the vector format as (X angle, Y angle, Z angle). Constructs a pure rotation basis matrix from the given Euler angles (in the YXZ convention: when *composing*, first Y, then X, and Z last), given in the vector format as (X angle, Y angle, Z angle).
Consider using the [Quat] constructor instead, which uses a quaternion instead of Euler angles.
</description> </description>
</method> </method>
<method name="Basis"> <method name="Basis">
@ -37,7 +41,7 @@
<argument index="1" name="phi" type="float"> <argument index="1" name="phi" type="float">
</argument> </argument>
<description> <description>
Create a rotation matrix which rotates around the given axis by the specified angle, in radians. The axis must be a normalized vector. Constructs a pure rotation basis matrix, rotated around the given [code]axis[/code] by [code]phi[/code], in radians. The axis must be a normalized vector.
</description> </description>
</method> </method>
<method name="Basis"> <method name="Basis">
@ -50,28 +54,30 @@
<argument index="2" name="z_axis" type="Vector3"> <argument index="2" name="z_axis" type="Vector3">
</argument> </argument>
<description> <description>
Create a matrix from 3 axis vectors. Constructs a basis matrix from 3 axis vectors (matrix columns).
</description> </description>
</method> </method>
<method name="determinant"> <method name="determinant">
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the determinant of the matrix. Returns the determinant of the basis matrix. If the basis is uniformly scaled, its determinant is the square of the scale.
A negative determinant means the basis has a negative scale. A zero determinant means the basis isn't invertible, and is usually considered invalid.
</description> </description>
</method> </method>
<method name="get_euler"> <method name="get_euler">
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the basis's rotation in the form of Euler angles (in the YXZ convention: first Z, then X, and Y last). The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle). See [method get_rotation_quat] if you need a quaternion instead. Returns the basis's rotation in the form of Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last). The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
Consider using the [method get_rotation_quat] method instead, which returns a [Quat] quaternion instead of Euler angles.
</description> </description>
</method> </method>
<method name="get_orthogonal_index"> <method name="get_orthogonal_index">
<return type="int"> <return type="int">
</return> </return>
<description> <description>
This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the grid map editor. For further details, refer to the Godot source code. This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code.
</description> </description>
</method> </method>
<method name="get_rotation_quat"> <method name="get_rotation_quat">
@ -193,25 +199,26 @@
<argument index="0" name="v" type="Vector3"> <argument index="0" name="v" type="Vector3">
</argument> </argument>
<description> <description>
Returns a vector transformed (multiplied) by the transposed matrix. Returns a vector transformed (multiplied) by the transposed basis matrix.
[b]Note:[/b] This results in a multiplication by the inverse of the matrix only if it represents a rotation-reflection. [b]Note:[/b] This results in a multiplication by the inverse of the matrix only if it represents a rotation-reflection.
</description> </description>
</method> </method>
</methods> </methods>
<members> <members>
<member name="x" type="Vector3" setter="" getter="" default="Vector3( 1, 0, 0 )"> <member name="x" type="Vector3" setter="" getter="" default="Vector3( 1, 0, 0 )">
The basis matrix's X vector. The basis matrix's X vector (column 0). Equivalent to array index [code]0[/code].
</member> </member>
<member name="y" type="Vector3" setter="" getter="" default="Vector3( 0, 1, 0 )"> <member name="y" type="Vector3" setter="" getter="" default="Vector3( 0, 1, 0 )">
The basis matrix's Y vector. The basis matrix's Y vector (column 1). Equivalent to array index [code]1[/code].
</member> </member>
<member name="z" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 1 )"> <member name="z" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 1 )">
The basis matrix's Z vector. The basis matrix's Z vector (column 2). Equivalent to array index [code]2[/code].
</member> </member>
</members> </members>
<constants> <constants>
<constant name="IDENTITY" value="Basis( 1, 0, 0, 0, 1, 0, 0, 0, 1 )"> <constant name="IDENTITY" value="Basis( 1, 0, 0, 0, 1, 0, 0, 0, 1 )">
The identity basis. This is identical to calling [code]Basis()[/code] without any parameters. This constant can be used to make your code clearer. The identity basis, with no rotation or scaling applied.
This is identical to calling [code]Basis()[/code] without any parameters. This constant can be used to make your code clearer, and for consistency with C#.
</constant> </constant>
<constant name="FLIP_X" value="Basis( -1, 0, 0, 0, 1, 0, 0, 0, 1 )"> <constant name="FLIP_X" value="Basis( -1, 0, 0, 0, 1, 0, 0, 0, 1 )">
The basis that will flip something along the X axis when used in a transformation. The basis that will flip something along the X axis when used in a transformation.

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="Color" version="3.2"> <class name="Color" version="3.2">
<brief_description> <brief_description>
Color in RGBA format with some support for ARGB format. Color in RGBA format using floats on the range of 0 to 1.
</brief_description> </brief_description>
<description> <description>
A color is represented by red, green, and blue [code](r, g, b)[/code] components. Additionally, [code]a[/code] represents the alpha component, often used for transparency. Values are in floating-point and usually range from 0 to 1. Some properties (such as [member CanvasItem.modulate]) may accept values greater than 1. A color represented by red, green, blue, and alpha (RGBA) components. The alpha component is often used for transparency. Values are in floating-point and usually range from 0 to 1. Some properties (such as CanvasItem.modulate) may accept values greater than 1 (overbright or HDR colors).
You can also create a color from standardized color names by using [method @GDScript.ColorN] or directly using the color constants defined here. The standardized color set is based on the [url=https://en.wikipedia.org/wiki/X11_color_names]X11 color names[/url]. You can also create a color from standardized color names by using [method @GDScript.ColorN] or directly using the color constants defined here. The standardized color set is based on the [url=https://en.wikipedia.org/wiki/X11_color_names]X11 color names[/url].
If you want to supply values in a range of 0 to 255, you should use [method @GDScript.Color8]. If you want to supply values in a range of 0 to 255, you should use [method @GDScript.Color8].
[b]Note:[/b] In a boolean context, a Color will evaluate to [code]false[/code] if it's equal to [code]Color(0, 0, 0, 1)[/code] (opaque black). Otherwise, a Color will always evaluate to [code]true[/code]. [b]Note:[/b] In a boolean context, a Color will evaluate to [code]false[/code] if it's equal to [code]Color(0, 0, 0, 1)[/code] (opaque black). Otherwise, a Color will always evaluate to [code]true[/code].
@ -275,37 +275,37 @@
</methods> </methods>
<members> <members>
<member name="a" type="float" setter="" getter="" default="1.0"> <member name="a" type="float" setter="" getter="" default="1.0">
Alpha value (range 0 to 1). The color's alpha (transparency) component, typically on the range of 0 to 1.
</member> </member>
<member name="a8" type="int" setter="" getter="" default="255"> <member name="a8" type="int" setter="" getter="" default="255">
Alpha value (range 0 to 255). Wrapper for [member a] that uses the range 0 to 255 instead of 0 to 1.
</member> </member>
<member name="b" type="float" setter="" getter="" default="0.0"> <member name="b" type="float" setter="" getter="" default="0.0">
Blue value (range 0 to 1). The color's blue component, typically on the range of 0 to 1.
</member> </member>
<member name="b8" type="int" setter="" getter="" default="0"> <member name="b8" type="int" setter="" getter="" default="0">
Blue value (range 0 to 255). Wrapper for [member b] that uses the range 0 to 255 instead of 0 to 1.
</member> </member>
<member name="g" type="float" setter="" getter="" default="0.0"> <member name="g" type="float" setter="" getter="" default="0.0">
Green value (range 0 to 1). The color's green component, typically on the range of 0 to 1.
</member> </member>
<member name="g8" type="int" setter="" getter="" default="0"> <member name="g8" type="int" setter="" getter="" default="0">
Green value (range 0 to 255). Wrapper for [member g] that uses the range 0 to 255 instead of 0 to 1.
</member> </member>
<member name="h" type="float" setter="" getter="" default="0.0"> <member name="h" type="float" setter="" getter="" default="0.0">
HSV hue value (range 0 to 1). The HSV hue of this color, on the range 0 to 1.
</member> </member>
<member name="r" type="float" setter="" getter="" default="0.0"> <member name="r" type="float" setter="" getter="" default="0.0">
Red value (range 0 to 1). The color's red component, typically on the range of 0 to 1.
</member> </member>
<member name="r8" type="int" setter="" getter="" default="0"> <member name="r8" type="int" setter="" getter="" default="0">
Red value (range 0 to 255). Wrapper for [member r] that uses the range 0 to 255 instead of 0 to 1.
</member> </member>
<member name="s" type="float" setter="" getter="" default="0.0"> <member name="s" type="float" setter="" getter="" default="0.0">
HSV saturation value (range 0 to 1). The HSV saturation of this color, on the range 0 to 1.
</member> </member>
<member name="v" type="float" setter="" getter="" default="0.0"> <member name="v" type="float" setter="" getter="" default="0.0">
HSV value (range 0 to 1). The HSV value (brightness) of this color, on the range 0 to 1.
</member> </member>
</members> </members>
<constants> <constants>

View File

@ -69,7 +69,8 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns a point on the plane. Returns the center of the plane.
This method is deprecated, please use [method center] instead.
</description> </description>
</method> </method>
<method name="has_point"> <method name="has_point">
@ -80,7 +81,7 @@
<argument index="1" name="epsilon" type="float" default="1e-05"> <argument index="1" name="epsilon" type="float" default="1e-05">
</argument> </argument>
<description> <description>
Returns [code]true[/code] if [code]point[/code] is inside the plane (by a very minimum [code]epsilon[/code] threshold). Returns [code]true[/code] if [code]point[/code] is inside the plane. Comparison uses a custom minimum [code]epsilon[/code] threshold.
</description> </description>
</method> </method>
<method name="intersect_3"> <method name="intersect_3">
@ -147,36 +148,38 @@
<argument index="0" name="point" type="Vector3"> <argument index="0" name="point" type="Vector3">
</argument> </argument>
<description> <description>
Returns the orthogonal projection of point [code]p[/code] into a point in the plane. Returns the orthogonal projection of [code]point[/code] into a point in the plane.
</description> </description>
</method> </method>
</methods> </methods>
<members> <members>
<member name="d" type="float" setter="" getter="" default="0.0"> <member name="d" type="float" setter="" getter="" default="0.0">
Distance from the origin to the plane, in the direction of [member normal]. The distance from the origin to the plane, in the direction of [member normal]. This value is typically non-negative.
In the scalar equation of the plane [code]ax + by + cz = d[/code], this is [code]d[/code], while the [code](a, b, c)[/code] coordinates are represented by the [member normal] property.
</member> </member>
<member name="normal" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> <member name="normal" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
The normal of the plane. "Over" or "Above" the plane is considered the side of the plane towards where the normal is pointing. The normal of the plane, which must be normalized.
In the scalar equation of the plane [code]ax + by + cz = d[/code], this is the vector [code](a, b, c)[/code], where [code]d[/code] is the [member d] property.
</member> </member>
<member name="x" type="float" setter="" getter="" default="0.0"> <member name="x" type="float" setter="" getter="" default="0.0">
The [member normal]'s X component. The X component of the plane's [member normal] vector.
</member> </member>
<member name="y" type="float" setter="" getter="" default="0.0"> <member name="y" type="float" setter="" getter="" default="0.0">
The [member normal]'s Y component. The Y component of the plane's [member normal] vector.
</member> </member>
<member name="z" type="float" setter="" getter="" default="0.0"> <member name="z" type="float" setter="" getter="" default="0.0">
The [member normal]'s Z component. The Z component of the plane's [member normal] vector.
</member> </member>
</members> </members>
<constants> <constants>
<constant name="PLANE_YZ" value="Plane( 1, 0, 0, 0 )"> <constant name="PLANE_YZ" value="Plane( 1, 0, 0, 0 )">
A plane that extends in the Y and Z axes. A plane that extends in the Y and Z axes (normal vector points +X).
</constant> </constant>
<constant name="PLANE_XZ" value="Plane( 0, 1, 0, 0 )"> <constant name="PLANE_XZ" value="Plane( 0, 1, 0, 0 )">
A plane that extends in the X and Z axes. A plane that extends in the X and Z axes (normal vector points +Y).
</constant> </constant>
<constant name="PLANE_XY" value="Plane( 0, 0, 1, 0 )"> <constant name="PLANE_XY" value="Plane( 0, 0, 1, 0 )">
A plane that extends in the X and Y axes. A plane that extends in the X and Y axes (normal vector points +Z).
</constant> </constant>
</constants> </constants>
</class> </class>

View File

@ -4,9 +4,9 @@
Quaternion. Quaternion.
</brief_description> </brief_description>
<description> <description>
A unit quaternion used for representing 3D rotations. A unit quaternion used for representing 3D rotations. Quaternions need to be normalized to be used for rotation.
It is similar to [Basis], which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. But due to its compactness and the way it is stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors. It is similar to Basis, which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. Basis stores rotation, scale, and shearing, while Quat only stores rotation.
Quaternions need to be (re)normalized. Due to its compactness and the way it is stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors.
</description> </description>
<tutorials> <tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link> <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
@ -18,7 +18,7 @@
<argument index="0" name="from" type="Basis"> <argument index="0" name="from" type="Basis">
</argument> </argument>
<description> <description>
Returns the rotation matrix corresponding to the given quaternion. Constructs a quaternion from the given [Basis].
</description> </description>
</method> </method>
<method name="Quat"> <method name="Quat">
@ -27,7 +27,7 @@
<argument index="0" name="euler" type="Vector3"> <argument index="0" name="euler" type="Vector3">
</argument> </argument>
<description> <description>
Returns a quaternion that will perform a rotation specified by Euler angles (in the YXZ convention: first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle). Constructs a quaternion that will perform a rotation specified by Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle).
</description> </description>
</method> </method>
<method name="Quat"> <method name="Quat">
@ -38,7 +38,7 @@
<argument index="1" name="angle" type="float"> <argument index="1" name="angle" type="float">
</argument> </argument>
<description> <description>
Returns a quaternion that will rotate around the given axis by the specified angle. The axis must be a normalized vector. Constructs a quaternion that will rotate around the given axis by the specified angle. The axis must be a normalized vector.
</description> </description>
</method> </method>
<method name="Quat"> <method name="Quat">
@ -53,7 +53,7 @@
<argument index="3" name="w" type="float"> <argument index="3" name="w" type="float">
</argument> </argument>
<description> <description>
Returns a quaternion defined by these values. Constructs a quaternion defined by the given values.
</description> </description>
</method> </method>
<method name="cubic_slerp"> <method name="cubic_slerp">
@ -68,7 +68,7 @@
<argument index="3" name="t" type="float"> <argument index="3" name="t" type="float">
</argument> </argument>
<description> <description>
Performs a cubic spherical-linear interpolation with another quaternion. Performs a cubic spherical interpolation between quaternions [code]preA[/code], this vector, [code]b[/code], and [code]postB[/code], by the given amount [code]t[/code].
</description> </description>
</method> </method>
<method name="dot"> <method name="dot">
@ -84,7 +84,7 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns Euler angles (in the YXZ convention: first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X angle, Y angle, Z angle). Returns Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last) corresponding to the rotation represented by the unit quaternion. Returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
</description> </description>
</method> </method>
<method name="inverse"> <method name="inverse">
@ -144,7 +144,7 @@
<argument index="0" name="euler" type="Vector3"> <argument index="0" name="euler" type="Vector3">
</argument> </argument>
<description> <description>
Sets the quaternion to a rotation specified by Euler angles (in the YXZ convention: first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle). Sets the quaternion to a rotation specified by Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle).
</description> </description>
</method> </method>
<method name="slerp"> <method name="slerp">
@ -155,7 +155,8 @@
<argument index="1" name="t" type="float"> <argument index="1" name="t" type="float">
</argument> </argument>
<description> <description>
Performs a spherical-linear interpolation with another quaternion. Returns the result of the spherical linear interpolation between this quaternion and [code]to[/code] by amount [code]weight[/code].
[b]Note:[/b] Both quaternions must be normalized.
</description> </description>
</method> </method>
<method name="slerpni"> <method name="slerpni">
@ -166,7 +167,7 @@
<argument index="1" name="t" type="float"> <argument index="1" name="t" type="float">
</argument> </argument>
<description> <description>
Performs a spherical-linear interpolation with another quaterion without checking if the rotation path is not bigger than 90°. Returns the result of the spherical linear interpolation between this quaternion and [code]to[/code] by amount [code]weight[/code], but without checking if the rotation path is not bigger than 90 degrees.
</description> </description>
</method> </method>
<method name="xform"> <method name="xform">
@ -175,27 +176,31 @@
<argument index="0" name="v" type="Vector3"> <argument index="0" name="v" type="Vector3">
</argument> </argument>
<description> <description>
Transforms the vector [code]v[/code] by this quaternion. Returns a vector transformed (multiplied) by this quaternion.
</description> </description>
</method> </method>
</methods> </methods>
<members> <members>
<member name="w" type="float" setter="" getter="" default="1.0"> <member name="w" type="float" setter="" getter="" default="1.0">
W component of the quaternion. W component of the quaternion (real part).
Quaternion components should usually not be manipulated directly.
</member> </member>
<member name="x" type="float" setter="" getter="" default="0.0"> <member name="x" type="float" setter="" getter="" default="0.0">
X component of the quaternion. X component of the quaternion (imaginary [code]i[/code] axis part).
Quaternion components should usually not be manipulated directly.
</member> </member>
<member name="y" type="float" setter="" getter="" default="0.0"> <member name="y" type="float" setter="" getter="" default="0.0">
Y component of the quaternion. Y component of the quaternion (imaginary [code]j[/code] axis part).
Quaternion components should usually not be manipulated directly.
</member> </member>
<member name="z" type="float" setter="" getter="" default="0.0"> <member name="z" type="float" setter="" getter="" default="0.0">
Z component of the quaternion. Z component of the quaternion (imaginary [code]k[/code] axis part).
Quaternion components should usually not be manipulated directly.
</member> </member>
</members> </members>
<constants> <constants>
<constant name="IDENTITY" value="Quat( 0, 0, 0, 1 )"> <constant name="IDENTITY" value="Quat( 0, 0, 0, 1 )">
The identity rotation. Equivalent to an identity matrix. If a vector is transformed by an identity quaternion, it will not change. The identity quaternion, representing no rotation. Equivalent to an identity [Basis] matrix. If a vector is transformed by an identity quaternion, it will not change.
</constant> </constant>
</constants> </constants>
</class> </class>

View File

@ -161,13 +161,14 @@
</methods> </methods>
<members> <members>
<member name="end" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> <member name="end" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )">
Ending corner. Ending corner. This is calculated as [code]position + size[/code]. Setting this value will change the size.
</member> </member>
<member name="position" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> <member name="position" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )">
Position (starting corner). Beginning corner. Typically has values lower than [member end].
</member> </member>
<member name="size" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> <member name="size" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )">
Size from position to end. Size from [member position] to [member end]. Typically all components are positive.
If the size is negative, you can use [method abs] to fix it.
</member> </member>
</members> </members>
<constants> <constants>

View File

@ -4,10 +4,12 @@
3D transformation (3×4 matrix). 3D transformation (3×4 matrix).
</brief_description> </brief_description>
<description> <description>
Represents one or many transformations in 3D space such as translation, rotation, or scaling. It consists of a [member basis] and an [member origin]. It is similar to a 3×4 matrix. 3×4 matrix (3 rows, 4 columns) used for 3D linear transformations. It can represent transformations such as translation, rotation, or scaling. It consists of a [member basis] (first 3 columns) and a [Vector3] for the [member origin] (last column).
For more information, read the "Matrices and transforms" documentation article.
</description> </description>
<tutorials> <tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link> <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
<link>https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
<link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link> <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
</tutorials> </tutorials>
<methods> <methods>
@ -23,7 +25,7 @@
<argument index="3" name="origin" type="Vector3"> <argument index="3" name="origin" type="Vector3">
</argument> </argument>
<description> <description>
Constructs the Transform from four [Vector3]. Each axis corresponds to local basis vectors (some of which may be scaled). Constructs a Transform from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled).
</description> </description>
</method> </method>
<method name="Transform"> <method name="Transform">
@ -34,7 +36,7 @@
<argument index="1" name="origin" type="Vector3"> <argument index="1" name="origin" type="Vector3">
</argument> </argument>
<description> <description>
Constructs the Transform from a [Basis] and [Vector3]. Constructs a Transform from a [Basis] and [Vector3].
</description> </description>
</method> </method>
<method name="Transform"> <method name="Transform">
@ -43,7 +45,7 @@
<argument index="0" name="from" type="Transform2D"> <argument index="0" name="from" type="Transform2D">
</argument> </argument>
<description> <description>
Constructs the Transform from a [Transform2D]. Constructs a Transform from a [Transform2D].
</description> </description>
</method> </method>
<method name="Transform"> <method name="Transform">
@ -52,7 +54,7 @@
<argument index="0" name="from" type="Quat"> <argument index="0" name="from" type="Quat">
</argument> </argument>
<description> <description>
Constructs the Transform from a [Quat]. The origin will be Vector3(0, 0, 0). Constructs a Transform from a [Quat]. The origin will be [code]Vector3(0, 0, 0)[/code].
</description> </description>
</method> </method>
<method name="Transform"> <method name="Transform">
@ -79,7 +81,7 @@
<argument index="1" name="weight" type="float"> <argument index="1" name="weight" type="float">
</argument> </argument>
<description> <description>
Interpolates the transform to other Transform by weight amount (0-1). Interpolates the transform to other Transform by weight amount (on the range of 0.0 to 1.0).
</description> </description>
</method> </method>
<method name="inverse"> <method name="inverse">
@ -172,7 +174,7 @@
The basis is a matrix containing 3 [Vector3] as its columns: X axis, Y axis, and Z axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. The basis is a matrix containing 3 [Vector3] as its columns: X axis, Y axis, and Z axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object.
</member> </member>
<member name="origin" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> <member name="origin" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )">
The translation offset of the transform. The translation offset of the transform (column 3, the fourth column). Equivalent to array index [code]3[/code].
</member> </member>
</members> </members>
<constants> <constants>

View File

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="Transform2D" version="3.2"> <class name="Transform2D" version="3.2">
<brief_description> <brief_description>
2D transformation (3×2 matrix). 2D transformation (2×3 matrix).
</brief_description> </brief_description>
<description> <description>
Represents one or many transformations in 2D space such as translation, rotation, or scaling. It consists of two [member x] and [member y] [Vector2]s and an [member origin]. It is similar to a 3×2 matrix. 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations. It can represent transformations such as translation, rotation, or scaling. It consists of a three [Vector2] values: [member x], [member y], and the [member origin].
For more information, read the "Matrices and transforms" documentation article.
</description> </description>
<tutorials> <tutorials>
<link>https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
</tutorials> </tutorials>
<methods> <methods>
<method name="Transform2D"> <method name="Transform2D">
@ -28,7 +30,7 @@
<argument index="2" name="origin" type="Vector2"> <argument index="2" name="origin" type="Vector2">
</argument> </argument>
<description> <description>
Constructs the transform from 3 [Vector2]s representing x, y, and origin. Constructs the transform from 3 [Vector2] values representing [member x], [member y], and the [member origin] (the three column vectors).
</description> </description>
</method> </method>
<method name="Transform2D"> <method name="Transform2D">
@ -46,7 +48,7 @@
<return type="Transform2D"> <return type="Transform2D">
</return> </return>
<description> <description>
Returns the inverse of the matrix. Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
</description> </description>
</method> </method>
<method name="basis_xform"> <method name="basis_xform">
@ -55,7 +57,8 @@
<argument index="0" name="v" type="Vector2"> <argument index="0" name="v" type="Vector2">
</argument> </argument>
<description> <description>
Transforms the given vector by this transform's basis (no translation). Returns a vector transformed (multiplied) by the basis matrix.
This method does not account for translation (the origin vector).
</description> </description>
</method> </method>
<method name="basis_xform_inv"> <method name="basis_xform_inv">
@ -64,7 +67,8 @@
<argument index="0" name="v" type="Vector2"> <argument index="0" name="v" type="Vector2">
</argument> </argument>
<description> <description>
Inverse-transforms the given vector by this transform's basis (no translation). Returns a vector transformed (multiplied) by the inverse basis matrix.
This method does not account for translation (the origin vector).
</description> </description>
</method> </method>
<method name="get_origin"> <method name="get_origin">
@ -96,14 +100,14 @@
<argument index="1" name="weight" type="float"> <argument index="1" name="weight" type="float">
</argument> </argument>
<description> <description>
Returns a transform interpolated between this transform and another by a given weight (0-1). Returns a transform interpolated between this transform and another by a given weight (on the range of 0.0 to 1.0).
</description> </description>
</method> </method>
<method name="inverse"> <method name="inverse">
<return type="Transform2D"> <return type="Transform2D">
</return> </return>
<description> <description>
Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling). Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use [method affine_inverse] for transforms with scaling).
</description> </description>
</method> </method>
<method name="is_equal_approx"> <method name="is_equal_approx">
@ -119,7 +123,7 @@
<return type="Transform2D"> <return type="Transform2D">
</return> </return>
<description> <description>
Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors. Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors (scale of 1 or -1).
</description> </description>
</method> </method>
<method name="rotated"> <method name="rotated">
@ -171,24 +175,24 @@
</methods> </methods>
<members> <members>
<member name="origin" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> <member name="origin" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )">
The transform's translation offset. The origin vector (column 2, the third column). Equivalent to array index [code]2[/code]. The origin vector represents translation.
</member> </member>
<member name="x" type="Vector2" setter="" getter="" default="Vector2( 1, 0 )"> <member name="x" type="Vector2" setter="" getter="" default="Vector2( 1, 0 )">
The X axis of 2×2 basis matrix containing 2 [Vector2]s as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. The basis matrix's X vector (column 0). Equivalent to array index [code]0[/code].
</member> </member>
<member name="y" type="Vector2" setter="" getter="" default="Vector2( 0, 1 )"> <member name="y" type="Vector2" setter="" getter="" default="Vector2( 0, 1 )">
The Y axis of 2×2 basis matrix containing 2 [Vector2]s as its columns: X axis and Y axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. The basis matrix's Y vector (column 1). Equivalent to array index [code]1[/code].
</member> </member>
</members> </members>
<constants> <constants>
<constant name="IDENTITY" value="Transform2D( 1, 0, 0, 1, 0, 0 )"> <constant name="IDENTITY" value="Transform2D( 1, 0, 0, 1, 0, 0 )">
[Transform2D] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation. The identity [Transform2D] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation.
</constant> </constant>
<constant name="FLIP_X" value="Transform2D( -1, 0, 0, 1, 0, 0 )"> <constant name="FLIP_X" value="Transform2D( -1, 0, 0, 1, 0, 0 )">
[Transform2D] with mirroring applied parallel to the X axis. The [Transform2D] that will flip something along the X axis.
</constant> </constant>
<constant name="FLIP_Y" value="Transform2D( 1, 0, 0, -1, 0, 0 )"> <constant name="FLIP_Y" value="Transform2D( 1, 0, 0, -1, 0, 0 )">
[Transform2D] with mirroring applied parallel to the Y axis. The [Transform2D] that will flip something along the Y axis.
</constant> </constant>
</constants> </constants>
</class> </class>

View File

@ -33,7 +33,7 @@
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the vector's angle in radians with respect to the X axis, or [code](1, 0)[/code] vector. Returns this vector's angle with respect to the X axis, or [code](1, 0)[/code] vector, in radians.
Equivalent to the result of [method @GDScript.atan2] when called with the vector's [member y] and [member x] as parameters: [code]atan2(y, x)[/code]. Equivalent to the result of [method @GDScript.atan2] when called with the vector's [member y] and [member x] as parameters: [code]atan2(y, x)[/code].
</description> </description>
</method> </method>
@ -43,7 +43,7 @@
<argument index="0" name="to" type="Vector2"> <argument index="0" name="to" type="Vector2">
</argument> </argument>
<description> <description>
Returns the angle in radians between the two vectors. Returns the angle to the given vector, in radians.
</description> </description>
</method> </method>
<method name="angle_to_point"> <method name="angle_to_point">
@ -52,14 +52,14 @@
<argument index="0" name="to" type="Vector2"> <argument index="0" name="to" type="Vector2">
</argument> </argument>
<description> <description>
Returns the angle in radians between the line connecting the two points and the X coordinate. Returns the angle between the line connecting the two points and the X axis, in radians.
</description> </description>
</method> </method>
<method name="aspect"> <method name="aspect">
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the ratio of [member x] to [member y]. Returns the aspect ratio of this vector, the ratio of [member x] to [member y].
</description> </description>
</method> </method>
<method name="bounce"> <method name="bounce">
@ -75,7 +75,7 @@
<return type="Vector2"> <return type="Vector2">
</return> </return>
<description> <description>
Returns the vector with all components rounded up. Returns the vector with all components rounded up (towards positive infinity).
</description> </description>
</method> </method>
<method name="clamped"> <method name="clamped">
@ -84,7 +84,7 @@
<argument index="0" name="length" type="float"> <argument index="0" name="length" type="float">
</argument> </argument>
<description> <description>
Returns the vector with a maximum length. Returns the vector with a maximum length by limiting its length to [code]length[/code].
</description> </description>
</method> </method>
<method name="cross"> <method name="cross">
@ -93,7 +93,7 @@
<argument index="0" name="with" type="Vector2"> <argument index="0" name="with" type="Vector2">
</argument> </argument>
<description> <description>
Returns the 2-dimensional analog of the cross product with the given vector. Returns the cross product of this vector and [code]with[/code].
</description> </description>
</method> </method>
<method name="cubic_interpolate"> <method name="cubic_interpolate">
@ -108,7 +108,7 @@
<argument index="3" name="t" type="float"> <argument index="3" name="t" type="float">
</argument> </argument>
<description> <description>
Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation. Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description> </description>
</method> </method>
<method name="direction_to"> <method name="direction_to">
@ -126,7 +126,8 @@
<argument index="0" name="to" type="Vector2"> <argument index="0" name="to" type="Vector2">
</argument> </argument>
<description> <description>
Returns the squared distance to vector [code]b[/code]. Prefer this function over [method distance_to] if you need to sort vectors or need the squared distance for some formula. Returns the squared distance between this vector and [code]b[/code].
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description> </description>
</method> </method>
<method name="distance_to"> <method name="distance_to">
@ -135,7 +136,7 @@
<argument index="0" name="to" type="Vector2"> <argument index="0" name="to" type="Vector2">
</argument> </argument>
<description> <description>
Returns the distance to vector [code]b[/code]. Returns the distance between this vector and [code]to[/code].
</description> </description>
</method> </method>
<method name="dot"> <method name="dot">
@ -144,14 +145,17 @@
<argument index="0" name="with" type="Vector2"> <argument index="0" name="with" type="Vector2">
</argument> </argument>
<description> <description>
Returns the dot product with vector [code]b[/code]. Returns the dot product of this vector and [code]with[/code]. This can be used to compare the angle between two vectors. For example, this can be used to determine whether an enemy is facing the player.
The dot product will be [code]0[/code] for a straight angle (90 degrees), greater than 0 for angles narrower than 90 degrees and lower than 0 for angles wider than 90 degrees.
When using unit (normalized) vectors, the result will always be between [code]-1.0[/code] (180 degree angle) when the vectors are facing opposite directions, and [code]1.0[/code] (0 degree angle) when the vectors are aligned.
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
</description> </description>
</method> </method>
<method name="floor"> <method name="floor">
<return type="Vector2"> <return type="Vector2">
</return> </return>
<description> <description>
Returns the vector with all components rounded down. Returns the vector with all components rounded down (towards negative infinity).
</description> </description>
</method> </method>
<method name="is_equal_approx"> <method name="is_equal_approx">
@ -167,21 +171,22 @@
<return type="bool"> <return type="bool">
</return> </return>
<description> <description>
Returns [code]true[/code] if the vector is normalized. Returns [code]true[/code] if the vector is normalized, and false otherwise.
</description> </description>
</method> </method>
<method name="length"> <method name="length">
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the vector's length. Returns the length (magnitude) of this vector.
</description> </description>
</method> </method>
<method name="length_squared"> <method name="length_squared">
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the vector's length squared. Prefer this method over [method length] if you need to sort vectors or need the squared length for some formula. Returns the squared length (squared magnitude) of this vector.
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description> </description>
</method> </method>
<method name="linear_interpolate"> <method name="linear_interpolate">
@ -192,7 +197,7 @@
<argument index="1" name="t" type="float"> <argument index="1" name="t" type="float">
</argument> </argument>
<description> <description>
Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation. Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description> </description>
</method> </method>
<method name="move_toward"> <method name="move_toward">
@ -219,7 +224,7 @@
<argument index="0" name="mod" type="float"> <argument index="0" name="mod" type="float">
</argument> </argument>
<description> <description>
Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]mod[/code]. Returns a vector composed of the [method @GDScript.fposmod] of this vector's components and [code]mod[/code].
</description> </description>
</method> </method>
<method name="posmodv"> <method name="posmodv">
@ -228,7 +233,7 @@
<argument index="0" name="modv" type="Vector2"> <argument index="0" name="modv" type="Vector2">
</argument> </argument>
<description> <description>
Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]modv[/code]'s components. Returns a vector composed of the [method @GDScript.fposmod] of this vector's components and [code]modv[/code]'s components.
</description> </description>
</method> </method>
<method name="project"> <method name="project">
@ -269,7 +274,7 @@
<return type="Vector2"> <return type="Vector2">
</return> </return>
<description> <description>
Returns the vector with each component set to one or negative one, depending on the signs of the components. Returns the vector with each component set to one or negative one, depending on the signs of the components, or zero if the component is zero, by calling [method @GDScript.sign] on each component.
</description> </description>
</method> </method>
<method name="slerp"> <method name="slerp">
@ -280,7 +285,7 @@
<argument index="1" name="t" type="float"> <argument index="1" name="t" type="float">
</argument> </argument>
<description> <description>
Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation. Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized. [b]Note:[/b] Both vectors must be normalized.
</description> </description>
</method> </method>
@ -290,7 +295,7 @@
<argument index="0" name="n" type="Vector2"> <argument index="0" name="n" type="Vector2">
</argument> </argument>
<description> <description>
Returns the component of the vector along a plane defined by the given normal. Returns this vector slid along a plane defined by the given normal.
</description> </description>
</method> </method>
<method name="snapped"> <method name="snapped">
@ -299,14 +304,14 @@
<argument index="0" name="by" type="Vector2"> <argument index="0" name="by" type="Vector2">
</argument> </argument>
<description> <description>
Returns the vector snapped to a grid with the given size. Returns this vector with each component snapped to the nearest multiple of [code]step[/code]. This can also be used to round to an arbitrary number of decimals.
</description> </description>
</method> </method>
<method name="tangent"> <method name="tangent">
<return type="Vector2"> <return type="Vector2">
</return> </return>
<description> <description>
Returns a perpendicular vector. Returns a perpendicular vector rotated 90 degrees counter-clockwise compared to the original, with the same length.
</description> </description>
</method> </method>
</methods> </methods>
@ -326,25 +331,25 @@
Enumerated value for the Y axis. Enumerated value for the Y axis.
</constant> </constant>
<constant name="ZERO" value="Vector2( 0, 0 )"> <constant name="ZERO" value="Vector2( 0, 0 )">
Zero vector. Zero vector, a vector with all components set to [code]0[/code].
</constant> </constant>
<constant name="ONE" value="Vector2( 1, 1 )"> <constant name="ONE" value="Vector2( 1, 1 )">
One vector. One vector, a vector with all components set to [code]1[/code].
</constant> </constant>
<constant name="INF" value="Vector2( inf, inf )"> <constant name="INF" value="Vector2( inf, inf )">
Infinity vector. Infinity vector, a vector with all components set to [constant @GDScript.INF].
</constant> </constant>
<constant name="LEFT" value="Vector2( -1, 0 )"> <constant name="LEFT" value="Vector2( -1, 0 )">
Left unit vector. Left unit vector. Represents the direction of left.
</constant> </constant>
<constant name="RIGHT" value="Vector2( 1, 0 )"> <constant name="RIGHT" value="Vector2( 1, 0 )">
Right unit vector. Right unit vector. Represents the direction of right.
</constant> </constant>
<constant name="UP" value="Vector2( 0, -1 )"> <constant name="UP" value="Vector2( 0, -1 )">
Up unit vector. Up unit vector. Y is down in 2D, so this vector points -Y.
</constant> </constant>
<constant name="DOWN" value="Vector2( 0, 1 )"> <constant name="DOWN" value="Vector2( 0, 1 )">
Down unit vector. Down unit vector. Y is down in 2D, so this vector points +Y.
</constant> </constant>
</constants> </constants>
</class> </class>

View File

@ -37,7 +37,7 @@
<argument index="0" name="to" type="Vector3"> <argument index="0" name="to" type="Vector3">
</argument> </argument>
<description> <description>
Returns the minimum angle to the given vector. Returns the minimum angle to the given vector, in radians.
</description> </description>
</method> </method>
<method name="bounce"> <method name="bounce">
@ -53,7 +53,7 @@
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns a new vector with all components rounded up. Returns a new vector with all components rounded up (towards positive infinity).
</description> </description>
</method> </method>
<method name="cross"> <method name="cross">
@ -62,7 +62,7 @@
<argument index="0" name="b" type="Vector3"> <argument index="0" name="b" type="Vector3">
</argument> </argument>
<description> <description>
Returns the cross product with [code]b[/code]. Returns the cross product of this vector and [code]b[/code].
</description> </description>
</method> </method>
<method name="cubic_interpolate"> <method name="cubic_interpolate">
@ -77,7 +77,7 @@
<argument index="3" name="t" type="float"> <argument index="3" name="t" type="float">
</argument> </argument>
<description> <description>
Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation. Performs a cubic interpolation between vectors [code]pre_a[/code], [code]a[/code], [code]b[/code], [code]post_b[/code] ([code]a[/code] is current), by the given amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description> </description>
</method> </method>
<method name="direction_to"> <method name="direction_to">
@ -95,7 +95,8 @@
<argument index="0" name="b" type="Vector3"> <argument index="0" name="b" type="Vector3">
</argument> </argument>
<description> <description>
Returns the squared distance to [code]b[/code]. Prefer this function over [method distance_to] if you need to sort vectors or need the squared distance for some formula. Returns the squared distance between this vector and [code]b[/code].
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description> </description>
</method> </method>
<method name="distance_to"> <method name="distance_to">
@ -104,7 +105,7 @@
<argument index="0" name="b" type="Vector3"> <argument index="0" name="b" type="Vector3">
</argument> </argument>
<description> <description>
Returns the distance to [code]b[/code]. Returns the distance between this vector and [code]b[/code].
</description> </description>
</method> </method>
<method name="dot"> <method name="dot">
@ -113,14 +114,17 @@
<argument index="0" name="b" type="Vector3"> <argument index="0" name="b" type="Vector3">
</argument> </argument>
<description> <description>
Returns the dot product with [code]b[/code]. Returns the dot product of this vector and [code]b[/code]. This can be used to compare the angle between two vectors. For example, this can be used to determine whether an enemy is facing the player.
The dot product will be [code]0[/code] for a straight angle (90 degrees), greater than 0 for angles narrower than 90 degrees and lower than 0 for angles wider than 90 degrees.
When using unit (normalized) vectors, the result will always be between [code]-1.0[/code] (180 degree angle) when the vectors are facing opposite directions, and [code]1.0[/code] (0 degree angle) when the vectors are aligned.
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
</description> </description>
</method> </method>
<method name="floor"> <method name="floor">
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns a new vector with all components rounded down. Returns a new vector with all components rounded down (towards negative infinity).
</description> </description>
</method> </method>
<method name="inverse"> <method name="inverse">
@ -143,21 +147,22 @@
<return type="bool"> <return type="bool">
</return> </return>
<description> <description>
Returns [code]true[/code] if the vector is normalized. Returns [code]true[/code] if the vector is normalized, and false otherwise.
</description> </description>
</method> </method>
<method name="length"> <method name="length">
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the vector's length. Returns the length (magnitude) of this vector.
</description> </description>
</method> </method>
<method name="length_squared"> <method name="length_squared">
<return type="float"> <return type="float">
</return> </return>
<description> <description>
Returns the vector's length squared. Prefer this function over [method length] if you need to sort vectors or need the squared length for some formula. Returns the squared length (squared magnitude) of this vector.
This method runs faster than [method length], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description> </description>
</method> </method>
<method name="linear_interpolate"> <method name="linear_interpolate">
@ -168,21 +173,21 @@
<argument index="1" name="t" type="float"> <argument index="1" name="t" type="float">
</argument> </argument>
<description> <description>
Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation.. Returns the result of the linear interpolation between this vector and [code]b[/code] by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description> </description>
</method> </method>
<method name="max_axis"> <method name="max_axis">
<return type="int"> <return type="int">
</return> </return>
<description> <description>
Returns the axis of the vector's largest value. See [code]AXIS_*[/code] constants. Returns the axis of the vector's largest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_X].
</description> </description>
</method> </method>
<method name="min_axis"> <method name="min_axis">
<return type="int"> <return type="int">
</return> </return>
<description> <description>
Returns the axis of the vector's smallest value. See [code]AXIS_*[/code] constants. Returns the axis of the vector's smallest value. See [code]AXIS_*[/code] constants. If all components are equal, this method returns [constant AXIS_Z].
</description> </description>
</method> </method>
<method name="move_toward"> <method name="move_toward">
@ -193,7 +198,7 @@
<argument index="1" name="delta" type="float"> <argument index="1" name="delta" type="float">
</argument> </argument>
<description> <description>
Moves the vector toward [code]to[/code] by the fixed [code]delta[/code] amount. Moves this vector toward [code]to[/code] by the fixed [code]delta[/code] amount.
</description> </description>
</method> </method>
<method name="normalized"> <method name="normalized">
@ -218,7 +223,7 @@
<argument index="0" name="mod" type="float"> <argument index="0" name="mod" type="float">
</argument> </argument>
<description> <description>
Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]mod[/code]. Returns a vector composed of the [method @GDScript.fposmod] of this vector's components and [code]mod[/code].
</description> </description>
</method> </method>
<method name="posmodv"> <method name="posmodv">
@ -227,7 +232,7 @@
<argument index="0" name="modv" type="Vector3"> <argument index="0" name="modv" type="Vector3">
</argument> </argument>
<description> <description>
Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]modv[/code]'s components. Returns a vector composed of the [method @GDScript.fposmod] of this vector's components and [code]modv[/code]'s components.
</description> </description>
</method> </method>
<method name="project"> <method name="project">
@ -236,7 +241,7 @@
<argument index="0" name="b" type="Vector3"> <argument index="0" name="b" type="Vector3">
</argument> </argument>
<description> <description>
Returns the vector projected onto the vector [code]b[/code]. Returns this vector projected onto another vector [code]b[/code].
</description> </description>
</method> </method>
<method name="reflect"> <method name="reflect">
@ -245,7 +250,7 @@
<argument index="0" name="n" type="Vector3"> <argument index="0" name="n" type="Vector3">
</argument> </argument>
<description> <description>
Returns the vector reflected from a plane defined by the given normal. Returns this vector reflected from a plane defined by the given normal.
</description> </description>
</method> </method>
<method name="rotated"> <method name="rotated">
@ -256,21 +261,21 @@
<argument index="1" name="phi" type="float"> <argument index="1" name="phi" type="float">
</argument> </argument>
<description> <description>
Rotates the vector around a given axis by [code]phi[/code] radians. The axis must be a normalized vector. Rotates this vector around a given axis by [code]phi[/code] radians. The axis must be a normalized vector.
</description> </description>
</method> </method>
<method name="round"> <method name="round">
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero. Returns this vector with all components rounded to the nearest integer, with halfway cases rounded away from zero.
</description> </description>
</method> </method>
<method name="sign"> <method name="sign">
<return type="Vector3"> <return type="Vector3">
</return> </return>
<description> <description>
Returns the vector with each component set to one or negative one, depending on the signs of the components. Returns a vector with each component set to one or negative one, depending on the signs of this vector's components, or zero if the component is zero, by calling [method @GDScript.sign] on each component.
</description> </description>
</method> </method>
<method name="slerp"> <method name="slerp">
@ -281,7 +286,7 @@
<argument index="1" name="t" type="float"> <argument index="1" name="t" type="float">
</argument> </argument>
<description> <description>
Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is in the range of [code]0.0 - 1.0[/code], representing the amount of interpolation. Returns the result of spherical linear interpolation between this vector and [code]b[/code], by amount [code]t[/code]. [code]t[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized. [b]Note:[/b] Both vectors must be normalized.
</description> </description>
</method> </method>
@ -291,7 +296,7 @@
<argument index="0" name="n" type="Vector3"> <argument index="0" name="n" type="Vector3">
</argument> </argument>
<description> <description>
Returns the component of the vector along a plane defined by the given normal. Returns this vector slid along a plane defined by the given normal.
</description> </description>
</method> </method>
<method name="snapped"> <method name="snapped">
@ -300,7 +305,7 @@
<argument index="0" name="by" type="Vector3"> <argument index="0" name="by" type="Vector3">
</argument> </argument>
<description> <description>
Returns the vector snapped to a grid with the given size. Returns this vector with each component snapped to the nearest multiple of [code]step[/code]. This can also be used to round to an arbitrary number of decimals.
</description> </description>
</method> </method>
<method name="to_diagonal_matrix"> <method name="to_diagonal_matrix">
@ -308,6 +313,7 @@
</return> </return>
<description> <description>
Returns a diagonal matrix with the vector as main diagonal. Returns a diagonal matrix with the vector as main diagonal.
This is equivalent to a Basis with no rotation or shearing and this vector's components set as the scale.
</description> </description>
</method> </method>
</methods> </methods>
@ -333,19 +339,19 @@
Enumerated value for the Z axis. Returned by [method max_axis] and [method min_axis]. Enumerated value for the Z axis. Returned by [method max_axis] and [method min_axis].
</constant> </constant>
<constant name="ZERO" value="Vector3( 0, 0, 0 )"> <constant name="ZERO" value="Vector3( 0, 0, 0 )">
Zero vector. Zero vector, a vector with all components set to [code]0[/code].
</constant> </constant>
<constant name="ONE" value="Vector3( 1, 1, 1 )"> <constant name="ONE" value="Vector3( 1, 1, 1 )">
One vector. One vector, a vector with all components set to [code]1[/code].
</constant> </constant>
<constant name="INF" value="Vector3( inf, inf, inf )"> <constant name="INF" value="Vector3( inf, inf, inf )">
Infinity vector. Infinity vector, a vector with all components set to [constant @GDScript.INF].
</constant> </constant>
<constant name="LEFT" value="Vector3( -1, 0, 0 )"> <constant name="LEFT" value="Vector3( -1, 0, 0 )">
Left unit vector. Left unit vector. Represents the local direction of left, and the global direction of west.
</constant> </constant>
<constant name="RIGHT" value="Vector3( 1, 0, 0 )"> <constant name="RIGHT" value="Vector3( 1, 0, 0 )">
Right unit vector. Right unit vector. Represents the local direction of right, and the global direction of east.
</constant> </constant>
<constant name="UP" value="Vector3( 0, 1, 0 )"> <constant name="UP" value="Vector3( 0, 1, 0 )">
Up unit vector. Up unit vector.
@ -354,10 +360,10 @@
Down unit vector. Down unit vector.
</constant> </constant>
<constant name="FORWARD" value="Vector3( 0, 0, -1 )"> <constant name="FORWARD" value="Vector3( 0, 0, -1 )">
Forward unit vector. Forward unit vector. Represents the local direction of forward, and the global direction of north.
</constant> </constant>
<constant name="BACK" value="Vector3( 0, 0, 1 )"> <constant name="BACK" value="Vector3( 0, 0, 1 )">
Back unit vector. Back unit vector. Represents the local direction of back, and the global direction of south.
</constant> </constant>
</constants> </constants>
</class> </class>

View File

@ -52,7 +52,7 @@
<argument index="0" name="s" type="float"> <argument index="0" name="s" type="float">
</argument> </argument>
<description> <description>
Returns the absolute value of parameter [code]s[/code] (i.e. unsigned value, works for integer and float). Returns the absolute value of parameter [code]s[/code] (i.e. positive value).
[codeblock] [codeblock]
# a is 1 # a is 1
a = abs(-1) a = abs(-1)
@ -112,7 +112,7 @@
</argument> </argument>
<description> <description>
Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code]. Returns the arc tangent of [code]s[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry: [code]atan(tan(angle)) == angle[/code].
The method cannot know in which quadrant the angle should fall. See [method atan2] if you always want an exact angle. The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[code] and [code]x[/code].
[codeblock] [codeblock]
a = atan(0.5) # a is 0.463648 a = atan(0.5) # a is 0.463648
[/codeblock] [/codeblock]
@ -127,6 +127,7 @@
</argument> </argument>
<description> <description>
Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle of tangent [code]y/x[/code]. To compute the value, the method takes into account the sign of both arguments in order to determine the quadrant. Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle of tangent [code]y/x[/code]. To compute the value, the method takes into account the sign of both arguments in order to determine the quadrant.
Important note: The Y coordinate comes first, by convention.
[codeblock] [codeblock]
a = atan2(0, -1) # a is 3.141593 a = atan2(0, -1) # a is 3.141593
[/codeblock] [/codeblock]
@ -161,7 +162,7 @@
<argument index="0" name="s" type="float"> <argument index="0" name="s" type="float">
</argument> </argument>
<description> <description>
Rounds [code]s[/code] upward, returning the smallest integral value that is not less than [code]s[/code]. Rounds [code]s[/code] upward (towards positive infinity), returning the smallest whole number that is not less than [code]s[/code].
[codeblock] [codeblock]
i = ceil(1.45) # i is 2 i = ceil(1.45) # i is 2
i = ceil(1.001) # i is 2 i = ceil(1.001) # i is 2
@ -292,7 +293,7 @@
<argument index="0" name="deg" type="float"> <argument index="0" name="deg" type="float">
</argument> </argument>
<description> <description>
Returns degrees converted to radians. Converts an angle expressed in degrees to radians.
[codeblock] [codeblock]
# r is 3.141593 # r is 3.141593
r = deg2rad(180) r = deg2rad(180)
@ -316,7 +317,7 @@
<argument index="1" name="curve" type="float"> <argument index="1" name="curve" type="float">
</argument> </argument>
<description> <description>
Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in. Easing function, based on exponent. The curve values are: 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in.
</description> </description>
</method> </method>
<method name="exp"> <method name="exp">
@ -339,7 +340,7 @@
<argument index="0" name="s" type="float"> <argument index="0" name="s" type="float">
</argument> </argument>
<description> <description>
Rounds [code]s[/code] to the closest smaller integer and returns it. Rounds [code]s[/code] downward (towards negative infinity), returning the largest whole number that is not more than [code]s[/code].
[codeblock] [codeblock]
# a is 2.0 # a is 2.0
a = floor(2.99) a = floor(2.99)
@ -539,7 +540,7 @@
<argument index="0" name="s" type="float"> <argument index="0" name="s" type="float">
</argument> </argument>
<description> <description>
Returns whether [code]s[/code] is a NaN (Not-A-Number) value. Returns whether [code]s[/code] is a NaN ("Not a Number" or invalid) value.
</description> </description>
</method> </method>
<method name="is_zero_approx"> <method name="is_zero_approx">
@ -549,6 +550,7 @@
</argument> </argument>
<description> <description>
Returns [code]true[/code] if [code]s[/code] is zero or almost zero. Returns [code]true[/code] if [code]s[/code] is zero or almost zero.
This method is faster than using [method is_equal_approx] with one value as zero.
</description> </description>
</method> </method>
<method name="len"> <method name="len">
@ -916,7 +918,7 @@
<argument index="0" name="rad" type="float"> <argument index="0" name="rad" type="float">
</argument> </argument>
<description> <description>
Converts from radians to degrees. Converts an angle expressed in radians to degrees.
[codeblock] [codeblock]
rad2deg(0.523599) # Returns 30 rad2deg(0.523599) # Returns 30
[/codeblock] [/codeblock]
@ -1035,7 +1037,7 @@
<argument index="0" name="s" type="float"> <argument index="0" name="s" type="float">
</argument> </argument>
<description> <description>
Returns the integral value that is nearest to [code]s[/code], with halfway cases rounded away from zero. Rounds [code]s[/code] to the nearest whole number, with halfway cases rounded away from zero.
[codeblock] [codeblock]
round(2.6) # Returns 3 round(2.6) # Returns 3
[/codeblock] [/codeblock]
@ -1117,10 +1119,11 @@
<argument index="0" name="s" type="float"> <argument index="0" name="s" type="float">
</argument> </argument>
<description> <description>
Returns the square root of [code]s[/code]. Returns the square root of [code]s[/code], where [code]s[/code] is a non-negative number.
[codeblock] [codeblock]
sqrt(9) # Returns 3 sqrt(9) # Returns 3
[/codeblock] [/codeblock]
If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
</description> </description>
</method> </method>
<method name="step_decimals"> <method name="step_decimals">
@ -1321,27 +1324,19 @@
Wraps float [code]value[/code] between [code]min[/code] and [code]max[/code]. Wraps float [code]value[/code] between [code]min[/code] and [code]max[/code].
Usable for creating loop-alike behavior or infinite surfaces. Usable for creating loop-alike behavior or infinite surfaces.
[codeblock] [codeblock]
# a is 0.5 # Infinite loop between 5.0 and 9.9
a = wrapf(10.5, 0.0, 10.0) value = wrapf(value + 0.1, 5.0, 10.0)
[/codeblock]
[codeblock]
# a is 9.5
a = wrapf(-0.5, 0.0, 10.0)
[/codeblock]
[codeblock]
# Infinite loop between 0.0 and 0.99
f = wrapf(f + 0.1, 0.0, 1.0)
[/codeblock] [/codeblock]
[codeblock] [codeblock]
# Infinite rotation (in radians) # Infinite rotation (in radians)
angle = wrapf(angle + 0.1, 0.0, TAU) angle = wrapf(angle + 0.1, 0.0, TAU)
[/codeblock] [/codeblock]
[b]Note:[/b] If you just want to wrap between 0.0 and [code]n[/code] (where [code]n[/code] is a positive floating-point value), it is better for performance to use the [method fmod] method like [code]fmod(number, n)[/code].
[code]wrapf[/code] is more flexible than using the [method fmod] approach by giving the user a simple control over the minimum value. It also fully supports negative numbers, e.g.
[codeblock] [codeblock]
# Infinite rotation (in radians) # Infinite rotation (in radians)
angle = wrapf(angle + 0.1, -PI, PI) angle = wrapf(angle + 0.1, -PI, PI)
[/codeblock] [/codeblock]
[b]Note:[/b] If [code]min[/code] is [code]0[/code], this is equivalent to [method fposmod], so prefer using that instead.
[code]wrapf[/code] is more flexible than using the [method fposmod] approach by giving the user control over the minimum value.
</description> </description>
</method> </method>
<method name="wrapi"> <method name="wrapi">
@ -1357,23 +1352,15 @@
Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/code]. Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/code].
Usable for creating loop-alike behavior or infinite surfaces. Usable for creating loop-alike behavior or infinite surfaces.
[codeblock] [codeblock]
# a is 0 # Infinite loop between 5 and 9
a = wrapi(10, 0, 10) frame = wrapi(frame + 1, 5, 10)
[/codeblock] [/codeblock]
[codeblock] [codeblock]
# a is 9
a = wrapi(-1, 0, 10)
[/codeblock]
[codeblock]
# Infinite loop between 0 and 9
frame = wrapi(frame + 1, 0, 10)
[/codeblock]
[b]Note:[/b] If you just want to wrap between 0 and [code]n[/code] (where [code]n[/code] is a positive integer value), it is better for performance to use the modulo operator like [code]number % n[/code].
[code]wrapi[/code] is more flexible than using the modulo approach by giving the user a simple control over the minimum value. It also fully supports negative numbers, e.g.
[codeblock]
# result is -2 # result is -2
var result = wrapi(-6, -5, -1) var result = wrapi(-6, -5, -1)
[/codeblock] [/codeblock]
[b]Note:[/b] If [code]min[/code] is [code]0[/code], this is equivalent to [method posmod], so prefer using that instead.
[code]wrapi[/code] is more flexible than using the [method posmod] approach by giving the user control over the minimum value.
</description> </description>
</method> </method>
<method name="yield"> <method name="yield">
@ -1415,17 +1402,16 @@
</methods> </methods>
<constants> <constants>
<constant name="PI" value="3.141593"> <constant name="PI" value="3.141593">
Constant that represents how many times the diameter of a circle fits around its perimeter. Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code].
</constant> </constant>
<constant name="TAU" value="6.283185"> <constant name="TAU" value="6.283185">
The circle constant, the circumference of the unit circle. The circle constant, the circumference of the unit circle in radians.
</constant> </constant>
<constant name="INF" value="inf"> <constant name="INF" value="inf">
A positive infinity. (For negative infinity, use -INF). Positive infinity. For negative infinity, use -INF.
</constant> </constant>
<constant name="NAN" value="nan"> <constant name="NAN" value="nan">
Macro constant that expands to an expression of type float that represents a NaN. "Not a Number", an invalid value. [code]NaN[/code] has special properties, including that it is not equal to itself. It is output by some invalid operations, such as dividing zero by zero.
The NaN values are used to identify undefined or non-representable values for floating-point elements, such as the square root of negative numbers or the result of 0/0.
</constant> </constant>
</constants> </constants>
</class> </class>

View File

@ -14,6 +14,10 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// Axis-Aligned Bounding Box. AABB consists of a position, a size, and
/// several utility functions. It is typically used for fast overlap tests.
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct AABB : IEquatable<AABB> public struct AABB : IEquatable<AABB>
@ -21,24 +25,55 @@ namespace Godot
private Vector3 _position; private Vector3 _position;
private Vector3 _size; private Vector3 _size;
/// <summary>
/// Beginning corner. Typically has values lower than End.
/// </summary>
/// <value>Directly uses a private field.</value>
public Vector3 Position public Vector3 Position
{ {
get { return _position; } get { return _position; }
set { _position = value; } set { _position = value; }
} }
/// <summary>
/// Size from Position to End. Typically all components are positive.
/// If the size is negative, you can use <see cref="Abs"/> to fix it.
/// </summary>
/// <value>Directly uses a private field.</value>
public Vector3 Size public Vector3 Size
{ {
get { return _size; } get { return _size; }
set { _size = value; } set { _size = value; }
} }
/// <summary>
/// Ending corner. This is calculated as <see cref="Position"/> plus
/// <see cref="Size"/>. Setting this value will change the size.
/// </summary>
/// <value>Getting is equivalent to `value = Position + Size`, setting is equivalent to `Size = value - Position`.</value>
public Vector3 End public Vector3 End
{ {
get { return _position + _size; } get { return _position + _size; }
set { _size = value - _position; } set { _size = value - _position; }
} }
/// <summary>
/// Returns an AABB with equivalent position and size, modified so that
/// the most-negative corner is the origin and the size is positive.
/// </summary>
/// <returns>The modified AABB.</returns>
public AABB Abs()
{
Vector3 end = End;
Vector3 topLeft = new Vector3(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y), Mathf.Min(_position.z, end.z));
return new AABB(topLeft, _size.Abs());
}
/// <summary>
/// Returns true if this AABB completely encloses another one.
/// </summary>
/// <param name="with">The other AABB that may be enclosed.</param>
/// <returns>A bool for whether or not this AABB encloses `b`.</returns>
public bool Encloses(AABB with) public bool Encloses(AABB with)
{ {
Vector3 src_min = _position; Vector3 src_min = _position;
@ -54,33 +89,59 @@ namespace Godot
src_max.z > dst_max.z; src_max.z > dst_max.z;
} }
/// <summary>
/// Returns this AABB expanded to include a given point.
/// </summary>
/// <param name="point">The point to include.</param>
/// <returns>The expanded AABB.</returns>
public AABB Expand(Vector3 point) public AABB Expand(Vector3 point)
{ {
Vector3 begin = _position; Vector3 begin = _position;
Vector3 end = _position + _size; Vector3 end = _position + _size;
if (point.x < begin.x) if (point.x < begin.x)
{
begin.x = point.x; begin.x = point.x;
}
if (point.y < begin.y) if (point.y < begin.y)
{
begin.y = point.y; begin.y = point.y;
}
if (point.z < begin.z) if (point.z < begin.z)
{
begin.z = point.z; begin.z = point.z;
}
if (point.x > end.x) if (point.x > end.x)
{
end.x = point.x; end.x = point.x;
}
if (point.y > end.y) if (point.y > end.y)
{
end.y = point.y; end.y = point.y;
}
if (point.z > end.z) if (point.z > end.z)
{
end.z = point.z; end.z = point.z;
}
return new AABB(begin, end - begin); return new AABB(begin, end - begin);
} }
/// <summary>
/// Returns the area of the AABB.
/// </summary>
/// <returns>The area.</returns>
public real_t GetArea() public real_t GetArea()
{ {
return _size.x * _size.y * _size.z; return _size.x * _size.y * _size.z;
} }
/// <summary>
/// Gets the position of one of the 8 endpoints of the AABB.
/// </summary>
/// <param name="idx">Which endpoint to get.</param>
/// <returns>An endpoint of the AABB.</returns>
public Vector3 GetEndpoint(int idx) public Vector3 GetEndpoint(int idx)
{ {
switch (idx) switch (idx)
@ -106,6 +167,10 @@ namespace Godot
} }
} }
/// <summary>
/// Returns the normalized longest axis of the AABB.
/// </summary>
/// <returns>A vector representing the normalized longest axis of the AABB.</returns>
public Vector3 GetLongestAxis() public Vector3 GetLongestAxis()
{ {
var axis = new Vector3(1f, 0f, 0f); var axis = new Vector3(1f, 0f, 0f);
@ -125,6 +190,10 @@ namespace Godot
return axis; return axis;
} }
/// <summary>
/// Returns the <see cref="Vector3.Axis"/> index of the longest axis of the AABB.
/// </summary>
/// <returns>A <see cref="Vector3.Axis"/> index for which axis is longest.</returns>
public Vector3.Axis GetLongestAxisIndex() public Vector3.Axis GetLongestAxisIndex()
{ {
var axis = Vector3.Axis.X; var axis = Vector3.Axis.X;
@ -144,6 +213,10 @@ namespace Godot
return axis; return axis;
} }
/// <summary>
/// Returns the scalar length of the longest axis of the AABB.
/// </summary>
/// <returns>The scalar length of the longest axis of the AABB.</returns>
public real_t GetLongestAxisSize() public real_t GetLongestAxisSize()
{ {
real_t max_size = _size.x; real_t max_size = _size.x;
@ -157,6 +230,10 @@ namespace Godot
return max_size; return max_size;
} }
/// <summary>
/// Returns the normalized shortest axis of the AABB.
/// </summary>
/// <returns>A vector representing the normalized shortest axis of the AABB.</returns>
public Vector3 GetShortestAxis() public Vector3 GetShortestAxis()
{ {
var axis = new Vector3(1f, 0f, 0f); var axis = new Vector3(1f, 0f, 0f);
@ -176,6 +253,10 @@ namespace Godot
return axis; return axis;
} }
/// <summary>
/// Returns the <see cref="Vector3.Axis"/> index of the shortest axis of the AABB.
/// </summary>
/// <returns>A <see cref="Vector3.Axis"/> index for which axis is shortest.</returns>
public Vector3.Axis GetShortestAxisIndex() public Vector3.Axis GetShortestAxisIndex()
{ {
var axis = Vector3.Axis.X; var axis = Vector3.Axis.X;
@ -195,6 +276,10 @@ namespace Godot
return axis; return axis;
} }
/// <summary>
/// Returns the scalar length of the shortest axis of the AABB.
/// </summary>
/// <returns>The scalar length of the shortest axis of the AABB.</returns>
public real_t GetShortestAxisSize() public real_t GetShortestAxisSize()
{ {
real_t max_size = _size.x; real_t max_size = _size.x;
@ -208,6 +293,12 @@ namespace Godot
return max_size; return max_size;
} }
/// <summary>
/// Returns the support point in a given direction.
/// This is useful for collision detection algorithms.
/// </summary>
/// <param name="dir">The direction to find support for.</param>
/// <returns>A vector representing the support.</returns>
public Vector3 GetSupport(Vector3 dir) public Vector3 GetSupport(Vector3 dir)
{ {
Vector3 half_extents = _size * 0.5f; Vector3 half_extents = _size * 0.5f;
@ -219,6 +310,11 @@ namespace Godot
dir.z > 0f ? -half_extents.z : half_extents.z); dir.z > 0f ? -half_extents.z : half_extents.z);
} }
/// <summary>
/// Returns a copy of the AABB grown a given amount of units towards all the sides.
/// </summary>
/// <param name="by">The amount to grow by.</param>
/// <returns>The grown AABB.</returns>
public AABB Grow(real_t by) public AABB Grow(real_t by)
{ {
var res = this; var res = this;
@ -233,16 +329,29 @@ namespace Godot
return res; return res;
} }
/// <summary>
/// Returns true if the AABB is flat or empty, or false otherwise.
/// </summary>
/// <returns>A bool for whether or not the AABB has area.</returns>
public bool HasNoArea() public bool HasNoArea()
{ {
return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f; return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f;
} }
/// <summary>
/// Returns true if the AABB has no surface (no size), or false otherwise.
/// </summary>
/// <returns>A bool for whether or not the AABB has area.</returns>
public bool HasNoSurface() public bool HasNoSurface()
{ {
return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f; return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f;
} }
/// <summary>
/// Returns true if the AABB contains a point, or false otherwise.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>A bool for whether or not the AABB contains `point`.</returns>
public bool HasPoint(Vector3 point) public bool HasPoint(Vector3 point)
{ {
if (point.x < _position.x) if (point.x < _position.x)
@ -261,6 +370,11 @@ namespace Godot
return true; return true;
} }
/// <summary>
/// Returns the intersection of this AABB and `b`.
/// </summary>
/// <param name="with">The other AABB.</param>
/// <returns>The clipped AABB.</returns>
public AABB Intersection(AABB with) public AABB Intersection(AABB with)
{ {
Vector3 src_min = _position; Vector3 src_min = _position;
@ -297,24 +411,57 @@ namespace Godot
return new AABB(min, max - min); return new AABB(min, max - min);
} }
public bool Intersects(AABB with) /// <summary>
/// Returns true if the AABB overlaps with `b`
/// (i.e. they have at least one point in common).
///
/// If `includeBorders` is true, they will also be considered overlapping
/// if their borders touch, even without intersection.
/// </summary>
/// <param name="with">The other AABB to check for intersections with.</param>
/// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A bool for whether or not they are intersecting.</returns>
public bool Intersects(AABB with, bool includeBorders = false)
{ {
if (_position.x >= with._position.x + with._size.x) if (includeBorders)
return false; {
if (_position.x + _size.x <= with._position.x) if (_position.x > with._position.x + with._size.x)
return false; return false;
if (_position.y >= with._position.y + with._size.y) if (_position.x + _size.x < with._position.x)
return false; return false;
if (_position.y + _size.y <= with._position.y) if (_position.y > with._position.y + with._size.y)
return false; return false;
if (_position.z >= with._position.z + with._size.z) if (_position.y + _size.y < with._position.y)
return false; return false;
if (_position.z + _size.z <= with._position.z) if (_position.z > with._position.z + with._size.z)
return false; return false;
if (_position.z + _size.z < with._position.z)
return false;
}
else
{
if (_position.x >= with._position.x + with._size.x)
return false;
if (_position.x + _size.x <= with._position.x)
return false;
if (_position.y >= with._position.y + with._size.y)
return false;
if (_position.y + _size.y <= with._position.y)
return false;
if (_position.z >= with._position.z + with._size.z)
return false;
if (_position.z + _size.z <= with._position.z)
return false;
}
return true; return true;
} }
/// <summary>
/// Returns true if the AABB is on both sides of `plane`.
/// </summary>
/// <param name="plane">The plane to check for intersection.</param>
/// <returns>A bool for whether or not the AABB intersects the plane.</returns>
public bool IntersectsPlane(Plane plane) public bool IntersectsPlane(Plane plane)
{ {
Vector3[] points = Vector3[] points =
@ -335,14 +482,24 @@ namespace Godot
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
if (plane.DistanceTo(points[i]) > 0) if (plane.DistanceTo(points[i]) > 0)
{
over = true; over = true;
}
else else
{
under = true; under = true;
}
} }
return under && over; return under && over;
} }
/// <summary>
/// Returns true if the AABB intersects the line segment between `from` and `to`.
/// </summary>
/// <param name="from">The start of the line segment.</param>
/// <param name="to">The end of the line segment.</param>
/// <returns>A bool for whether or not the AABB intersects the line segment.</returns>
public bool IntersectsSegment(Vector3 from, Vector3 to) public bool IntersectsSegment(Vector3 from, Vector3 to)
{ {
real_t min = 0f; real_t min = 0f;
@ -359,7 +516,9 @@ namespace Godot
if (segFrom < segTo) if (segFrom < segTo)
{ {
if (segFrom > boxEnd || segTo < boxBegin) if (segFrom > boxEnd || segTo < boxBegin)
{
return false; return false;
}
real_t length = segTo - segFrom; real_t length = segTo - segFrom;
cmin = segFrom < boxBegin ? (boxBegin - segFrom) / length : 0f; cmin = segFrom < boxBegin ? (boxBegin - segFrom) / length : 0f;
@ -368,7 +527,9 @@ namespace Godot
else else
{ {
if (segTo > boxEnd || segFrom < boxBegin) if (segTo > boxEnd || segFrom < boxBegin)
{
return false; return false;
}
real_t length = segTo - segFrom; real_t length = segTo - segFrom;
cmin = segFrom > boxEnd ? (boxEnd - segFrom) / length : 0f; cmin = segFrom > boxEnd ? (boxEnd - segFrom) / length : 0f;
@ -381,14 +542,23 @@ namespace Godot
} }
if (cmax < max) if (cmax < max)
{
max = cmax; max = cmax;
}
if (max < min) if (max < min)
{
return false; return false;
}
} }
return true; return true;
} }
/// <summary>
/// Returns a larger AABB that contains this AABB and `b`.
/// </summary>
/// <param name="with">The other AABB.</param>
/// <returns>The merged AABB.</returns>
public AABB Merge(AABB with) public AABB Merge(AABB with)
{ {
Vector3 beg1 = _position; Vector3 beg1 = _position;
@ -411,22 +581,52 @@ namespace Godot
return new AABB(min, max - min); return new AABB(min, max - min);
} }
// Constructors /// <summary>
/// Constructs an AABB from a position and size.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="size">The size, typically positive.</param>
public AABB(Vector3 position, Vector3 size) public AABB(Vector3 position, Vector3 size)
{ {
_position = position; _position = position;
_size = size; _size = size;
} }
/// <summary>
/// Constructs an AABB from a position, width, height, and depth.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="width">The width, typically positive.</param>
/// <param name="height">The height, typically positive.</param>
/// <param name="depth">The depth, typically positive.</param>
public AABB(Vector3 position, real_t width, real_t height, real_t depth) public AABB(Vector3 position, real_t width, real_t height, real_t depth)
{ {
_position = position; _position = position;
_size = new Vector3(width, height, depth); _size = new Vector3(width, height, depth);
} }
/// <summary>
/// Constructs an AABB from x, y, z, and size.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="z">The position's Z coordinate.</param>
/// <param name="size">The size, typically positive.</param>
public AABB(real_t x, real_t y, real_t z, Vector3 size) public AABB(real_t x, real_t y, real_t z, Vector3 size)
{ {
_position = new Vector3(x, y, z); _position = new Vector3(x, y, z);
_size = size; _size = size;
} }
/// <summary>
/// Constructs an AABB from x, y, z, width, height, and depth.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="z">The position's Z coordinate.</param>
/// <param name="width">The width, typically positive.</param>
/// <param name="height">The height, typically positive.</param>
/// <param name="depth">The depth, typically positive.</param>
public AABB(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth) public AABB(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth)
{ {
_position = new Vector3(x, y, z); _position = new Vector3(x, y, z);
@ -458,6 +658,12 @@ namespace Godot
return _position == other._position && _size == other._size; return _position == other._position && _size == other._size;
} }
/// <summary>
/// Returns true if this AABB and `other` are approximately equal, by running
/// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component.
/// </summary>
/// <param name="other">The other AABB to compare.</param>
/// <returns>Whether or not the AABBs are approximately equal.</returns>
public bool IsEqualApprox(AABB other) public bool IsEqualApprox(AABB other)
{ {
return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size); return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size);

View File

@ -8,6 +8,20 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// 3×3 matrix used for 3D rotation and scale.
/// Almost always used as an orthogonal basis for a Transform.
///
/// Contains 3 vector fields X, Y and Z as its columns, which are typically
/// interpreted as the local basis vectors of a 3D transformation. For such use,
/// it is composed of a scaling and a rotation matrix, in that order (M = R.S).
///
/// Can also be accessed as array of 3D vectors. These vectors are normally
/// orthogonal to each other, but are not necessarily normalized (due to scaling).
///
/// For more information, read this documentation article:
/// https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Basis : IEquatable<Basis> public struct Basis : IEquatable<Basis>
@ -15,9 +29,9 @@ namespace Godot
// NOTE: x, y and z are public-only. Use Column0, Column1 and Column2 internally. // NOTE: x, y and z are public-only. Use Column0, Column1 and Column2 internally.
/// <summary> /// <summary>
/// Returns the basis matrixs x vector. /// The basis matrix's X vector (column 0).
/// This is equivalent to <see cref="Column0"/>.
/// </summary> /// </summary>
/// <value>Equivalent to <see cref="Column0"/> and array index `[0]`.</value>
public Vector3 x public Vector3 x
{ {
get => Column0; get => Column0;
@ -25,9 +39,9 @@ namespace Godot
} }
/// <summary> /// <summary>
/// Returns the basis matrixs y vector. /// The basis matrix's Y vector (column 1).
/// This is equivalent to <see cref="Column1"/>.
/// </summary> /// </summary>
/// <value>Equivalent to <see cref="Column1"/> and array index `[1]`.</value>
public Vector3 y public Vector3 y
{ {
get => Column1; get => Column1;
@ -35,19 +49,40 @@ namespace Godot
} }
/// <summary> /// <summary>
/// Returns the basis matrixs z vector. /// The basis matrix's Z vector (column 2).
/// This is equivalent to <see cref="Column2"/>.
/// </summary> /// </summary>
/// <value>Equivalent to <see cref="Column2"/> and array index `[2]`.</value>
public Vector3 z public Vector3 z
{ {
get => Column2; get => Column2;
set => Column2 = value; set => Column2 = value;
} }
/// <summary>
/// Row 0 of the basis matrix. Shows which vectors contribute
/// to the X direction. Rows are not very useful for user code,
/// but are more efficient for some internal calculations.
/// </summary>
public Vector3 Row0; public Vector3 Row0;
/// <summary>
/// Row 1 of the basis matrix. Shows which vectors contribute
/// to the Y direction. Rows are not very useful for user code,
/// but are more efficient for some internal calculations.
/// </summary>
public Vector3 Row1; public Vector3 Row1;
/// <summary>
/// Row 2 of the basis matrix. Shows which vectors contribute
/// to the Z direction. Rows are not very useful for user code,
/// but are more efficient for some internal calculations.
/// </summary>
public Vector3 Row2; public Vector3 Row2;
/// <summary>
/// Column 0 of the basis matrix (the X vector).
/// </summary>
/// <value>Equivalent to <see cref="x"/> and array index `[0]`.</value>
public Vector3 Column0 public Vector3 Column0
{ {
get => new Vector3(Row0.x, Row1.x, Row2.x); get => new Vector3(Row0.x, Row1.x, Row2.x);
@ -58,6 +93,11 @@ namespace Godot
this.Row2.x = value.z; this.Row2.x = value.z;
} }
} }
/// <summary>
/// Column 1 of the basis matrix (the Y vector).
/// </summary>
/// <value>Equivalent to <see cref="y"/> and array index `[1]`.</value>
public Vector3 Column1 public Vector3 Column1
{ {
get => new Vector3(Row0.y, Row1.y, Row2.y); get => new Vector3(Row0.y, Row1.y, Row2.y);
@ -68,6 +108,11 @@ namespace Godot
this.Row2.y = value.z; this.Row2.y = value.z;
} }
} }
/// <summary>
/// Column 2 of the basis matrix (the Z vector).
/// </summary>
/// <value>Equivalent to <see cref="z"/> and array index `[2]`.</value>
public Vector3 Column2 public Vector3 Column2
{ {
get => new Vector3(Row0.z, Row1.z, Row2.z); get => new Vector3(Row0.z, Row1.z, Row2.z);
@ -79,6 +124,10 @@ namespace Godot
} }
} }
/// <summary>
/// The scale of this basis.
/// </summary>
/// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value>
public Vector3 Scale public Vector3 Scale
{ {
get get
@ -86,11 +135,18 @@ namespace Godot
real_t detSign = Mathf.Sign(Determinant()); real_t detSign = Mathf.Sign(Determinant());
return detSign * new Vector3 return detSign * new Vector3
( (
new Vector3(this.Row0[0], this.Row1[0], this.Row2[0]).Length(), Column0.Length(),
new Vector3(this.Row0[1], this.Row1[1], this.Row2[1]).Length(), Column1.Length(),
new Vector3(this.Row0[2], this.Row1[2], this.Row2[2]).Length() Column2.Length()
); );
} }
set
{
value /= Scale; // Value becomes what's called "delta_scale" in core.
Column0 *= value.x;
Column1 *= value.y;
Column2 *= value.z;
}
} }
/// <summary> /// <summary>
@ -157,8 +213,9 @@ namespace Godot
real_t det = orthonormalizedBasis.Determinant(); real_t det = orthonormalizedBasis.Determinant();
if (det < 0) if (det < 0)
{ {
// Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. // Ensure that the determinant is 1, such that result is a proper
orthonormalizedBasis = orthonormalizedBasis.Scaled(Vector3.NegOne); // rotation matrix which can be represented by Euler angles.
orthonormalizedBasis = orthonormalizedBasis.Scaled(-Vector3.One);
} }
return orthonormalizedBasis.Quat(); return orthonormalizedBasis.Quat();
@ -182,6 +239,15 @@ namespace Godot
Row2 = new Vector3(0, 0, diagonal.z); Row2 = new Vector3(0, 0, diagonal.z);
} }
/// <summary>
/// Returns the determinant of the basis matrix. If the basis is
/// uniformly scaled, its determinant is the square of the scale.
///
/// A negative determinant means the basis has a negative scale.
/// A zero determinant means the basis isn't invertible,
/// and is usually considered invalid.
/// </summary>
/// <returns>The determinant of the basis matrix.</returns>
public real_t Determinant() public real_t Determinant()
{ {
real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1]; real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
@ -191,6 +257,16 @@ namespace Godot
return Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20; return Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
} }
/// <summary>
/// Returns the basis's rotation in the form of Euler angles
/// (in the YXZ convention: when *decomposing*, first Z, then X, and Y last).
/// The returned vector contains the rotation angles in
/// the format (X angle, Y angle, Z angle).
///
/// Consider using the <see cref="Basis.Quat()"/> method instead, which
/// returns a <see cref="Godot.Quat"/> quaternion instead of Euler angles.
/// </summary>
/// <returns>A Vector3 representing the basis rotation in Euler angles.</returns>
public Vector3 GetEuler() public Vector3 GetEuler()
{ {
Basis m = Orthonormalized(); Basis m = Orthonormalized();
@ -223,6 +299,12 @@ namespace Godot
return euler; return euler;
} }
/// <summary>
/// Get rows by index. Rows are not very useful for user code,
/// but are more efficient for some internal calculations.
/// </summary>
/// <param name="index">Which row.</param>
/// <returns>One of `Row0`, `Row1`, or `Row2`.</returns>
public Vector3 GetRow(int index) public Vector3 GetRow(int index)
{ {
switch (index) switch (index)
@ -238,6 +320,12 @@ namespace Godot
} }
} }
/// <summary>
/// Sets rows by index. Rows are not very useful for user code,
/// but are more efficient for some internal calculations.
/// </summary>
/// <param name="index">Which row.</param>
/// <param name="value">The vector to set the row to.</param>
public void SetRow(int index, Vector3 value) public void SetRow(int index, Vector3 value)
{ {
switch (index) switch (index)
@ -256,22 +344,49 @@ namespace Godot
} }
} }
/// <summary>
/// Deprecated, please use the array operator instead.
/// </summary>
/// <param name="index">Which column.</param>
/// <returns>One of `Column0`, `Column1`, or `Column2`.</returns>
[Obsolete("GetColumn is deprecated. Use the array operator instead.")]
public Vector3 GetColumn(int index) public Vector3 GetColumn(int index)
{ {
return this[index]; return this[index];
} }
/// <summary>
/// Deprecated, please use the array operator instead.
/// </summary>
/// <param name="index">Which column.</param>
/// <param name="value">The vector to set the column to.</param>
[Obsolete("SetColumn is deprecated. Use the array operator instead.")]
public void SetColumn(int index, Vector3 value) public void SetColumn(int index, Vector3 value)
{ {
this[index] = value; this[index] = value;
} }
[Obsolete("GetAxis is deprecated. Use GetColumn instead.")] /// <summary>
/// Deprecated, please use the array operator instead.
/// </summary>
/// <param name="axis">Which column.</param>
/// <returns>One of `Column0`, `Column1`, or `Column2`.</returns>
[Obsolete("GetAxis is deprecated. Use the array operator instead.")]
public Vector3 GetAxis(int axis) public Vector3 GetAxis(int axis)
{ {
return new Vector3(this.Row0[axis], this.Row1[axis], this.Row2[axis]); return new Vector3(this.Row0[axis], this.Row1[axis], this.Row2[axis]);
} }
/// <summary>
/// This function considers a discretization of rotations into
/// 24 points on unit sphere, lying along the vectors (x, y, z) with
/// each component being either -1, 0, or 1, and returns the index
/// of the point best representing the orientation of the object.
/// It is mainly used by the <see cref="GridMap"/> editor.
///
/// For further details, refer to the Godot source code.
/// </summary>
/// <returns>The orthogonal index.</returns>
public int GetOrthogonalIndex() public int GetOrthogonalIndex()
{ {
var orth = this; var orth = this;
@ -285,11 +400,17 @@ namespace Godot
real_t v = row[j]; real_t v = row[j];
if (v > 0.5f) if (v > 0.5f)
{
v = 1.0f; v = 1.0f;
}
else if (v < -0.5f) else if (v < -0.5f)
{
v = -1.0f; v = -1.0f;
}
else else
{
v = 0f; v = 0f;
}
row[j] = v; row[j] = v;
@ -300,12 +421,18 @@ namespace Godot
for (int i = 0; i < 24; i++) for (int i = 0; i < 24; i++)
{ {
if (orth == _orthoBases[i]) if (orth == _orthoBases[i])
{
return i; return i;
}
} }
return 0; return 0;
} }
/// <summary>
/// Returns the inverse of the matrix.
/// </summary>
/// <returns>The inverse matrix.</returns>
public Basis Inverse() public Basis Inverse()
{ {
real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1]; real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
@ -315,7 +442,9 @@ namespace Godot
real_t det = Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20; real_t det = Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
if (det == 0) if (det == 0)
{
throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted."); throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted.");
}
real_t detInv = 1.0f / det; real_t detInv = 1.0f / det;
@ -334,11 +463,17 @@ namespace Godot
); );
} }
/// <summary>
/// Returns the orthonormalized version of the basis matrix (useful to
/// call occasionally to avoid rounding errors for orthogonal matrices).
/// This performs a Gram-Schmidt orthonormalization on the basis of the matrix.
/// </summary>
/// <returns>An orthonormalized basis matrix.</returns>
public Basis Orthonormalized() public Basis Orthonormalized()
{ {
Vector3 column0 = GetColumn(0); Vector3 column0 = this[0];
Vector3 column1 = GetColumn(1); Vector3 column1 = this[1];
Vector3 column2 = GetColumn(2); Vector3 column2 = this[2];
column0.Normalize(); column0.Normalize();
column1 = column1 - column0 * column0.Dot(column1); column1 = column1 - column0 * column0.Dot(column1);
@ -349,48 +484,86 @@ namespace Godot
return new Basis(column0, column1, column2); return new Basis(column0, column1, column2);
} }
/// <summary>
/// Introduce an additional rotation around the given `axis`
/// by `phi` (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="phi">The angle to rotate, in radians.</param>
/// <returns>The rotated basis matrix.</returns>
public Basis Rotated(Vector3 axis, real_t phi) public Basis Rotated(Vector3 axis, real_t phi)
{ {
return new Basis(axis, phi) * this; return new Basis(axis, phi) * this;
} }
/// <summary>
/// Introduce an additional scaling specified by the given 3D scaling factor.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled basis matrix.</returns>
public Basis Scaled(Vector3 scale) public Basis Scaled(Vector3 scale)
{ {
var b = this; Basis b = this;
b.Row0 *= scale.x; b.Row0 *= scale.x;
b.Row1 *= scale.y; b.Row1 *= scale.y;
b.Row2 *= scale.z; b.Row2 *= scale.z;
return b; return b;
} }
public Basis Slerp(Basis target, real_t t) /// <summary>
/// Assuming that the matrix is a proper rotation matrix, slerp performs
/// a spherical-linear interpolation with another rotation matrix.
/// </summary>
/// <param name="target">The destination basis for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting basis matrix of the interpolation.</returns>
public Basis Slerp(Basis target, real_t weight)
{ {
var from = new Quat(this); Quat from = new Quat(this);
var to = new Quat(target); Quat to = new Quat(target);
var b = new Basis(from.Slerp(to, t)); Basis b = new Basis(from.Slerp(to, weight));
b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), t); b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), weight);
b.Row1 *= Mathf.Lerp(Row1.Length(), target.Row1.Length(), t); b.Row1 *= Mathf.Lerp(Row1.Length(), target.Row1.Length(), weight);
b.Row2 *= Mathf.Lerp(Row2.Length(), target.Row2.Length(), t); b.Row2 *= Mathf.Lerp(Row2.Length(), target.Row2.Length(), weight);
return b; return b;
} }
/// <summary>
/// Transposed dot product with the X axis of the matrix.
/// </summary>
/// <param name="with">A vector to calculate the dot product with.</param>
/// <returns>The resulting dot product.</returns>
public real_t Tdotx(Vector3 with) public real_t Tdotx(Vector3 with)
{ {
return this.Row0[0] * with[0] + this.Row1[0] * with[1] + this.Row2[0] * with[2]; return this.Row0[0] * with[0] + this.Row1[0] * with[1] + this.Row2[0] * with[2];
} }
/// <summary>
/// Transposed dot product with the Y axis of the matrix.
/// </summary>
/// <param name="with">A vector to calculate the dot product with.</param>
/// <returns>The resulting dot product.</returns>
public real_t Tdoty(Vector3 with) public real_t Tdoty(Vector3 with)
{ {
return this.Row0[1] * with[0] + this.Row1[1] * with[1] + this.Row2[1] * with[2]; return this.Row0[1] * with[0] + this.Row1[1] * with[1] + this.Row2[1] * with[2];
} }
/// <summary>
/// Transposed dot product with the Z axis of the matrix.
/// </summary>
/// <param name="with">A vector to calculate the dot product with.</param>
/// <returns>The resulting dot product.</returns>
public real_t Tdotz(Vector3 with) public real_t Tdotz(Vector3 with)
{ {
return this.Row0[2] * with[0] + this.Row1[2] * with[1] + this.Row2[2] * with[2]; return this.Row0[2] * with[0] + this.Row1[2] * with[1] + this.Row2[2] * with[2];
} }
/// <summary>
/// Returns the transposed version of the basis matrix.
/// </summary>
/// <returns>The transposed basis matrix.</returns>
public Basis Transposed() public Basis Transposed()
{ {
var tr = this; var tr = this;
@ -410,6 +583,11 @@ namespace Godot
return tr; return tr;
} }
/// <summary>
/// Returns a vector transformed (multiplied) by the basis matrix.
/// </summary>
/// <param name="v">A vector to transform.</param>
/// <returns>The transfomed vector.</returns>
public Vector3 Xform(Vector3 v) public Vector3 Xform(Vector3 v)
{ {
return new Vector3 return new Vector3
@ -420,6 +598,14 @@ namespace Godot
); );
} }
/// <summary>
/// Returns a vector transformed (multiplied) by the transposed basis matrix.
///
/// Note: This results in a multiplication by the inverse of the
/// basis matrix only if it represents a rotation-reflection.
/// </summary>
/// <param name="v">A vector to inversely transform.</param>
/// <returns>The inversely transfomed vector.</returns>
public Vector3 XformInv(Vector3 v) public Vector3 XformInv(Vector3 v)
{ {
return new Vector3 return new Vector3
@ -430,6 +616,12 @@ namespace Godot
); );
} }
/// <summary>
/// Returns the basis's rotation in the form of a quaternion.
/// See <see cref="GetEuler()"/> if you need Euler angles, but keep in
/// mind that quaternions should generally be preferred to Euler angles.
/// </summary>
/// <returns>A <see cref="Godot.Quat"/> representing the basis's rotation.</returns>
public Quat Quat() public Quat Quat()
{ {
real_t trace = Row0[0] + Row1[1] + Row2[2]; real_t trace = Row0[0] + Row1[1] + Row2[2];
@ -514,11 +706,33 @@ namespace Godot
private static readonly Basis _flipY = new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1); private static readonly Basis _flipY = new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
private static readonly Basis _flipZ = new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1); private static readonly Basis _flipZ = new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
/// <summary>
/// The identity basis, with no rotation or scaling applied.
/// This is used as a replacement for `Basis()` in GDScript.
/// Do not use `new Basis()` with no arguments in C#, because it sets all values to zero.
/// </summary>
/// <value>Equivalent to `new Basis(Vector3.Right, Vector3.Up, Vector3.Back)`.</value>
public static Basis Identity { get { return _identity; } } public static Basis Identity { get { return _identity; } }
/// <summary>
/// The basis that will flip something along the X axis when used in a transformation.
/// </summary>
/// <value>Equivalent to `new Basis(Vector3.Left, Vector3.Up, Vector3.Back)`.</value>
public static Basis FlipX { get { return _flipX; } } public static Basis FlipX { get { return _flipX; } }
/// <summary>
/// The basis that will flip something along the Y axis when used in a transformation.
/// </summary>
/// <value>Equivalent to `new Basis(Vector3.Right, Vector3.Down, Vector3.Back)`.</value>
public static Basis FlipY { get { return _flipY; } } public static Basis FlipY { get { return _flipY; } }
/// <summary>
/// The basis that will flip something along the Z axis when used in a transformation.
/// </summary>
/// <value>Equivalent to `new Basis(Vector3.Right, Vector3.Up, Vector3.Forward)`.</value>
public static Basis FlipZ { get { return _flipZ; } } public static Basis FlipZ { get { return _flipZ; } }
/// <summary>
/// Constructs a pure rotation basis matrix from the given quaternion.
/// </summary>
/// <param name="quat">The quaternion to create the basis from.</param>
public Basis(Quat quat) public Basis(Quat quat)
{ {
real_t s = 2.0f / quat.LengthSquared; real_t s = 2.0f / quat.LengthSquared;
@ -541,26 +755,41 @@ namespace Godot
Row2 = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy)); Row2 = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
} }
public Basis(Vector3 euler) /// <summary>
/// Constructs a pure rotation basis matrix from the given Euler angles
/// (in the YXZ convention: when *composing*, first Y, then X, and Z last),
/// given in the vector format as (X angle, Y angle, Z angle).
///
/// Consider using the <see cref="Basis(Quat)"/> constructor instead, which
/// uses a <see cref="Godot.Quat"/> quaternion instead of Euler angles.
/// </summary>
/// <param name="eulerYXZ">The Euler angles to create the basis from.</param>
public Basis(Vector3 eulerYXZ)
{ {
real_t c; real_t c;
real_t s; real_t s;
c = Mathf.Cos(euler.x); c = Mathf.Cos(eulerYXZ.x);
s = Mathf.Sin(euler.x); s = Mathf.Sin(eulerYXZ.x);
var xmat = new Basis(1, 0, 0, 0, c, -s, 0, s, c); var xmat = new Basis(1, 0, 0, 0, c, -s, 0, s, c);
c = Mathf.Cos(euler.y); c = Mathf.Cos(eulerYXZ.y);
s = Mathf.Sin(euler.y); s = Mathf.Sin(eulerYXZ.y);
var ymat = new Basis(c, 0, s, 0, 1, 0, -s, 0, c); var ymat = new Basis(c, 0, s, 0, 1, 0, -s, 0, c);
c = Mathf.Cos(euler.z); c = Mathf.Cos(eulerYXZ.z);
s = Mathf.Sin(euler.z); s = Mathf.Sin(eulerYXZ.z);
var zmat = new Basis(c, -s, 0, s, c, 0, 0, 0, 1); var zmat = new Basis(c, -s, 0, s, c, 0, 0, 0, 1);
this = ymat * xmat * zmat; this = ymat * xmat * zmat;
} }
/// <summary>
/// Constructs a pure rotation basis matrix, rotated around the given `axis`
/// by `phi` (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="phi">The angle to rotate, in radians.</param>
public Basis(Vector3 axis, real_t phi) public Basis(Vector3 axis, real_t phi)
{ {
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
@ -588,6 +817,12 @@ namespace Godot
Row2.y = xyzt + zyxs; Row2.y = xyzt + zyxs;
} }
/// <summary>
/// Constructs a basis matrix from 3 axis vectors (matrix columns).
/// </summary>
/// <param name="column0">The X vector, or Column0.</param>
/// <param name="column1">The Y vector, or Column1.</param>
/// <param name="column2">The Z vector, or Column2.</param>
public Basis(Vector3 column0, Vector3 column1, Vector3 column2) public Basis(Vector3 column0, Vector3 column1, Vector3 column2)
{ {
Row0 = new Vector3(column0.x, column1.x, column2.x); Row0 = new Vector3(column0.x, column1.x, column2.x);
@ -643,6 +878,12 @@ namespace Godot
return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2); return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
} }
/// <summary>
/// Returns true if this basis and `other` are approximately equal, by running
/// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component.
/// </summary>
/// <param name="other">The other basis to compare.</param>
/// <returns>Whether or not the matrices are approximately equal.</returns>
public bool IsEqualApprox(Basis other) public bool IsEqualApprox(Basis other)
{ {
return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2); return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2);

View File

@ -3,15 +3,44 @@ using System.Runtime.InteropServices;
namespace Godot namespace Godot
{ {
/// <summary>
/// A color represented by red, green, blue, and alpha (RGBA) components.
/// The alpha component is often used for transparency.
/// Values are in floating-point and usually range from 0 to 1.
/// Some properties (such as CanvasItem.modulate) may accept values
/// greater than 1 (overbright or HDR colors).
///
/// If you want to supply values in a range of 0 to 255, you should use
/// <see cref="Color8"/> and the `r8`/`g8`/`b8`/`a8` properties.
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Color : IEquatable<Color> public struct Color : IEquatable<Color>
{ {
/// <summary>
/// The color's red component, typically on the range of 0 to 1.
/// </summary>
public float r; public float r;
/// <summary>
/// The color's green component, typically on the range of 0 to 1.
/// </summary>
public float g; public float g;
/// <summary>
/// The color's blue component, typically on the range of 0 to 1.
/// </summary>
public float b; public float b;
/// <summary>
/// The color's alpha (transparency) component, typically on the range of 0 to 1.
/// </summary>
public float a; public float a;
/// <summary>
/// Wrapper for <see cref="r"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
public int r8 public int r8
{ {
get get
@ -24,6 +53,10 @@ namespace Godot
} }
} }
/// <summary>
/// Wrapper for <see cref="g"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
public int g8 public int g8
{ {
get get
@ -36,6 +69,10 @@ namespace Godot
} }
} }
/// <summary>
/// Wrapper for <see cref="b"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
public int b8 public int b8
{ {
get get
@ -48,6 +85,10 @@ namespace Godot
} }
} }
/// <summary>
/// Wrapper for <see cref="a"/> that uses the range 0 to 255 instead of 0 to 1.
/// </summary>
/// <value>Getting is equivalent to multiplying by 255 and rounding. Setting is equivalent to dividing by 255.</value>
public int a8 public int a8
{ {
get get
@ -60,6 +101,10 @@ namespace Godot
} }
} }
/// <summary>
/// The HSV hue of this color, on the range 0 to 1.
/// </summary>
/// <value>Getting is a long process, refer to the source code for details. Setting uses <see cref="FromHsv"/>.</value>
public float h public float h
{ {
get get
@ -70,21 +115,31 @@ namespace Godot
float delta = max - min; float delta = max - min;
if (delta == 0) if (delta == 0)
{
return 0; return 0;
}
float h; float h;
if (r == max) if (r == max)
{
h = (g - b) / delta; // Between yellow & magenta h = (g - b) / delta; // Between yellow & magenta
}
else if (g == max) else if (g == max)
{
h = 2 + (b - r) / delta; // Between cyan & yellow h = 2 + (b - r) / delta; // Between cyan & yellow
}
else else
{
h = 4 + (r - g) / delta; // Between magenta & cyan h = 4 + (r - g) / delta; // Between magenta & cyan
}
h /= 6.0f; h /= 6.0f;
if (h < 0) if (h < 0)
{
h += 1.0f; h += 1.0f;
}
return h; return h;
} }
@ -94,6 +149,10 @@ namespace Godot
} }
} }
/// <summary>
/// The HSV saturation of this color, on the range 0 to 1.
/// </summary>
/// <value>Getting is equivalent to the ratio between the min and max RGB value. Setting uses <see cref="FromHsv"/>.</value>
public float s public float s
{ {
get get
@ -103,7 +162,7 @@ namespace Godot
float delta = max - min; float delta = max - min;
return max != 0 ? delta / max : 0; return max == 0 ? 0 : delta / max;
} }
set set
{ {
@ -111,6 +170,10 @@ namespace Godot
} }
} }
/// <summary>
/// The HSV value (brightness) of this color, on the range 0 to 1.
/// </summary>
/// <value>Getting is equivalent to using `Max()` on the RGB components. Setting uses <see cref="FromHsv"/>.</value>
public float v public float v
{ {
get get
@ -123,6 +186,14 @@ namespace Godot
} }
} }
/// <summary>
/// Returns a color according to the standardized name, with the
/// specified alpha value. Supported color names are the same as
/// the constants defined in <see cref="Colors"/>.
/// </summary>
/// <param name="name">The name of the color.</param>
/// <param name="alpha">The alpha (transparency) component represented on the range of 0 to 1. Default: 1.</param>
/// <returns>The constructed color.</returns>
public static Color ColorN(string name, float alpha = 1f) public static Color ColorN(string name, float alpha = 1f)
{ {
name = name.Replace(" ", String.Empty); name = name.Replace(" ", String.Empty);
@ -142,6 +213,10 @@ namespace Godot
return color; return color;
} }
/// <summary>
/// Access color components using their index.
/// </summary>
/// <value>`[0]` is equivalent to `.r`, `[1]` is equivalent to `.g`, `[2]` is equivalent to `.b`, `[3]` is equivalent to `.a`.</value>
public float this[int index] public float this[int index]
{ {
get get
@ -182,6 +257,13 @@ namespace Godot
} }
} }
/// <summary>
/// Converts a color to HSV values. This is equivalent to using each of
/// the `h`/`s`/`v` properties, but much more efficient.
/// </summary>
/// <param name="hue">Output parameter for the HSV hue.</param>
/// <param name="saturation">Output parameter for the HSV saturation.</param>
/// <param name="value">Output parameter for the HSV value.</param>
public void ToHsv(out float hue, out float saturation, out float value) public void ToHsv(out float hue, out float saturation, out float value)
{ {
float max = (float)Mathf.Max(r, Mathf.Max(g, b)); float max = (float)Mathf.Max(r, Mathf.Max(g, b));
@ -212,6 +294,16 @@ namespace Godot
value = max; value = max;
} }
/// <summary>
/// Constructs a color from an HSV profile, with values on the
/// range of 0 to 1. This is equivalent to using each of
/// the `h`/`s`/`v` properties, but much more efficient.
/// </summary>
/// <param name="hue">The HSV hue, typically on the range of 0 to 1.</param>
/// <param name="saturation">The HSV saturation, typically on the range of 0 to 1.</param>
/// <param name="value">The HSV value (brightness), typically on the range of 0 to 1.</param>
/// <param name="alpha">The alpha (transparency) value, typically on the range of 0 to 1.</param>
/// <returns>The constructed color.</returns>
public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f) public static Color FromHsv(float hue, float saturation, float value, float alpha = 1.0f)
{ {
if (saturation == 0) if (saturation == 0)
@ -249,6 +341,13 @@ namespace Godot
} }
} }
/// <summary>
/// Returns a new color resulting from blending this color over another.
/// If the color is opaque, the result is also opaque.
/// The second color may have a range of alpha values.
/// </summary>
/// <param name="over">The color to blend over.</param>
/// <returns>This color blended over `over`.</returns>
public Color Blend(Color over) public Color Blend(Color over)
{ {
Color res; Color res;
@ -268,6 +367,10 @@ namespace Godot
return res; return res;
} }
/// <summary>
/// Returns the most contrasting color.
/// </summary>
/// <returns>The most contrasting color</returns>
public Color Contrasted() public Color Contrasted()
{ {
return new Color( return new Color(
@ -278,6 +381,12 @@ namespace Godot
); );
} }
/// <summary>
/// Returns a new color resulting from making this color darker
/// by the specified ratio (on the range of 0 to 1).
/// </summary>
/// <param name="amount">The ratio to darken by.</param>
/// <returns>The darkened color.</returns>
public Color Darkened(float amount) public Color Darkened(float amount)
{ {
Color res = this; Color res = this;
@ -287,6 +396,10 @@ namespace Godot
return res; return res;
} }
/// <summary>
/// Returns the inverted color: `(1 - r, 1 - g, 1 - b, a)`.
/// </summary>
/// <returns>The inverted color.</returns>
public Color Inverted() public Color Inverted()
{ {
return new Color( return new Color(
@ -297,6 +410,12 @@ namespace Godot
); );
} }
/// <summary>
/// Returns a new color resulting from making this color lighter
/// by the specified ratio (on the range of 0 to 1).
/// </summary>
/// <param name="amount">The ratio to lighten by.</param>
/// <returns>The darkened color.</returns>
public Color Lightened(float amount) public Color Lightened(float amount)
{ {
Color res = this; Color res = this;
@ -306,18 +425,48 @@ namespace Godot
return res; return res;
} }
public Color LinearInterpolate(Color c, float t) /// <summary>
/// Returns the result of the linear interpolation between
/// this color and `to` by amount `weight`.
/// </summary>
/// <param name="to">The destination color for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting color of the interpolation.</returns>
public Color LinearInterpolate(Color to, float weight)
{ {
var res = this; return new Color
(
res.r += t * (c.r - r); Mathf.Lerp(r, to.r, weight),
res.g += t * (c.g - g); Mathf.Lerp(g, to.g, weight),
res.b += t * (c.b - b); Mathf.Lerp(b, to.b, weight),
res.a += t * (c.a - a); Mathf.Lerp(a, to.a, weight)
);
return res;
} }
/// <summary>
/// Returns the result of the linear interpolation between
/// this color and `to` by color amount `weight`.
/// </summary>
/// <param name="to">The destination color for interpolation.</param>
/// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting color of the interpolation.</returns>
public Color LinearInterpolate(Color to, Color weight)
{
return new Color
(
Mathf.Lerp(r, to.r, weight.r),
Mathf.Lerp(g, to.g, weight.g),
Mathf.Lerp(b, to.b, weight.b),
Mathf.Lerp(a, to.a, weight.a)
);
}
/// <summary>
/// Returns the color's 32-bit integer in ABGR format
/// (each byte represents a component of the ABGR profile).
/// ABGR is the reversed version of the default format.
/// </summary>
/// <returns>An int representing this color in ABGR32 format.</returns>
public int ToAbgr32() public int ToAbgr32()
{ {
int c = (byte)Math.Round(a * 255); int c = (byte)Math.Round(a * 255);
@ -331,6 +480,12 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the color's 64-bit integer in ABGR format
/// (each byte represents a component of the ABGR profile).
/// ABGR is the reversed version of the default format.
/// </summary>
/// <returns>An int representing this color in ABGR64 format.</returns>
public long ToAbgr64() public long ToAbgr64()
{ {
long c = (ushort)Math.Round(a * 65535); long c = (ushort)Math.Round(a * 65535);
@ -344,6 +499,12 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the color's 32-bit integer in ARGB format
/// (each byte represents a component of the ARGB profile).
/// ARGB is more compatible with DirectX, but not used much in Godot.
/// </summary>
/// <returns>An int representing this color in ARGB32 format.</returns>
public int ToArgb32() public int ToArgb32()
{ {
int c = (byte)Math.Round(a * 255); int c = (byte)Math.Round(a * 255);
@ -357,6 +518,12 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the color's 64-bit integer in ARGB format
/// (each word represents a component of the ARGB profile).
/// ARGB is more compatible with DirectX, but not used much in Godot.
/// </summary>
/// <returns>A long representing this color in ARGB64 format.</returns>
public long ToArgb64() public long ToArgb64()
{ {
long c = (ushort)Math.Round(a * 65535); long c = (ushort)Math.Round(a * 65535);
@ -370,6 +537,12 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the color's 32-bit integer in RGBA format
/// (each byte represents a component of the RGBA profile).
/// RGBA is Godot's default and recommended format.
/// </summary>
/// <returns>An int representing this color in RGBA32 format.</returns>
public int ToRgba32() public int ToRgba32()
{ {
int c = (byte)Math.Round(r * 255); int c = (byte)Math.Round(r * 255);
@ -383,6 +556,12 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the color's 64-bit integer in RGBA format
/// (each word represents a component of the RGBA profile).
/// RGBA is Godot's default and recommended format.
/// </summary>
/// <returns>A long representing this color in RGBA64 format.</returns>
public long ToRgba64() public long ToRgba64()
{ {
long c = (ushort)Math.Round(r * 65535); long c = (ushort)Math.Round(r * 65535);
@ -396,6 +575,11 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the color's HTML hexadecimal color string in RGBA format.
/// </summary>
/// <param name="includeAlpha">Whether or not to include alpha. If false, the color is RGB instead of RGBA.</param>
/// <returns>A string for the HTML hexadecimal representation of this color.</returns>
public string ToHtml(bool includeAlpha = true) public string ToHtml(bool includeAlpha = true)
{ {
var txt = string.Empty; var txt = string.Empty;
@ -410,7 +594,13 @@ namespace Godot
return txt; return txt;
} }
// Constructors /// <summary>
/// Constructs a color from RGBA values on the range of 0 to 1.
/// </summary>
/// <param name="r">The color's red component, typically on the range of 0 to 1.</param>
/// <param name="g">The color's green component, typically on the range of 0 to 1.</param>
/// <param name="b">The color's blue component, typically on the range of 0 to 1.</param>
/// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param>
public Color(float r, float g, float b, float a = 1.0f) public Color(float r, float g, float b, float a = 1.0f)
{ {
this.r = r; this.r = r;
@ -419,6 +609,24 @@ namespace Godot
this.a = a; this.a = a;
} }
/// <summary>
/// Constructs a color from an existing color and an alpha value.
/// </summary>
/// <param name="c">The color to construct from. Only its RGB values are used.</param>
/// <param name="a">The color's alpha (transparency) value, typically on the range of 0 to 1. Default: 1.</param>
public Color(Color c, float a = 1.0f)
{
r = c.r;
g = c.g;
b = c.b;
this.a = a;
}
/// <summary>
/// Constructs a color from a 32-bit integer
/// (each byte represents a component of the RGBA profile).
/// </summary>
/// <param name="rgba">The int representing the color.</param>
public Color(int rgba) public Color(int rgba)
{ {
a = (rgba & 0xFF) / 255.0f; a = (rgba & 0xFF) / 255.0f;
@ -430,6 +638,11 @@ namespace Godot
r = (rgba & 0xFF) / 255.0f; r = (rgba & 0xFF) / 255.0f;
} }
/// <summary>
/// Constructs a color from a 64-bit integer
/// (each word represents a component of the RGBA profile).
/// </summary>
/// <param name="rgba">The long representing the color.</param>
public Color(long rgba) public Color(long rgba)
{ {
a = (rgba & 0xFFFF) / 65535.0f; a = (rgba & 0xFFFF) / 65535.0f;
@ -470,9 +683,13 @@ namespace Godot
} }
if (i == 0) if (i == 0)
{
ig += v * 16; ig += v * 16;
}
else else
{
ig += v; ig += v;
}
} }
return ig; return ig;
@ -490,9 +707,13 @@ namespace Godot
int lv = v & 0xF; int lv = v & 0xF;
if (lv < 10) if (lv < 10)
{
c = (char)('0' + lv); c = (char)('0' + lv);
}
else else
{
c = (char)('a' + lv - 10); c = (char)('a' + lv - 10);
}
v >>= 4; v >>= 4;
ret = c + ret; ret = c + ret;
@ -504,10 +725,14 @@ namespace Godot
internal static bool HtmlIsValid(string color) internal static bool HtmlIsValid(string color)
{ {
if (color.Length == 0) if (color.Length == 0)
{
return false; return false;
}
if (color[0] == '#') if (color[0] == '#')
{
color = color.Substring(1, color.Length - 1); color = color.Substring(1, color.Length - 1);
}
bool alpha; bool alpha;
@ -526,7 +751,9 @@ namespace Godot
if (alpha) if (alpha)
{ {
if (ParseCol8(color, 0) < 0) if (ParseCol8(color, 0) < 0)
{
return false; return false;
}
} }
int from = alpha ? 2 : 0; int from = alpha ? 2 : 0;
@ -541,11 +768,24 @@ namespace Godot
return true; return true;
} }
/// <summary>
/// Returns a color constructed from integer red, green, blue, and alpha channels.
/// Each channel should have 8 bits of information ranging from 0 to 255.
/// </summary>
/// <param name="r8">The red component represented on the range of 0 to 255.</param>
/// <param name="g8">The green component represented on the range of 0 to 255.</param>
/// <param name="b8">The blue component represented on the range of 0 to 255.</param>
/// <param name="a8">The alpha (transparency) component represented on the range of 0 to 255.</param>
/// <returns>The constructed color.</returns>
public static Color Color8(byte r8, byte g8, byte b8, byte a8 = 255) public static Color Color8(byte r8, byte g8, byte b8, byte a8 = 255)
{ {
return new Color(r8 / 255f, g8 / 255f, b8 / 255f, a8 / 255f); return new Color(r8 / 255f, g8 / 255f, b8 / 255f, a8 / 255f);
} }
/// <summary>
/// Constructs a color from the HTML hexadecimal color string in RGBA format.
/// </summary>
/// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param>
public Color(string rgba) public Color(string rgba)
{ {
if (rgba.Length == 0) if (rgba.Length == 0)
@ -690,13 +930,13 @@ namespace Godot
if (Mathf.IsEqualApprox(left.g, right.g)) if (Mathf.IsEqualApprox(left.g, right.g))
{ {
if (Mathf.IsEqualApprox(left.b, right.b)) if (Mathf.IsEqualApprox(left.b, right.b))
{
return left.a < right.a; return left.a < right.a;
}
return left.b < right.b; return left.b < right.b;
} }
return left.g < right.g; return left.g < right.g;
} }
return left.r < right.r; return left.r < right.r;
} }
@ -707,13 +947,13 @@ namespace Godot
if (Mathf.IsEqualApprox(left.g, right.g)) if (Mathf.IsEqualApprox(left.g, right.g))
{ {
if (Mathf.IsEqualApprox(left.b, right.b)) if (Mathf.IsEqualApprox(left.b, right.b))
{
return left.a > right.a; return left.a > right.a;
}
return left.b > right.b; return left.b > right.b;
} }
return left.g > right.g; return left.g > right.g;
} }
return left.r > right.r; return left.r > right.r;
} }
@ -732,6 +972,12 @@ namespace Godot
return r == other.r && g == other.g && b == other.b && a == other.a; return r == other.r && g == other.g && b == other.b && a == other.a;
} }
/// <summary>
/// Returns true if this color and `other` are approximately equal, by running
/// <see cref="Godot.Mathf.IsEqualApprox(float, float)"/> on each component.
/// </summary>
/// <param name="other">The other color to compare.</param>
/// <returns>Whether or not the colors are approximately equal.</returns>
public bool IsEqualApprox(Color other) public bool IsEqualApprox(Color other)
{ {
return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a); return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);

View File

@ -3,6 +3,10 @@ using System.Collections.Generic;
namespace Godot namespace Godot
{ {
/// <summary>
/// This class contains color constants created from standardized color names.
/// The standardized color set is based on the X11 and .NET color names.
/// </summary>
public static class Colors public static class Colors
{ {
// Color names and values are derived from core/color_names.inc // Color names and values are derived from core/color_names.inc

View File

@ -11,79 +11,185 @@ namespace Godot
{ {
// Define constants with Decimal precision and cast down to double or float. // Define constants with Decimal precision and cast down to double or float.
/// <summary>
/// The circle constant, the circumference of the unit circle in radians.
/// </summary>
public const real_t Tau = (real_t) 6.2831853071795864769252867666M; // 6.2831855f and 6.28318530717959 public const real_t Tau = (real_t) 6.2831853071795864769252867666M; // 6.2831855f and 6.28318530717959
/// <summary>
/// Constant that represents how many times the diameter of a circle
/// fits around its perimeter. This is equivalent to `Mathf.Tau / 2`.
/// </summary>
public const real_t Pi = (real_t) 3.1415926535897932384626433833M; // 3.1415927f and 3.14159265358979 public const real_t Pi = (real_t) 3.1415926535897932384626433833M; // 3.1415927f and 3.14159265358979
/// <summary>
/// Positive infinity. For negative infinity, use `-Mathf.Inf`.
/// </summary>
public const real_t Inf = real_t.PositiveInfinity; public const real_t Inf = real_t.PositiveInfinity;
/// <summary>
/// "Not a Number", an invalid value. `NaN` has special properties, including
/// that it is not equal to itself. It is output by some invalid operations,
/// such as dividing zero by zero.
/// </summary>
public const real_t NaN = real_t.NaN; public const real_t NaN = real_t.NaN;
private const real_t Deg2RadConst = (real_t) 0.0174532925199432957692369077M; // 0.0174532924f and 0.0174532925199433 private const real_t Deg2RadConst = (real_t) 0.0174532925199432957692369077M; // 0.0174532924f and 0.0174532925199433
private const real_t Rad2DegConst = (real_t) 57.295779513082320876798154814M; // 57.29578f and 57.2957795130823 private const real_t Rad2DegConst = (real_t) 57.295779513082320876798154814M; // 57.29578f and 57.2957795130823
/// <summary>
/// Returns the absolute value of `s` (i.e. positive value).
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>The absolute value of `s`.</returns>
public static int Abs(int s) public static int Abs(int s)
{ {
return Math.Abs(s); return Math.Abs(s);
} }
/// <summary>
/// Returns the absolute value of `s` (i.e. positive value).
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>The absolute value of `s`.</returns>
public static real_t Abs(real_t s) public static real_t Abs(real_t s)
{ {
return Math.Abs(s); return Math.Abs(s);
} }
/// <summary>
/// Returns the arc cosine of `s` in radians. Use to get the angle of cosine s.
/// </summary>
/// <param name="s">The input cosine value. Must be on the range of -1.0 to 1.0.</param>
/// <returns>An angle that would result in the given cosine value. On the range `0` to `Tau/2`.</returns>
public static real_t Acos(real_t s) public static real_t Acos(real_t s)
{ {
return (real_t)Math.Acos(s); return (real_t)Math.Acos(s);
} }
/// <summary>
/// Returns the arc sine of `s` in radians. Use to get the angle of sine s.
/// </summary>
/// <param name="s">The input sine value. Must be on the range of -1.0 to 1.0.</param>
/// <returns>An angle that would result in the given sine value. On the range `-Tau/4` to `Tau/4`.</returns>
public static real_t Asin(real_t s) public static real_t Asin(real_t s)
{ {
return (real_t)Math.Asin(s); return (real_t)Math.Asin(s);
} }
/// <summary>
/// Returns the arc tangent of `s` in radians. Use to get the angle of tangent s.
///
/// The method cannot know in which quadrant the angle should fall.
/// See <see cref="Atan2(real_t, real_t)"/> if you have both `y` and `x`.
/// </summary>
/// <param name="s">The input tangent value.</param>
/// <returns>An angle that would result in the given tangent value. On the range `-Tau/4` to `Tau/4`.</returns>
public static real_t Atan(real_t s) public static real_t Atan(real_t s)
{ {
return (real_t)Math.Atan(s); return (real_t)Math.Atan(s);
} }
/// <summary>
/// Returns the arc tangent of `y` and `x` in radians. Use to get the angle
/// of the tangent of `y/x`. To compute the value, the method takes into
/// account the sign of both arguments in order to determine the quadrant.
///
/// Important note: The Y coordinate comes first, by convention.
/// </summary>
/// <param name="y">The Y coordinate of the point to find the angle to.</param>
/// <param name="x">The X coordinate of the point to find the angle to.</param>
/// <returns>An angle that would result in the given tangent value. On the range `-Tau/2` to `Tau/2`.</returns>
public static real_t Atan2(real_t y, real_t x) public static real_t Atan2(real_t y, real_t x)
{ {
return (real_t)Math.Atan2(y, x); return (real_t)Math.Atan2(y, x);
} }
/// <summary>
/// Converts a 2D point expressed in the cartesian coordinate
/// system (X and Y axis) to the polar coordinate system
/// (a distance from the origin and an angle).
/// </summary>
/// <param name="x">The input X coordinate.</param>
/// <param name="y">The input Y coordinate.</param>
/// <returns>A <see cref="Vector2"/> with X representing the distance and Y representing the angle.</returns>
public static Vector2 Cartesian2Polar(real_t x, real_t y) public static Vector2 Cartesian2Polar(real_t x, real_t y)
{ {
return new Vector2(Sqrt(x * x + y * y), Atan2(y, x)); return new Vector2(Sqrt(x * x + y * y), Atan2(y, x));
} }
/// <summary>
/// Rounds `s` upward (towards positive infinity).
/// </summary>
/// <param name="s">The number to ceil.</param>
/// <returns>The smallest whole number that is not less than `s`.</returns>
public static real_t Ceil(real_t s) public static real_t Ceil(real_t s)
{ {
return (real_t)Math.Ceiling(s); return (real_t)Math.Ceiling(s);
} }
/// <summary>
/// Clamps a `value` so that it is not less than `min` and not more than `max`.
/// </summary>
/// <param name="value">The value to clamp.</param>
/// <param name="min">The minimum allowed value.</param>
/// <param name="max">The maximum allowed value.</param>
/// <returns>The clamped value.</returns>
public static int Clamp(int value, int min, int max) public static int Clamp(int value, int min, int max)
{ {
return value < min ? min : value > max ? max : value; return value < min ? min : value > max ? max : value;
} }
/// <summary>
/// Clamps a `value` so that it is not less than `min` and not more than `max`.
/// </summary>
/// <param name="value">The value to clamp.</param>
/// <param name="min">The minimum allowed value.</param>
/// <param name="max">The maximum allowed value.</param>
/// <returns>The clamped value.</returns>
public static real_t Clamp(real_t value, real_t min, real_t max) public static real_t Clamp(real_t value, real_t min, real_t max)
{ {
return value < min ? min : value > max ? max : value; return value < min ? min : value > max ? max : value;
} }
/// <summary>
/// Returns the cosine of angle `s` in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The cosine of that angle.</returns>
public static real_t Cos(real_t s) public static real_t Cos(real_t s)
{ {
return (real_t)Math.Cos(s); return (real_t)Math.Cos(s);
} }
/// <summary>
/// Returns the hyperbolic cosine of angle `s` in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The hyperbolic cosine of that angle.</returns>
public static real_t Cosh(real_t s) public static real_t Cosh(real_t s)
{ {
return (real_t)Math.Cosh(s); return (real_t)Math.Cosh(s);
} }
/// <summary>
/// Converts an angle expressed in degrees to radians.
/// </summary>
/// <param name="deg">An angle expressed in degrees.</param>
/// <returns>The same angle expressed in radians.</returns>
public static real_t Deg2Rad(real_t deg) public static real_t Deg2Rad(real_t deg)
{ {
return deg * Deg2RadConst; return deg * Deg2RadConst;
} }
/// <summary>
/// Easing function, based on exponent. The curve values are:
/// `0` is constant, `1` is linear, `0` to `1` is ease-in, `1` or more is ease-out.
/// Negative values are in-out/out-in.
/// </summary>
/// <param name="s">The value to ease.</param>
/// <param name="curve">`0` is constant, `1` is linear, `0` to `1` is ease-in, `1` or more is ease-out.</param>
/// <returns>The eased value.</returns>
public static real_t Ease(real_t s, real_t curve) public static real_t Ease(real_t s, real_t curve)
{ {
if (s < 0f) if (s < 0f)
@ -118,21 +224,47 @@ namespace Godot
return 0f; return 0f;
} }
/// <summary>
/// The natural exponential function. It raises the mathematical
/// constant `e` to the power of `s` and returns it.
/// </summary>
/// <param name="s">The exponent to raise `e` to.</param>
/// <returns>`e` raised to the power of `s`.</returns>
public static real_t Exp(real_t s) public static real_t Exp(real_t s)
{ {
return (real_t)Math.Exp(s); return (real_t)Math.Exp(s);
} }
/// <summary>
/// Rounds `s` downward (towards negative infinity).
/// </summary>
/// <param name="s">The number to floor.</param>
/// <returns>The largest whole number that is not more than `s`.</returns>
public static real_t Floor(real_t s) public static real_t Floor(real_t s)
{ {
return (real_t)Math.Floor(s); return (real_t)Math.Floor(s);
} }
/// <summary>
/// Returns a normalized value considering the given range.
/// This is the opposite of <see cref="Lerp(real_t, real_t, real_t)"/>.
/// </summary>
/// <param name="from">The interpolated value.</param>
/// <param name="to">The destination value for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the inverse interpolation.</returns>
public static real_t InverseLerp(real_t from, real_t to, real_t weight) public static real_t InverseLerp(real_t from, real_t to, real_t weight)
{ {
return (weight - from) / (to - from); return (weight - from) / (to - from);
} }
/// <summary>
/// Returns true if `a` and `b` are approximately equal to each other.
/// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>A bool for whether or not the two values are approximately equal.</returns>
public static bool IsEqualApprox(real_t a, real_t b) public static bool IsEqualApprox(real_t a, real_t b)
{ {
// Check for exact equality first, required to handle "infinity" values. // Check for exact equality first, required to handle "infinity" values.
@ -149,26 +281,62 @@ namespace Godot
return Abs(a - b) < tolerance; return Abs(a - b) < tolerance;
} }
/// <summary>
/// Returns whether `s` is an infinity value (either positive infinity or negative infinity).
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A bool for whether or not the value is an infinity value.</returns>
public static bool IsInf(real_t s) public static bool IsInf(real_t s)
{ {
return real_t.IsInfinity(s); return real_t.IsInfinity(s);
} }
/// <summary>
/// Returns whether `s` is a `NaN` ("Not a Number" or invalid) value.
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A bool for whether or not the value is a `NaN` value.</returns>
public static bool IsNaN(real_t s) public static bool IsNaN(real_t s)
{ {
return real_t.IsNaN(s); return real_t.IsNaN(s);
} }
/// <summary>
/// Returns true if `s` is approximately zero.
/// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
///
/// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with one value as zero.
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A bool for whether or not the value is nearly zero.</returns>
public static bool IsZeroApprox(real_t s) public static bool IsZeroApprox(real_t s)
{ {
return Abs(s) < Epsilon; return Abs(s) < Epsilon;
} }
/// <summary>
/// Linearly interpolates between two values by a normalized value.
/// This is the opposite <see cref="InverseLerp(real_t, real_t, real_t)"/>.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
public static real_t Lerp(real_t from, real_t to, real_t weight) public static real_t Lerp(real_t from, real_t to, real_t weight)
{ {
return from + (to - from) * weight; return from + (to - from) * weight;
} }
/// <summary>
/// Linearly interpolates between two angles (in radians) by a normalized value.
///
/// Similar to <see cref="Lerp(real_t, real_t, real_t)"/>,
/// but interpolates correctly when the angles wrap around <see cref="Tau"/>.
/// </summary>
/// <param name="from">The start angle for interpolation.</param>
/// <param name="to">The destination angle for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting angle of the interpolation.</returns>
public static real_t LerpAngle(real_t from, real_t to, real_t weight) public static real_t LerpAngle(real_t from, real_t to, real_t weight)
{ {
real_t difference = (to - from) % Mathf.Tau; real_t difference = (to - from) % Mathf.Tau;
@ -176,36 +344,81 @@ namespace Godot
return from + distance * weight; return from + distance * weight;
} }
/// <summary>
/// Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
///
/// Note: This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
/// </summary>
/// <param name="s">The input value.</param>
/// <returns>The natural log of `s`.</returns>
public static real_t Log(real_t s) public static real_t Log(real_t s)
{ {
return (real_t)Math.Log(s); return (real_t)Math.Log(s);
} }
/// <summary>
/// Returns the maximum of two values.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is higher.</returns>
public static int Max(int a, int b) public static int Max(int a, int b)
{ {
return a > b ? a : b; return a > b ? a : b;
} }
/// <summary>
/// Returns the maximum of two values.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is higher.</returns>
public static real_t Max(real_t a, real_t b) public static real_t Max(real_t a, real_t b)
{ {
return a > b ? a : b; return a > b ? a : b;
} }
/// <summary>
/// Returns the minimum of two values.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is lower.</returns>
public static int Min(int a, int b) public static int Min(int a, int b)
{ {
return a < b ? a : b; return a < b ? a : b;
} }
/// <summary>
/// Returns the minimum of two values.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <returns>Whichever of the two values is lower.</returns>
public static real_t Min(real_t a, real_t b) public static real_t Min(real_t a, real_t b)
{ {
return a < b ? a : b; return a < b ? a : b;
} }
/// <summary>
/// Moves `from` toward `to` by the `delta` value.
///
/// Use a negative delta value to move away.
/// </summary>
/// <param name="from">The start value.</param>
/// <param name="to">The value to move towards.</param>
/// <param name="delta">The amount to move by.</param>
/// <returns>The value after moving.</returns>
public static real_t MoveToward(real_t from, real_t to, real_t delta) public static real_t MoveToward(real_t from, real_t to, real_t delta)
{ {
return Abs(to - from) <= delta ? to : from + Sign(to - from) * delta; return Abs(to - from) <= delta ? to : from + Sign(to - from) * delta;
} }
/// <summary>
/// Returns the nearest larger power of 2 for the integer `value`.
/// </summary>
/// <param name="value">The input value.</param>
/// <returns>The nearest larger power of 2.</returns>
public static int NearestPo2(int value) public static int NearestPo2(int value)
{ {
value--; value--;
@ -218,14 +431,25 @@ namespace Godot
return value; return value;
} }
/// <summary>
/// Converts a 2D point expressed in the polar coordinate
/// system (a distance from the origin `r` and an angle `th`)
/// to the cartesian coordinate system (X and Y axis).
/// </summary>
/// <param name="r">The distance from the origin.</param>
/// <param name="th">The angle of the point.</param>
/// <returns>A <see cref="Vector2"/> representing the cartesian coordinate.</returns>
public static Vector2 Polar2Cartesian(real_t r, real_t th) public static Vector2 Polar2Cartesian(real_t r, real_t th)
{ {
return new Vector2(r * Cos(th), r * Sin(th)); return new Vector2(r * Cos(th), r * Sin(th));
} }
/// <summary> /// <summary>
/// Performs a canonical Modulus operation, where the output is on the range [0, b). /// Performs a canonical Modulus operation, where the output is on the range `[0, b)`.
/// </summary> /// </summary>
/// <param name="a">The dividend, the primary input.</param>
/// <param name="b">The divisor. The output is on the range `[0, b)`.</param>
/// <returns>The resulting output.</returns>
public static int PosMod(int a, int b) public static int PosMod(int a, int b)
{ {
int c = a % b; int c = a % b;
@ -237,8 +461,11 @@ namespace Godot
} }
/// <summary> /// <summary>
/// Performs a canonical Modulus operation, where the output is on the range [0, b). /// Performs a canonical Modulus operation, where the output is on the range `[0, b)`.
/// </summary> /// </summary>
/// <param name="a">The dividend, the primary input.</param>
/// <param name="b">The divisor. The output is on the range `[0, b)`.</param>
/// <returns>The resulting output.</returns>
public static real_t PosMod(real_t a, real_t b) public static real_t PosMod(real_t a, real_t b)
{ {
real_t c = a % b; real_t c = a % b;
@ -249,43 +476,89 @@ namespace Godot
return c; return c;
} }
/// <summary>
/// Returns the result of `x` raised to the power of `y`.
/// </summary>
/// <param name="x">The base.</param>
/// <param name="y">The exponent.</param>
/// <returns>`x` raised to the power of `y`.</returns>
public static real_t Pow(real_t x, real_t y) public static real_t Pow(real_t x, real_t y)
{ {
return (real_t)Math.Pow(x, y); return (real_t)Math.Pow(x, y);
} }
/// <summary>
/// Converts an angle expressed in radians to degrees.
/// </summary>
/// <param name="rad">An angle expressed in radians.</param>
/// <returns>The same angle expressed in degrees.</returns>
public static real_t Rad2Deg(real_t rad) public static real_t Rad2Deg(real_t rad)
{ {
return rad * Rad2DegConst; return rad * Rad2DegConst;
} }
/// <summary>
/// Rounds `s` to the nearest whole number,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <param name="s">The number to round.</param>
/// <returns>The rounded number.</returns>
public static real_t Round(real_t s) public static real_t Round(real_t s)
{ {
return (real_t)Math.Round(s); return (real_t)Math.Round(s);
} }
/// <summary>
/// Returns the sign of `s`: `-1` or `1`. Returns `0` if `s` is `0`.
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>One of three possible values: `1`, `-1`, or `0`.</returns>
public static int Sign(int s) public static int Sign(int s)
{ {
if (s == 0) return 0; if (s == 0) return 0;
return s < 0 ? -1 : 1; return s < 0 ? -1 : 1;
} }
/// <summary>
/// Returns the sign of `s`: `-1` or `1`. Returns `0` if `s` is `0`.
/// </summary>
/// <param name="s">The input number.</param>
/// <returns>One of three possible values: `1`, `-1`, or `0`.</returns>
public static int Sign(real_t s) public static int Sign(real_t s)
{ {
if (s == 0) return 0; if (s == 0) return 0;
return s < 0 ? -1 : 1; return s < 0 ? -1 : 1;
} }
/// <summary>
/// Returns the sine of angle `s` in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The sine of that angle.</returns>
public static real_t Sin(real_t s) public static real_t Sin(real_t s)
{ {
return (real_t)Math.Sin(s); return (real_t)Math.Sin(s);
} }
/// <summary>
/// Returns the hyperbolic sine of angle `s` in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The hyperbolic sine of that angle.</returns>
public static real_t Sinh(real_t s) public static real_t Sinh(real_t s)
{ {
return (real_t)Math.Sinh(s); return (real_t)Math.Sinh(s);
} }
/// <summary>
/// Returns a number smoothly interpolated between `from` and `to`,
/// based on the `weight`. Similar to <see cref="Lerp(real_t, real_t, real_t)"/>,
/// but interpolates faster at the beginning and slower at the end.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
/// <param name="weight">A value representing the amount of interpolation.</param>
/// <returns>The resulting value of the interpolation.</returns>
public static real_t SmoothStep(real_t from, real_t to, real_t weight) public static real_t SmoothStep(real_t from, real_t to, real_t weight)
{ {
if (IsEqualApprox(from, to)) if (IsEqualApprox(from, to))
@ -296,11 +569,25 @@ namespace Godot
return x * x * (3 - 2 * x); return x * x * (3 - 2 * x);
} }
/// <summary>
/// Returns the square root of `s`, where `s` is a non-negative number.
///
/// If you need negative inputs, use `System.Numerics.Complex`.
/// </summary>
/// <param name="s">The input number. Must not be negative.</param>
/// <returns>The square root of `s`.</returns>
public static real_t Sqrt(real_t s) public static real_t Sqrt(real_t s)
{ {
return (real_t)Math.Sqrt(s); return (real_t)Math.Sqrt(s);
} }
/// <summary>
/// Returns the position of the first non-zero digit, after the
/// decimal point. Note that the maximum return value is 10,
/// which is a design decision in the implementation.
/// </summary>
/// <param name="step">The input value.</param>
/// <returns>The position of the first non-zero digit.</returns>
public static int StepDecimals(real_t step) public static int StepDecimals(real_t step)
{ {
double[] sd = new double[] { double[] sd = new double[] {
@ -326,32 +613,68 @@ namespace Godot
return 0; return 0;
} }
/// <summary>
/// Snaps float value `s` to a given `step`.
/// This can also be used to round a floating point
/// number to an arbitrary number of decimals.
/// </summary>
/// <param name="s">The value to stepify.</param>
/// <param name="step">The step size to snap to.</param>
/// <returns></returns>
public static real_t Stepify(real_t s, real_t step) public static real_t Stepify(real_t s, real_t step)
{ {
if (step != 0f) if (step != 0f)
{ {
s = Floor(s / step + 0.5f) * step; return Floor(s / step + 0.5f) * step;
} }
return s; return s;
} }
/// <summary>
/// Returns the tangent of angle `s` in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The tangent of that angle.</returns>
public static real_t Tan(real_t s) public static real_t Tan(real_t s)
{ {
return (real_t)Math.Tan(s); return (real_t)Math.Tan(s);
} }
/// <summary>
/// Returns the hyperbolic tangent of angle `s` in radians.
/// </summary>
/// <param name="s">The angle in radians.</param>
/// <returns>The hyperbolic tangent of that angle.</returns>
public static real_t Tanh(real_t s) public static real_t Tanh(real_t s)
{ {
return (real_t)Math.Tanh(s); return (real_t)Math.Tanh(s);
} }
/// <summary>
/// Wraps `value` between `min` and `max`. Usable for creating loop-alike
/// behavior or infinite surfaces. If `min` is `0`, this is equivalent
/// to <see cref="PosMod(int, int)"/>, so prefer using that instead.
/// </summary>
/// <param name="value">The value to wrap.</param>
/// <param name="min">The minimum allowed value and lower bound of the range.</param>
/// <param name="max">The maximum allowed value and upper bound of the range.</param>
/// <returns>The wrapped value.</returns>
public static int Wrap(int value, int min, int max) public static int Wrap(int value, int min, int max)
{ {
int range = max - min; int range = max - min;
return range == 0 ? min : min + ((value - min) % range + range) % range; return range == 0 ? min : min + ((value - min) % range + range) % range;
} }
/// <summary>
/// Wraps `value` between `min` and `max`. Usable for creating loop-alike
/// behavior or infinite surfaces. If `min` is `0`, this is equivalent
/// to <see cref="PosMod(real_t, real_t)"/>, so prefer using that instead.
/// </summary>
/// <param name="value">The value to wrap.</param>
/// <param name="min">The minimum allowed value and lower bound of the range.</param>
/// <param name="max">The maximum allowed value and upper bound of the range.</param>
/// <returns>The wrapped value.</returns>
public static real_t Wrap(real_t value, real_t min, real_t max) public static real_t Wrap(real_t value, real_t min, real_t max)
{ {
real_t range = max - min; real_t range = max - min;

View File

@ -12,40 +12,89 @@ namespace Godot
{ {
// Define constants with Decimal precision and cast down to double or float. // Define constants with Decimal precision and cast down to double or float.
/// <summary>
/// The natural number `e`.
/// </summary>
public const real_t E = (real_t) 2.7182818284590452353602874714M; // 2.7182817f and 2.718281828459045 public const real_t E = (real_t) 2.7182818284590452353602874714M; // 2.7182817f and 2.718281828459045
/// <summary>
/// The square root of 2.
/// </summary>
public const real_t Sqrt2 = (real_t) 1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095 public const real_t Sqrt2 = (real_t) 1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095
/// <summary>
/// A very small number used for float comparison with error tolerance.
/// 1e-06 with single-precision floats, but 1e-14 if `REAL_T_IS_DOUBLE`.
/// </summary>
#if REAL_T_IS_DOUBLE #if REAL_T_IS_DOUBLE
public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used. public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used.
#else #else
public const real_t Epsilon = 1e-06f; public const real_t Epsilon = 1e-06f;
#endif #endif
/// <summary>
/// Returns the amount of digits after the decimal place.
/// </summary>
/// <param name="s">The input value.</param>
/// <returns>The amount of digits.</returns>
public static int DecimalCount(real_t s) public static int DecimalCount(real_t s)
{ {
return DecimalCount((decimal)s); return DecimalCount((decimal)s);
} }
/// <summary>
/// Returns the amount of digits after the decimal place.
/// </summary>
/// <param name="s">The input <see cref="System.Decimal"/> value.</param>
/// <returns>The amount of digits.</returns>
public static int DecimalCount(decimal s) public static int DecimalCount(decimal s)
{ {
return BitConverter.GetBytes(decimal.GetBits(s)[3])[2]; return BitConverter.GetBytes(decimal.GetBits(s)[3])[2];
} }
/// <summary>
/// Rounds `s` upward (towards positive infinity).
///
/// This is the same as <see cref="Ceil(real_t)"/>, but returns an `int`.
/// </summary>
/// <param name="s">The number to ceil.</param>
/// <returns>The smallest whole number that is not less than `s`.</returns>
public static int CeilToInt(real_t s) public static int CeilToInt(real_t s)
{ {
return (int)Math.Ceiling(s); return (int)Math.Ceiling(s);
} }
/// <summary>
/// Rounds `s` downward (towards negative infinity).
///
/// This is the same as <see cref="Floor(real_t)"/>, but returns an `int`.
/// </summary>
/// <param name="s">The number to floor.</param>
/// <returns>The largest whole number that is not more than `s`.</returns>
public static int FloorToInt(real_t s) public static int FloorToInt(real_t s)
{ {
return (int)Math.Floor(s); return (int)Math.Floor(s);
} }
/// <summary>
///
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static int RoundToInt(real_t s) public static int RoundToInt(real_t s)
{ {
return (int)Math.Round(s); return (int)Math.Round(s);
} }
/// <summary>
/// Returns true if `a` and `b` are approximately equal to each other.
/// The comparison is done using the provided tolerance value.
/// If you want the tolerance to be calculated for you, use <see cref="IsEqualApprox(real_t, real_t)"/>.
/// </summary>
/// <param name="a">One of the values.</param>
/// <param name="b">The other value.</param>
/// <param name="tolerance">The pre-calculated tolerance value.</param>
/// <returns>A bool for whether or not the two values are equal.</returns>
public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance) public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance)
{ {
// Check for exact equality first, required to handle "infinity" values. // Check for exact equality first, required to handle "infinity" values.

View File

@ -8,18 +8,33 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// Plane represents a normalized plane equation.
/// "Over" or "Above" the plane is considered the side of
/// the plane towards where the normal is pointing.
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Plane : IEquatable<Plane> public struct Plane : IEquatable<Plane>
{ {
private Vector3 _normal; private Vector3 _normal;
/// <summary>
/// The normal of the plane, which must be normalized.
/// In the scalar equation of the plane `ax + by + cz = d`, this is
/// the vector `(a, b, c)`, where `d` is the <see cref="D"/> property.
/// </summary>
/// <value>Equivalent to `x`, `y`, and `z`.</value>
public Vector3 Normal public Vector3 Normal
{ {
get { return _normal; } get { return _normal; }
set { _normal = value; } set { _normal = value; }
} }
/// <summary>
/// The X component of the plane's normal vector.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/>'s X value.</value>
public real_t x public real_t x
{ {
get get
@ -32,6 +47,10 @@ namespace Godot
} }
} }
/// <summary>
/// The Y component of the plane's normal vector.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/>'s Y value.</value>
public real_t y public real_t y
{ {
get get
@ -44,6 +63,10 @@ namespace Godot
} }
} }
/// <summary>
/// The Z component of the plane's normal vector.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/>'s Z value.</value>
public real_t z public real_t z
{ {
get get
@ -56,38 +79,82 @@ namespace Godot
} }
} }
/// <summary>
/// The distance from the origin to the plane (in the direction of
/// <see cref="Normal"/>). This value is typically non-negative.
/// In the scalar equation of the plane `ax + by + cz = d`,
/// this is `d`, while the `(a, b, c)` coordinates are represented
/// by the <see cref="Normal"/> property.
/// </summary>
/// <value>The plane's distance from the origin.</value>
public real_t D { get; set; } public real_t D { get; set; }
/// <summary>
/// The center of the plane, the point where the normal line intersects the plane.
/// </summary>
/// <value>Equivalent to <see cref="Normal"/> multiplied by `D`.</value>
public Vector3 Center public Vector3 Center
{ {
get get
{ {
return _normal * D; return _normal * D;
} }
set
{
_normal = value.Normalized();
D = value.Length();
}
} }
/// <summary>
/// Returns the shortest distance from this plane to the position `point`.
/// </summary>
/// <param name="point">The position to use for the calcualtion.</param>
/// <returns>The shortest distance.</returns>
public real_t DistanceTo(Vector3 point) public real_t DistanceTo(Vector3 point)
{ {
return _normal.Dot(point) - D; return _normal.Dot(point) - D;
} }
/// <summary>
/// The center of the plane, the point where the normal line intersects the plane.
/// Deprecated, use the Center property instead.
/// </summary>
/// <returns>Equivalent to <see cref="Normal"/> multiplied by `D`.</returns>
[Obsolete("GetAnyPoint is deprecated. Use the Center property instead.")]
public Vector3 GetAnyPoint() public Vector3 GetAnyPoint()
{ {
return _normal * D; return _normal * D;
} }
/// <summary>
/// Returns true if point is inside the plane.
/// Comparison uses a custom minimum epsilon threshold.
/// </summary>
/// <param name="point">The point to check.</param>
/// <param name="epsilon">The tolerance threshold.</param>
/// <returns>A bool for whether or not the plane has the point.</returns>
public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon) public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon)
{ {
real_t dist = _normal.Dot(point) - D; real_t dist = _normal.Dot(point) - D;
return Mathf.Abs(dist) <= epsilon; return Mathf.Abs(dist) <= epsilon;
} }
/// <summary>
/// Returns the intersection point of the three planes: `b`, `c`,
/// and this plane. If no intersection is found, `null` is returned.
/// </summary>
/// <param name="b">One of the three planes to use in the calculation.</param>
/// <param name="c">One of the three planes to use in the calculation.</param>
/// <returns>The intersection, or `null` if none is found.</returns>
public Vector3? Intersect3(Plane b, Plane c) public Vector3? Intersect3(Plane b, Plane c)
{ {
real_t denom = _normal.Cross(b._normal).Dot(c._normal); real_t denom = _normal.Cross(b._normal).Dot(c._normal);
if (Mathf.IsZeroApprox(denom)) if (Mathf.IsZeroApprox(denom))
{
return null; return null;
}
Vector3 result = b._normal.Cross(c._normal) * D + Vector3 result = b._normal.Cross(c._normal) * D +
c._normal.Cross(_normal) * b.D + c._normal.Cross(_normal) * b.D +
@ -96,54 +163,94 @@ namespace Godot
return result / denom; return result / denom;
} }
/// <summary>
/// Returns the intersection point of a ray consisting of the
/// position `from` and the direction normal `dir` with this plane.
/// If no intersection is found, `null` is returned.
/// </summary>
/// <param name="from">The start of the ray.</param>
/// <param name="dir">The direction of the ray, normalized.</param>
/// <returns>The intersection, or `null` if none is found.</returns>
public Vector3? IntersectRay(Vector3 from, Vector3 dir) public Vector3? IntersectRay(Vector3 from, Vector3 dir)
{ {
real_t den = _normal.Dot(dir); real_t den = _normal.Dot(dir);
if (Mathf.IsZeroApprox(den)) if (Mathf.IsZeroApprox(den))
{
return null; return null;
}
real_t dist = (_normal.Dot(from) - D) / den; real_t dist = (_normal.Dot(from) - D) / den;
// This is a ray, before the emitting pos (from) does not exist // This is a ray, before the emitting pos (from) does not exist
if (dist > Mathf.Epsilon) if (dist > Mathf.Epsilon)
{
return null; return null;
}
return from + dir * -dist; return from + dir * -dist;
} }
/// <summary>
/// Returns the intersection point of a line segment from
/// position `begin` to position `end` with this plane.
/// If no intersection is found, `null` is returned.
/// </summary>
/// <param name="begin">The start of the line segment.</param>
/// <param name="end">The end of the line segment.</param>
/// <returns>The intersection, or `null` if none is found.</returns>
public Vector3? IntersectSegment(Vector3 begin, Vector3 end) public Vector3? IntersectSegment(Vector3 begin, Vector3 end)
{ {
Vector3 segment = begin - end; Vector3 segment = begin - end;
real_t den = _normal.Dot(segment); real_t den = _normal.Dot(segment);
if (Mathf.IsZeroApprox(den)) if (Mathf.IsZeroApprox(den))
{
return null; return null;
}
real_t dist = (_normal.Dot(begin) - D) / den; real_t dist = (_normal.Dot(begin) - D) / den;
// Only allow dist to be in the range of 0 to 1, with tolerance. // Only allow dist to be in the range of 0 to 1, with tolerance.
if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon) if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon)
{
return null; return null;
}
return begin + segment * -dist; return begin + segment * -dist;
} }
/// <summary>
/// Returns true if `point` is located above the plane.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>A bool for whether or not the point is above the plane.</returns>
public bool IsPointOver(Vector3 point) public bool IsPointOver(Vector3 point)
{ {
return _normal.Dot(point) > D; return _normal.Dot(point) > D;
} }
/// <summary>
/// Returns the plane scaled to unit length.
/// </summary>
/// <returns>A normalized version of the plane.</returns>
public Plane Normalized() public Plane Normalized()
{ {
real_t len = _normal.Length(); real_t len = _normal.Length();
if (len == 0) if (len == 0)
{
return new Plane(0, 0, 0, 0); return new Plane(0, 0, 0, 0);
}
return new Plane(_normal / len, D / len); return new Plane(_normal / len, D / len);
} }
/// <summary>
/// Returns the orthogonal projection of `point` into the plane.
/// </summary>
/// <param name="point">The point to project.</param>
/// <returns>The projected point.</returns>
public Vector3 Project(Vector3 point) public Vector3 Project(Vector3 point)
{ {
return point - _normal * DistanceTo(point); return point - _normal * DistanceTo(point);
@ -154,22 +261,56 @@ namespace Godot
private static readonly Plane _planeXZ = new Plane(0, 1, 0, 0); private static readonly Plane _planeXZ = new Plane(0, 1, 0, 0);
private static readonly Plane _planeXY = new Plane(0, 0, 1, 0); private static readonly Plane _planeXY = new Plane(0, 0, 1, 0);
/// <summary>
/// A plane that extends in the Y and Z axes (normal vector points +X).
/// </summary>
/// <value>Equivalent to `new Plane(1, 0, 0, 0)`.</value>
public static Plane PlaneYZ { get { return _planeYZ; } } public static Plane PlaneYZ { get { return _planeYZ; } }
/// <summary>
/// A plane that extends in the X and Z axes (normal vector points +Y).
/// </summary>
/// <value>Equivalent to `new Plane(0, 1, 0, 0)`.</value>
public static Plane PlaneXZ { get { return _planeXZ; } } public static Plane PlaneXZ { get { return _planeXZ; } }
/// <summary>
/// A plane that extends in the X and Y axes (normal vector points +Z).
/// </summary>
/// <value>Equivalent to `new Plane(0, 0, 1, 0)`.</value>
public static Plane PlaneXY { get { return _planeXY; } } public static Plane PlaneXY { get { return _planeXY; } }
// Constructors /// <summary>
/// Constructs a plane from four values. `a`, `b` and `c` become the
/// components of the resulting plane's <see cref="Normal"/> vector.
/// `d` becomes the plane's distance from the origin.
/// </summary>
/// <param name="a">The X component of the plane's normal vector.</param>
/// <param name="b">The Y component of the plane's normal vector.</param>
/// <param name="c">The Z component of the plane's normal vector.</param>
/// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param>
public Plane(real_t a, real_t b, real_t c, real_t d) public Plane(real_t a, real_t b, real_t c, real_t d)
{ {
_normal = new Vector3(a, b, c); _normal = new Vector3(a, b, c);
this.D = d; this.D = d;
} }
/// <summary>
/// Constructs a plane from a normal vector and the plane's distance to the origin.
/// </summary>
/// <param name="normal">The normal of the plane, must be normalized.</param>
/// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param>
public Plane(Vector3 normal, real_t d) public Plane(Vector3 normal, real_t d)
{ {
this._normal = normal; this._normal = normal;
this.D = d; this.D = d;
} }
/// <summary>
/// Constructs a plane from the three points, given in clockwise order.
/// </summary>
/// <param name="v1">The first point.</param>
/// <param name="v2">The second point.</param>
/// <param name="v3">The third point.</param>
public Plane(Vector3 v1, Vector3 v2, Vector3 v3) public Plane(Vector3 v1, Vector3 v2, Vector3 v3)
{ {
_normal = (v1 - v3).Cross(v1 - v2); _normal = (v1 - v3).Cross(v1 - v2);
@ -207,6 +348,12 @@ namespace Godot
return _normal == other._normal && D == other.D; return _normal == other._normal && D == other.D;
} }
/// <summary>
/// Returns true if this plane and `other` are approximately equal, by running
/// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component.
/// </summary>
/// <param name="other">The other plane to compare.</param>
/// <returns>Whether or not the planes are approximately equal.</returns>
public bool IsEqualApprox(Plane other) public bool IsEqualApprox(Plane other)
{ {
return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D); return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D);

View File

@ -8,15 +8,51 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// A unit quaternion used for representing 3D rotations.
/// Quaternions need to be normalized to be used for rotation.
///
/// It is similar to Basis, which implements matrix representation of
/// rotations, and can be parametrized using both an axis-angle pair
/// or Euler angles. Basis stores rotation, scale, and shearing,
/// while Quat only stores rotation.
///
/// Due to its compactness and the way it is stored in memory, certain
/// operations (obtaining axis-angle and performing SLERP, in particular)
/// are more efficient and robust against floating-point errors.
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Quat : IEquatable<Quat> public struct Quat : IEquatable<Quat>
{ {
/// <summary>
/// X component of the quaternion (imaginary `i` axis part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
public real_t x; public real_t x;
/// <summary>
/// Y component of the quaternion (imaginary `j` axis part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
public real_t y; public real_t y;
/// <summary>
/// Z component of the quaternion (imaginary `k` axis part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
public real_t z; public real_t z;
/// <summary>
/// W component of the quaternion (real part).
/// Quaternion components should usually not be manipulated directly.
/// </summary>
public real_t w; public real_t w;
/// <summary>
/// Access quaternion components using their index.
/// </summary>
/// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`, `[2]` is equivalent to `.z`, `[3]` is equivalent to `.w`.</value>
public real_t this[int index] public real_t this[int index]
{ {
get get
@ -57,16 +93,35 @@ namespace Godot
} }
} }
/// <summary>
/// Returns the length (magnitude) of the quaternion.
/// </summary>
/// <value>Equivalent to `Mathf.Sqrt(LengthSquared)`.</value>
public real_t Length public real_t Length
{ {
get { return Mathf.Sqrt(LengthSquared); } get { return Mathf.Sqrt(LengthSquared); }
} }
/// <summary>
/// Returns the squared length (squared magnitude) of the quaternion.
/// This method runs faster than <see cref="Length"/>, so prefer it if
/// you need to compare quaternions or need the squared length for some formula.
/// </summary>
/// <value>Equivalent to `Dot(this)`.</value>
public real_t LengthSquared public real_t LengthSquared
{ {
get { return Dot(this); } get { return Dot(this); }
} }
/// <summary>
/// Performs a cubic spherical interpolation between quaternions `preA`,
/// this vector, `b`, and `postB`, by the given amount `t`.
/// </summary>
/// <param name="b">The destination quaternion.</param>
/// <param name="preA">A quaternion before this quaternion.</param>
/// <param name="postB">A quaternion after `b`.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated quaternion.</returns>
public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t) public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t)
{ {
real_t t2 = (1.0f - t) * t * 2f; real_t t2 = (1.0f - t) * t * 2f;
@ -75,30 +130,63 @@ namespace Godot
return sp.Slerpni(sq, t2); return sp.Slerpni(sq, t2);
} }
/// <summary>
/// Returns the dot product of two quaternions.
/// </summary>
/// <param name="b">The other quaternion.</param>
/// <returns>The dot product.</returns>
public real_t Dot(Quat b) public real_t Dot(Quat b)
{ {
return x * b.x + y * b.y + z * b.z + w * b.w; return x * b.x + y * b.y + z * b.z + w * b.w;
} }
/// <summary>
/// Returns Euler angles (in the YXZ convention: when decomposing,
/// first Z, then X, and Y last) corresponding to the rotation
/// represented by the unit quaternion. Returned vector contains
/// the rotation angles in the format (X angle, Y angle, Z angle).
/// </summary>
/// <returns>The Euler angle representation of this quaternion.</returns>
public Vector3 GetEuler() public Vector3 GetEuler()
{ {
#if DEBUG #if DEBUG
if (!IsNormalized()) if (!IsNormalized())
{
throw new InvalidOperationException("Quat is not normalized"); throw new InvalidOperationException("Quat is not normalized");
}
#endif #endif
var basis = new Basis(this); var basis = new Basis(this);
return basis.GetEuler(); return basis.GetEuler();
} }
/// <summary>
/// Returns the inverse of the quaternion.
/// </summary>
/// <returns>The inverse quaternion.</returns>
public Quat Inverse() public Quat Inverse()
{ {
#if DEBUG #if DEBUG
if (!IsNormalized()) if (!IsNormalized())
{
throw new InvalidOperationException("Quat is not normalized"); throw new InvalidOperationException("Quat is not normalized");
}
#endif #endif
return new Quat(-x, -y, -z, w); return new Quat(-x, -y, -z, w);
} }
/// <summary>
/// Returns whether the quaternion is normalized or not.
/// </summary>
/// <returns>A bool for whether the quaternion is normalized or not.</returns>
public bool IsNormalized()
{
return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon;
}
/// <summary>
/// Returns a copy of the quaternion, normalized to unit length.
/// </summary>
/// <returns>The normalized quaternion.</returns>
public Quat Normalized() public Quat Normalized()
{ {
return this / Length; return this / Length;
@ -131,56 +219,69 @@ namespace Godot
this = new Quat(eulerYXZ); this = new Quat(eulerYXZ);
} }
public Quat Slerp(Quat b, real_t t) /// <summary>
/// Returns the result of the spherical linear interpolation between
/// this quaternion and `to` by amount `weight`.
///
/// Note: Both quaternions must be normalized.
/// </summary>
/// <param name="to">The destination quaternion for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting quaternion of the interpolation.</returns>
public Quat Slerp(Quat to, real_t weight)
{ {
#if DEBUG #if DEBUG
if (!IsNormalized()) if (!IsNormalized())
{
throw new InvalidOperationException("Quat is not normalized"); throw new InvalidOperationException("Quat is not normalized");
if (!b.IsNormalized()) }
throw new ArgumentException("Argument is not normalized", nameof(b)); if (!to.IsNormalized())
{
throw new ArgumentException("Argument is not normalized", nameof(to));
}
#endif #endif
// Calculate cosine // Calculate cosine.
real_t cosom = x * b.x + y * b.y + z * b.z + w * b.w; real_t cosom = x * to.x + y * to.y + z * to.z + w * to.w;
var to1 = new Quat(); var to1 = new Quat();
// Adjust signs if necessary // Adjust signs if necessary.
if (cosom < 0.0) if (cosom < 0.0)
{ {
cosom = -cosom; cosom = -cosom;
to1.x = -b.x; to1.x = -to.x;
to1.y = -b.y; to1.y = -to.y;
to1.z = -b.z; to1.z = -to.z;
to1.w = -b.w; to1.w = -to.w;
} }
else else
{ {
to1.x = b.x; to1.x = to.x;
to1.y = b.y; to1.y = to.y;
to1.z = b.z; to1.z = to.z;
to1.w = b.w; to1.w = to.w;
} }
real_t sinom, scale0, scale1; real_t sinom, scale0, scale1;
// Calculate coefficients // Calculate coefficients.
if (1.0 - cosom > Mathf.Epsilon) if (1.0 - cosom > Mathf.Epsilon)
{ {
// Standard case (Slerp) // Standard case (Slerp).
real_t omega = Mathf.Acos(cosom); real_t omega = Mathf.Acos(cosom);
sinom = Mathf.Sin(omega); sinom = Mathf.Sin(omega);
scale0 = Mathf.Sin((1.0f - t) * omega) / sinom; scale0 = Mathf.Sin((1.0f - weight) * omega) / sinom;
scale1 = Mathf.Sin(t * omega) / sinom; scale1 = Mathf.Sin(weight * omega) / sinom;
} }
else else
{ {
// Quaternions are very close so we can do a linear interpolation // Quaternions are very close so we can do a linear interpolation.
scale0 = 1.0f - t; scale0 = 1.0f - weight;
scale1 = t; scale1 = weight;
} }
// Calculate final values // Calculate final values.
return new Quat return new Quat
( (
scale0 * x + scale1 * to1.x, scale0 * x + scale1 * to1.x,
@ -190,9 +291,17 @@ namespace Godot
); );
} }
public Quat Slerpni(Quat b, real_t t) /// <summary>
/// Returns the result of the spherical linear interpolation between
/// this quaternion and `to` by amount `weight`, but without
/// checking if the rotation path is not bigger than 90 degrees.
/// </summary>
/// <param name="to">The destination quaternion for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting quaternion of the interpolation.</returns>
public Quat Slerpni(Quat to, real_t weight)
{ {
real_t dot = Dot(b); real_t dot = Dot(to);
if (Mathf.Abs(dot) > 0.9999f) if (Mathf.Abs(dot) > 0.9999f)
{ {
@ -201,33 +310,54 @@ namespace Godot
real_t theta = Mathf.Acos(dot); real_t theta = Mathf.Acos(dot);
real_t sinT = 1.0f / Mathf.Sin(theta); real_t sinT = 1.0f / Mathf.Sin(theta);
real_t newFactor = Mathf.Sin(t * theta) * sinT; real_t newFactor = Mathf.Sin(weight * theta) * sinT;
real_t invFactor = Mathf.Sin((1.0f - t) * theta) * sinT; real_t invFactor = Mathf.Sin((1.0f - weight) * theta) * sinT;
return new Quat return new Quat
( (
invFactor * x + newFactor * b.x, invFactor * x + newFactor * to.x,
invFactor * y + newFactor * b.y, invFactor * y + newFactor * to.y,
invFactor * z + newFactor * b.z, invFactor * z + newFactor * to.z,
invFactor * w + newFactor * b.w invFactor * w + newFactor * to.w
); );
} }
/// <summary>
/// Returns a vector transformed (multiplied) by this quaternion.
/// </summary>
/// <param name="v">A vector to transform.</param>
/// <returns>The transfomed vector.</returns>
public Vector3 Xform(Vector3 v) public Vector3 Xform(Vector3 v)
{ {
#if DEBUG #if DEBUG
if (!IsNormalized()) if (!IsNormalized())
{
throw new InvalidOperationException("Quat is not normalized"); throw new InvalidOperationException("Quat is not normalized");
}
#endif #endif
var u = new Vector3(x, y, z); var u = new Vector3(x, y, z);
Vector3 uv = u.Cross(v); Vector3 uv = u.Cross(v);
return v + ((uv * w) + u.Cross(uv)) * 2; return v + ((uv * w) + u.Cross(uv)) * 2;
} }
// Static Readonly Properties // Constants
public static Quat Identity { get; } = new Quat(0f, 0f, 0f, 1f); private static readonly Quat _identity = new Quat(0, 0, 0, 1);
// Constructors /// <summary>
/// The identity quaternion, representing no rotation.
/// Equivalent to an identity <see cref="Basis"/> matrix. If a vector is transformed by
/// an identity quaternion, it will not change.
/// </summary>
/// <value>Equivalent to `new Quat(0, 0, 0, 1)`.</value>
public static Quat Identity { get { return _identity; } }
/// <summary>
/// Constructs a quaternion defined by the given values.
/// </summary>
/// <param name="x">X component of the quaternion (imaginary `i` axis part).</param>
/// <param name="y">Y component of the quaternion (imaginary `j` axis part).</param>
/// <param name="z">Z component of the quaternion (imaginary `k` axis part).</param>
/// <param name="w">W component of the quaternion (real part).</param>
public Quat(real_t x, real_t y, real_t z, real_t w) public Quat(real_t x, real_t y, real_t z, real_t w)
{ {
this.x = x; this.x = x;
@ -236,21 +366,31 @@ namespace Godot
this.w = w; this.w = w;
} }
public bool IsNormalized() /// <summary>
{ /// Constructs a quaternion from the given quaternion.
return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon; /// </summary>
} /// <param name="q">The existing quaternion.</param>
public Quat(Quat q) public Quat(Quat q)
{ {
this = q; this = q;
} }
/// <summary>
/// Constructs a quaternion from the given <see cref="Basis"/>.
/// </summary>
/// <param name="basis">The basis to construct from.</param>
public Quat(Basis basis) public Quat(Basis basis)
{ {
this = basis.Quat(); this = basis.Quat();
} }
/// <summary>
/// Constructs a quaternion that will perform a rotation specified by
/// Euler angles (in the YXZ convention: when decomposing,
/// first Z, then X, and Y last),
/// given in the vector format as (X angle, Y angle, Z angle).
/// </summary>
/// <param name="eulerYXZ"></param>
public Quat(Vector3 eulerYXZ) public Quat(Vector3 eulerYXZ)
{ {
real_t half_a1 = eulerYXZ.y * 0.5f; real_t half_a1 = eulerYXZ.y * 0.5f;
@ -274,11 +414,19 @@ namespace Godot
w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3; w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
} }
/// <summary>
/// Constructs a quaternion that will rotate around the given axis
/// by the specified angle. The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
public Quat(Vector3 axis, real_t angle) public Quat(Vector3 axis, real_t angle)
{ {
#if DEBUG #if DEBUG
if (!axis.IsNormalized()) if (!axis.IsNormalized())
{
throw new ArgumentException("Argument is not normalized", nameof(axis)); throw new ArgumentException("Argument is not normalized", nameof(axis));
}
#endif #endif
real_t d = axis.Length(); real_t d = axis.Length();
@ -391,6 +539,12 @@ namespace Godot
return x == other.x && y == other.y && z == other.z && w == other.w; return x == other.x && y == other.y && z == other.z && w == other.w;
} }
/// <summary>
/// Returns true if this quaternion and `other` are approximately equal, by running
/// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component.
/// </summary>
/// <param name="other">The other quaternion to compare.</param>
/// <returns>Whether or not the quaternions are approximately equal.</returns>
public bool IsEqualApprox(Quat other) public bool IsEqualApprox(Quat other)
{ {
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);

View File

@ -8,6 +8,10 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// 2D axis-aligned bounding box. Rect2 consists of a position, a size, and
/// several utility functions. It is typically used for fast overlap tests.
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Rect2 : IEquatable<Rect2> public struct Rect2 : IEquatable<Rect2>
@ -15,29 +19,52 @@ namespace Godot
private Vector2 _position; private Vector2 _position;
private Vector2 _size; private Vector2 _size;
/// <summary>
/// Beginning corner. Typically has values lower than End.
/// </summary>
/// <value>Directly uses a private field.</value>
public Vector2 Position public Vector2 Position
{ {
get { return _position; } get { return _position; }
set { _position = value; } set { _position = value; }
} }
/// <summary>
/// Size from Position to End. Typically all components are positive.
/// If the size is negative, you can use <see cref="Abs"/> to fix it.
/// </summary>
/// <value>Directly uses a private field.</value>
public Vector2 Size public Vector2 Size
{ {
get { return _size; } get { return _size; }
set { _size = value; } set { _size = value; }
} }
/// <summary>
/// Ending corner. This is calculated as <see cref="Position"/> plus
/// <see cref="Size"/>. Setting this value will change the size.
/// </summary>
/// <value>Getting is equivalent to `value = Position + Size`, setting is equivalent to `Size = value - Position`.</value>
public Vector2 End public Vector2 End
{ {
get { return _position + _size; } get { return _position + _size; }
set { _size = value - _position; } set { _size = value - _position; }
} }
/// <summary>
/// The area of this rect.
/// </summary>
/// <value>Equivalent to <see cref="GetArea()"/>.</value>
public real_t Area public real_t Area
{ {
get { return GetArea(); } get { return GetArea(); }
} }
/// <summary>
/// Returns a Rect2 with equivalent position and size, modified so that
/// the top-left corner is the origin and width and height are positive.
/// </summary>
/// <returns>The modified rect.</returns>
public Rect2 Abs() public Rect2 Abs()
{ {
Vector2 end = End; Vector2 end = End;
@ -45,12 +72,19 @@ namespace Godot
return new Rect2(topLeft, _size.Abs()); return new Rect2(topLeft, _size.Abs());
} }
/// <summary>
/// Returns the intersection of this Rect2 and `b`.
/// </summary>
/// <param name="b">The other rect.</param>
/// <returns>The clipped rect.</returns>
public Rect2 Clip(Rect2 b) public Rect2 Clip(Rect2 b)
{ {
var newRect = b; var newRect = b;
if (!Intersects(newRect)) if (!Intersects(newRect))
{
return new Rect2(); return new Rect2();
}
newRect._position.x = Mathf.Max(b._position.x, _position.x); newRect._position.x = Mathf.Max(b._position.x, _position.x);
newRect._position.y = Mathf.Max(b._position.y, _position.y); newRect._position.y = Mathf.Max(b._position.y, _position.y);
@ -64,6 +98,11 @@ namespace Godot
return newRect; return newRect;
} }
/// <summary>
/// Returns true if this Rect2 completely encloses another one.
/// </summary>
/// <param name="b">The other rect that may be enclosed.</param>
/// <returns>A bool for whether or not this rect encloses `b`.</returns>
public bool Encloses(Rect2 b) public bool Encloses(Rect2 b)
{ {
return b._position.x >= _position.x && b._position.y >= _position.y && return b._position.x >= _position.x && b._position.y >= _position.y &&
@ -71,6 +110,11 @@ namespace Godot
b._position.y + b._size.y < _position.y + _size.y; b._position.y + b._size.y < _position.y + _size.y;
} }
/// <summary>
/// Returns this Rect2 expanded to include a given point.
/// </summary>
/// <param name="to">The point to include.</param>
/// <returns>The expanded rect.</returns>
public Rect2 Expand(Vector2 to) public Rect2 Expand(Vector2 to)
{ {
var expanded = this; var expanded = this;
@ -79,14 +123,22 @@ namespace Godot
Vector2 end = expanded._position + expanded._size; Vector2 end = expanded._position + expanded._size;
if (to.x < begin.x) if (to.x < begin.x)
{
begin.x = to.x; begin.x = to.x;
}
if (to.y < begin.y) if (to.y < begin.y)
{
begin.y = to.y; begin.y = to.y;
}
if (to.x > end.x) if (to.x > end.x)
{
end.x = to.x; end.x = to.x;
}
if (to.y > end.y) if (to.y > end.y)
{
end.y = to.y; end.y = to.y;
}
expanded._position = begin; expanded._position = begin;
expanded._size = end - begin; expanded._size = end - begin;
@ -94,11 +146,20 @@ namespace Godot
return expanded; return expanded;
} }
/// <summary>
/// Returns the area of the Rect2.
/// </summary>
/// <returns>The area.</returns>
public real_t GetArea() public real_t GetArea()
{ {
return _size.x * _size.y; return _size.x * _size.y;
} }
/// <summary>
/// Returns a copy of the Rect2 grown a given amount of units towards all the sides.
/// </summary>
/// <param name="by">The amount to grow by.</param>
/// <returns>The grown rect.</returns>
public Rect2 Grow(real_t by) public Rect2 Grow(real_t by)
{ {
var g = this; var g = this;
@ -111,6 +172,14 @@ namespace Godot
return g; return g;
} }
/// <summary>
/// Returns a copy of the Rect2 grown a given amount of units towards each direction individually.
/// </summary>
/// <param name="left">The amount to grow by on the left.</param>
/// <param name="top">The amount to grow by on the top.</param>
/// <param name="right">The amount to grow by on the right.</param>
/// <param name="bottom">The amount to grow by on the bottom.</param>
/// <returns>The grown rect.</returns>
public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom) public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom)
{ {
var g = this; var g = this;
@ -123,6 +192,12 @@ namespace Godot
return g; return g;
} }
/// <summary>
/// Returns a copy of the Rect2 grown a given amount of units towards the <see cref="Margin"/> direction.
/// </summary>
/// <param name="margin">The direction to grow in.</param>
/// <param name="by">The amount to grow by.</param>
/// <returns>The grown rect.</returns>
public Rect2 GrowMargin(Margin margin, real_t by) public Rect2 GrowMargin(Margin margin, real_t by)
{ {
var g = this; var g = this;
@ -135,11 +210,20 @@ namespace Godot
return g; return g;
} }
/// <summary>
/// Returns true if the Rect2 is flat or empty, or false otherwise.
/// </summary>
/// <returns>A bool for whether or not the rect has area.</returns>
public bool HasNoArea() public bool HasNoArea()
{ {
return _size.x <= 0 || _size.y <= 0; return _size.x <= 0 || _size.y <= 0;
} }
/// <summary>
/// Returns true if the Rect2 contains a point, or false otherwise.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>A bool for whether or not the rect contains `point`.</returns>
public bool HasPoint(Vector2 point) public bool HasPoint(Vector2 point)
{ {
if (point.x < _position.x) if (point.x < _position.x)
@ -155,20 +239,65 @@ namespace Godot
return true; return true;
} }
public bool Intersects(Rect2 b) /// <summary>
/// Returns true if the Rect2 overlaps with `b`
/// (i.e. they have at least one point in common).
///
/// If `includeBorders` is true, they will also be considered overlapping
/// if their borders touch, even without intersection.
/// </summary>
/// <param name="b">The other rect to check for intersections with.</param>
/// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A bool for whether or not they are intersecting.</returns>
public bool Intersects(Rect2 b, bool includeBorders = false)
{ {
if (_position.x >= b._position.x + b._size.x) if (includeBorders)
return false; {
if (_position.x + _size.x <= b._position.x) if (_position.x > b._position.x + b._size.x)
return false; {
if (_position.y >= b._position.y + b._size.y) return false;
return false; }
if (_position.y + _size.y <= b._position.y) if (_position.x + _size.x < b._position.x)
return false; {
return false;
}
if (_position.y > b._position.y + b._size.y)
{
return false;
}
if (_position.y + _size.y < b._position.y)
{
return false;
}
}
else
{
if (_position.x >= b._position.x + b._size.x)
{
return false;
}
if (_position.x + _size.x <= b._position.x)
{
return false;
}
if (_position.y >= b._position.y + b._size.y)
{
return false;
}
if (_position.y + _size.y <= b._position.y)
{
return false;
}
}
return true; return true;
} }
/// <summary>
/// Returns a larger Rect2 that contains this Rect2 and `b`.
/// </summary>
/// <param name="b">The other rect.</param>
/// <returns>The merged rect.</returns>
public Rect2 Merge(Rect2 b) public Rect2 Merge(Rect2 b)
{ {
Rect2 newRect; Rect2 newRect;
@ -179,27 +308,53 @@ namespace Godot
newRect._size.x = Mathf.Max(b._position.x + b._size.x, _position.x + _size.x); newRect._size.x = Mathf.Max(b._position.x + b._size.x, _position.x + _size.x);
newRect._size.y = Mathf.Max(b._position.y + b._size.y, _position.y + _size.y); newRect._size.y = Mathf.Max(b._position.y + b._size.y, _position.y + _size.y);
newRect._size = newRect._size - newRect._position; // Make relative again newRect._size -= newRect._position; // Make relative again
return newRect; return newRect;
} }
// Constructors /// <summary>
/// Constructs a Rect2 from a position and size.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="size">The size.</param>
public Rect2(Vector2 position, Vector2 size) public Rect2(Vector2 position, Vector2 size)
{ {
_position = position; _position = position;
_size = size; _size = size;
} }
/// <summary>
/// Constructs a Rect2 from a position, width, and height.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public Rect2(Vector2 position, real_t width, real_t height) public Rect2(Vector2 position, real_t width, real_t height)
{ {
_position = position; _position = position;
_size = new Vector2(width, height); _size = new Vector2(width, height);
} }
/// <summary>
/// Constructs a Rect2 from x, y, and size.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="size">The size.</param>
public Rect2(real_t x, real_t y, Vector2 size) public Rect2(real_t x, real_t y, Vector2 size)
{ {
_position = new Vector2(x, y); _position = new Vector2(x, y);
_size = size; _size = size;
} }
/// <summary>
/// Constructs a Rect2 from x, y, width, and height.
/// </summary>
/// <param name="x">The position's X coordinate.</param>
/// <param name="y">The position's Y coordinate.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public Rect2(real_t x, real_t y, real_t width, real_t height) public Rect2(real_t x, real_t y, real_t width, real_t height)
{ {
_position = new Vector2(x, y); _position = new Vector2(x, y);
@ -231,6 +386,12 @@ namespace Godot
return _position.Equals(other._position) && _size.Equals(other._size); return _position.Equals(other._position) && _size.Equals(other._size);
} }
/// <summary>
/// Returns true if this rect and `other` are approximately equal, by running
/// <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component.
/// </summary>
/// <param name="other">The other rect to compare.</param>
/// <returns>Whether or not the rects are approximately equal.</returns>
public bool IsEqualApprox(Rect2 other) public bool IsEqualApprox(Rect2 other)
{ {
return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size); return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size);

View File

@ -8,11 +8,28 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// 3×4 matrix (3 rows, 4 columns) used for 3D linear transformations.
/// It can represent transformations such as translation, rotation, or scaling.
/// It consists of a <see cref="Basis"/> (first 3 columns) and a
/// <see cref="Vector3"/> for the origin (last column).
///
/// For more information, read this documentation article:
/// https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Transform : IEquatable<Transform> public struct Transform : IEquatable<Transform>
{ {
/// <summary>
/// The <see cref="Basis"/> of this transform. Contains the X, Y, and Z basis
/// vectors (columns 0 to 2) and is responsible for rotation and scale.
/// </summary>
public Basis basis; public Basis basis;
/// <summary>
/// The origin vector (column 3, the fourth column). Equivalent to array index `[3]`.
/// </summary>
public Vector3 origin; public Vector3 origin;
/// <summary> /// <summary>
@ -85,13 +102,24 @@ namespace Godot
} }
} }
/// <summary>
/// Returns the inverse of the transform, under the assumption that
/// the transformation is composed of rotation, scaling, and translation.
/// </summary>
/// <returns>The inverse transformation matrix.</returns>
public Transform AffineInverse() public Transform AffineInverse()
{ {
Basis basisInv = basis.Inverse(); Basis basisInv = basis.Inverse();
return new Transform(basisInv, basisInv.Xform(-origin)); return new Transform(basisInv, basisInv.Xform(-origin));
} }
public Transform InterpolateWith(Transform transform, real_t c) /// <summary>
/// Interpolates this transform to the other `transform` by `weight`.
/// </summary>
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
public Transform InterpolateWith(Transform transform, real_t weight)
{ {
/* not sure if very "efficient" but good enough? */ /* not sure if very "efficient" but good enough? */
@ -104,18 +132,37 @@ namespace Godot
Vector3 destinationLocation = transform.origin; Vector3 destinationLocation = transform.origin;
var interpolated = new Transform(); var interpolated = new Transform();
interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c)); interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.LinearInterpolate(destinationScale, weight));
interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, c); interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, weight);
return interpolated; return interpolated;
} }
/// <summary>
/// Returns the inverse of the transform, under the assumption that
/// the transformation is composed of rotation and translation
/// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling).
/// </summary>
/// <returns>The inverse matrix.</returns>
public Transform Inverse() public Transform Inverse()
{ {
Basis basisTr = basis.Transposed(); Basis basisTr = basis.Transposed();
return new Transform(basisTr, basisTr.Xform(-origin)); return new Transform(basisTr, basisTr.Xform(-origin));
} }
/// <summary>
/// Returns a copy of the transform rotated such that its
/// -Z axis (forward) points towards the target position.
///
/// The transform will first be rotated around the given up vector,
/// and then fully aligned to the target by a further rotation around
/// an axis perpendicular to both the target and up vectors.
///
/// Operations take place in global space.
/// </summary>
/// <param name="target">The object to look at.</param>
/// <param name="up">The relative up direction</param>
/// <returns>The resulting transform.</returns>
public Transform LookingAt(Vector3 target, Vector3 up) public Transform LookingAt(Vector3 target, Vector3 up)
{ {
var t = this; var t = this;
@ -123,16 +170,33 @@ namespace Godot
return t; return t;
} }
/// <summary>
/// Returns the transform with the basis orthogonal (90 degrees),
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
/// <returns>The orthonormalized transform.</returns>
public Transform Orthonormalized() public Transform Orthonormalized()
{ {
return new Transform(basis.Orthonormalized(), origin); return new Transform(basis.Orthonormalized(), origin);
} }
/// <summary>
/// Rotates the transform around the given `axis` by `phi` (in radians),
/// using matrix multiplication. The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="phi">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform Rotated(Vector3 axis, real_t phi) public Transform Rotated(Vector3 axis, real_t phi)
{ {
return new Transform(new Basis(axis, phi), new Vector3()) * this; return new Transform(new Basis(axis, phi), new Vector3()) * this;
} }
/// <summary>
/// Scales the transform by the given 3D scaling factor, using matrix multiplication.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
public Transform Scaled(Vector3 scale) public Transform Scaled(Vector3 scale)
{ {
return new Transform(basis.Scaled(scale), origin * scale); return new Transform(basis.Scaled(scale), origin * scale);
@ -161,16 +225,30 @@ namespace Godot
origin = eye; origin = eye;
} }
public Transform Translated(Vector3 ofs) /// <summary>
/// Translates the transform by the given `offset`,
/// relative to the transform's basis vectors.
///
/// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
/// this does not use matrix multiplication.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
public Transform Translated(Vector3 offset)
{ {
return new Transform(basis, new Vector3 return new Transform(basis, new Vector3
( (
origin[0] += basis.Row0.Dot(ofs), origin[0] += basis.Row0.Dot(offset),
origin[1] += basis.Row1.Dot(ofs), origin[1] += basis.Row1.Dot(offset),
origin[2] += basis.Row2.Dot(ofs) origin[2] += basis.Row2.Dot(offset)
)); ));
} }
/// <summary>
/// Returns a vector transformed (multiplied) by this transformation matrix.
/// </summary>
/// <param name="v">A vector to transform.</param>
/// <returns>The transfomed vector.</returns>
public Vector3 Xform(Vector3 v) public Vector3 Xform(Vector3 v)
{ {
return new Vector3 return new Vector3
@ -181,6 +259,14 @@ namespace Godot
); );
} }
/// <summary>
/// Returns a vector transformed (multiplied) by the transposed transformation matrix.
///
/// Note: This results in a multiplication by the inverse of the
/// transformation matrix only if it represents a rotation-reflection.
/// </summary>
/// <param name="v">A vector to inversely transform.</param>
/// <returns>The inversely transfomed vector.</returns>
public Vector3 XformInv(Vector3 v) public Vector3 XformInv(Vector3 v)
{ {
Vector3 vInv = v - origin; Vector3 vInv = v - origin;
@ -199,24 +285,58 @@ namespace Godot
private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero);
private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero);
/// <summary>
/// The identity transform, with no translation, rotation, or scaling applied.
/// This is used as a replacement for `Transform()` in GDScript.
/// Do not use `new Transform()` with no arguments in C#, because it sets all values to zero.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value>
public static Transform Identity { get { return _identity; } } public static Transform Identity { get { return _identity; } }
/// <summary>
/// The transform that will flip something along the X axis.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Left, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value>
public static Transform FlipX { get { return _flipX; } } public static Transform FlipX { get { return _flipX; } }
/// <summary>
/// The transform that will flip something along the Y axis.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Down, Vector3.Back, Vector3.Zero)`.</value>
public static Transform FlipY { get { return _flipY; } } public static Transform FlipY { get { return _flipY; } }
/// <summary>
/// The transform that will flip something along the Z axis.
/// </summary>
/// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Forward, Vector3.Zero)`.</value>
public static Transform FlipZ { get { return _flipZ; } } public static Transform FlipZ { get { return _flipZ; } }
// Constructors /// <summary>
/// Constructs a transformation matrix from 4 vectors (matrix columns).
/// </summary>
/// <param name="column0">The X vector, or column index 0.</param>
/// <param name="column1">The Y vector, or column index 1.</param>
/// <param name="column2">The Z vector, or column index 2.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin)
{ {
basis = new Basis(column0, column1, column2); basis = new Basis(column0, column1, column2);
this.origin = origin; this.origin = origin;
} }
/// <summary>
/// Constructs a transformation matrix from the given quaternion and origin vector.
/// </summary>
/// <param name="quat">The <see cref="Godot.Quat"/> to create the basis from.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
public Transform(Quat quat, Vector3 origin) public Transform(Quat quat, Vector3 origin)
{ {
basis = new Basis(quat); basis = new Basis(quat);
this.origin = origin; this.origin = origin;
} }
/// <summary>
/// Constructs a transformation matrix from the given basis and origin vector.
/// </summary>
/// <param name="basis">The <see cref="Godot.Basis"/> to create the basis from.</param>
/// <param name="origin">The origin vector, or column index 3.</param>
public Transform(Basis basis, Vector3 origin) public Transform(Basis basis, Vector3 origin)
{ {
this.basis = basis; this.basis = basis;
@ -255,6 +375,12 @@ namespace Godot
return basis.Equals(other.basis) && origin.Equals(other.origin); return basis.Equals(other.basis) && origin.Equals(other.origin);
} }
/// <summary>
/// Returns true if this transform and `other` are approximately equal, by running
/// <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component.
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are approximately equal.</returns>
public bool IsEqualApprox(Transform other) public bool IsEqualApprox(Transform other)
{ {
return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin); return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin);

View File

@ -8,25 +8,44 @@ using real_t = System.Single;
namespace Godot namespace Godot
{ {
/// <summary>
/// 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations.
/// It can represent transformations such as translation, rotation, or scaling.
/// It consists of a three <see cref="Vector2"/> values: x, y, and the origin.
///
/// For more information, read this documentation article:
/// https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html
/// </summary>
[Serializable] [Serializable]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Transform2D : IEquatable<Transform2D> public struct Transform2D : IEquatable<Transform2D>
{ {
/// <summary>
/// The basis matrix's X vector (column 0). Equivalent to array index `[0]`.
/// </summary>
/// <value></value>
public Vector2 x; public Vector2 x;
/// <summary>
/// The basis matrix's Y vector (column 1). Equivalent to array index `[1]`.
/// </summary>
public Vector2 y; public Vector2 y;
/// <summary>
/// The origin vector (column 2, the third column). Equivalent to array index `[2]`.
/// The origin vector represents translation.
/// </summary>
public Vector2 origin; public Vector2 origin;
/// <summary>
/// The rotation of this transformation matrix.
/// </summary>
/// <value>Getting is equivalent to calling <see cref="Mathf.Atan2(real_t, real_t)"/> with the values of <see cref="x"/>.</value>
public real_t Rotation public real_t Rotation
{ {
get get
{ {
real_t det = BasisDeterminant(); return Mathf.Atan2(x.y, x.x);
Transform2D t = Orthonormalized();
if (det < 0)
{
t.ScaleBasis(new Vector2(1, -1));
}
return Mathf.Atan2(t.x.y, t.x.x);
} }
set set
{ {
@ -38,6 +57,10 @@ namespace Godot
} }
} }
/// <summary>
/// The scale of this transformation matrix.
/// </summary>
/// <value>Equivalent to the lengths of each column vector, but Y is negative if the determinant is negative.</value>
public Vector2 Scale public Vector2 Scale
{ {
get get
@ -47,8 +70,7 @@ namespace Godot
} }
set set
{ {
x = x.Normalized(); value /= Scale; // Value becomes what's called "delta_scale" in core.
y = y.Normalized();
x *= value.x; x *= value.x;
y *= value.y; y *= value.y;
} }
@ -112,6 +134,11 @@ namespace Godot
} }
} }
/// <summary>
/// Returns the inverse of the transform, under the assumption that
/// the transformation is composed of rotation, scaling, and translation.
/// </summary>
/// <returns>The inverse transformation matrix.</returns>
public Transform2D AffineInverse() public Transform2D AffineInverse()
{ {
real_t det = BasisDeterminant(); real_t det = BasisDeterminant();
@ -135,28 +162,58 @@ namespace Godot
return inv; return inv;
} }
/// <summary>
/// Returns the determinant of the basis matrix. If the basis is
/// uniformly scaled, its determinant is the square of the scale.
///
/// A negative determinant means the Y scale is negative.
/// A zero determinant means the basis isn't invertible,
/// and is usually considered invalid.
/// </summary>
/// <returns>The determinant of the basis matrix.</returns>
private real_t BasisDeterminant() private real_t BasisDeterminant()
{ {
return x.x * y.y - x.y * y.x; return x.x * y.y - x.y * y.x;
} }
/// <summary>
/// Returns a vector transformed (multiplied) by the basis matrix.
/// This method does not account for translation (the origin vector).
/// </summary>
/// <param name="v">A vector to transform.</param>
/// <returns>The transfomed vector.</returns>
public Vector2 BasisXform(Vector2 v) public Vector2 BasisXform(Vector2 v)
{ {
return new Vector2(Tdotx(v), Tdoty(v)); return new Vector2(Tdotx(v), Tdoty(v));
} }
/// <summary>
/// Returns a vector transformed (multiplied) by the inverse basis matrix.
/// This method does not account for translation (the origin vector).
///
/// Note: This results in a multiplication by the inverse of the
/// basis matrix only if it represents a rotation-reflection.
/// </summary>
/// <param name="v">A vector to inversely transform.</param>
/// <returns>The inversely transfomed vector.</returns>
public Vector2 BasisXformInv(Vector2 v) public Vector2 BasisXformInv(Vector2 v)
{ {
return new Vector2(x.Dot(v), y.Dot(v)); return new Vector2(x.Dot(v), y.Dot(v));
} }
public Transform2D InterpolateWith(Transform2D m, real_t c) /// <summary>
/// Interpolates this transform to the other `transform` by `weight`.
/// </summary>
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
public Transform2D InterpolateWith(Transform2D transform, real_t weight)
{ {
real_t r1 = Rotation; real_t r1 = Rotation;
real_t r2 = m.Rotation; real_t r2 = transform.Rotation;
Vector2 s1 = Scale; Vector2 s1 = Scale;
Vector2 s2 = m.Scale; Vector2 s2 = transform.Scale;
// Slerp rotation // Slerp rotation
var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1)); var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1));
@ -172,28 +229,34 @@ namespace Godot
if (dot > 0.9995f) if (dot > 0.9995f)
{ {
// Linearly interpolate to avoid numerical precision issues // Linearly interpolate to avoid numerical precision issues
v = v1.LinearInterpolate(v2, c).Normalized(); v = v1.LinearInterpolate(v2, weight).Normalized();
} }
else else
{ {
real_t angle = c * Mathf.Acos(dot); real_t angle = weight * Mathf.Acos(dot);
Vector2 v3 = (v2 - v1 * dot).Normalized(); Vector2 v3 = (v2 - v1 * dot).Normalized();
v = v1 * Mathf.Cos(angle) + v3 * Mathf.Sin(angle); v = v1 * Mathf.Cos(angle) + v3 * Mathf.Sin(angle);
} }
// Extract parameters // Extract parameters
Vector2 p1 = origin; Vector2 p1 = origin;
Vector2 p2 = m.origin; Vector2 p2 = transform.origin;
// Construct matrix // Construct matrix
var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, c)); var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, weight));
Vector2 scale = s1.LinearInterpolate(s2, c); Vector2 scale = s1.LinearInterpolate(s2, weight);
res.x *= scale; res.x *= scale;
res.y *= scale; res.y *= scale;
return res; return res;
} }
/// <summary>
/// Returns the inverse of the transform, under the assumption that
/// the transformation is composed of rotation and translation
/// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling).
/// </summary>
/// <returns>The inverse matrix.</returns>
public Transform2D Inverse() public Transform2D Inverse()
{ {
var inv = this; var inv = this;
@ -208,6 +271,11 @@ namespace Godot
return inv; return inv;
} }
/// <summary>
/// Returns the transform with the basis orthogonal (90 degrees),
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
/// <returns>The orthonormalized transform.</returns>
public Transform2D Orthonormalized() public Transform2D Orthonormalized()
{ {
var on = this; var on = this;
@ -225,11 +293,21 @@ namespace Godot
return on; return on;
} }
/// <summary>
/// Rotates the transform by `phi` (in radians), using matrix multiplication.
/// </summary>
/// <param name="phi">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform2D Rotated(real_t phi) public Transform2D Rotated(real_t phi)
{ {
return this * new Transform2D(phi, new Vector2()); return this * new Transform2D(phi, new Vector2());
} }
/// <summary>
/// Scales the transform by the given scaling factor, using matrix multiplication.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
public Transform2D Scaled(Vector2 scale) public Transform2D Scaled(Vector2 scale)
{ {
var copy = this; var copy = this;
@ -257,6 +335,15 @@ namespace Godot
return this[0, 1] * with[0] + this[1, 1] * with[1]; return this[0, 1] * with[0] + this[1, 1] * with[1];
} }
/// <summary>
/// Translates the transform by the given `offset`,
/// relative to the transform's basis vectors.
///
/// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
/// this does not use matrix multiplication.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
public Transform2D Translated(Vector2 offset) public Transform2D Translated(Vector2 offset)
{ {
var copy = this; var copy = this;
@ -264,11 +351,21 @@ namespace Godot
return copy; return copy;
} }
/// <summary>
/// Returns a vector transformed (multiplied) by this transformation matrix.
/// </summary>
/// <param name="v">A vector to transform.</param>
/// <returns>The transfomed vector.</returns>
public Vector2 Xform(Vector2 v) public Vector2 Xform(Vector2 v)
{ {
return new Vector2(Tdotx(v), Tdoty(v)) + origin; return new Vector2(Tdotx(v), Tdoty(v)) + origin;
} }
/// <summary>
/// Returns a vector transformed (multiplied) by the inverse transformation matrix.
/// </summary>
/// <param name="v">A vector to inversely transform.</param>
/// <returns>The inversely transfomed vector.</returns>
public Vector2 XformInv(Vector2 v) public Vector2 XformInv(Vector2 v)
{ {
Vector2 vInv = v - origin; Vector2 vInv = v - origin;
@ -280,11 +377,30 @@ namespace Godot
private static readonly Transform2D _flipX = new Transform2D(-1, 0, 0, 1, 0, 0); private static readonly Transform2D _flipX = new Transform2D(-1, 0, 0, 1, 0, 0);
private static readonly Transform2D _flipY = new Transform2D(1, 0, 0, -1, 0, 0); private static readonly Transform2D _flipY = new Transform2D(1, 0, 0, -1, 0, 0);
public static Transform2D Identity => _identity; /// <summary>
public static Transform2D FlipX => _flipX; /// The identity transform, with no translation, rotation, or scaling applied.
public static Transform2D FlipY => _flipY; /// This is used as a replacement for `Transform2D()` in GDScript.
/// Do not use `new Transform2D()` with no arguments in C#, because it sets all values to zero.
/// </summary>
/// <value>Equivalent to `new Transform2D(Vector2.Right, Vector2.Down, Vector2.Zero)`.</value>
public static Transform2D Identity { get { return _identity; } }
/// <summary>
/// The transform that will flip something along the X axis.
/// </summary>
/// <value>Equivalent to `new Transform2D(Vector2.Left, Vector2.Down, Vector2.Zero)`.</value>
public static Transform2D FlipX { get { return _flipX; } }
/// <summary>
/// The transform that will flip something along the Y axis.
/// </summary>
/// <value>Equivalent to `new Transform2D(Vector2.Right, Vector2.Up, Vector2.Zero)`.</value>
public static Transform2D FlipY { get { return _flipY; } }
// Constructors /// <summary>
/// Constructs a transformation matrix from 3 vectors (matrix columns).
/// </summary>
/// <param name="xAxis">The X vector, or column index 0.</param>
/// <param name="yAxis">The Y vector, or column index 1.</param>
/// <param name="originPos">The origin vector, or column index 2.</param>
public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 originPos) public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 originPos)
{ {
x = xAxis; x = xAxis;
@ -292,7 +408,16 @@ namespace Godot
origin = originPos; origin = originPos;
} }
// Arguments are named such that xy is equal to calling x.y /// <summary>
/// Constructs a transformation matrix from the given components.
/// Arguments are named such that xy is equal to calling x.y
/// </summary>
/// <param name="xx">The X component of the X column vector, accessed via `t.x.x` or `[0][0]`</param>
/// <param name="xy">The Y component of the X column vector, accessed via `t.x.y` or `[0][1]`</param>
/// <param name="yx">The X component of the Y column vector, accessed via `t.y.x` or `[1][0]`</param>
/// <param name="yy">The Y component of the Y column vector, accessed via `t.y.y` or `[1][1]`</param>
/// <param name="ox">The X component of the origin vector, accessed via `t.origin.x` or `[2][0]`</param>
/// <param name="oy">The Y component of the origin vector, accessed via `t.origin.y` or `[2][1]`</param>
public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy)
{ {
x = new Vector2(xx, xy); x = new Vector2(xx, xy);
@ -300,6 +425,11 @@ namespace Godot
origin = new Vector2(ox, oy); origin = new Vector2(ox, oy);
} }
/// <summary>
/// Constructs a transformation matrix from a rotation value and origin vector.
/// </summary>
/// <param name="rot">The rotation of the new transform, in radians.</param>
/// <param name="pos">The origin vector, or column index 2.</param>
public Transform2D(real_t rot, Vector2 pos) public Transform2D(real_t rot, Vector2 pos)
{ {
x.x = y.y = Mathf.Cos(rot); x.x = y.y = Mathf.Cos(rot);
@ -345,6 +475,12 @@ namespace Godot
return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin); return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin);
} }
/// <summary>
/// Returns true if this transform and `other` are approximately equal, by running
/// <see cref="Vector2.IsEqualApprox(Vector2)"/> on each component.
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are approximately equal.</returns>
public bool IsEqualApprox(Transform2D other) public bool IsEqualApprox(Transform2D other)
{ {
return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin); return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin);

View File

@ -21,15 +21,29 @@ namespace Godot
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Vector2 : IEquatable<Vector2> public struct Vector2 : IEquatable<Vector2>
{ {
/// <summary>
/// Enumerated index values for the axes.
/// Returned by <see cref="MaxAxis"/> and <see cref="MinAxis"/>.
/// </summary>
public enum Axis public enum Axis
{ {
X = 0, X = 0,
Y Y
} }
/// <summary>
/// The vector's X component. Also accessible by using the index position `[0]`.
/// </summary>
public real_t x; public real_t x;
/// <summary>
/// The vector's Y component. Also accessible by using the index position `[1]`.
/// </summary>
public real_t y; public real_t y;
/// <summary>
/// Access vector components using their index.
/// </summary>
/// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`.</value>
public real_t this[int index] public real_t this[int index]
{ {
get get
@ -76,46 +90,80 @@ namespace Godot
} }
} }
public real_t Cross(Vector2 b) /// <summary>
{ /// Returns a new vector with all components in absolute values (i.e. positive).
return x * b.y - y * b.x; /// </summary>
} /// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
public Vector2 Abs() public Vector2 Abs()
{ {
return new Vector2(Mathf.Abs(x), Mathf.Abs(y)); return new Vector2(Mathf.Abs(x), Mathf.Abs(y));
} }
/// <summary>
/// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians.
///
/// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when
/// called with the vector's `y` and `x` as parameters: `Mathf.Atan2(v.y, v.x)`.
/// </summary>
/// <returns>The angle of this vector, in radians.</returns>
public real_t Angle() public real_t Angle()
{ {
return Mathf.Atan2(y, x); return Mathf.Atan2(y, x);
} }
/// <summary>
/// Returns the angle to the given vector, in radians.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The angle between the two vectors, in radians.</returns>
public real_t AngleTo(Vector2 to) public real_t AngleTo(Vector2 to)
{ {
return Mathf.Atan2(Cross(to), Dot(to)); return Mathf.Atan2(Cross(to), Dot(to));
} }
/// <summary>
/// Returns the angle between the line connecting the two points and the X axis, in radians.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The angle between the two vectors, in radians.</returns>
public real_t AngleToPoint(Vector2 to) public real_t AngleToPoint(Vector2 to)
{ {
return Mathf.Atan2(y - to.y, x - to.x); return Mathf.Atan2(y - to.y, x - to.x);
} }
/// <summary>
/// Returns the aspect ratio of this vector, the ratio of `x` to `y`.
/// </summary>
/// <returns>The `x` component divided by the `y` component.</returns>
public real_t Aspect() public real_t Aspect()
{ {
return x / y; return x / y;
} }
public Vector2 Bounce(Vector2 n) /// <summary>
/// Returns the vector "bounced off" from a plane defined by the given normal.
/// </summary>
/// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param>
/// <returns>The bounced vector.</returns>
public Vector2 Bounce(Vector2 normal)
{ {
return -Reflect(n); return -Reflect(normal);
} }
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
public Vector2 Ceil() public Vector2 Ceil()
{ {
return new Vector2(Mathf.Ceil(x), Mathf.Ceil(y)); return new Vector2(Mathf.Ceil(x), Mathf.Ceil(y));
} }
/// <summary>
/// Returns the vector with a maximum length by limiting its length to `length`.
/// </summary>
/// <param name="length">The length to limit to.</param>
/// <returns>The vector with its length limited.</returns>
public Vector2 Clamped(real_t length) public Vector2 Clamped(real_t length)
{ {
var v = this; var v = this;
@ -130,12 +178,30 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns the cross product of this vector and `b`.
/// </summary>
/// <param name="b">The other vector.</param>
/// <returns>The cross product value.</returns>
public real_t Cross(Vector2 b)
{
return x * b.y - y * b.x;
}
/// <summary>
/// Performs a cubic interpolation between vectors `preA`, this vector, `b`, and `postB`, by the given amount `t`.
/// </summary>
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after `b`.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t) public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t)
{ {
var p0 = preA; Vector2 p0 = preA;
var p1 = this; Vector2 p1 = this;
var p2 = b; Vector2 p2 = b;
var p3 = postB; Vector2 p3 = postB;
real_t t2 = t * t; real_t t2 = t * t;
real_t t3 = t2 * t; real_t t3 = t2 * t;
@ -146,56 +212,153 @@ namespace Godot
(-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
} }
/// <summary>
/// Returns the normalized vector pointing from this vector to `b`.
/// </summary>
/// <param name="b">The other vector to point towards.</param>
/// <returns>The direction from this vector to `b`.</returns>
public Vector2 DirectionTo(Vector2 b) public Vector2 DirectionTo(Vector2 b)
{ {
return new Vector2(b.x - x, b.y - y).Normalized(); return new Vector2(b.x - x, b.y - y).Normalized();
} }
/// <summary>
/// Returns the squared distance between this vector and `to`.
/// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
/// you need to compare vectors or need the squared distance for some formula.
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The squared distance between the two vectors.</returns>
public real_t DistanceSquaredTo(Vector2 to) public real_t DistanceSquaredTo(Vector2 to)
{ {
return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y); return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
} }
/// <summary>
/// Returns the distance between this vector and `to`.
/// </summary>
/// <param name="to">The other vector to use.</param>
/// <returns>The distance between the two vectors.</returns>
public real_t DistanceTo(Vector2 to) public real_t DistanceTo(Vector2 to)
{ {
return Mathf.Sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y)); return Mathf.Sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y));
} }
/// <summary>
/// Returns the dot product of this vector and `with`.
/// </summary>
/// <param name="with">The other vector to use.</param>
/// <returns>The dot product of the two vectors.</returns>
public real_t Dot(Vector2 with) public real_t Dot(Vector2 with)
{ {
return x * with.x + y * with.y; return x * with.x + y * with.y;
} }
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
public Vector2 Floor() public Vector2 Floor()
{ {
return new Vector2(Mathf.Floor(x), Mathf.Floor(y)); return new Vector2(Mathf.Floor(x), Mathf.Floor(y));
} }
/// <summary>
/// Returns the inverse of this vector. This is the same as `new Vector2(1 / v.x, 1 / v.y)`.
/// </summary>
/// <returns>The inverse of this vector.</returns>
public Vector2 Inverse()
{
return new Vector2(1 / x, 1 / y);
}
/// <summary>
/// Returns true if the vector is normalized, and false otherwise.
/// </summary>
/// <returns>A bool indicating whether or not the vector is normalized.</returns>
public bool IsNormalized() public bool IsNormalized()
{ {
return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
} }
/// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <returns>The length of this vector.</returns>
public real_t Length() public real_t Length()
{ {
return Mathf.Sqrt(x * x + y * y); return Mathf.Sqrt(x * x + y * y);
} }
/// <summary>
/// Returns the squared length (squared magnitude) of this vector.
/// This method runs faster than <see cref="Length"/>, so prefer it if
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
public real_t LengthSquared() public real_t LengthSquared()
{ {
return x * x + y * y; return x * x + y * y;
} }
public Vector2 LinearInterpolate(Vector2 b, real_t t) /// <summary>
/// Returns the result of the linear interpolation between
/// this vector and `to` by amount `weight`.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public Vector2 LinearInterpolate(Vector2 to, real_t weight)
{ {
var res = this; return new Vector2
(
res.x += t * (b.x - x); Mathf.Lerp(x, to.x, weight),
res.y += t * (b.y - y); Mathf.Lerp(y, to.y, weight)
);
return res;
} }
/// <summary>
/// Returns the result of the linear interpolation between
/// this vector and `to` by the vector amount `weight`.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public Vector2 LinearInterpolate(Vector2 to, Vector2 weight)
{
return new Vector2
(
Mathf.Lerp(x, to.x, weight.x),
Mathf.Lerp(y, to.y, weight.y)
);
}
/// <summary>
/// Returns the axis of the vector's largest value. See <see cref="Axis"/>.
/// If both components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the largest axis.</returns>
public Axis MaxAxis()
{
return x < y ? Axis.Y : Axis.X;
}
/// <summary>
/// Returns the axis of the vector's smallest value. See <see cref="Axis"/>.
/// If both components are equal, this method returns <see cref="Axis.Y"/>.
/// </summary>
/// <returns>The index of the smallest axis.</returns>
public Axis MinAxis()
{
return x < y ? Axis.X : Axis.Y;
}
/// <summary>
/// Moves this vector toward `to` by the fixed `delta` amount.
/// </summary>
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
public Vector2 MoveToward(Vector2 to, real_t delta) public Vector2 MoveToward(Vector2 to, real_t delta)
{ {
var v = this; var v = this;
@ -204,6 +367,10 @@ namespace Godot
return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta; return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta;
} }
/// <summary>
/// Returns the vector scaled to unit length. Equivalent to `v / v.Length()`.
/// </summary>
/// <returns>A normalized version of the vector.</returns>
public Vector2 Normalized() public Vector2 Normalized()
{ {
var v = this; var v = this;
@ -211,6 +378,21 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns a perpendicular vector rotated 90 degrees counter-clockwise
/// compared to the original, with the same length.
/// </summary>
/// <returns>The perpendicular vector.</returns>
public Vector2 Perpendicular()
{
return new Vector2(y, -x);
}
/// <summary>
/// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `mod`.
/// </summary>
/// <param name="mod">A value representing the divisor of the operation.</param>
/// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `mod`.</returns>
public Vector2 PosMod(real_t mod) public Vector2 PosMod(real_t mod)
{ {
Vector2 v; Vector2 v;
@ -219,6 +401,11 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `modv`'s components.
/// </summary>
/// <param name="modv">A vector representing the divisors of the operation.</param>
/// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `modv`'s components.</returns>
public Vector2 PosMod(Vector2 modv) public Vector2 PosMod(Vector2 modv)
{ {
Vector2 v; Vector2 v;
@ -227,22 +414,48 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns this vector projected onto another vector.
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
public Vector2 Project(Vector2 onNormal) public Vector2 Project(Vector2 onNormal)
{ {
return onNormal * (Dot(onNormal) / onNormal.LengthSquared()); return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
} }
public Vector2 Reflect(Vector2 n) /// <summary>
/// Returns this vector reflected from a plane defined by the given `normal`.
/// </summary>
/// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param>
/// <returns>The reflected vector.</returns>
public Vector2 Reflect(Vector2 normal)
{ {
return 2.0f * n * Dot(n) - this; #if DEBUG
if (!normal.IsNormalized())
{
throw new ArgumentException("Argument is not normalized", nameof(normal));
}
#endif
return 2 * Dot(normal) * normal - this;
} }
/// <summary>
/// Rotates this vector by `phi` radians.
/// </summary>
/// <param name="phi">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public Vector2 Rotated(real_t phi) public Vector2 Rotated(real_t phi)
{ {
real_t rads = Angle() + phi; real_t rads = Angle() + phi;
return new Vector2(Mathf.Cos(rads), Mathf.Sin(rads)) * Length(); return new Vector2(Mathf.Cos(rads), Mathf.Sin(rads)) * Length();
} }
/// <summary>
/// Returns this vector with all components rounded to the nearest integer,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <returns>The rounded vector.</returns>
public Vector2 Round() public Vector2 Round()
{ {
return new Vector2(Mathf.Round(x), Mathf.Round(y)); return new Vector2(Mathf.Round(x), Mathf.Round(y));
@ -261,6 +474,12 @@ namespace Godot
y = v.y; y = v.y;
} }
/// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either `1`, `-1`, or `0`.</returns>
public Vector2 Sign() public Vector2 Sign()
{ {
Vector2 v; Vector2 v;
@ -269,22 +488,57 @@ namespace Godot
return v; return v;
} }
public Vector2 Slerp(Vector2 b, real_t t) /// <summary>
/// Returns the result of the spherical linear interpolation between
/// this vector and `to` by amount `weight`.
///
/// Note: Both vectors must be normalized.
/// </summary>
/// <param name="to">The destination vector for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public Vector2 Slerp(Vector2 to, real_t weight)
{ {
real_t theta = AngleTo(b); #if DEBUG
return Rotated(theta * t); if (!IsNormalized())
{
throw new InvalidOperationException("Vector2.Slerp: From vector is not normalized.");
}
if (!to.IsNormalized())
{
throw new InvalidOperationException("Vector2.Slerp: `to` is not normalized.");
}
#endif
return Rotated(AngleTo(to) * weight);
} }
public Vector2 Slide(Vector2 n) /// <summary>
/// Returns this vector slid along a plane defined by the given normal.
/// </summary>
/// <param name="normal">The normal vector defining the plane to slide on.</param>
/// <returns>The slid vector.</returns>
public Vector2 Slide(Vector2 normal)
{ {
return this - n * Dot(n); return this - normal * Dot(normal);
} }
public Vector2 Snapped(Vector2 by) /// <summary>
/// Returns this vector with each component snapped to the nearest multiple of `step`.
/// This can also be used to round to an arbitrary number of decimals.
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
/// <returns>The snapped vector.</returns>
public Vector2 Snapped(Vector2 step)
{ {
return new Vector2(Mathf.Stepify(x, by.x), Mathf.Stepify(y, by.y)); return new Vector2(Mathf.Stepify(x, step.x), Mathf.Stepify(y, step.y));
} }
/// <summary>
/// Returns a perpendicular vector rotated 90 degrees counter-clockwise
/// compared to the original, with the same length.
/// Deprecated, will be replaced by <see cref="Perpendicular"/> in 4.0.
/// </summary>
/// <returns>The perpendicular vector.</returns>
public Vector2 Tangent() public Vector2 Tangent()
{ {
return new Vector2(y, -x); return new Vector2(y, -x);
@ -301,22 +555,63 @@ namespace Godot
private static readonly Vector2 _right = new Vector2(1, 0); private static readonly Vector2 _right = new Vector2(1, 0);
private static readonly Vector2 _left = new Vector2(-1, 0); private static readonly Vector2 _left = new Vector2(-1, 0);
/// <summary>
/// Zero vector, a vector with all components set to `0`.
/// </summary>
/// <value>Equivalent to `new Vector2(0, 0)`</value>
public static Vector2 Zero { get { return _zero; } } public static Vector2 Zero { get { return _zero; } }
/// <summary>
/// Deprecated, please use a negative sign with <see cref="One"/> instead.
/// </summary>
/// <value>Equivalent to `new Vector2(-1, -1)`</value>
public static Vector2 NegOne { get { return _negOne; } } public static Vector2 NegOne { get { return _negOne; } }
/// <summary>
/// One vector, a vector with all components set to `1`.
/// </summary>
/// <value>Equivalent to `new Vector2(1, 1)`</value>
public static Vector2 One { get { return _one; } } public static Vector2 One { get { return _one; } }
/// <summary>
/// Infinity vector, a vector with all components set to `Mathf.Inf`.
/// </summary>
/// <value>Equivalent to `new Vector2(Mathf.Inf, Mathf.Inf)`</value>
public static Vector2 Inf { get { return _inf; } } public static Vector2 Inf { get { return _inf; } }
/// <summary>
/// Up unit vector. Y is down in 2D, so this vector points -Y.
/// </summary>
/// <value>Equivalent to `new Vector2(0, -1)`</value>
public static Vector2 Up { get { return _up; } } public static Vector2 Up { get { return _up; } }
/// <summary>
/// Down unit vector. Y is down in 2D, so this vector points +Y.
/// </summary>
/// <value>Equivalent to `new Vector2(0, 1)`</value>
public static Vector2 Down { get { return _down; } } public static Vector2 Down { get { return _down; } }
/// <summary>
/// Right unit vector. Represents the direction of right.
/// </summary>
/// <value>Equivalent to `new Vector2(1, 0)`</value>
public static Vector2 Right { get { return _right; } } public static Vector2 Right { get { return _right; } }
/// <summary>
/// Left unit vector. Represents the direction of left.
/// </summary>
/// <value>Equivalent to `new Vector2(-1, 0)`</value>
public static Vector2 Left { get { return _left; } } public static Vector2 Left { get { return _left; } }
// Constructors /// <summary>
/// Constructs a new <see cref="Vector2"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
/// <param name="y">The vector's Y component.</param>
public Vector2(real_t x, real_t y) public Vector2(real_t x, real_t y)
{ {
this.x = x; this.x = x;
this.y = y; this.y = y;
} }
/// <summary>
/// Constructs a new <see cref="Vector2"/> from an existing <see cref="Vector2"/>.
/// </summary>
/// <param name="v">The existing <see cref="Vector2"/>.</param>
public Vector2(Vector2 v) public Vector2(Vector2 v)
{ {
x = v.x; x = v.x;
@ -365,18 +660,18 @@ namespace Godot
return left; return left;
} }
public static Vector2 operator /(Vector2 vec, real_t scale) public static Vector2 operator /(Vector2 vec, real_t divisor)
{ {
vec.x /= scale; vec.x /= divisor;
vec.y /= scale; vec.y /= divisor;
return vec; return vec;
} }
public static Vector2 operator /(Vector2 left, Vector2 right) public static Vector2 operator /(Vector2 vec, Vector2 divisorv)
{ {
left.x /= right.x; vec.x /= divisorv.x;
left.y /= right.y; vec.y /= divisorv.y;
return left; return vec;
} }
public static Vector2 operator %(Vector2 vec, real_t divisor) public static Vector2 operator %(Vector2 vec, real_t divisor)
@ -458,6 +753,12 @@ namespace Godot
return x == other.x && y == other.y; return x == other.x && y == other.y;
} }
/// <summary>
/// Returns true if this vector and `other` are approximately equal, by running
/// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component.
/// </summary>
/// <param name="other">The other vector to compare.</param>
/// <returns>Whether or not the vectors are approximately equal.</returns>
public bool IsEqualApprox(Vector2 other) public bool IsEqualApprox(Vector2 other)
{ {
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y); return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);

View File

@ -21,6 +21,10 @@ namespace Godot
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Vector3 : IEquatable<Vector3> public struct Vector3 : IEquatable<Vector3>
{ {
/// <summary>
/// Enumerated index values for the axes.
/// Returned by <see cref="MaxAxis"/> and <see cref="MinAxis"/>.
/// </summary>
public enum Axis public enum Axis
{ {
X = 0, X = 0,
@ -28,10 +32,23 @@ namespace Godot
Z Z
} }
/// <summary>
/// The vector's X component. Also accessible by using the index position `[0]`.
/// </summary>
public real_t x; public real_t x;
/// <summary>
/// The vector's Y component. Also accessible by using the index position `[1]`.
/// </summary>
public real_t y; public real_t y;
/// <summary>
/// The vector's Z component. Also accessible by using the index position `[2]`.
/// </summary>
public real_t z; public real_t z;
/// <summary>
/// Access vector components using their index.
/// </summary>
/// <value>`[0]` is equivalent to `.x`, `[1]` is equivalent to `.y`, `[2]` is equivalent to `.z`.</value>
public real_t this[int index] public real_t this[int index]
{ {
get get
@ -84,26 +101,49 @@ namespace Godot
} }
} }
/// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns>
public Vector3 Abs() public Vector3 Abs()
{ {
return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z)); return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z));
} }
/// <summary>
/// Returns the minimum angle to the given vector, in radians.
/// </summary>
/// <param name="to">The other vector to compare this vector to.</param>
/// <returns>The angle between the two vectors, in radians.</returns>
public real_t AngleTo(Vector3 to) public real_t AngleTo(Vector3 to)
{ {
return Mathf.Atan2(Cross(to).Length(), Dot(to)); return Mathf.Atan2(Cross(to).Length(), Dot(to));
} }
public Vector3 Bounce(Vector3 n) /// <summary>
/// Returns this vector "bounced off" from a plane defined by the given normal.
/// </summary>
/// <param name="normal">The normal vector defining the plane to bounce off. Must be normalized.</param>
/// <returns>The bounced vector.</returns>
public Vector3 Bounce(Vector3 normal)
{ {
return -Reflect(n); return -Reflect(normal);
} }
/// <summary>
/// Returns a new vector with all components rounded up (towards positive infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns>
public Vector3 Ceil() public Vector3 Ceil()
{ {
return new Vector3(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z)); return new Vector3(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z));
} }
/// <summary>
/// Returns the cross product of this vector and `b`.
/// </summary>
/// <param name="b">The other vector.</param>
/// <returns>The cross product vector.</returns>
public Vector3 Cross(Vector3 b) public Vector3 Cross(Vector3 b)
{ {
return new Vector3 return new Vector3
@ -114,12 +154,21 @@ namespace Godot
); );
} }
/// <summary>
/// Performs a cubic interpolation between vectors `preA`, this vector,
/// `b`, and `postB`, by the given amount `t`.
/// </summary>
/// <param name="b">The destination vector.</param>
/// <param name="preA">A vector before this vector.</param>
/// <param name="postB">A vector after `b`.</param>
/// <param name="t">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated vector.</returns>
public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t) public Vector3 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t)
{ {
var p0 = preA; Vector3 p0 = preA;
var p1 = this; Vector3 p1 = this;
var p2 = b; Vector3 p2 = b;
var p3 = postB; Vector3 p3 = postB;
real_t t2 = t * t; real_t t2 = t * t;
real_t t3 = t2 * t; real_t t3 = t2 * t;
@ -131,41 +180,79 @@ namespace Godot
); );
} }
/// <summary>
/// Returns the normalized vector pointing from this vector to `b`.
/// </summary>
/// <param name="b">The other vector to point towards.</param>
/// <returns>The direction from this vector to `b`.</returns>
public Vector3 DirectionTo(Vector3 b) public Vector3 DirectionTo(Vector3 b)
{ {
return new Vector3(b.x - x, b.y - y, b.z - z).Normalized(); return new Vector3(b.x - x, b.y - y, b.z - z).Normalized();
} }
/// <summary>
/// Returns the squared distance between this vector and `b`.
/// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
/// you need to compare vectors or need the squared distance for some formula.
/// </summary>
/// <param name="b">The other vector to use.</param>
/// <returns>The squared distance between the two vectors.</returns>
public real_t DistanceSquaredTo(Vector3 b) public real_t DistanceSquaredTo(Vector3 b)
{ {
return (b - this).LengthSquared(); return (b - this).LengthSquared();
} }
/// <summary>
/// Returns the distance between this vector and `b`.
/// </summary>
/// <param name="b">The other vector to use.</param>
/// <returns>The distance between the two vectors.</returns>
public real_t DistanceTo(Vector3 b) public real_t DistanceTo(Vector3 b)
{ {
return (b - this).Length(); return (b - this).Length();
} }
/// <summary>
/// Returns the dot product of this vector and `b`.
/// </summary>
/// <param name="b">The other vector to use.</param>
/// <returns>The dot product of the two vectors.</returns>
public real_t Dot(Vector3 b) public real_t Dot(Vector3 b)
{ {
return x * b.x + y * b.y + z * b.z; return x * b.x + y * b.y + z * b.z;
} }
/// <summary>
/// Returns a new vector with all components rounded down (towards negative infinity).
/// </summary>
/// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
public Vector3 Floor() public Vector3 Floor()
{ {
return new Vector3(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z)); return new Vector3(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z));
} }
/// <summary>
/// Returns the inverse of this vector. This is the same as `new Vector3(1 / v.x, 1 / v.y, 1 / v.z)`.
/// </summary>
/// <returns>The inverse of this vector.</returns>
public Vector3 Inverse() public Vector3 Inverse()
{ {
return new Vector3(1.0f / x, 1.0f / y, 1.0f / z); return new Vector3(1 / x, 1 / y, 1 / z);
} }
/// <summary>
/// Returns true if the vector is normalized, and false otherwise.
/// </summary>
/// <returns>A bool indicating whether or not the vector is normalized.</returns>
public bool IsNormalized() public bool IsNormalized()
{ {
return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
} }
/// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <returns>The length of this vector.</returns>
public real_t Length() public real_t Length()
{ {
real_t x2 = x * x; real_t x2 = x * x;
@ -175,6 +262,12 @@ namespace Godot
return Mathf.Sqrt(x2 + y2 + z2); return Mathf.Sqrt(x2 + y2 + z2);
} }
/// <summary>
/// Returns the squared length (squared magnitude) of this vector.
/// This method runs faster than <see cref="Length"/>, so prefer it if
/// you need to compare vectors or need the squared length for some formula.
/// </summary>
/// <returns>The squared length of this vector.</returns>
public real_t LengthSquared() public real_t LengthSquared()
{ {
real_t x2 = x * x; real_t x2 = x * x;
@ -184,16 +277,66 @@ namespace Godot
return x2 + y2 + z2; return x2 + y2 + z2;
} }
public Vector3 LinearInterpolate(Vector3 b, real_t t) /// <summary>
/// Returns the result of the linear interpolation between
/// this vector and `to` by amount `weight`.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public Vector3 LinearInterpolate(Vector3 to, real_t weight)
{ {
return new Vector3 return new Vector3
( (
x + t * (b.x - x), Mathf.Lerp(x, to.x, weight),
y + t * (b.y - y), Mathf.Lerp(y, to.y, weight),
z + t * (b.z - z) Mathf.Lerp(z, to.z, weight)
); );
} }
/// <summary>
/// Returns the result of the linear interpolation between
/// this vector and `to` by the vector amount `weight`.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public Vector3 LinearInterpolate(Vector3 to, Vector3 weight)
{
return new Vector3
(
Mathf.Lerp(x, to.x, weight.x),
Mathf.Lerp(y, to.y, weight.y),
Mathf.Lerp(z, to.z, weight.z)
);
}
/// <summary>
/// Returns the axis of the vector's largest value. See <see cref="Axis"/>.
/// If all components are equal, this method returns <see cref="Axis.X"/>.
/// </summary>
/// <returns>The index of the largest axis.</returns>
public Axis MaxAxis()
{
return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
}
/// <summary>
/// Returns the axis of the vector's smallest value. See <see cref="Axis"/>.
/// If all components are equal, this method returns <see cref="Axis.Z"/>.
/// </summary>
/// <returns>The index of the smallest axis.</returns>
public Axis MinAxis()
{
return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
}
/// <summary>
/// Moves this vector toward `to` by the fixed `delta` amount.
/// </summary>
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
public Vector3 MoveToward(Vector3 to, real_t delta) public Vector3 MoveToward(Vector3 to, real_t delta)
{ {
var v = this; var v = this;
@ -202,16 +345,10 @@ namespace Godot
return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta; return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta;
} }
public Axis MaxAxis() /// <summary>
{ /// Returns the vector scaled to unit length. Equivalent to `v / v.Length()`.
return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X); /// </summary>
} /// <returns>A normalized version of the vector.</returns>
public Axis MinAxis()
{
return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
}
public Vector3 Normalized() public Vector3 Normalized()
{ {
var v = this; var v = this;
@ -219,6 +356,11 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns the outer product with `b`.
/// </summary>
/// <param name="b">The other vector.</param>
/// <returns>A <see cref="Basis"/> representing the outer product matrix.</returns>
public Basis Outer(Vector3 b) public Basis Outer(Vector3 b)
{ {
return new Basis( return new Basis(
@ -228,6 +370,11 @@ namespace Godot
); );
} }
/// <summary>
/// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `mod`.
/// </summary>
/// <param name="mod">A value representing the divisor of the operation.</param>
/// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `mod`.</returns>
public Vector3 PosMod(real_t mod) public Vector3 PosMod(real_t mod)
{ {
Vector3 v; Vector3 v;
@ -237,6 +384,11 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components and `modv`'s components.
/// </summary>
/// <param name="modv">A vector representing the divisors of the operation.</param>
/// <returns>A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by `modv`'s components.</returns>
public Vector3 PosMod(Vector3 modv) public Vector3 PosMod(Vector3 modv)
{ {
Vector3 v; Vector3 v;
@ -246,30 +398,60 @@ namespace Godot
return v; return v;
} }
/// <summary>
/// Returns this vector projected onto another vector `b`.
/// </summary>
/// <param name="onNormal">The vector to project onto.</param>
/// <returns>The projected vector.</returns>
public Vector3 Project(Vector3 onNormal) public Vector3 Project(Vector3 onNormal)
{ {
return onNormal * (Dot(onNormal) / onNormal.LengthSquared()); return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
} }
public Vector3 Reflect(Vector3 n) /// <summary>
/// Returns this vector reflected from a plane defined by the given `normal`.
/// </summary>
/// <param name="normal">The normal vector defining the plane to reflect from. Must be normalized.</param>
/// <returns>The reflected vector.</returns>
public Vector3 Reflect(Vector3 normal)
{ {
#if DEBUG #if DEBUG
if (!n.IsNormalized()) if (!normal.IsNormalized())
throw new ArgumentException("Argument is not normalized", nameof(n)); {
throw new ArgumentException("Argument is not normalized", nameof(normal));
}
#endif #endif
return 2.0f * n * Dot(n) - this; return 2.0f * Dot(normal) * normal - this;
} }
/// <summary>
/// Rotates this vector around a given `axis` vector by `phi` radians.
/// The `axis` vector must be a normalized vector.
/// </summary>
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
/// <param name="phi">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public Vector3 Rotated(Vector3 axis, real_t phi)
{
#if DEBUG
if (!axis.IsNormalized())
{
throw new ArgumentException("Argument is not normalized", nameof(axis));
}
#endif
return new Basis(axis, phi).Xform(this);
}
/// <summary>
/// Returns this vector with all components rounded to the nearest integer,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
/// <returns>The rounded vector.</returns>
public Vector3 Round() public Vector3 Round()
{ {
return new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z)); return new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z));
} }
public Vector3 Rotated(Vector3 axis, real_t phi)
{
return new Basis(axis, phi).Xform(this);
}
[Obsolete("Set is deprecated. Use the Vector3(" + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)] [Obsolete("Set is deprecated. Use the Vector3(" + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)]
public void Set(real_t x, real_t y, real_t z) public void Set(real_t x, real_t y, real_t z)
{ {
@ -285,6 +467,12 @@ namespace Godot
z = v.z; z = v.z;
} }
/// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(real_t)"/> on each component.
/// </summary>
/// <returns>A vector with all components as either `1`, `-1`, or `0`.</returns>
public Vector3 Sign() public Vector3 Sign()
{ {
Vector3 v; Vector3 v;
@ -294,37 +482,70 @@ namespace Godot
return v; return v;
} }
public Vector3 Slerp(Vector3 b, real_t t) /// <summary>
/// Returns the result of the spherical linear interpolation between
/// this vector and `to` by amount `weight`.
///
/// Note: Both vectors must be normalized.
/// </summary>
/// <param name="to">The destination vector for interpolation. Must be normalized.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The resulting vector of the interpolation.</returns>
public Vector3 Slerp(Vector3 to, real_t weight)
{ {
#if DEBUG #if DEBUG
if (!IsNormalized()) if (!IsNormalized())
throw new InvalidOperationException("Vector3 is not normalized"); {
throw new InvalidOperationException("Vector3.Slerp: From vector is not normalized.");
}
if (!to.IsNormalized())
{
throw new InvalidOperationException("Vector3.Slerp: `to` is not normalized.");
}
#endif #endif
real_t theta = AngleTo(b); real_t theta = AngleTo(to);
return Rotated(Cross(b), theta * t); return Rotated(Cross(to), theta * weight);
} }
public Vector3 Slide(Vector3 n) /// <summary>
/// Returns this vector slid along a plane defined by the given normal.
/// </summary>
/// <param name="normal">The normal vector defining the plane to slide on.</param>
/// <returns>The slid vector.</returns>
public Vector3 Slide(Vector3 normal)
{ {
return this - n * Dot(n); return this - normal * Dot(normal);
} }
public Vector3 Snapped(Vector3 by) /// <summary>
/// Returns this vector with each component snapped to the nearest multiple of `step`.
/// This can also be used to round to an arbitrary number of decimals.
/// </summary>
/// <param name="step">A vector value representing the step size to snap to.</param>
/// <returns>The snapped vector.</returns>
public Vector3 Snapped(Vector3 step)
{ {
return new Vector3 return new Vector3
( (
Mathf.Stepify(x, by.x), Mathf.Stepify(x, step.x),
Mathf.Stepify(y, by.y), Mathf.Stepify(y, step.y),
Mathf.Stepify(z, by.z) Mathf.Stepify(z, step.z)
); );
} }
/// <summary>
/// Returns a diagonal matrix with the vector as main diagonal.
///
/// This is equivalent to a Basis with no rotation or shearing and
/// this vector's components set as the scale.
/// </summary>
/// <returns>A Basis with the vector as its main diagonal.</returns>
public Basis ToDiagonalMatrix() public Basis ToDiagonalMatrix()
{ {
return new Basis( return new Basis(
x, 0f, 0f, x, 0, 0,
0f, y, 0f, 0, y, 0,
0f, 0f, z 0, 0, z
); );
} }
@ -341,25 +562,79 @@ namespace Godot
private static readonly Vector3 _forward = new Vector3(0, 0, -1); private static readonly Vector3 _forward = new Vector3(0, 0, -1);
private static readonly Vector3 _back = new Vector3(0, 0, 1); private static readonly Vector3 _back = new Vector3(0, 0, 1);
/// <summary>
/// Zero vector, a vector with all components set to `0`.
/// </summary>
/// <value>Equivalent to `new Vector3(0, 0, 0)`</value>
public static Vector3 Zero { get { return _zero; } } public static Vector3 Zero { get { return _zero; } }
/// <summary>
/// One vector, a vector with all components set to `1`.
/// </summary>
/// <value>Equivalent to `new Vector3(1, 1, 1)`</value>
public static Vector3 One { get { return _one; } } public static Vector3 One { get { return _one; } }
/// <summary>
/// Deprecated, please use a negative sign with <see cref="One"/> instead.
/// </summary>
/// <value>Equivalent to `new Vector3(-1, -1, -1)`</value>
public static Vector3 NegOne { get { return _negOne; } } public static Vector3 NegOne { get { return _negOne; } }
/// <summary>
/// Infinity vector, a vector with all components set to `Mathf.Inf`.
/// </summary>
/// <value>Equivalent to `new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf)`</value>
public static Vector3 Inf { get { return _inf; } } public static Vector3 Inf { get { return _inf; } }
/// <summary>
/// Up unit vector.
/// </summary>
/// <value>Equivalent to `new Vector3(0, 1, 0)`</value>
public static Vector3 Up { get { return _up; } } public static Vector3 Up { get { return _up; } }
/// <summary>
/// Down unit vector.
/// </summary>
/// <value>Equivalent to `new Vector3(0, -1, 0)`</value>
public static Vector3 Down { get { return _down; } } public static Vector3 Down { get { return _down; } }
/// <summary>
/// Right unit vector. Represents the local direction of right,
/// and the global direction of east.
/// </summary>
/// <value>Equivalent to `new Vector3(1, 0, 0)`</value>
public static Vector3 Right { get { return _right; } } public static Vector3 Right { get { return _right; } }
/// <summary>
/// Left unit vector. Represents the local direction of left,
/// and the global direction of west.
/// </summary>
/// <value>Equivalent to `new Vector3(-1, 0, 0)`</value>
public static Vector3 Left { get { return _left; } } public static Vector3 Left { get { return _left; } }
/// <summary>
/// Forward unit vector. Represents the local direction of forward,
/// and the global direction of north.
/// </summary>
/// <value>Equivalent to `new Vector3(0, 0, -1)`</value>
public static Vector3 Forward { get { return _forward; } } public static Vector3 Forward { get { return _forward; } }
/// <summary>
/// Back unit vector. Represents the local direction of back,
/// and the global direction of south.
/// </summary>
/// <value>Equivalent to `new Vector3(0, 0, 1)`</value>
public static Vector3 Back { get { return _back; } } public static Vector3 Back { get { return _back; } }
// Constructors /// <summary>
/// Constructs a new <see cref="Vector3"/> with the given components.
/// </summary>
/// <param name="x">The vector's X component.</param>
/// <param name="y">The vector's Y component.</param>
/// <param name="z">The vector's Z component.</param>
public Vector3(real_t x, real_t y, real_t z) public Vector3(real_t x, real_t y, real_t z)
{ {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
} }
/// <summary>
/// Constructs a new <see cref="Vector3"/> from an existing <see cref="Vector3"/>.
/// </summary>
/// <param name="v">The existing <see cref="Vector3"/>.</param>
public Vector3(Vector3 v) public Vector3(Vector3 v)
{ {
x = v.x; x = v.x;
@ -415,20 +690,20 @@ namespace Godot
return left; return left;
} }
public static Vector3 operator /(Vector3 vec, real_t scale) public static Vector3 operator /(Vector3 vec, real_t divisor)
{ {
vec.x /= scale; vec.x /= divisor;
vec.y /= scale; vec.y /= divisor;
vec.z /= scale; vec.z /= divisor;
return vec; return vec;
} }
public static Vector3 operator /(Vector3 left, Vector3 right) public static Vector3 operator /(Vector3 vec, Vector3 divisorv)
{ {
left.x /= right.x; vec.x /= divisorv.x;
left.y /= right.y; vec.y /= divisorv.y;
left.z /= right.z; vec.z /= divisorv.z;
return left; return vec;
} }
public static Vector3 operator %(Vector3 vec, real_t divisor) public static Vector3 operator %(Vector3 vec, real_t divisor)
@ -520,6 +795,12 @@ namespace Godot
return x == other.x && y == other.y && z == other.z; return x == other.x && y == other.y && z == other.z;
} }
/// <summary>
/// Returns true if this vector and `other` are approximately equal, by running
/// <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component.
/// </summary>
/// <param name="other">The other vector to compare.</param>
/// <returns>Whether or not the vectors are approximately equal.</returns>
public bool IsEqualApprox(Vector3 other) public bool IsEqualApprox(Vector3 other)
{ {
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z); return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z);