# ifndef magnum_math_vector_h
# define magnum_math_vector_h
/*
This file is part of Magnum .
Copyright © 2010 , 2011 , 2012 , 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019
Vladimír Vondruš < mosra @ centrum . cz >
Permission is hereby granted , free of charge , to any person obtaining a
copy of this software and associated documentation files ( the " Software " ) ,
to deal in the Software without restriction , including without limitation
the rights to use , copy , modify , merge , publish , distribute , sublicense ,
and / or sell copies of the Software , and to permit persons to whom the
Software is furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE .
*/
# include <pybind11/operators.h>
# include <Corrade/Utility/FormatStl.h>
# include <Magnum/Math/Color.h>
# include <Magnum/Math/Vector4.h>
# include "corrade/PybindExtras.h"
# include "magnum/math.h"
namespace magnum {
template < class > bool isTypeCompatible ( const std : : string & ) ;
template < > inline bool isTypeCompatible < Float > ( const std : : string & format ) {
return format = = " f " | | format = = " d " ;
}
template < > inline bool isTypeCompatible < Double > ( const std : : string & format ) {
return format = = " f " | | format = = " d " ;
}
template < > inline bool isTypeCompatible < Int > ( const std : : string & format ) {
return format = = " i " | | format = = " l " ;
}
template < > inline bool isTypeCompatible < UnsignedInt > ( const std : : string & format ) {
return format = = " I " | | format = = " L " ;
}
template < class U , class T > void initFromBuffer ( T & out , const py : : buffer_info & info ) {
for ( std : : size_t i = 0 ; i ! = T : : Size ; + + i )
out [ i ] = static_cast < typename T : : Type > ( * reinterpret_cast < const U * > ( static_cast < const char * > ( info . ptr ) + i * info . strides [ 0 ] ) ) ;
}
/* Floating-point init */
template < class T > void initFromBuffer ( T & out , const py : : buffer_info & info , std : : true_type , std : : true_type ) {
if ( info . format = = " f " ) initFromBuffer < Float > ( out , info ) ;
else if ( info . format = = " d " ) initFromBuffer < Double > ( out , info ) ;
else CORRADE_ASSERT_UNREACHABLE ( ) ; /* LCOV_EXCL_LINE */
}
/* Signed integeral init */
template < class T > void initFromBuffer ( T & out , const py : : buffer_info & info , std : : false_type , std : : true_type ) {
if ( info . format = = " i " ) initFromBuffer < Int > ( out , info ) ;
else if ( info . format = = " l " ) initFromBuffer < Long > ( out , info ) ;
else CORRADE_ASSERT_UNREACHABLE ( ) ; /* LCOV_EXCL_LINE */
}
/* Unsigned integeral init */
template < class T > void initFromBuffer ( T & out , const py : : buffer_info & info , std : : false_type , std : : false_type ) {
if ( info . format = = " I " ) initFromBuffer < UnsignedInt > ( out , info ) ;
else if ( info . format = = " L " ) initFromBuffer < UnsignedLong > ( out , info ) ;
else CORRADE_ASSERT_UNREACHABLE ( ) ; /* LCOV_EXCL_LINE */
}
/* Things that have to be defined for both VectorN and Color so they construct
/ return a proper type */
template < class T , class . . . Args > void everyVector ( py : : class_ < T , Args . . . > & c ) {
/* Implicitly convertible from a buffer (which is a numpy array as well).
Without this implicit conversion from numpy arrays sometimes doesn ' t
work . */
py : : implicitly_convertible < py : : buffer , T > ( ) ;
c
/* Constructors */
. def_static ( " zero_init " , [ ] ( ) {
return T { Math : : ZeroInit } ;
} , " Construct a zero vector " )
. def ( py : : init ( ) , " Default constructor " )
/* Buffer protocol. If not present, implicit conversion from numpy
arrays of non - default types somehow doesn ' t work . On the other hand
only the constructor is needed ( and thus also no py : : buffer_protocol ( )
specified for the class ) , converting vectors to numpy arrays is
doable using the simple iteration iterface . */
. def ( py : : init ( [ ] ( py : : buffer buffer ) {
py : : buffer_info info = buffer . request ( ) ;
if ( info . ndim ! = 1 )
throw py : : buffer_error { Utility : : formatString ( " expected 1 dimension but got {} " , info . ndim ) } ;
if ( info . shape [ 0 ] ! = T : : Size )
throw py : : buffer_error { Utility : : formatString ( " expected {} elements but got {} " , T : : Size , info . shape [ 0 ] ) } ;
if ( ! isTypeCompatible < typename T : : Type > ( info . format ) )
throw py : : buffer_error { Utility : : formatString ( " unexpected format {} for a {} vector " , info . format , py : : format_descriptor < typename T : : Type > : : format ( ) ) } ;
T out { Math : : NoInit } ;
initFromBuffer ( out , info , std : : is_floating_point < typename T : : Type > { } , std : : is_signed < typename T : : Type > { } ) ;
return out ;
} ) , " Construct from a buffer " )
/* Operators */
. def ( - py : : self , " Negated vector " )
. def ( py : : self + = py : : self , " Add and assign a vector " )
. def ( py : : self + py : : self , " Add a vector " )
. def ( py : : self - = py : : self , " Subtract and assign a vector " )
. def ( py : : self - py : : self , " Subtract a vector " )
. def ( py : : self * = typename T : : Type { } , " Multiply with a scalar and assign " )
. def ( py : : self * typename T : : Type { } , " Multiply with a scalar " )
. def ( py : : self / = typename T : : Type { } , " Divide with a scalar and assign " )
. def ( py : : self / typename T : : Type { } , " Divide with a scalar " )
. def ( py : : self * = py : : self , " Multiply a vector component-wise and assign " )
. def ( py : : self * py : : self , " Multiply a vector component-wise " )
. def ( py : : self / = py : : self , " Divide a vector component-wise and assign " )
. def ( py : : self / py : : self , " Divide a vector component-wise " )
. def ( typename T : : Type { } * py : : self , " Multiply a scalar with a vector " )
. def ( typename T : : Type { } / py : : self , " Divide a vector with a scalar and invert " ) ;
}
/* Things common for vectors of all sizes and types */
template < class T > void vector ( py : : module & m , py : : class_ < T > & c ) {
/*
Missing APIs :
from ( T * )
Type
construction from different types
VectorNi * VectorN and variants ( 5 )
*/
m
. def ( " dot " , [ ] ( const T & a , const T & b ) { return Math : : dot ( a , b ) ; } ,
" Dot product of two vectors " ) ;
c
/* Constructors */
. def ( py : : init < typename T : : Type > ( ) , " Construct a vector with one value for all components " )
/* Comparison */
. def ( py : : self = = py : : self , " Equality comparison " )
. def ( py : : self ! = py : : self , " Non-equality comparison " )
. def ( py : : self < py : : self , " Component-wise less than comparison " )
. def ( py : : self > py : : self , " Component-wise greater than comparison " )
. def ( py : : self < = py : : self , " Component-wise less than or equal comparison " )
. def ( py : : self > = py : : self , " Component-wise greater than or equal comparison " )
/* Set / get. Need to throw IndexError in order to allow iteration:
https : //docs.python.org/3/reference/datamodel.html#object.__getitem__ */
. def ( " __setitem__ " , [ ] ( T & self , std : : size_t i , typename T : : Type value ) {
if ( i > = T : : Size ) throw pybind11 : : index_error { } ;
self [ i ] = value ;
} , " Set a value at given position " )
. def ( " __getitem__ " , [ ] ( const T & self , std : : size_t i ) {
if ( i > = T : : Size ) throw pybind11 : : index_error { } ;
return self [ i ] ;
} , " Value at given position " )
/* Member functions common for floating-point and integer types */
. def ( " is_zero " , & T : : isZero , " Whether the vector is zero " )
. def ( " dot " , static_cast < typename T : : Type ( T : : * ) ( ) const > ( & T : : dot ) , " Dot product of the vector " )
. def ( " flipped " , & T : : flipped , " Flipped vector " )
. def ( " sum " , & T : : sum , " Sum of values in the vector " )
. def ( " product " , & T : : product , " Product of values in the vector " )
. def ( " min " , & T : : min , " Minimal value in the vector " )
. def ( " max " , & T : : max , " Maximal value in the vector " )
. def ( " minmax " , & T : : minmax , " Minimal and maximal value in the vector " )
. def ( " __repr__ " , repr < T > , " Object representation " ) ;
/* Vector length */
char lenDocstring [ ] = " Vector size. Returns _. " ;
lenDocstring [ sizeof ( lenDocstring ) - 3 ] = ' 0 ' + T : : Size ;
c . def_static ( " __len__ " , [ ] ( ) { return int ( T : : Size ) ; } , lenDocstring ) ;
}
template < class T > void vector2 ( py : : class_ < Math : : Vector2 < T > > & c ) {
py : : implicitly_convertible < const std : : tuple < T , T > & , Math : : Vector2 < T > > ( ) ;
c
/* Constructors */
. def ( py : : init < T , T > ( ) , " Constructor " )
. def ( py : : init ( [ ] ( const std : : tuple < T , T > & value ) {
return Math : : Vector2 < T > { std : : get < 0 > ( value ) , std : : get < 1 > ( value ) } ;
} ) , " Construct from a tuple " )
/* Static constructors */
. def_static ( " x_axis " , & Math : : Vector2 < T > : : xAxis ,
" Vector in a direction of X axis (right) " , py : : arg ( " length " ) = T ( 1 ) )
. def_static ( " y_axis " , & Math : : Vector2 < T > : : yAxis ,
" Vector in a direction of Y axis (up) " , py : : arg ( " length " ) = T ( 1 ) )
. def_static ( " x_scale " , & Math : : Vector2 < T > : : xScale ,
" Scaling vector in a direction of X axis (width) " , py : : arg ( " scale " ) )
. def_static ( " y_scale " , & Math : : Vector2 < T > : : yScale ,
" Scaling vector in a direction of Y axis (height) " , py : : arg ( " scale " ) )
/* Methods */
. def ( " perpendicular " , & Math : : Vector2 < T > : : perpendicular ,
" Perpendicular vector " )
/* Properties */
. def_property ( " x " ,
static_cast < T ( Math : : Vector2 < T > : : * ) ( ) const > ( & Math : : Vector2 < T > : : x ) ,
[ ] ( Math : : Vector2 < T > & self , T value ) { self . x ( ) = value ; } ,
" X component " )
. def_property ( " y " ,
static_cast < T ( Math : : Vector2 < T > : : * ) ( ) const > ( & Math : : Vector2 < T > : : y ) ,
[ ] ( Math : : Vector2 < T > & self , T value ) { self . y ( ) = value ; } ,
" Y component " ) ;
}
template < class T > void vector3 ( py : : class_ < Math : : Vector3 < T > > & c ) {
py : : implicitly_convertible < const std : : tuple < T , T , T > & , Math : : Vector3 < T > > ( ) ;
c
/* Constructors */
. def ( py : : init < T , T , T > ( ) , " Constructor " )
. def ( py : : init ( [ ] ( const std : : tuple < T , T , T > & value ) {
return Math : : Vector3 < T > { std : : get < 0 > ( value ) , std : : get < 1 > ( value ) , std : : get < 2 > ( value ) } ;
} ) , " Construct from a tuple " )
/* Static constructors */
. def_static ( " x_axis " , & Math : : Vector3 < T > : : xAxis ,
" Vector in a direction of X axis (right) " , py : : arg ( " length " ) = T ( 1 ) )
. def_static ( " y_axis " , & Math : : Vector3 < T > : : yAxis ,
" Vector in a direction of Y axis (up) " , py : : arg ( " length " ) = T ( 1 ) )
. def_static ( " z_axis " , & Math : : Vector3 < T > : : zAxis ,
" Vector in a direction of Z axis (backward) " , py : : arg ( " length " ) = T ( 1 ) )
. def_static ( " x_scale " , & Math : : Vector3 < T > : : xScale ,
" Scaling vector in a direction of X axis (width) " , py : : arg ( " scale " ) )
. def_static ( " y_scale " , & Math : : Vector3 < T > : : yScale ,
" Scaling vector in a direction of Y axis (height) " , py : : arg ( " scale " ) )
. def_static ( " z_scale " , & Math : : Vector3 < T > : : zScale ,
" Scaling vector in a direction of Z axis (depth) " , py : : arg ( " scale " ) )
/* Properties */
. def_property ( " x " ,
static_cast < T ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : x ) ,
[ ] ( Math : : Vector3 < T > & self , T value ) { self . x ( ) = value ; } ,
" X component " )
. def_property ( " y " ,
static_cast < T ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : y ) ,
[ ] ( Math : : Vector3 < T > & self , T value ) { self . y ( ) = value ; } ,
" Y component " )
. def_property ( " z " ,
static_cast < T ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : z ) ,
[ ] ( Math : : Vector3 < T > & self , T value ) { self . z ( ) = value ; } ,
" Z component " )
. def_property ( " r " ,
static_cast < T ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : r ) ,
[ ] ( Math : : Vector3 < T > & self , T value ) { self . r ( ) = value ; } ,
" R component " )
. def_property ( " g " ,
static_cast < T ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : g ) ,
[ ] ( Math : : Vector3 < T > & self , T value ) { self . g ( ) = value ; } ,
" G component " )
. def_property ( " b " ,
static_cast < T ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : b ) ,
[ ] ( Math : : Vector3 < T > & self , T value ) { self . b ( ) = value ; } ,
" B component " )
. def_property ( " xy " ,
static_cast < const Math : : Vector2 < T > ( Math : : Vector3 < T > : : * ) ( ) const > ( & Math : : Vector3 < T > : : xy ) ,
[ ] ( Math : : Vector3 < T > & self , const Math : : Vector2 < T > & value ) { self . xy ( ) = value ; } ,
" XY part of the vector " ) ;
}
template < class T > void vector4 ( py : : class_ < Math : : Vector4 < T > > & c ) {
py : : implicitly_convertible < const std : : tuple < T , T , T , T > & , Math : : Vector4 < T > > ( ) ;
c
/* Constructors */
. def ( py : : init < T , T , T , T > ( ) , " Constructor " )
. def ( py : : init ( [ ] ( const std : : tuple < T , T , T , T > & value ) {
return Math : : Vector4 < T > { std : : get < 0 > ( value ) , std : : get < 1 > ( value ) , std : : get < 2 > ( value ) , std : : get < 3 > ( value ) } ;
} ) , " Construct from a tuple " )
/* Properties */
. def_property ( " x " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : x ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . x ( ) = value ; } ,
" X component " )
. def_property ( " y " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : y ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . y ( ) = value ; } ,
" Y component " )
. def_property ( " z " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : z ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . z ( ) = value ; } ,
" Z component " )
. def_property ( " w " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : w ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . w ( ) = value ; } ,
" W component " )
. def_property ( " r " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : r ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . r ( ) = value ; } ,
" R component " )
. def_property ( " g " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : g ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . g ( ) = value ; } ,
" G component " )
. def_property ( " b " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : b ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . b ( ) = value ; } ,
" B component " )
. def_property ( " a " ,
static_cast < T ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : a ) ,
[ ] ( Math : : Vector4 < T > & self , T value ) { self . a ( ) = value ; } ,
" A component " )
. def_property ( " xyz " ,
static_cast < const Math : : Vector3 < T > ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : xyz ) ,
[ ] ( Math : : Vector4 < T > & self , const Math : : Vector3 < T > & value ) { self . xyz ( ) = value ; } ,
" XYZ part of the vector " )
. def_property ( " rgb " ,
static_cast < const Math : : Vector3 < T > ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : rgb ) ,
[ ] ( Math : : Vector4 < T > & self , const Math : : Vector3 < T > & value ) { self . rgb ( ) = value ; } ,
" RGB part of the vector " )
. def_property ( " xy " ,
static_cast < const Math : : Vector2 < T > ( Math : : Vector4 < T > : : * ) ( ) const > ( & Math : : Vector4 < T > : : xy ) ,
[ ] ( Math : : Vector4 < T > & self , const Math : : Vector2 < T > & value ) { self . xy ( ) = value ; } ,
" XY part of the vector " ) ;
}
template < class U , template < class > class Type , class T , class . . . Args > void convertibleImplementation ( py : : class_ < Type < T > , Args . . . > & c , std : : false_type ) {
c . def ( py : : init < Type < U > > ( ) , " Construct from different underlying type " ) ;
}
template < class U , template < class > class Type , class T , class . . . Args > void convertibleImplementation ( py : : class_ < Type < T > , Args . . . > & , std : : true_type ) { }
template < template < class > class Type , class T , class . . . Args > void convertible ( py : : class_ < Type < T > , Args . . . > & c ) {
convertibleImplementation < UnsignedInt > ( c , std : : is_same < T , UnsignedInt > { } ) ;
convertibleImplementation < Int > ( c , std : : is_same < T , Int > { } ) ;
convertibleImplementation < Float > ( c , std : : is_same < T , Float > { } ) ;
convertibleImplementation < Double > ( c , std : : is_same < T , Double > { } ) ;
}
template < class T , class Base > void color ( py : : class_ < T , Base > & c ) {
c
. def_static ( " zero_init " , [ ] ( ) {
return T { Math : : ZeroInit } ;
} , " Construct a zero color " )
. def ( py : : init ( ) , " Default constructor " ) ;
}
template < class T > void color3 ( py : : class_ < Math : : Color3 < T > , Math : : Vector3 < T > > & c ) {
py : : implicitly_convertible < const std : : tuple < T , T , T > & , Math : : Color3 < T > > ( ) ;
c
/* Constructors */
. def ( py : : init < T , T , T > ( ) , " Constructor " )
. def ( py : : init < T > ( ) , " Construct with one value for all components " )
. def ( py : : init < Math : : Vector3 < T > > ( ) , " Construct from a vector " )
. def ( py : : init ( [ ] ( const std : : tuple < T , T , T > & value ) {
return Math : : Color3 < T > { std : : get < 0 > ( value ) , std : : get < 1 > ( value ) , std : : get < 2 > ( value ) } ;
} ) , " Construct from a tuple " )
. def_static ( " from_hsv " , [ ] ( Degd hue , typename Math : : Color3 < T > : : FloatingPointType saturation , typename Math : : Color3 < T > : : FloatingPointType value ) {
return Math : : Color3 < T > : : fromHsv ( { Math : : Deg < T > ( hue ) , saturation , value } ) ;
} , " Create RGB color from HSV representation " , py : : arg ( " hue " ) , py : : arg ( " saturation " ) , py : : arg ( " value " ) )
/* Accessors */
. def ( " to_hsv " , [ ] ( Math : : Color3 < T > & self ) {
auto hsv = self . toHsv ( ) ;
return std : : make_tuple ( Degd ( hsv . hue ) , hsv . saturation , hsv . value ) ;
} , " Convert to HSV representation " )
. def ( " hue " , [ ] ( Math : : Color3 < T > & self ) {
return Degd ( self . hue ( ) ) ;
} , " Hue " )
. def ( " saturation " , & Math : : Color3 < T > : : saturation , " Saturation " )
. def ( " value " , & Math : : Color3 < T > : : value , " Value " ) ;
}
template < class T > void color4 ( py : : class_ < Math : : Color4 < T > , Math : : Vector4 < T > > & c ) {
py : : implicitly_convertible < const std : : tuple < T , T , T > & , Math : : Color4 < T > > ( ) ;
py : : implicitly_convertible < const std : : tuple < T , T , T , T > & , Math : : Color4 < T > > ( ) ;
py : : implicitly_convertible < const Math : : Color3 < T > & , Math : : Color4 < T > > ( ) ;
c
/* Constructors */
. def ( py : : init < T , T , T , T > ( ) , " Constructor " , py : : arg ( " r " ) , py : : arg ( " g " ) , py : : arg ( " b " ) , py : : arg ( " a " ) = Math : : Implementation : : fullChannel < T > ( ) )
. def ( py : : init < T , T > ( ) , " Construct with one value for all components " , py : : arg ( " rgb " ) , py : : arg ( " alpha " ) = Math : : Implementation : : fullChannel < T > ( ) )
. def ( py : : init < Math : : Color3 < T > , T > ( ) , " Construct from a vector " , py : : arg ( " rgb " ) , py : : arg ( " alpha " ) = Math : : Implementation : : fullChannel < T > ( ) )
. def ( py : : init < Math : : Vector4 < T > > ( ) , " Construct from a vector " )
. def ( py : : init ( [ ] ( const std : : tuple < T , T , T > & value ) {
return Math : : Color4 < T > { std : : get < 0 > ( value ) , std : : get < 1 > ( value ) , std : : get < 2 > ( value ) } ;
} ) , " Construct from a RGB tuple " )
. def ( py : : init ( [ ] ( const std : : tuple < T , T , T , T > & value ) {
return Math : : Color4 < T > { std : : get < 0 > ( value ) , std : : get < 1 > ( value ) , std : : get < 2 > ( value ) , std : : get < 3 > ( value ) } ;
} ) , " Construct from a RGBA tuple " )
. def_static ( " from_hsv " , [ ] ( Degd hue , typename Math : : Color4 < T > : : FloatingPointType saturation , typename Math : : Color4 < T > : : FloatingPointType value , T alpha ) {
return Math : : Color4 < T > : : fromHsv ( { Math : : Deg < T > ( hue ) , saturation , value } , alpha ) ;
} , " Create RGB color from HSV representation " , py : : arg ( " hue " ) , py : : arg ( " saturation " ) , py : : arg ( " value " ) , py : : arg ( " alpha " ) = Math : : Implementation : : fullChannel < T > ( ) )
/* Accessors */
. def ( " to_hsv " , [ ] ( Math : : Color4 < T > & self ) {
auto hsv = self . toHsv ( ) ;
return std : : make_tuple ( Degd ( hsv . hue ) , hsv . saturation , hsv . value ) ;
} , " Convert to HSV representation " )
. def ( " hue " , [ ] ( Math : : Color4 < T > & self ) {
return Degd ( self . hue ( ) ) ;
} , " Hue " )
. def ( " saturation " , & Math : : Color4 < T > : : saturation , " Saturation " )
. def ( " value " , & Math : : Color4 < T > : : value , " Value " )
/* Properties */
. def_property ( " xyz " ,
static_cast < const Math : : Color3 < T > ( Math : : Color4 < T > : : * ) ( ) const > ( & Math : : Color4 < T > : : xyz ) ,
[ ] ( Math : : Color4 < T > & self , const Math : : Color3 < T > & value ) { self . xyz ( ) = value ; } ,
" XYZ part of the vector " )
. def_property ( " rgb " ,
static_cast < const Math : : Color3 < T > ( Math : : Color4 < T > : : * ) ( ) const > ( & Math : : Color4 < T > : : rgb ) ,
[ ] ( Math : : Color4 < T > & self , const Math : : Color3 < T > & value ) { self . rgb ( ) = value ; } ,
" RGB part of the vector " ) ;
}
}
# endif