tomato 1.2.4 Reference Manual

::tomato::mathquatTop, Main, Index

A Class representing a Quaternion

ClassesTop, Main, Index

Quaternion [::tomato::mathquat]Top, Main, Index

Method summary
constructorConstructor for the class.
!=Inequality operator for two quaternions if $obj is quaternion component.
Inequality operator for quaternion and double if $obj is double.
*Multiply a floating point number with a quaternion, if $obj is double.
Or multiply a quaternion with a quaternion, if $obj is an Quaternion object.
+Add a floating point number to a quaternion, if $obj is double or add a quaternion to a quaternion, if $obj is an Quaternion object.
-Subtract a floating point number from a quaternion, if $obj is double.
Or subtract a quaternion from a quaternion, if $obj is an Quaternion object.
/Divide a quaternion by a floating point number, if $obj is double.
Or divide a quaternion by a quaternion, if $obj is an Quaternion object.
==Equality operator for two quaternions if $obj is quaternion component.
Equality operator for quaternion and double if $obj is double.
^Raise a quaternion to a floating point number.
AngleGets the angle (in radians) describing the magnitude of the quaternion rotation about it's rotation axis.
ArgGets the argument phi = arg(q) of the quaternion q, such that q = r*(cos(phi) + u*sin(phi)) = r*exp(phi*u)
where r is the absolute and u the unit vector of q.
ConjugateConjugate this quaternion.
DistanceGets the distance |a-b| of two quaternions, forming a metric space.
ExpExponential Function.
GetGets values from the Quaternion Class under Tcl list form.
GetTypeGets the name of class.
ImagXGets the imaginary X part (coefficient of complex I) of the quaternion.
ImagYGets the imaginary Y part (coefficient of complex J) of the quaternion.
ImagZGets the imaginary Z part (coefficient of complex K) of the quaternion.
InversedGets an inverted quaternion. Inversing Zero returns Zero
IsInfinityGets a value indicating whether the quaternion is not a number
IsNanGets a value indicating whether the quaternion is not a number
IsUnitQuaternionGets a value indicating whether the quaternion q has length |q| = 1. To normalize a quaternion to a length of 1, use the Normalized method. All unit quaternions form a 3-sphere.
LogLogarithm to a given base.
Log10Common Logarithm to base 10.
NegateNegate a quaternion.
NormGets the norm of the quaternion q: square root of the sum of the squares of the four components.
NormalizedGets a new normalized Quaternion q with the direction of this quaternion.
NormalizedVectorGets a new normalized Quaternion u with the Vector part only, such that ||u|| = 1.
NormSquaredGets the sum of the squares of the four components.
RealGets the real part of the quaternion.
RotateRotate a 3D vector or 3D point by the rotation stored in the Quaternion object
RotateRotationQuaternionRotates the provided rotation quaternion with this quaternion.
RotateUnitQuaternionRotates the provided unit quaternion with this quaternion.
ScalarGets a new Quaternion q with the Scalar part only.
SqrtSquare root of the Quaternion: q^(1/2).
ToStringReturns a string representation of this object.
ToVector3DGets the Vector part only.
VectorGets a new Quaternion q with the Vector part only.

constructor [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Initializes a new Quaternion Class.

Quaternion create OBJNAME ?args?
Quaternion new ?args?
Parameters
argsOptions described below.
component1-scalar & -vector
component2-axis & -angle
listA list of 4 elements
no valuesdefault to Quaternion(1 +0i +0j +0k).
scalarA scalar value
values3 values or 4 values
vectorA Vector3d Class mathvec3d::Vector3d
Description
tomato::mathquat::Quaternion new {1 2 3 4}
> (1 + 2i + 3j + 4k)
tomato::mathquat::Quaternion new $vectorobj
> (0 + xi + yj + zk)
tomato::mathquat::Quaternion new "2"
The imaginary part of the resulting quaternion will always be 0i + 0j + 0k.
> (2 + 0i + 0j + 0k)
tomato::mathquat::Quaternion new 1 2 3
> (0 + 1i + 2j + 3k)
tomato::mathquat::Quaternion new 1 1 1 1
> (1 + 1i + 1j + 1k)
-vectorCan be a Vector3d class mathvec3d::Vector3d or list of 3 values
tomato::mathquat::Quaternion new -scalar 1 -vector {1 1 1}
> (1 + 1i + 1j + 1k)
-axisCan be a Vector3d class mathvec3d::Vector3d or list of 3 values
tomato::mathquat::Quaternion new -axis {0 1 0} -angle 90
> (0.707 +0i +0.707j +0k)
tomato::mathquat::Quaternion new
> (1 +0i +0j +0k)

An error exception is raised if args is not the one desired.

method constructor {args} {

    # Initializes a new Quaternion Class.
    #
    # args - Options described below.
    #
    # list       - A list of 4 elements
    # vector     - A Vector3d Class [mathvec3d::Vector3d]
    # scalar     - A scalar value
    # values     - 3 values or 4 values
    # component1 - -scalar & -vector
    # component2 - -axis & -angle
    # no values  - default to `Quaternion(1 +0i +0j +0k)`.
    #

    if {[llength $args] == 1} {

        if {[llength {*}$args] == 4} {
            #ruff
            # * Create a quaternion by specifying a list of 4 real-numbered scalar elements.<br>
            # ```
            # tomato::mathquat::Quaternion new {1 2 3 4}
            # > (1 + 2i + 3j + 4k)
            # ```
            lassign {*}$args w x y z
            set _w $w
            set _x $x
            set _y $y
            set _z $z

        } elseif {[tomato::helper::TypeOf $args Isa "Vector3d"]} {
            #ruff
            # * Create a quaternion by specifying a Vector3d Class.<br>
            # ```
            # tomato::mathquat::Quaternion new $vectorobj
            # > (0 + xi + yj + zk)
            # ```
            lassign [$args Get] x y z
            set _w 0
            set _x $x
            set _y $y
            set _z $z

        } elseif {[tomato::mathquat::_checkvalue $args]} {
            #ruff
            # * Create the quaternion representation of a scalar (single real number) value.<br>
            # ```
            # tomato::mathquat::Quaternion new "2"
            # The imaginary part of the resulting quaternion will always be 0i + 0j + 0k.
            # > (2 + 0i + 0j + 0k)
            # ```
            set _w $args
            set _x 0
            set _y 0
            set _z 0

        } else {
            error "arg must be a Vector3d, one scalar value, or 4 values ..."
        }

    } elseif {[llength $args] == 3} {
        #ruff
        # * Create a quaternion by specifying 3 real-numbered scalar elements.<br>
        # ```
        # tomato::mathquat::Quaternion new 1 2 3
        # > (0 + 1i + 2j + 3k)
        # ```
        lassign $args x y z
        set _w 0
        set _x $x
        set _y $y
        set _z $z

    } elseif {[llength $args] == 4} {

        if {[tomato::mathquat::_checkvalue $args]} {
            #ruff
            # * Create a quaternion by specifying 4 real-numbered scalar elements.<br>
            # ```
            # tomato::mathquat::Quaternion new 1 1 1 1
            # > (1 + 1i + 1j + 1k)
            # ```
            lassign $args w x y z
            set _w $w
            set _x $x
            set _y $y
            set _z $z

        } else {

            if {[string match "*-scalar*" $args] && ![string match "*-vector*" $args]} {
                #ruff
                # * Create a quaternion by specifying a scalar and a vector.<br>
                # The scalar (real) and vector (imaginary) parts of the desired quaternion.<br>
                # -vector - Can be a Vector3d class [mathvec3d::Vector3d] or list of 3 values
                # ```
                # tomato::mathquat::Quaternion new -scalar 1 -vector {1 1 1}
                # > (1 + 1i + 1j + 1k)
                # ```
                error "Key 'scalar' must be associated with 'vector'"
            }

            if {[string match "*-axis*" $args] && ![string match "*-angle*" $args]} {
                #ruff
                # * Create a quaternion by specifying a axis and a angle in degrees.<br>
                # Specify the angle (degrees) for a rotation about an axis vector \[x, y, z] to be described by the quaternion object<br>
                # -axis - Can be a Vector3d class [mathvec3d::Vector3d] or list of 3 values
                # ```
                # tomato::mathquat::Quaternion new -axis {0 1 0} -angle 90
                # > (0.707 +0i +0.707j +0k)
                # ```
                error "Key 'axis' must be associated with 'angle'"
            }

            set options [dict create]

            foreach {key value} $args {

                if {$value eq ""} {
                    error "No value specified for key '$key'"
                }

                switch -exact -- $key {
                    "-scalar" {dict set options Scalar $value}
                    "-axis" -
                    "-vector" {
                                if {[tomato::helper::TypeOf $value Isa "Vector3d"]} {
                                    dict set options Vector $value
                                } elseif {[string is list $value] && [llength $value] == 3} {
                                    dict set options Vector [tomato::mathvec3d::Vector3d new $value]
                                } else {
                                    error "Value for Key '$key' must be an Class Vector3d or a list of 3 elements..."
                                }
                              }
                    "-angle" {dict set options Angle $value}
                    default  {error "Unknown key '$key' specified"}

                }

            }

            if {[dict exists $options Vector] && [dict exists $options Angle]} {
                lassign [tomato::mathquat::_init_from_vector_angle [dict get $options Vector]  [dict get $options Angle]] w x y z

                set _w $w ; set _x $x ; set _y $y ; set _z $z

            } elseif {[dict exists $options Scalar] && [dict exists $options Vector]} {

                lassign [[dict get $options Vector] Get] x y z

                set _w [dict get $options Scalar] ; set _x $x ; set _y $y ; set _z $z
            }


        }

    } elseif {[llength $args] == 0} {
        #ruff
        # * Default value :
        # ```
        # tomato::mathquat::Quaternion new
        # > (1 +0i +0j +0k)
        # ```
        set _w 1
        set _x 0
        set _y 0
        set _z 0
    } else {
        #ruff
        # An error exception is raised if `args` is not the one desired.
        error "The argument does not match the requested values, please refer to the documentation..."
    }
}

!= [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Inequality operator for two quaternions if $obj is quaternion component.
Inequality operator for quaternion and double if $obj is double.

QUATERNIONOBJ != obj ?tolerance?
Parameters
objOptions described below.
toleranceA tolerance (epsilon) to adjust for floating point error. Optional, default $::tomato::helper::TolEquals.
objectA Quaternion component.
scalarA double value.
Return value

Returns True if the quaternions are not the same if $obj is a quaternion or True if the real part of the quaternion is not equal to the double and the rest of the quaternion is almost 0. Otherwise False.

method != {obj {tolerance {$::tomato::helper::TolEquals}}} {

    # Inequality operator for two quaternions if $obj is quaternion component.<br>
    # Inequality operator for quaternion and double if $obj is double.
    #
    # obj - Options described below.
    #
    # scalar    - A double value.
    # object    - A Quaternion component.
    # tolerance - A tolerance (epsilon) to adjust for floating point error.
    #
    # Returns `True` if the quaternions are not the same if $obj is a quaternion or
    # True if the real part of the quaternion is not equal to the double and the rest of the quaternion is almost 0. Otherwise `False`.
    if {[llength [info level 0]] < 4} {
        set tolerance $::tomato::helper::TolEquals
    }

    return [expr {![my == $obj $tolerance]}]
}

* [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Multiply a floating point number with a quaternion, if $obj is double.
Or multiply a quaternion with a quaternion, if $obj is an Quaternion object.

QUATERNIONOBJ * obj
Parameters
objOptions described below.
objectA Quaternion component.
scalarA double value.
Return value

Returns A new quaternion Quaternion.

method * {obj} {

    # Multiply a floating point number with a quaternion, if $obj is double.<br>
    # Or multiply a quaternion with a quaternion, if $obj is an Quaternion object.
    #
    # obj - Options described below.
    #
    # scalar - A double value.
    # object - A Quaternion component.
    #
    # Returns A new quaternion [Quaternion].
    if {[string is double $obj]} {
        return [tomato::mathquat::Quaternion new [expr {$_w * $obj}]  [expr {$_x * $obj}]  [expr {$_y * $obj}]  [expr {$_z * $obj}]]
    }

    if {[tomato::helper::TypeOf $obj Isa "Quaternion"]} {

        set ci [expr {($_x      * [$obj Real])  + ($_y * [$obj ImagZ]) - ($_z * [$obj ImagY]) + ($_w * [$obj ImagX])}]
        set cj [expr {(Inv($_x) * [$obj ImagZ]) + ($_y * [$obj Real])  + ($_z * [$obj ImagX]) + ($_w * [$obj ImagY])}]
        set ck [expr {($_x      * [$obj ImagY]) - ($_y * [$obj ImagX]) + ($_z * [$obj Real])  + ($_w * [$obj ImagZ])}]
        set cr [expr {(Inv($_x) * [$obj ImagX]) - ($_y * [$obj ImagY]) - ($_z * [$obj ImagZ]) + ($_w * [$obj Real])}]

        return [tomato::mathquat::Quaternion new $cr $ci $cj $ck]
    }
}

+ [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Add a floating point number to a quaternion, if $obj is double or add a quaternion to a quaternion, if $obj is an Quaternion object.

QUATERNIONOBJ + obj
Parameters
objOptions described below.
objectA Quaternion component.
scalarA double value.
Return value

Returns A quaternion whose real value is increased by a scalar if $obj is double value.
Or the sum of two quaternions Quaternion if $obj is a quaternion object.

method + {obj} {

    # Add a floating point number to a quaternion, if $obj is double
    # or add a quaternion to a quaternion, if $obj is an Quaternion object.
    #
    # obj - Options described below.
    #
    # scalar - A double value.
    # object - A Quaternion component.
    #
    # Returns A quaternion whose real value is increased by a scalar if $obj is double value.<br>
    # Or the sum of two quaternions [Quaternion] if $obj is a quaternion object.
    if {[string is double $obj]} {
        return [tomato::mathquat::Quaternion new [expr {$_w + $obj}] $_x $_y $_z]
    }

    if {[tomato::helper::TypeOf $obj Isa "Quaternion"]} {
        return [tomato::mathquat::Quaternion new [expr {$_w + [$obj Real]}]  [expr {$_x + [$obj ImagX]}]  [expr {$_y + [$obj ImagY]}]  [expr {$_z + [$obj ImagZ]}]]
    }
}

- [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Subtract a floating point number from a quaternion, if $obj is double.
Or subtract a quaternion from a quaternion, if $obj is an Quaternion object.

QUATERNIONOBJ - obj
Parameters
objOptions described below.
objectA Quaternion component.
scalarA double value.
Return value

Returns A quaternion whose real value is discreased by a scalar if $obj is double value.
Or the quaternion Quaternion difference if $obj is a quaternion object.

method - {obj} {

    # Subtract a floating point number from a quaternion, if $obj is double.<br>
    # Or subtract a quaternion from a quaternion, if $obj is an Quaternion object.
    #
    # obj - Options described below.
    #
    # scalar - A double value.
    # object - A Quaternion component.
    #
    # Returns A quaternion whose real value is discreased by a scalar if $obj is double value.<br>
    # Or the quaternion [Quaternion] difference if $obj is a quaternion object.
    if {[string is double $obj]} {
        return [tomato::mathquat::Quaternion new [expr {$_w - $obj}] $_x $_y $_z]
    }

    if {[tomato::helper::TypeOf $obj Isa "Quaternion"]} {
        return [tomato::mathquat::Quaternion new [expr {$_w - [$obj Real]}]  [expr {$_x - [$obj ImagX]}]  [expr {$_y - [$obj ImagY]}]  [expr {$_z - [$obj ImagZ]}]]
    }
}

/ [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Divide a quaternion by a floating point number, if $obj is double.
Or divide a quaternion by a quaternion, if $obj is an Quaternion object.

QUATERNIONOBJ / obj
Parameters
objOptions described below.
objectA Quaternion component.
scalarA double value.
Return value

Returns A new divided quaternion Quaternion.

method / {obj} {

    # Divide a quaternion by a floating point number, if $obj is double.<br>
    # Or divide a quaternion by a quaternion, if $obj is an Quaternion object.
    #
    # obj - Options described below.
    #
    # scalar - A double value.
    # object - A Quaternion component.
    #
    # Returns A new divided quaternion [Quaternion].
    if {[string is double $obj]} {
        return [tomato::mathquat::Quaternion new [expr {$_w / double($obj)}]  [expr {$_x / double($obj)}]  [expr {$_y / double($obj)}]  [expr {$_z / double($obj)}]]
    }

    if {[tomato::helper::TypeOf $obj Isa "Quaternion"]} {

        if {[$obj == $::tomato::mathquat::Zero]} {
            if {[[self] == $::tomato::mathquat::Zero]} {
                return [tomato::mathquat::Quaternion new "NaN" "NaN" "NaN" "NaN"]
            }

            return [tomato::mathquat::Quaternion new "Inf" "Inf" "Inf" "Inf"]

        }

        set normSquared [$obj NormSquared]
        set t0 [expr {(([$obj Real] * $_w) + ([$obj ImagX] * $_x) + ([$obj ImagY] * $_y) + ([$obj ImagZ] * $_z)) / double($normSquared)}]
        set t1 [expr {(([$obj Real] * $_x) - ([$obj ImagX] * $_w) - ([$obj ImagY] * $_z) + ([$obj ImagZ] * $_y)) / double($normSquared)}]
        set t2 [expr {(([$obj Real] * $_y) + ([$obj ImagX] * $_z) - ([$obj ImagY] * $_w) - ([$obj ImagZ] * $_x)) / double($normSquared)}]
        set t3 [expr {(([$obj Real] * $_z) - ([$obj ImagX] * $_y) + ([$obj ImagY] * $_x) - ([$obj ImagZ] * $_w)) / double($normSquared)}]

        return [tomato::mathquat::Quaternion new $t0 $t1 $t2 $t3]
    }
}

== [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Equality operator for two quaternions if $obj is quaternion component.
Equality operator for quaternion and double if $obj is double.

QUATERNIONOBJ == obj ?tolerance?
Parameters
objOptions described below.
toleranceA tolerance (epsilon) to adjust for floating point error. Optional, default $::tomato::helper::TolEquals.
objectA Quaternion component.
scalarA double value.
Return value

Returns True if the quaternions are the same if $obj is a quaternion or True if the real part of the quaternion is almost equal to the double and the rest of the quaternion is almost 0. Otherwise False.

method == {obj {tolerance {$::tomato::helper::TolEquals}}} {

    # Equality operator for two quaternions if $obj is quaternion component.<br>
    # Equality operator for quaternion and double if $obj is double.
    #
    # obj - Options described below.
    #
    # scalar    - A double value.
    # object    - A Quaternion component.
    # tolerance - A tolerance (epsilon) to adjust for floating point error.
    #
    # Returns `True` if the quaternions are the same if $obj is a quaternion or
    # True if the real part of the quaternion is almost equal to the double and the rest of the quaternion is almost 0. Otherwise `False`.
    if {[llength [info level 0]] < 4} {
        set tolerance $::tomato::helper::TolEquals
    }

    if {[string is double $obj]} {
        return [expr {
                        (($_w - $obj) < $tolerance) &&
                        (($_x - 0) < $tolerance) &&
                        (($_y - 0) < $tolerance) &&
                        (($_z - 0) < $tolerance)
                    }]
    }

    if {[tomato::helper::TypeOf $obj Isa "Quaternion"]} {
        return [tomato::mathquat::Equals [self] $obj $tolerance]
    }
}

^ [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Raise a quaternion to a floating point number.

QUATERNIONOBJ ^ obj
Parameters
objA double value.
Return value

Returns A new quaternion Quaternion.

method ^ {obj} {

    # Raise a quaternion to a floating point number.
    #
    # obj - A double value.
    #
    # Returns A new quaternion [Quaternion].
    return [tomato::mathquat::Pow [self] $obj]
}

Angle [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the angle (in radians) describing the magnitude of the quaternion rotation about it's rotation axis.

QUATERNIONOBJ Angle
Return value

Returns A real number in the range [-pi:pi] describing the angle of rotation in radians about a Quaternion object's axis of rotation

method Angle {} {

    # Gets the angle (in radians) describing the magnitude of the quaternion rotation about it's rotation axis.
    #
    # Returns A real number in the range `[-pi:pi]` describing the angle of rotation
    # in radians about a Quaternion object's axis of rotation
    set q [self]

    if {![$q IsUnitQuaternion]} {
        set q [$q Normalized]
    }

    set norm [[$q ToVector3D] Length]

    return [tomato::mathquat::_wrap_angle [expr {2.0 * atan2($norm, [my Real])}]]
}

Arg [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the argument phi = arg(q) of the quaternion q, such that q = r*(cos(phi) + u*sin(phi)) = r*exp(phi*u)
where r is the absolute and u the unit vector of q.

QUATERNIONOBJ Arg
method Arg {} {

    # Gets the argument `phi = arg(q)` of the quaternion `q`, such that `q = r*(cos(phi) +
    # u*sin(phi)) = r*exp(phi*u)`<br> where `r` is the absolute and `u` the unit vector of
    # `q`.
    return [expr {acos($_w / [my Norm])}]
}

Conjugate [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Conjugate this quaternion.

QUATERNIONOBJ Conjugate
Return value

Returns A new conjugated quaternion Quaternion

method Conjugate {} {

    # Conjugate this quaternion.
    #
    # Returns A new conjugated quaternion [Quaternion]
    return [tomato::mathquat::Quaternion new $_w  [expr {Inv($_x)}]  [expr {Inv($_y)}]  [expr {Inv($_z)}]]
}

Distance [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the distance |a-b| of two quaternions, forming a metric space.

QUATERNIONOBJ Distance q
Parameters
qA Quaternion component.
Return value

Returns The distance between two quaternions.

method Distance {q} {

    # Gets the distance |a-b| of two quaternions, forming a metric space.
    #
    # q - A Quaternion component.
    #
    # Returns The distance between two quaternions.
    return [[my - $q] Norm]
}

Exp [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Exponential Function.

QUATERNIONOBJ Exp
Return value

Returns A new quaternion Quaternion

method Exp {} {

    # Exponential Function.
    #
    # Returns A new quaternion [Quaternion]
    set mathE 2.7182818284590451 ; # https://docs.microsoft.com/en-us/dotnet/api/system.math.e?view=net-5.0

    set real       [expr {pow($mathE, $_w)}]
    set vector     [my Vector]
    set vectorNorm [$vector Norm]
    set cos [expr {cos($vectorNorm)}]
    set sgn [expr {[$vector == $::tomato::mathquat::Zero] ? $::tomato::mathquat::Zero : [$vector / $vectorNorm]}]
    set sin [expr {sin($vectorNorm)}]

    return [[[$sgn * $sin] + $cos] * $real]
}

Get [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets values from the Quaternion Class under Tcl list form.

QUATERNIONOBJ Get
method Get {} {

    # Gets values from the Quaternion Class under Tcl list form.
    return [list $_x $_y $_z $_w]
}

GetType [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the name of class.

QUATERNIONOBJ GetType
method GetType {} {

    # Gets the name of class.
    return [tomato::helper::TypeClass [self]]
}

ImagX [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the imaginary X part (coefficient of complex I) of the quaternion.

QUATERNIONOBJ ImagX
method ImagX {} {

    # Gets the imaginary X part (coefficient of complex I) of the quaternion.
    return $_x
}

ImagY [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the imaginary Y part (coefficient of complex J) of the quaternion.

QUATERNIONOBJ ImagY
method ImagY {} {

    # Gets the imaginary Y part (coefficient of complex J) of the quaternion.
    return $_y
}

ImagZ [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the imaginary Z part (coefficient of complex K) of the quaternion.

QUATERNIONOBJ ImagZ
method ImagZ {} {

    # Gets the imaginary Z part (coefficient of complex K) of the quaternion.
    return $_z
}

Inversed [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets an inverted quaternion. Inversing Zero returns Zero

QUATERNIONOBJ Inversed
method Inversed {} {

    # Gets an inverted quaternion. Inversing Zero returns Zero
    if {[[self] == $::tomato::mathquat::Zero]} {
        return [self]
    }

    set normSquared [my NormSquared]
    return [tomato::mathquat::Quaternion new [expr {$_w      / double($normSquared)}]  [expr {Inv($_x) / double($normSquared)}]  [expr {Inv($_y) / double($normSquared)}]  [expr {Inv($_z) / double($normSquared)}]]
}

IsInfinity [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a value indicating whether the quaternion is not a number

QUATERNIONOBJ IsInfinity
method IsInfinity {} {

    # Gets a value indicating whether the quaternion is not a number
    foreach value [my Get] {
        if {$value eq "Inf"} {
            return 1
        }
    }
    return 0
}

IsNan [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a value indicating whether the quaternion is not a number

QUATERNIONOBJ IsNan
method IsNan {} {

    # Gets a value indicating whether the quaternion is not a number
    foreach value [my Get] {
        if {$value eq "NaN"} {
            return 1
        }
    }
    return 0
}

IsUnitQuaternion [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a value indicating whether the quaternion q has length |q| = 1. To normalize a quaternion to a length of 1, use the Normalized method. All unit quaternions form a 3-sphere.

QUATERNIONOBJ IsUnitQuaternion
method IsUnitQuaternion {} {

    # Gets a value indicating whether the quaternion q has length |q| = 1.
    # To normalize a quaternion to a length of 1, use the [Normalized] method.
    # All unit quaternions form a 3-sphere.
    return [expr {abs(1.0 - [my NormSquared]) < 1e-15}]
}

Log [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Logarithm to a given base.

QUATERNIONOBJ Log ?lbase?
Parameters
lbaseA base Optional, default "".
Return value

Returns A new quaternion Quaternion

method Log {{lbase {}}} {

    # Logarithm to a given base.
    #
    # lbase - A base
    #
    # Returns A new quaternion [Quaternion]
    if {[llength [info level 0]] < 3} {

        if {[my == $::tomato::mathquat::One]} {return $::tomato::mathquat::One}

        set quat [[my NormalizedVector] * [my Arg]]
        return [tomato::mathquat::Quaternion new [expr {log([my Norm])}] [$quat ImagX] [$quat ImagY] [$quat ImagZ]]

    } else {
        return [[my Log] / [expr {log($lbase)}]]
    }
}

Log10 [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Common Logarithm to base 10.

QUATERNIONOBJ Log10
Return value

Returns A new quaternion

method Log10 {} {

    # Common Logarithm to base 10.
    #
    # Returns A new quaternion
    return [[my Log] / [expr {log(10)}]]
}

Negate [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Negate a quaternion.

QUATERNIONOBJ Negate
Return value

Returns A negated quaternion Quaternion.

method Negate {} {

    # Negate a quaternion.
    #
    # Returns A negated quaternion [Quaternion].
    return [tomato::mathquat::Quaternion new [expr {Inv($_w)}]  [expr {Inv($_x)}]  [expr {Inv($_y)}]  [expr {Inv($_z)}]]
}

Norm [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the norm of the quaternion q: square root of the sum of the squares of the four components.

QUATERNIONOBJ Norm
method Norm {} {

    # Gets the norm of the quaternion q: square root of the sum of the squares of the four components.
    return [expr {sqrt([my NormSquared])}]
}

Normalized [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a new normalized Quaternion q with the direction of this quaternion.

QUATERNIONOBJ Normalized
method Normalized {} {

    # Gets a new normalized Quaternion `q` with the direction of this quaternion.
    return [expr {[[self] == $::tomato::mathquat::Zero] ? [self] : [tomato::mathquat::ToUnitQuaternion $_w $_x $_y $_z]}]
}

NormalizedVector [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a new normalized Quaternion u with the Vector part only, such that ||u|| = 1.

QUATERNIONOBJ NormalizedVector
method NormalizedVector {} {

    # Gets a new normalized Quaternion `u` with the Vector part only, such that `||u|| = 1`.
    return [tomato::mathquat::ToUnitQuaternion 0 $_x $_y $_z]
}

NormSquared [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the sum of the squares of the four components.

QUATERNIONOBJ NormSquared
method NormSquared {} {

    # Gets the sum of the squares of the four components.
    return [tomato::mathquat::ToNormSquared $_w $_x $_y $_z]
}

Real [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the real part of the quaternion.

QUATERNIONOBJ Real
method Real {} {

    # Gets the real part of the quaternion.
    return $_w
}

Rotate [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Rotate a 3D vector or 3D point by the rotation stored in the Quaternion object

QUATERNIONOBJ Rotate obj
Parameters
objOptions described below.
pointA point object.
vectorA vector object.
Return value

Returns The rotated vector or point returned as the same type it was specified at input

method Rotate {obj} {

    # Rotate a 3D vector or 3D point by the rotation stored in the Quaternion object
    #
    # obj - Options described below.
    #
    # point  - A point object.
    # vector - A vector object.
    #
    # Returns The rotated vector or point returned as the same type it was specified at input
    set myentity $obj

    if {[tomato::helper::TypeOf $obj Isa "Vector3d"]} {

        if {![$obj IsNormalized]} {
            set myentity [$obj Normalized]
        }

    } elseif {[tomato::helper::TypeOf $obj Isa "Point3d"]} {

        set myentity [$obj ToVector3D] ; # convert to vector

    } else {
        error "Obj must be an Class Vector3d Or an Class Point3d..."
    }

    set quat [tomato::mathquat::Quaternion new $myentity]
    set q    [self]

    if {![$q IsUnitQuaternion]} {
        set q [my Normalized]
    }

    set result [$q RotateUnitQuaternion $quat]

    if {[tomato::helper::TypeOf $obj Isa "Vector3d"]} {
        return [$result ToVector3D]
    } else {
        return [[$result ToVector3D] ToPoint3D]
    }
}

RotateRotationQuaternion [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Rotates the provided rotation quaternion with this quaternion.

QUATERNIONOBJ RotateRotationQuaternion rotation
Parameters
rotationThe rotation quaternion to rotate.
Return value

Returns A rotated quaternion Quaternion.

method RotateRotationQuaternion {rotation} {

    # Rotates the provided rotation quaternion with this quaternion.
    #
    # rotation - The rotation quaternion to rotate.
    #
    # Returns A rotated quaternion [Quaternion].
    if {![$rotation IsUnitQuaternion]} {
        error "The quaternion provided is not a rotation"
    }

    return [$rotation * [self]]
}

RotateUnitQuaternion [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Rotates the provided unit quaternion with this quaternion.

QUATERNIONOBJ RotateUnitQuaternion unitQuaternion
Parameters
unitQuaternionThe rotation quaternion to rotate.
Return value

Returns A rotated quaternion Quaternion.

method RotateUnitQuaternion {unitQuaternion} {

    # Rotates the provided unit quaternion with this quaternion.
    #
    # unitQuaternion - The rotation quaternion to rotate.
    #
    # Returns A rotated quaternion [Quaternion].
    if {![my IsUnitQuaternion]} {
        error "You cannot rotate with this quaternion as it is not a Unit Quaternion"
    }

    # if {![$unitQuaternion IsUnitQuaternion]} {
    #     error "The quaternion provided is not a Unit Quaternion"
    # }

    return [[my * $unitQuaternion] * [my Conjugate]]
}

Scalar [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a new Quaternion q with the Scalar part only.

QUATERNIONOBJ Scalar
method Scalar {} {

    # Gets a new Quaternion `q` with the Scalar part only.
    return [tomato::mathquat::Quaternion new $_w 0 0 0]
}

Sqrt [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Square root of the Quaternion: q^(1/2).

QUATERNIONOBJ Sqrt
Return value

Returns A new quaternion Quaternion

method Sqrt {} {

    # Square root of the Quaternion: q^(1/2).
    #
    # Returns A new quaternion [Quaternion]
    set arg [expr {[my Arg] * 0.5}]

    return [[my NormalizedVector] * [expr {sin($arg) + cos($arg) + sqrt($_w)}]]
}

ToString [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Returns a string representation of this object.

QUATERNIONOBJ ToString
Return value

Returns a string representation of this object.

method ToString {} {

    # Returns a string representation of this object.

    set formatimgx [expr {($_x < 0 ) ? "%si" : "+%si"}]
    set formatimgy [expr {($_y < 0 ) ? "%sj" : "+%sj"}]
    set formatimgz [expr {($_z < 0 ) ? "%sk" : "+%sk"}]


    return [format [list %s $formatimgx $formatimgy $formatimgz] $_w $_x $_y $_z]
}

ToVector3D [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets the Vector part only.

QUATERNIONOBJ ToVector3D
Return value

Returns A new vector3d mathvec3d::Vector3d

method ToVector3D {} {

    # Gets the Vector part only.
    #
    # Returns A new vector3d [mathvec3d::Vector3d]
    return [tomato::mathvec3d::Vector3d new $_x $_y $_z]
}

Vector [::tomato::mathquat::Quaternion]Quaternion, Top, Main, Index

Gets a new Quaternion q with the Vector part only.

QUATERNIONOBJ Vector
method Vector {} {

    # Gets a new Quaternion `q` with the Vector part only.
    return [tomato::mathquat::Quaternion new 0 $_x $_y $_z]
}

CommandsTop, Main, Index

Dot [::tomato::mathquat]Top, Main, Index

Dot Product between 2 quaternions

Dot q0 q1
Parameters
q0First quaternion component
q1Second quaternion component
Return value

Returns the dot product.

proc ::tomato::mathquat::Dot {q0 q1} {

    # Dot Product between 2 quaternions
    #
    # q0 - First quaternion component
    # q1 - Second quaternion component
    #
    # Returns the dot product.
    return [expr {
                    ([$q0 ImagX] * [$q1 ImagX]) +
                    ([$q0 ImagY] * [$q1 ImagY]) +
                    ([$q0 ImagZ] * [$q1 ImagZ]) +
                    ([$q0 Real]  * [$q1 Real])
                 }]
}

Equals [::tomato::mathquat]Top, Main, Index

Indicate if this quaternion is equivalent to a given quaternion

Equals quaternion other tolerance
Parameters
quaternionFirst input vector Quaternion
otherSecond input vector Quaternion
toleranceA tolerance (epsilon) to adjust for floating point error
Description

See : methods == !=

An error exception is raised if tolerance (epsilon) < 0.

Return value

Returns True if the quaternions are equal, otherwise false.

proc ::tomato::mathquat::Equals {quaternion other tolerance} {

    # Indicate if this quaternion is equivalent to a given quaternion
    #
    # quaternion - First input vector  [Quaternion]
    # other      - Second input vector [Quaternion]
    # tolerance  - A tolerance (epsilon) to adjust for floating point error
    #
    # Returns `True` if the quaternions are equal, otherwise false.
    #
    # See : methods == !=

    if {([$other IsNan] && [$quaternion IsNan]) || ([$other IsInfinity] && [$quaternion IsInfinity])} {
        return 1
    }

    if {$tolerance < 0} {
        #ruff
        # An error exception is raised if tolerance (epsilon) < 0.
        error "epsilon < 0"
    }

    return [expr {
                  abs([$quaternion Real]  - [$other Real])  < $tolerance &&
                  abs([$quaternion ImagX] - [$other ImagX]) < $tolerance &&
                  abs([$quaternion ImagY] - [$other ImagY]) < $tolerance &&
                  abs([$quaternion ImagZ] - [$other ImagZ]) < $tolerance
                }]
}

Pow [::tomato::mathquat]Top, Main, Index

Raise the quaternion to a given power.

Pow q power
Parameters
qA quaternion component.
powerA double, integer or quaternion value.
Return value

Returns The quaternion Quaternion raised to a power of another quaternion

proc ::tomato::mathquat::Pow {q power} {

    # Raise the quaternion to a given power.
    #
    # q     - A quaternion component.
    # power - A double, integer or quaternion value.
    #
    # Returns The quaternion [Quaternion] raised to a power of another quaternion
    if {[string is double -strict $power]} {

        if {[$q == $::tomato::mathquat::Zero]} {return $::tomato::mathquat::Zero}
        if {[$q == $::tomato::mathquat::One]} {return $::tomato::mathquat::One}

        return [[[$q Log] * $power] Exp]
    }

    if {[string is integer -strict $power]} {

        if {$power == 0} {return $::tomato::mathquat::One}
        if {$power == 1} {return $q}
        if {[$q == $::tomato::mathquat::Zero] || [$q == $::tomato::mathquat::One]} {return $q}

        set quat [tomato::mathquat::Quaternion new [$q Real] [$q ImagX] [$q ImagY] [$q ImagZ]]

        return [$quat * [tomato::mathquat::Pow $quat [expr {$power - 1}]]]

    }

    if {[tomato::helper::TypeOf $power Isa "Quaternion"]} {

        if {[$q == $::tomato::mathquat::Zero]} {return $::tomato::mathquat::Zero}
        if {[$q == $::tomato::mathquat::One]} {return $::tomato::mathquat::One}

        return [[$power * [$q Log]] Exp]

    }
}

Slerp [::tomato::mathquat]Top, Main, Index

Spherical Linear Interpolation between quaternions. Implemented as described in wiki/Slerp

Slerp q0 q1 ?arcposition?
Parameters
q0First endpoint rotation as a Quaternion object.
q1Second endpoint rotation as a Quaternion object.
arcpositioninterpolation parameter between 0 and 1. This describes the linear placement position of
the result along the arc between endpoints; 0 being at q0 and 1 being at q1. Optional, default 0.5.
Return value

Returns A new Quaternion object representing the interpolated rotation

proc ::tomato::mathquat::Slerp {q0 q1 {arcposition 0.5}} {

    # Spherical Linear Interpolation between quaternions.
    # Implemented as described in [wiki/Slerp](https://en.wikipedia.org/wiki/Slerp)
    #
    # q0          - First endpoint rotation as a Quaternion object.
    # q1          - Second endpoint rotation as a Quaternion object.
    # arcposition - interpolation parameter between 0 and 1. This describes the linear placement position of <br>
    #               the result along the arc between endpoints; 0 being at `q0` and 1 being at `q1`.
    #
    # Returns A new Quaternion object representing the interpolated rotation

    # Ensure quaternion inputs are unit quaternions and 0 <= amount <=1
    if {![$q0 IsUnitQuaternion]} {
        set q0 [$q0 Normalized]
    }

    if {![$q1 IsUnitQuaternion]} {
        set q1 [$q1 Normalized]
    }

    set clamparcpos [tomato::helper::Clamp $arcposition 0 1]

    set dot [tomato::mathquat::Dot $q0 $q1]

    # If the dot product is negative, slerp won't take the shorter path.
    # Note that v1 and -v1 are equivalent when the negation is applied to all four components.
    # Fix by reversing one quaternion
    if {$dot < 0.0} {
        set q0  [$q0 Negate]
        set dot [expr {Inv($dot)}]
    }

    # sinalpha0 can not be zero
    if {$dot > 0.9995} {
        set q [$q0 + [[$q1 - $q0] * $clamparcpos]]
        if {![$q IsUnitQuaternion]} {
            set q [$q Normalized]
        }
        return $q
    }

    set alpha0    [expr {acos($dot)}] ; # # Since dot is in range [0, 0.9995], acos() is safe
    set sinalpha0 [expr {sin($alpha0)}]

    set alpha [expr {$alpha0 * $clamparcpos}]
    set sinalpha [expr {sin($alpha)}]

    set s0 [expr {cos($alpha) - (($dot * $sinalpha) / double($sinalpha0))}]
    set s1 [expr {$sinalpha / double($sinalpha0)}]

    set q [[$q0 * $s0] + [$q1 * $s1]]

    if {![$q IsUnitQuaternion]} {
        set q [$q Normalized]
    }

    return $q
}

ToNormSquared [::tomato::mathquat]Top, Main, Index

Calculates norm of quaternion from it's algebraical notation

ToNormSquared real imagX imagY imagZ
Parameters
realThe rotation component of the Quaternion.
imagXThe X-value of the vector component of the Quaternion.
imagYThe Y-value of the vector component of the Quaternion.
imagZThe Z-value of the vector component of the Quaternion.
Return value

Returns A norm squared quaternion

proc ::tomato::mathquat::ToNormSquared {real imagX imagY imagZ} {

    # Calculates norm of quaternion from it's algebraical notation
    #
    # real  - The rotation component of the Quaternion.
    # imagX - The X-value of the vector component of the Quaternion.
    # imagY - The Y-value of the vector component of the Quaternion.
    # imagZ - The Z-value of the vector component of the Quaternion.
    #
    # Returns A norm squared quaternion
    return [expr {($imagX**2) + ($imagY**2) + ($imagZ**2) + ($real**2)}]
}

ToUnitQuaternion [::tomato::mathquat]Top, Main, Index

Creates unit quaternion (it's norm == 1) from it's algebraical notation

ToUnitQuaternion real imagX imagY imagZ
Parameters
realThe rotation component of the Quaternion.
imagXThe X-value of the vector component of the Quaternion.
imagYThe Y-value of the vector component of the Quaternion.
imagZThe Z-value of the vector component of the Quaternion.
Return value

Returns A unit quaternion Quaternion

proc ::tomato::mathquat::ToUnitQuaternion {real imagX imagY imagZ} {

    # Creates unit quaternion (it's norm == 1) from it's algebraical notation
    #
    # real  - The rotation component of the Quaternion.
    # imagX - The X-value of the vector component of the Quaternion.
    # imagY - The Y-value of the vector component of the Quaternion.
    # imagZ - The Z-value of the vector component of the Quaternion.
    #
    # Returns A unit quaternion [Quaternion]
    set norm [expr {sqrt([tomato::mathquat::ToNormSquared $real $imagX $imagY $imagZ])}]

    return [tomato::mathquat::Quaternion new [list [expr {$real  / double($norm)}]  [expr {$imagX / double($norm)}]  [expr {$imagY / double($norm)}]  [expr {$imagZ / double($norm)}]]]
}