Fast Linear Algebra Classes for Games and Graphics
The Harlinn.Math library contains a set of optimized linear algebra classes and functions for games and other graphic intensive apps. The operations are implemented using a blend of SIMD and regular C/C++, performing as well as, and sometimes outperforming, the DirectXMath library.
This is a raytraced image generated by pbrto.
pbrto is the main example/demonstration of how to use the library to improve the performance of a complex, computationally intensive, app.
The classes and functions are designed to make it easier to implement, understand and maintain efficient solutions, and the Benchmarks shows that this can be done without loss of performance.
Harlinn/Math/VectorMath.h
is header only.
This document and related pages are under construction.
Concepts
Classes and Templates
Functions
- Basic operations
- Exponential functions
- Power functions
- Trigonometric functions
- Hyperbolic functions
- Error and gamma functions
- Nearest integer floating point operations
- Floating point manipulation functions
- Classification and comparison
- Other functions
- Special Functions
- Vector Operations and Functions
- Quaternion Operations and Functions
- Plane Operations and Functions
- Matrix Operations and Functions
- Geometric Functions
Introduction
The code for the mathematical classes and functions lives inside the Harlinn::Math
namespace, and all that is needed to use this part of the library is to include the Harlinn/Math/VectorMath.h
header file:
#include <Harlinn/Math/VectorMath.h>
and you are ready to code.
In Game Programming Gems, Sam Melax describes a function for calculating the shortest arc quaternion between to vectors that can be implemented like this:
using namespace Harlinn
using namespace Harlinn::Math;
namespace Basics
{
using Quaternion = Math::Quaternion<float>;
Quaternion ShortestArc1( const Vector3f& fromDir,
const Vector3f& toDir ) noexcept
{
using Constants = Vector3f::Traits::Constants::Base;
Vector3f fromDirNormalized = Normalize( fromDir );
Vector3f toDirNormalized = Normalize( toDir );
const float dot = ScalarDot( fromDirNormalized, toDirNormalized );
if ( dot >= 1.f )
{
return Quaternion::Identity( );
}
else if ( dot <= -1.f )
{
Vector3f axis = Cross( fromDirNormalized, Vector3f::Right( ) );
if ( AreNearlyEqual( ScalarLengthSquared( axis ), 0.f,
Constants::EpsilonValue ) )
{
axis = Cross( fromDirNormalized, Vector3f::Up() );
}
return Quaternion::FromAxisAndAngle( axis, Constants::Pi );
}
else
{
const float s = Sqrt( ( 1.f + dot ) * 2.f );
Vector3f cp = Cross( fromDirNormalized, toDirNormalized ) / s;
Quaternion result( cp, s * 0.5f );
return result;
}
}
}
No surprises here, the above looks like something that could easily be done using most 3D math libraries.
Currently, this implementation is as fast as Quaternion::FromToRotation
from DirectXTK12,
which is cool:
BenchmarkShortestArc1 29.8 ns 29.3 ns 22400000
BenchmarkDirectXTK12QuaternionFromToRotation 30.5 ns 30.0 ns 21333333
A better performing version would look like:
Quaternion ShortestArc2( const Vector3f::Simd& fromDir,
const Vector3f::Simd& toDir ) noexcept
{
using Constants = Vector3f::Traits::Constants::Base;
auto fromDirNormalized = Normalize( fromDir );
auto toDirNormalized = Normalize( toDir );
const auto dot = Dot( fromDirNormalized, toDirNormalized );
const auto dotf = dot[ 0 ];
if ( dotf >= 1.f )
{
return Quaternion::Identity( );
}
else if ( dotf <= -1.f )
{
auto axis = Cross( fromDirNormalized, Vector3f::Right( ) );
if ( AreNearlyEqual( ScalarLengthSquared( axis ), 0.f,
Constants::EpsilonValue ) )
{
axis = Cross( fromDirNormalized, Vector3f::Up( ) );
}
return Quaternion::FromAxisAndAngle( axis, Constants::Pi );
}
else
{
const auto s = Sqrt( ( 1.f + dot ) * 2.f );
auto cp = Cross( fromDirNormalized, toDirNormalized ) / s;
Quaternion result( cp, s[0] * 0.5f );
return result;
}
}
which looks almost identical to ShortestArc1
, but the benchmark:
BenchmarkShortestArc2 14.6 ns 14.6 ns 44800000
shows that ShortestArc2
is more than twice as fast as ShortestArc1
. Like ShortestArc2
,
ShortestArc1
also does most of its calculations using functions that are implemented
using SIMD, but ShortestArc2
is smarter about how it does that.
The short explanation is that ShortestArc2
avoids a bunch of calls to _mm_load_ps
and _mm_store_ps
,
and their sibling intrinsic functions, and here is why:
Quaternion ShortestArc2( const Vector3f::Simd& fromDir,
const Vector3f::Simd& toDir ) noexcept
{
using Constants = Vector3f::Traits::Constants::Base;
Since Normalize
returns a Vector3f::Simd
object, and using this for the calculations
eliminates calls to _mm_load_ps
and _mm_store_ps
, we replace Vector3f
with auto
in the code.
auto fromDirNormalized = Normalize( fromDir );
auto toDirNormalized = Normalize( toDir );
Next we replace the call to ScalarDot( fromDirNormalized, toDirNormalized )
that returns
the dot product as a scalar, with Dot( fromDirNormalized, toDirNormalized )
which returns
a Vector3f::Simd
object.
const auto dot = Dot( fromDirNormalized, toDirNormalized );
The Vector3f::Simd
type doesn’t have member variables for x
, y
and z
, as it
uses a member variable simd
of type __m128
to store its data. x
, y
and z
occupies the first, second and third position of the __m128
, respectively. Dot
sets
the first, second and third position of the __m128
to the value of the dot product
between the argument vectors. Vector3f::Simd
provides access to the individual
values through its float x( ) const noexcept
, float y( ) const noexcept
and
float z( ) const noexcept
member functions, and we need this value to be able to
handle possible singularities.
const auto dotf = dot.x( );
With that out of the way, we replace the remaining Vector3f
declarations with auto
:
if ( dotf >= 1.f )
{
return Quaternion::Identity( );
}
else if ( dotf <= -1.f )
{
auto axis = Cross( fromDirNormalized, Vector3f::Right( ) );
if ( AreNearlyEqual( ScalarLengthSquared( axis ), 0.f,
Constants::EpsilonValue ) )
{
axis = Cross( fromDirNormalized, Vector3f::Up( ) );
}
return Quaternion::FromAxisAndAngle( axis, Constants::Pi );
}
else
{
The next line of code is interesting, as diving into the details about what’s happening explains a lot about how the library works.
The expression 1.f + dot
is handled by an operator +
overload that widens 1.f
to a
__m128
value with 1.f
in the three first positions before doing vector addition with
the simd
variable of dot
, returning the result as a Vector3f::Simd
object. The result
then gets passed to an operator +
overload that widens 2.f
into __m128
value with
2.f
in the three first positions before doing vector multiplication with the result
of 1.f + dot
, returning the result as Vector3f::Simd
object. This is then passed to
an overload of Sqrt
that calculates the square root for each of the elements in the
result of ( 1.f + dot ) * 2.f
, returning a Vector3f::Simd
object which is stored in s
.
const auto s = Sqrt( ( 1.f + dot ) * 2.f );
So s
is now a Vector3f::Simd
object, with relevant values in its
first three positions, and naturally Cross
also returns a Vector3f::Simd
object.
The result of the call to Cross
and s
gets handled by an operator /
overload
dividing each of the elements of the first by its corresponding element in s
,
again returning a Vector3f::Simd
object which is assigned to cp
.
auto cp = Cross( fromDirNormalized, toDirNormalized ) / s;
Quaternion result( cp, s[0] * 0.5f );
return result;
}
}
ShortestArc2
is as readable as ShortestArc1
, and most of the increased performance
was achieved by replacing Vector3f
with auto
, which is good C++ practice, anyway.
Could it be even faster? Sure:
BenchmarkShortestArc 11.1 ns 11.2 ns 56000000
This benchmark, BenchmarkShortestArc
, is for the ShortestArc
implementation found
in Harlinn/Math/VectorMath.h
.
Implementation Details
The following operations are currently supported for Tuple2
, Tuple3
and Tuple4
:
+
, -
, unary -
, *
, /
,
+=
, -=
, *=
, /=
, Abs
, Min
, Max
, Sqr
, Ceil
, Floor
, Round
,
Trunc
, Lerp
, Saturate
, Sqrt
, FMA
, FMSub
, Sin
, Cos
, Tan
,
ASin
, ACos
, ATan
, ATan2
, SinH
, CosH
, TanH
, ASinH
, ACosH
,
ATanH
, Log
, Log1P
, Log10
, Log2
, Exp
, Exp10
, Exp2
, ExpM1
,
Pow
, Dot
, Hypot
, Permute
, Cross
, LengthSquared
, Length
Normalize
, ReciprocalLength
, DistanceSquared
, Distance
, HProd
HSum
, DifferenceOfProducts
, SumOfProducts
Tuple2, Tuple3, Tuple4 and TupleSimd Functions
- HSum and ScalarHSum
- HProd and ScalarHProd
- Abs
- Min
- Max
- Sqr
- Ceil
- Floor
- Round
- Trunc
- Lerp
- Clamp
- Saturate
- Sqrt
- ReciprocalSqrt
- Reciprocal
- FMA
- FMSub
- FMAddSub
- FMSubAdd
- FNMAdd
- FNMSub
- Sin
- Cos
- Tan
- ASin
- ACos
- ATan
- ATan2
- ModAngles
- AddAngles
- SubtractAngles
- SinH
- CosH
- TanH
- ASinH
- ACosH
- ATanH
- Log
- Log1P
- Log10
- Log2
- Exp
- Exp10
- Exp2
- ExpM1
- Pow
- Hypot
- Hermite
- Dot and ScalarDot
- AbsDot and ScalarAbsDot
- Cross
- LengthSquared and ScalarLengthSquared
- Length and ScalarLength
- Normalize
- ReciprocalLength and ScalarReciprocalLength
- DistanceSquared and ScalarDistanceSquared
- Distance and ScalarDistance
- InBounds
- ClampLength
- Reflect
- Refract
- Orthogonal
- DifferenceOfProducts
- SumOfProducts
- BaryCentric
- CatmullRom
- MinComponentValue
- MaxComponentValue
- MinComponentIndex
- MaxComponentIndex
The functions that work with the Tuple2
, Tuple3
, Tuple4
and TupleSimd
types
generally returns a TupleSimd
holding the result of the operation.
There are usually several overloads for each function, allowing the values
held by the Tuple2
, Tuple3
and Tuple4
derived types to be automatically
loaded into a SIMD type/register.
Functions that calculate a single scalar value, returns a TupleSimd
where every
element holds the calculated value. These functions also have an implementation that
returns the scalar as single value. For instance, Dot
returns a TupleSimd
, while ScalarDot
returns
a floating point value of the same type as a single element from the TupleSimd
type.
HSum and ScalarHSum
Calculates the horizontal sum of the elements in the vector.
template<Internal::SimdType T>
inline T HSum( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
inline ResultT ScalarHSum( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT HSum( const T& t ) noexcept;
HProd and ScalarHProd
Calculates the horizontal product of the elements in the vector.
template<Internal::SimdType T>
inline T HProd( const T& t ) noexcept;
template<Internal::SimdType T>
inline auto ScalarHProd( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
inline ResultT ScalarHProd( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT HProd( const T& t ) noexcept;
Abs
Computes the absolute value of each element held by the argument.
template<Internal::SimdType T>
inline T Abs( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Abs( const T& t ) noexcept;
Min
Makes a comparison between the elements held by the two arguments, and returns a TupleSimd containing the smallest elements.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Min( const T& lhs, const U& rhs ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Min( const T& lhs, const U& rhs ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Min( const U& lhs, const T& rhs ) noexcept;
template<Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Min( const T& lhs, const U& rhs ) noexcept;
Max
Makes a comparison between the elements held by the two arguments, and returns a TupleSimd containing the largest elements.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Max( const T& lhs, const U& rhs ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Max( const T& lhs, const U& rhs ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Max( const U& lhs, const T& rhs ) noexcept;
template<Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Max( const T& lhs, const U& rhs ) noexcept;
Sqr
Computes the square value of each element held by the argument.
template<Internal::SimdType T>
inline T Sqr( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Sqr( const T& t ) noexcept;
Ceil
Computes the ceiling of each element held by the argument.
template<Internal::SimdType T>
inline T Ceil( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Ceil( const T& t ) noexcept;
Floor
Computes the floor of each element held by the argument.
template<Internal::SimdType T>
inline T Floor( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Floor( const T& t ) noexcept;
Round
Rounds each element held by the argument towards the nearest even integer.
template<Internal::SimdType T>
inline T Round( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Round( const T& t ) noexcept;
Trunc
Rounds each element held by the argument to the nearest integer in the direction of zero.
template<Internal::SimdType T>
inline T Trunc( const T& t ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Trunc( const T& t ) noexcept;
Lerp
Calculates the linear interpolation between the
the elements of a
and the elements of b
, for elements of
c
is inside [0,1), or the linear extrapolation for elements
in c
outside [0,1).
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT> && Internal::IsCompatible<T, U>
inline T Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT Lerp( NumberT a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Lerp( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT Lerp( const S& a, const T& b, const U& c ) noexcept;
Clamp
Returns the elements of v, if the elements are between their respective boundaries specified the elements of lowerBounds and the elements of upperBounds, otherwise the value of nearest boundary is returned.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename S::Simd>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT Clamp( const S& v, const T& lowerBounds, const U& upperBounds ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT> && Internal::IsCompatible<T, U>
inline ResultT Clamp( NumberT v, const T& lowerBounds, const U& upperBounds ) noexcept;
Saturate
Saturates the elements of v to the range 0.0 to 1.0.
template<Internal::SimdType T>
inline T Saturate( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Saturate( const T& v ) noexcept;
Sqrt
Calculates the square root of each element in the argument.
template<Internal::SimdType T>
inline T Sqrt( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Sqrt( const T& v ) noexcept;
ReciprocalSqrt
Calculates the reciprocal square root of each element in the argument.
template<Internal::SimdType T>
inline T ReciprocalSqrt( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ReciprocalSqrt( const T& v ) noexcept;
Reciprocal
Calculates the reciprocal of each element in the argument.
template<Internal::SimdType T>
inline T Reciprocal( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Reciprocal( const T& v ) noexcept;
FMA
Multiplies the corresponding elements of a and b, adding the result to the corresponding element of c.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMA( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMA( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMA( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMA( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMA( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U,
typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMA( const S& a, const T& b, const U& c ) noexcept;
FMSub
Performs a set of multiply-subtract computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and the infinite precision intermediate results are obtained. From the infinite precision intermediate results, the values in the third operand, c, are subtracted. The final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSub( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMSub( const S& a, const T& b, const U& c ) noexcept;
FMAddSub
Performs a set of multiply-add-subtract computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and infinite precision intermediate results are obtained. The odd values in the third operand, c, are added to the intermediate results while the even values are subtracted from them. The final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMAddSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMAddSub( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMAddSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMAddSub( const S& a, const T& b, const U& c ) noexcept;
FMSubAdd
Performs a set of multiply-subtract-add computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and infinite precision intermediate results are obtained. The odd values in the third operand, c, are subtracted from the intermediate results while the even values are added to them. The final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSubAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FMSubAdd( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FMSubAdd( const S& a, const T& b, const U& c ) noexcept;
FNMAdd
Performs a set of negated multiply-add computation on a, b, and c. Corresponding values in two operands, a and b, are multiplied and the negated infinite precision intermediate results are added to the values in the third operand, c, after which the final results are rounded to the nearest floating point values.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMAdd( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMAdd( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMAdd( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FNMAdd( const S& a, const T& b, const U& c ) noexcept;
FNMSub
Performs a set of negated multiply-subtract computation on a, b, and c. The values in two operands, a and b, are multiplied and the negated infinite precision intermediate result is obtained. From this negated intermediate result, the value in the third operand, c, is subtracted. The final result is rounded to the nearest floating point value.
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMSub( NumberT a, const T& b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::SimdType T, Internal::TupleType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline T FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::SimdType U>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline U FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<typename NumberT, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires std::is_arithmetic_v<NumberT>&& Internal::IsCompatible<T, U>
inline ResultT FNMSub( const T& a, NumberT b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline S FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline T FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline U FNMSub( const S& a, const T& b, const U& c ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd >
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<T, U>
inline ResultT FNMSub( const S& a, const T& b, const U& c ) noexcept;
Sin
Calculates the sine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T Sin( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Sin( const T& v ) noexcept;
Cos
Calculates the cosine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T Cos( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Cos( const T& v ) noexcept;
Tan
Calculates the tangent of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T Tan( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Tan( const T& v ) noexcept;
ASin
Calculates the inverse sine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ASin( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ASin( const T& v ) noexcept;
ACos
Calculates the inverse cosine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ACos( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ACos( const T& v ) noexcept;
ATan
Calculates the inverse tangent of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ATan( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ATan( const T& v ) noexcept;
ATan2
Calculates the inverse tangent of each element in x divided by the corresponding element in y, in radians.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T ATan2( const T& x, const U& y ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T ATan2( const T& x, const U& y ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T ATan2( const U& x, const T& y ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT ATan2( const T& x, const U& y ) noexcept;
ModAngles
Calculates the angle modulo \(2\pi\) of each element in the argument.
template<Internal::SimdType T>
inline T ModAngles( const T& angles );
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ModAngles( const T& v ) noexcept;
AddAngles
Adds the angles in the corresponding elements of v1 and v2. The argument angles must be in the range \([-\pi,\pi)\), and the computed angles will be in the range \([-\pi,\pi)\).
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T AddAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T AddAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T AddAngles( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT AddAngles( const T& v1, const U& v2 ) noexcept;
SubtractAngles
Subtracts the angles in v2 from the corresponding elements of v1. The argument angles must be in the range \([-\pi,\pi)\), and the computed angles will be in the range \([-\pi,\pi)\)
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T SubtractAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T SubtractAngles( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T SubtractAngles( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT SubtractAngles( const T& v1, const U& v2 ) noexcept;
SinH
Calculates the hyperbolic sine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T SinH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT SinH( const T& v ) noexcept;
CosH
Calculates the hyperbolic cosine of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T CosH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT CosH( const T& v ) noexcept;
TanH
Calculates the hyperbolic tangent of each element in the argument expressed in radians.
template<Internal::SimdType T>
inline T TanH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT TanH( const T& v ) noexcept;
ASinH
Calculates the inverse hyperbolic sine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ASinH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ASinH( const T& v ) noexcept;
ACosH
Calculates the inverse hyperbolic cosine of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ACosH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ACosH( const T& v ) noexcept;
ATanH
Calculates the inverse hyperbolic tangent of each element in the argument, in radians.
template<Internal::SimdType T>
inline T ATanH( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ATanH( const T& v ) noexcept;
Log
Calculates the natural logarithm of each element in the argument.
template<Internal::SimdType T>
inline T Log( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log( const T& v ) noexcept;
Log1P
Calculates the natural logarithm of \(1 +\) each element in the argument.
template<Internal::SimdType T>
inline T Log1P( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log1P( const T& v ) noexcept;
Log10
Calculates the base-10 logarithm, \(log_{10}\), of each element in the argument.
template<Internal::SimdType T>
inline T Log10( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log10( const T& v ) noexcept;
Log2
Calculates the base-2 logarithm, \(log_{2}\), of each element in the argument.
template<Internal::SimdType T>
inline T Log2( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Log2( const T& v ) noexcept;
Exp
Calculates \(e\) (Euler’s number, 2.7182818…), raised to the power of each element in the argument.
template<Internal::SimdType T>
inline T Exp( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Exp( const T& v ) noexcept;
Exp10
Calculates the base-10 exponential of each element in the argument.
template<Internal::SimdType T>
inline T Exp10( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Exp10( const T& v ) noexcept;
Exp2
Calculates the base-2 exponential of each element in the argument.
template<Internal::SimdType T>
inline T Exp2( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Exp2( const T& v ) noexcept;
ExpM1
Calculates \(e\) (Euler’s number, 2.7182818…), raised to the power of each element in the argument, \(-1.0\).
template<Internal::SimdType T>
inline T ExpM1( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ExpM1( const T& v ) noexcept;
Pow
Calculates the elements in base
raised to the corresponding elements in exponent
.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Pow( const T& base, const U& exponent ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Pow( const T& base, const U& exponent ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Pow( const U& base, const T& exponent ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Pow( const T& base, const U& exponent ) noexcept;
Hypot
Calculates the square root of the sum of the squares of each corresponding element in x and y, without undue overflow or underflow at intermediate stages of the computation.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Hypot( const T& x, const U& y ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Hypot( const T& x, const U& y ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Hypot( const U& x, const T& y ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Hypot( const T& x, const U& y ) noexcept;
Hermite
Calculates the Hermite spline interpolation, using the specified arguments.
template<Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<T, U> &&
Internal::IsCompatible<T, V> &&
Internal::IsCompatible<T, W>
inline T Hermite( const T& firstPosition, const U& firstTangent,
const V& secondPosition, const W& secondTangent,
typename T::value_type t ) noexcept;
Dot and ScalarDot
Calculates the dot product between v1 and v2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Dot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Dot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Dot( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Dot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
constexpr inline typename T::value_type ScalarDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
constexpr inline typename T::value_type ScalarDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
constexpr inline typename T::value_type ScalarDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::value_type>
requires Internal::IsCompatible<T, U>
constexpr inline ResultT ScalarDot( const T& v1, const U& v2 ) noexcept;
AbsDot and ScalarAbsDot
Calculates the absolute value of the dot product between v1 and v2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T AbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T AbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T AbsDot( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT AbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarAbsDot( const T& v1, const U& v2 ) noexcept;
Cross
Calculates the cross product between v1 and v2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Cross( const T& v1, const U& v2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Cross( const T& v1, const U& v2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Cross( const U& v1, const T& v2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Cross( const T& v1, const U& v2 ) noexcept;
LengthSquared and ScalarLengthSquared
Calculates the squared length of v.
template<Internal::SimdType T>
inline T LengthSquared( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT LengthSquared( const T& v ) noexcept;
template<Internal::SimdType T>
inline auto ScalarLengthSquared( const T& v ) noexcept;
template<Internal::TupleType T>
inline auto ScalarLengthSquared( const T& v ) noexcept;
Length and ScalarLength
Calculates the length of v.
template<Internal::SimdType T>
inline T Length( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Length( const T& v ) noexcept;
template<Internal::SimdType T>
inline auto ScalarLength( const T& v ) noexcept;
template<Internal::TupleType T>
inline auto ScalarLength( const T& v ) noexcept;
Normalize
Normalizes v.
template<Internal::SimdType T>
inline T Normalize( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT Normalize( const T& v ) noexcept;
ReciprocalLength and ScalarReciprocalLength
Calculates the reciprocal length of v.
template<Internal::SimdType T>
inline T ReciprocalLength( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::Simd>
inline ResultT ReciprocalLength( const T& v ) noexcept;
template<Internal::SimdType T>
inline auto ScalarReciprocalLength( const T& v ) noexcept;
template<Internal::TupleType T>
inline auto ScalarReciprocalLength( const T& v ) noexcept;
DistanceSquared and ScalarDistanceSquared
Calculates the squared distance between p1 and p2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T DistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T DistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T DistanceSquared( const U& p1, const T& p2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT DistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const U& p1, const T& p2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistanceSquared( const T& p1, const U& p2 ) noexcept;
Distance and ScalarDistance
Calculates the distance between p1 and p2.
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline T Distance( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline T Distance( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline T Distance( const U& p1, const T& p2 ) noexcept;
template<Internal::TupleType T, Internal::TupleType U, typename ResultT = typename T::Simd>
requires Internal::IsCompatible<T, U>
inline ResultT Distance( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistance( const T& p1, const U& p2 ) noexcept;
template<Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistance( const T& p1, const U& p2 ) noexcept;
template<Internal::TupleType U, Internal::SimdType T>
requires Internal::IsCompatible<T, U>
inline auto ScalarDistance( const U& p1, const T& p2 ) noexcept;
InBounds
Detects if the elements of a vector are within bounds.
template<Internal::SimdType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline S InBounds( const S& v, const T& bounds ) noexcept;
template<Internal::SimdType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline S InBounds( const S& v, const T& bounds ) noexcept;
template<Internal::TupleType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline T InBounds( const S& v, const T& bounds ) noexcept;
template<Internal::TupleType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline typename S::Simd InBounds( const S& v, const T& bounds ) noexcept;
ClampLength
Clamps the length of a vector to a given range.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd ClampLength( const S& v, const T& lengthMin, const U& lengthMax ) noexcept;
template<Internal::SimdType S, typename T, typename U>
requires IsFloatingPoint<T> && IsFloatingPoint<U>
inline S ClampLength( const S& v, const T lengthMin, const U lengthMax ) noexcept;
template<Internal::TupleType S, typename T, typename U>
requires IsFloatingPoint<T>&& IsFloatingPoint<U>
inline S ClampLength( const S& v, const T lengthMin, const U lengthMax ) noexcept;
Reflect
Reflects an incident vector across a normal vector.
template<Internal::SimdType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline S Reflect( const S& incident, const T& normal ) noexcept;
template<Internal::SimdType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline S Reflect( const S& incident, const T& normal ) noexcept;
template<Internal::TupleType S, Internal::SimdType T>
requires Internal::IsCompatible<S, T>
inline T Reflect( const S& incident, const T& normal ) noexcept;
template<Internal::TupleType S, Internal::TupleType T>
requires Internal::IsCompatible<S, T>
inline typename S::Simd Reflect( const S& incident, const T& normal ) noexcept;
Refract
Refracts an incident vector across a normal vector.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline S Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U& refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline S Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline S Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, typename U>
requires Internal::IsCompatible<S, T>&& IsFloatingPoint<U>
inline typename S::Simd Refract( const S& incident, const T& normal, const U refractionIndex ) noexcept;
Orthogonal
Computes a vector perpendicular to the argument vector.
template<Internal::SimdType S>
inline S Orthogonal( const S& v ) noexcept;
template<Internal::TupleType S>
inline typename S::Simd Orthogonal( const S& v ) noexcept;
DifferenceOfProducts
Calculates the difference between the product of the first and the second argument, and the product of the third and fourth argument.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U> && Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline V DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline typename S::Simd DifferenceOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
SumOfProducts
Calculates the sum of the product of the first and the second argument, and the product of the third and fourth argument.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U> && Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline S SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline T SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline U SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline V SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>
inline typename S::Simd SumOfProducts( const S& v1, const T& v2, const U& v3, const V& v4 ) noexcept;
BaryCentric
Calculates a point in Barycentric coordinates, using the specified triangle.
see https://en.wikipedia.org/wiki/Barycentric_coordinate_system
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U> && Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V& f, const W& g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T> && Internal::IsCompatible<S, U> && IsFloatingPoint<V> && IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, typename V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& IsFloatingPoint<V>&& IsFloatingPoint<W>
inline typename S::Simd BaryCentric( const S& p1, const T& p2, const U& p3, const V f, const W g ) noexcept;
CatmullRom
Calculates the Catmull-Rom interpolation, using the specified positions.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::SimdType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, Internal::TupleType W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& Internal::IsCompatible<S, W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W& t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::SimdType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline S CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::SimdType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::SimdType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::SimdType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
template<Internal::TupleType S, Internal::TupleType T, Internal::TupleType U, Internal::TupleType V, typename W>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U>&& Internal::IsCompatible<S, V>&& IsFloatingPoint<W>
inline typename S::Simd CatmullRom( const S& p1, const T& p2, const U& p3, const V& p4, const W t ) noexcept;
MinComponentValue
Retrieves the lowest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MinComponentValue( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MinComponentValue( const T& v ) noexcept;
MaxComponentValue
Retrieves the highest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MaxComponentValue( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MaxComponentValue( const T& v ) noexcept;
MinComponentIndex
Retrieves the offset of the lowest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MinComponentIndex( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MinComponentIndex( const T& v ) noexcept;
MaxComponentIndex
Retrieves the offset of the highest value held by the argument.
template<Internal::SimdType T, typename ResultT = typename T::value_type >
inline ResultT MaxComponentIndex( const T& v ) noexcept;
template<Internal::TupleType T, typename ResultT = typename T::value_type>
constexpr inline ResultT MaxComponentIndex( const T& v ) noexcept;
Vector2f, Vector3f, Vector4f, Vector2i, Vector3i, Vector4i
Vector<float,2>
, Vector<float,3>
and Vector<float,4>
are specializations of Vector<T,N>
that
supports a wider repertoire of operations than the general Vector<T,N>
.
Vector<float,2>
is derived from the Tuple2
template, Vector<float,3>
is derived
from the Tuple3
, and Vector<float,4>
is derived from Tuple4
.
Just a few lines of code are required to create the Vector<float, 3>
specialization of Vector<T,N>
with the full repertoire of features available for Tuple3
:
template<>
class Vector<float, 3> : public Tuple3<Vector<float, 3>,float>
{
public:
using Base = Tuple3<Vector<float, 3>, float>;
using Traits = Base::Traits;
Vector( ) noexcept = default;
explicit Vector( float v ) noexcept
: Base( v, v, v )
{ }
Vector( float xv, float yv, float zv ) noexcept
: Base( xv, yv, zv )
{ }
template<typename T>
requires std::is_same_v<typename T::SIMDType, typename Traits::SIMDType >
Vector( const T& other ) noexcept
: Base( other )
{ }
};
Below are two benchmarks, the first using Math::Vector<float, 3>
,
while the second uses pbrt::Vector3f
.
static void BenchmarkVector3( benchmark::State& state )
{
using namespace Harlinn::Math;
using Vector = Math::Vector<float, 3>;
DoubleGenerator.Reset( );
for ( auto _ : state )
{
Vector v1( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
Vector v2( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
benchmark::DoNotOptimize( Dot( Abs( Max( Ceil( -v1 ), Floor( v2 ) ) ), v2 ) );
}
}
BENCHMARK( BenchmarkVector3 );
static void BenchmarkPBRTVector3f( benchmark::State& state )
{
using namespace pbrt;
using Vector = pbrt::Vector3f;
DoubleGenerator.Reset( );
for ( auto _ : state )
{
Vector v1( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
Vector v2( FloatGenerator( ), FloatGenerator( ), FloatGenerator( ) );
benchmark::DoNotOptimize( Dot( Abs( Max( Ceil( -v1 ), Floor( v2 ) ) ), v2 ) );
}
}
BENCHMARK( BenchmarkPBRTVector3f );
BenchmarkVector2
runs 20
% faster than BenchmarkPBRTVector3f
which is
optimized by the compiler for the AVX2 instruction set:
-------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------
BenchmarkVector3 5.63 ns 4.85 ns 186666667
BenchmarkPBRTVector3f 7.08 ns 5.86 ns 112000000
Vector functions
AngleBetween
Calculates the angle in radians between two vectors.
AngleBetweenNormals
Calculates the angle in radians between two normalized vectors.
Transform
Transforms a 3D vector by a matrix.
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>& matrix );
Normal3f and Normal3i
The surface normal is a vector perpendicular to a surface at a specific position. It can be defined as the cross product of any two nonparallel vectors that are tangent to the surface at a point. Normals are similar to vectors, but it’s important to distinguish between the two of them: since normals are defined in terms of their relationship to a surface, they behave differently than vectors in some situations, particularly when applying transformations.
Normal3f functions
Transform
Transforms the Normal3f object by the given matrix.
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 3>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 3>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 3>& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 3>& matrix );
inline Normal3f::Simd Transform( const Normal3f& v,
const SquareMatrix<float, 4>& matrix );
Point3f and Point3i
A point is a zero-dimensional location in 2D or 3D space. The Point2i/f and Point3i/f classes represent points in the obvious way: using \(x, y, z\) (in 3D) coordinates with respect to a coordinate system. Although the same representation is used for vectors, the fact that a point represents a position whereas a vector represents a direction leads to a number of important differences in how they are treated.
Point3f
LinePointDistance
Calculates the minimum distance between a line and a point.
Transform
Transforms the Point3f object by the provided transformation matrix.
inline Point3f::Simd Transform( const Point3f::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Point3f::Simd Transform( const Point3f& v,
const SquareMatrix<float, 4>& matrix );
SquareMatrix
The SquareMatrix
template class is used to represent transformations that can be applied
to vectors, points and surface normals.
The template is designed as a row oriented matrix, that can be instantiated for single and double precision floating point types. The template can be instantiated as a \(2 x 2\), \(3 x 3\) or \(4 x 4\) matrix.
Internally, computations on \(2 x 2\) matrices are performed using a single SIMD type/register, while operations on \(3 x 3\) and \(4 x 4\) matrices are performed using one SIMD type/register for each row.
SquareMatrix
support matrix addition, scalar addition, matrix multiplication, scalar multiplication,
the matrices can be transposed using Transpose
and inverted using Inverse
, and Determinant
calculates
the determinant. The default constructor creates an identity matrix, so SquareMatrix
handles the usual
operations associated with small square matrices.
SquareMatrix<float,4> functions
Transpose
Calculates the transpose of the matrix.
inline SquareMatrix<float, 4>::Simd Transpose( const SquareMatrix<float, 4>::Simd& matrix );
inline SquareMatrix<float, 4>::Simd Transpose( const SquareMatrix<float, 4>& matrix );
Inverse
Calculates the inverse of the matrix.
inline SquareMatrix<float, 4>::Simd Inverse( const SquareMatrix<float, 4>::Simd& matrix,
typename Vector<float, 4>::Simd* determinant = nullptr );
inline typename SquareMatrix<float, 4>::Simd Inverse( const SquareMatrix<float, 4>& matrix,
typename Vector<float, 4>::Simd* determinant = nullptr );
Determinant and ScalarDeterminant
Calculates the determinant of a matrix.
inline typename Vector<float,4>::Simd Determinant( const typename SquareMatrix<float, 4>::Simd& matrix );
inline typename Vector<float, 4>::Simd Determinant( const SquareMatrix<float, 4>& matrix );
inline float ScalarDeterminant( const SquareMatrix<float, 4>::Simd& matrix );
inline float ScalarDeterminant( const SquareMatrix<float, 4>& matrix );
Translation
Creates a translation matrix using the provided offsets.
inline SquareMatrix<float, 4>::Simd Translation( float offsetX, float offsetY, float offsetZ );
template<Internal::SimdType S>
requires (S::Size > 2) && std::is_same_v<typename S::value_type, float>
inline SquareMatrix<float, 4>::Simd Translation( const S& offsets );
template<Internal::TupleType S>
requires ( S::Size > 2 ) && std::is_same_v<typename S::value_type, float>
inline SquareMatrix<float, 4>::Simd Translation( const S& offsets );
Scaling
Creates a transformation matrix for scaling along the x-axis, y-axis, and z-axis.
inline SquareMatrix<float, 4>::Simd Scaling( float scaleX, float scaleY, float scaleZ );
template<Internal::SimdType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd Scaling( const S& v ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd Scaling( const S& v ) noexcept;
Rotation
Creates a transformation matrix that rotates about the y-axis, then the x-axis, and finally the z-axis.
template<Internal::SimdType S>
requires (S::Size > 2)
inline SquareMatrix<float, 4>::Simd Rotation( const S& v ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd Rotation( const S& v ) noexcept;
inline SquareMatrix<float, 4>::Simd Rotation( float xAxisRotation,
float yAxisRotation, float zAxisRotation ) noexcept;
RotationNormal
Creates a matrix that rotates around a normalized vector.
template<Internal::SimdType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationNormal( const S& normalizedAxis, float angle ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationNormal( const S& normalizedAxis, float angle ) noexcept;
RotationAxis
Creates a matrix that rotates around an arbitrary axis.
template<Internal::SimdType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationAxis( const S& axis, float angle ) noexcept;
template<Internal::TupleType S>
requires ( S::Size > 2 )
inline SquareMatrix<float, 4>::Simd RotationAxis( const S& axis, float angle ) noexcept;
RotationQuaternion
Creates a rotation matrix from a quaternion.
inline SquareMatrix<float, 4>::Simd RotationQuaternion( const QuaternionSimd<Quaternion<float>>& q );
inline SquareMatrix<float, 4>::Simd RotationQuaternion( const Quaternion<float>& q );
TransformationMatrix
Creates a transformation matrix.
inline SquareMatrix<float, 4>::Simd TransformationMatrix( const Point3f::Simd& scalingOrigin,
const QuaternionSimd<Quaternion<float>>& scalingOrientationQuaternion,
const Vector<float,3>::Simd& scaling,
const Point3f::Simd& rotationOrigin,
const QuaternionSimd<Quaternion<float>>& rotationQuaternion,
const Vector<float, 3>::Simd& translation ) noexcept;
AffineTransformationMatrix
Creates an affine transformation matrix.
template<Internal::SimdType S, Internal::SimdType T, typename U, Internal::SimdType W>
requires (S::Size > 2) && (T::Size > 2) && (W::Size > 2) && IsFloatingPoint<U> &&
std::is_same_v<typename S::value_type,U> &&
std::is_same_v<typename T::value_type, U> &&
std::is_same_v<typename W::value_type, U>
inline SquareMatrix<U, 4>::Simd AffineTransformationMatrix( const S& scaling,
const T& rotationOrigin,
const QuaternionSimd<Quaternion<U>>& rotationQuaternion,
const W& translation ) noexcept;
LookTo
Creates a view matrix using the left-handed coordinate system for the provided camera position, camera direction, and up direction.
template<Internal::SimdType S, Internal::SimdType T, Internal::SimdType U>
requires Internal::IsCompatible<S,T> && Internal::IsCompatible<S, U> && (S::Size == 3)
inline SquareMatrix<typename S::value_type, 4>::Simd LookTo( const S& cameraPosition,
const T& cameraDirection,
const U& upDirection ) noexcept;
LookAt
Creates a view matrix using the left-handed coordinate system for the provided camera position, focal point, and up direction.
template<Internal::SimdType S, Internal::SimdType T, Internal::TupleType U>
requires Internal::IsCompatible<S, T>&& Internal::IsCompatible<S, U> && ( S::Size == 3 )
inline SquareMatrix<typename S::value_type, 4>::Simd LookAt( const S& cameraPosition,
const T& focusPosition,
const U& upDirection ) noexcept;
PerspectiveProjection
Creates a left-handed perspective projection matrix.
template<typename T>
requires IsFloatingPoint<T>
inline SquareMatrix<T, 4>::Simd PerspectiveProjection( T viewWidth,
T viewHeight,
T nearZ,
T farZ ) noexcept;
PerspectiveFovProjection
Creates a left-handed perspective projection matrix based on a field of view.
template<typename T>
requires IsFloatingPoint<T>
inline SquareMatrix<T, 4>::Simd PerspectiveFovProjection( T fovAngleY,
T aspectRatio,
T nearZ,
T farZ ) noexcept;
Transform
Applies a transformation matrix to a 3D vector.
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>::Simd& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>::Simd& v,
const SquareMatrix<float, 4>& matrix );
inline Vector<float, 3>::Simd Transform( const Vector<float, 3>& v,
const SquareMatrix<float, 4>& matrix );
Applies a transformation matrix to a 3D coordinate.
inline Point3f::Simd Transform( const Point3f::Simd& p,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f& p,
const SquareMatrix<float, 4>::Simd& matrix );
inline Point3f::Simd Transform( const Point3f::Simd& p,
const SquareMatrix<float, 4>& matrix );
inline Point3f::Simd Transform( const Point3f& p,
const SquareMatrix<float, 4>& matrix );
Applies a transformation matrix to a normal.
inline Normal3f::Simd Transform( const Normal3f::Simd& n,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f& n,
const SquareMatrix<float, 4>::Simd& matrix );
inline Normal3f::Simd Transform( const Normal3f::Simd& n,
const SquareMatrix<float, 4>& matrix );
inline Normal3f::Simd Transform( const Normal3f& n,
const SquareMatrix<float, 4>& matrix );
Quaternion
Quaternions provides a compact representation of rotations.
The Quaternion
template can be used with both single and double precision floating
point types.
Like the tuple templates, there is a QuaternionSimd
template that represents
quaternions loaded into a SIMD register.
Quaternion
and QuaternionSimd
supports addition, subtraction, multiplication,
scalar multiplication and scalar division.
Quaternion member functions
Constructors
constexpr Quaternion( ) noexcept;
The default constructor initializes v.x
, v.y
, v.z
and w
to 0.0
.
constexpr Quaternion( ValueType xv, ValueType yv, ValueType zv, ValueType wv ) noexcept;
Initializes v.x
to xv
, v.y
to yv
, v.z
to zv
and w
to wv
.
constexpr Quaternion( const Vector<ValueType,3>& vv, ValueType wv ) noexcept;
Initializes v
to xv
and w
to wv
.
Quaternion( const Simd& qsimd ) noexcept
Initializes the quaternion using the values held by qsimd.simd
.
Quaternion( ValueType pitch, ValueType yaw, ValueType roll ) noexcept
Creates a quaternion based on the pitch, yaw, and roll (Euler angles), where:
pitch
is the angle of rotation around the x-axis, in radians.yaw
is the angle of rotation around the y-axis, in radians.roll
is the angle of rotation around the z-axis, in radians.
Quaternion functions
Dot
Calculates the dot product of two quaternions.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T,4>::Simd Dot( const QuaternionSimd<Quaternion<T>>& q1,
const QuaternionSimd<Quaternion<T>>& q2 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Dot( const Quaternion<T>& q1,
const QuaternionSimd<Quaternion<T>>& q2 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Dot( const QuaternionSimd<Quaternion<T>>& q1,
const Quaternion<T>& q2 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Dot( const Quaternion<T>& q1,
const Quaternion<T>& q2 ) noexcept;
Length and ScalarLength
Calculates the magnitude of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Length( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd Length( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLength( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLength( const Quaternion<T>& q1 ) noexcept;
LengthSquared and ScalarLengthSquared
Calculates the square of the magnitude of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd LengthSquared( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd LengthSquared( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLengthSquared( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarLengthSquared( const Quaternion<T>& q1 ) noexcept;
ReciprocalLength and ScalarReciprocalLength
Calculates the reciprocal of the magnitude of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd ReciprocalLength( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename Vector<T, 4>::Simd ReciprocalLength( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarReciprocalLength( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
typename T ScalarReciprocalLength( const Quaternion<T>& q1 ) noexcept;
Conjugate
Calculates the conjugate of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Conjugate( const Quaternion<T>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Normalize( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
Normalize
Normalizes a quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Normalize( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Normalize( const Quaternion<T>& q1 ) noexcept;
Inverse
Calculates the inverse of a quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Inverse( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Inverse( const Quaternion<T>& q1 ) noexcept;
Log
Calculates the natural logarithm of a unit quaternion.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Log( const QuaternionSimd<Quaternion<T>>& q1 ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Log( const Quaternion<T>& q1 ) noexcept;
Slerp
Spherical linear interpolation between two unit quaternions.
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const Vector<T, 4>& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const Quaternion<T>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const QuaternionSimd<Quaternion<T>>& q1,
const Quaternion<T>& q2,
const Vector<T, 4>& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const QuaternionSimd<Quaternion<T>>& q2,
const Vector<T, 4>& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const Quaternion<T>& q2,
const typename Vector<T, 4>::Simd& t ) noexcept;
template<typename T>
requires IsFloatingPoint<T>
QuaternionSimd<Quaternion<T>> Slerp( const Quaternion<T>& q1,
const Quaternion<T>& q2,
const Vector<T, 4>& t ) noexcept;
Transforms
A transform is a mapping from vectors to vectors or points to points.
Taking a point, vector, or normal defined with respect to one coordinate frame and finding its coordinate values with respect to another coordinate frame is a useful capability.
AffineTransformation
Affine transformations are transformations that preserves collinearity; where all points lying on a line initially, still lie on a line after transformation; and ratios of distances, like the midpoint of a line segment, which remains the midpoint after transformation. In this sense, affine indicates a special class of projective transformations that do not move any objects from the affine space \(R^3\) to the plane at infinity or conversely.
Geometric contraction, expansion, dilation, reflection, rotation, shear, similarity transformations, spiral similarities, and translation are all affine transformations, as are their combinations. In general, an affine transformation is a composition of rotations, translations, dilations, and shears.
While an affine transformation preserves proportions on lines, it does not necessarily preserve angles or lengths. Any triangle can be transformed into any other by an affine transformation, so all triangles are affine and, in this sense, affine is a generalization of congruent and similar.
Use the AffineTransformation
class to efficiently transform Vector3f
, Point3f
,
Normal3f
, and AffineTransformation
objects from one coordinate space to another.
The transformation of a AffineTransformation
object, results in an AffineTransformation
object combining the transformations of both into a single transformation.