From 70e2c5700b70d0c2c49c4d66a69a92d185c1da89 Mon Sep 17 00:00:00 2001 From: liu Date: Thu, 23 Dec 2021 16:20:24 +0800 Subject: [PATCH] add cmake targets --- CMakeLists.txt | 42 + cmake/cyCodeBaseConfig.cmake.in | 3 + .../cyAlphaDistribution.h | 0 cyBVH.h => include/cyBVH.h | 792 +-- cyColor.h => include/cyColor.h | 708 +-- cyCore.h => include/cyCore.h | 0 cyGL.h => include/cyGL.h | 0 cyHairFile.h => include/cyHairFile.h | 840 +-- cyHeap.h => include/cyHeap.h | 0 cyIPoint.h => include/cyIPoint.h | 0 cyIVector.h => include/cyIVector.h | 0 cyLightingGrid.h => include/cyLightingGrid.h | 0 cyMatrix.h => include/cyMatrix.h | 4840 ++++++++--------- cyPoint.h => include/cyPoint.h | 156 +- cyPointCloud.h => include/cyPointCloud.h | 0 cyQuat.h => include/cyQuat.h | 320 +- cySampleElim.h => include/cySampleElim.h | 0 cySpatial.h => include/cySpatial.h | 544 +- cyString.h => include/cyString.h | 2126 ++++---- cyTimer.h => include/cyTimer.h | 360 +- cyTriMesh.h => include/cyTriMesh.h | 862 +-- cyVector.h => include/cyVector.h | 0 22 files changed, 5819 insertions(+), 5774 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/cyCodeBaseConfig.cmake.in rename cyAlphaDistribution.h => include/cyAlphaDistribution.h (100%) rename cyBVH.h => include/cyBVH.h (97%) rename cyColor.h => include/cyColor.h (98%) rename cyCore.h => include/cyCore.h (100%) rename cyGL.h => include/cyGL.h (100%) rename cyHairFile.h => include/cyHairFile.h (97%) rename cyHeap.h => include/cyHeap.h (100%) rename cyIPoint.h => include/cyIPoint.h (100%) rename cyIVector.h => include/cyIVector.h (100%) rename cyLightingGrid.h => include/cyLightingGrid.h (100%) rename cyMatrix.h => include/cyMatrix.h (98%) rename cyPoint.h => include/cyPoint.h (97%) rename cyPointCloud.h => include/cyPointCloud.h (100%) rename cyQuat.h => include/cyQuat.h (97%) rename cySampleElim.h => include/cySampleElim.h (100%) rename cySpatial.h => include/cySpatial.h (97%) rename cyString.h => include/cyString.h (96%) rename cyTimer.h => include/cyTimer.h (97%) rename cyTriMesh.h => include/cyTriMesh.h (98%) rename cyVector.h => include/cyVector.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9081d49 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required (VERSION 3.5.1) + +project(cyCodeBase VERSION 1.0.0) +include(GNUInstallDirs) +add_library(${PROJECT_NAME} INTERFACE) +target_include_directories(${PROJECT_NAME} INTERFACE + $ + $ + + ) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17) +install(TARGETS ${PROJECT_NAME} + EXPORT ${PROJECT_NAME}_Targets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + +file(WRITE "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" "@PACKAGE_INIT@\n") +file(APPEND "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" "include(\"\${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake\")\n") +file(APPEND "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" "check_required_components(\"@PROJECT_NAME@\")\n") + +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION + ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + +install(EXPORT ${PROJECT_NAME}_Targets + FILE ${PROJECT_NAME}Targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + +install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) + +install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME} DESTINATION include) \ No newline at end of file diff --git a/cmake/cyCodeBaseConfig.cmake.in b/cmake/cyCodeBaseConfig.cmake.in new file mode 100644 index 0000000..2b68c78 --- /dev/null +++ b/cmake/cyCodeBaseConfig.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/cyAlphaDistribution.h b/include/cyAlphaDistribution.h similarity index 100% rename from cyAlphaDistribution.h rename to include/cyAlphaDistribution.h diff --git a/cyBVH.h b/include/cyBVH.h similarity index 97% rename from cyBVH.h rename to include/cyBVH.h index eb0227f..4249a69 100644 --- a/cyBVH.h +++ b/include/cyBVH.h @@ -1,396 +1,396 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyBVH.h -//! \author Cem Yuksel -//! -//! \brief Bounding Volume Hierarchy class. -//! -//! BVH is a storage class for Bounding Volume Hierarchies. -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_BVH_H_INCLUDED_ -#define _CY_BVH_H_INCLUDED_ - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -#ifndef CY_BVH_ELEMENT_COUNT_BITS -#define CY_BVH_ELEMENT_COUNT_BITS 3 //!< Determines the number of bits needed to represent the maximum number of elements in a node (8) -#endif - -#ifndef CY_BVH_MAX_ELEMENT_COUNT -#define CY_BVH_MAX_ELEMENT_COUNT (1< CY_BVH_MAX_ELEMENT_COUNT ) maxElementsPerNode = CY_BVH_MAX_ELEMENT_COUNT; - elements = new unsigned int[numElements]; - for ( unsigned int i=0; iGetNumNodes(); - nodes = new Node[ numNodes+1 ]; - ConvertTempData( 1, tempRoot, 2 ); - delete tempRoot; - } - - ///////////////////////////////////////////////////////////////////////////////// - -protected: - - ///////////////////////////////////////////////////////////////////////////////// - //@ Methods to be implemented by sub-classes - ///////////////////////////////////////////////////////////////////////////////// - - virtual void GetElementBounds(unsigned int i, float box[6] ) const=0; //!< Sets box as the i^th element's bounding box. - virtual float GetElementCenter(unsigned int i, int dimension) const=0; //!< Returns the center of the i^th element in the given dimension - - ///////////////////////////////////////////////////////////////////////////////// - //@ Building method that can be overloaded - ///////////////////////////////////////////////////////////////////////////////// - - //! Sorts the given elements of a temporary node while building the BVH hierarchy, - //! such that first N elements are to be assigned to the first child and the - //! remaining elements are to be assigned to the second child node, then returns N. - //! Returns zero, if the node is not to be split. - //! The default implementation splits the temporary node down the middle of the - //! widest axis of its bounding box. - virtual unsigned int FindSplit( unsigned int elementCount, unsigned int *elements, float const *box, unsigned int maxElementsPerNode ) - { - return MeanSplit(elementCount,elements,box,maxElementsPerNode); - } - - ///////////////////////////////////////////////////////////////////////////////// - -private: - - ///////////////////////////////////////////////////////////////////////////////// - //@ Internal storage - ///////////////////////////////////////////////////////////////////////////////// - - struct Box - { - float b[6]; - Box() { Init(); } - Box( Box const &box ) { for(int i=0; i<6; i++) b[i]=box.b[i]; } - void Init() { b[0]=b[1]=b[2]=1e30f; b[3]=b[4]=b[5]=-1e30f; } - void operator += ( Box const &box ) { for(int i=0; i<3; i++) { if(b[i]>box.b[i])b[i]=box.b[i]; if(b[i+3]>_CY_BVH_ELEMENT_OFFSET_BITS)&_CY_BVH_ELEMENT_COUNT_MASK)+1; } //!< returns the number of elements in this node (must be leaf node) - bool IsLeafNode () const { return (data&_CY_BVH_LEAF_BIT_MASK)>0; } //!< returns true if this is a leaf node - float const * GetBounds () const { return box.b; } //!< returns the bounding box of the node - private: - Box box; //!< bounding box of the node - unsigned int data; //!< node data bits that keep the leaf node flag and the child node index or element count and element offset. - }; - - Node *nodes; //!< the tree structure that keeps all the node data (nodeData[0] is not used for cache coherency) - unsigned int *elements; //!< indices of all elements in all nodes - - ///////////////////////////////////////////////////////////////////////////////// - //@ Internal methods for building the BVH tree - ///////////////////////////////////////////////////////////////////////////////// - - //! Temporary node class used for building the hierarchy and then converted to NodeData. - class TempNode - { - public: - TempNode( unsigned int count, unsigned int offset, Box const &boundBox) : child1(0), child2(0), elementCount(count), elementOffset(offset), box(boundBox) {} - ~TempNode() { if ( child1 ) delete child1; if ( child2 ) delete child2; } - - void Split( unsigned int child1ElementCount, Box const &child1Box, Box const &child2Box ) - { - child1 = new TempNode(child1ElementCount,elementOffset,child1Box); - child2 = new TempNode(ElementCount()-child1ElementCount,elementOffset+child1ElementCount,child2Box); - } - unsigned int GetNumNodes() const - { - unsigned int n = 1; - if ( child1 ) n += child1->GetNumNodes(); - if ( child2 ) n += child2->GetNumNodes(); - return n; - } - bool IsLeafNode() const { return child1==0; } - unsigned int ElementCount () const { return elementCount; } - unsigned int ElementOffset() const { return elementOffset; } - TempNode* GetChild1() { return child1; } - TempNode* GetChild2() { return child2; } - Box const & GetBounds() const { return box; } - private: - TempNode *child1, *child2; - Box box; - unsigned int elementCount; - unsigned int elementOffset; - }; - - //! Recursively splits the given temporary node. - void SplitTempNode(TempNode *tNode, unsigned int maxElementsPerNode) - { - float const *box = tNode->GetBounds().b; - unsigned int *nodeElements = &elements[tNode->ElementOffset()]; - unsigned int child1ElemCount = FindSplit(tNode->ElementCount(),nodeElements,box,maxElementsPerNode); - - // If the FindSplit call does not return a valid split position - if ( child1ElemCount == 0 || child1ElemCount >= tNode->ElementCount() ) { - // if we must split anyway - if ( tNode->ElementCount() > CY_BVH_MAX_ELEMENT_COUNT ) { - // we split in half arbitrarily. - child1ElemCount = tNode->ElementCount() / 2; - } else { - // otherwise, we reached a leaf node and no more split is necessary. - return; - } - } - - // Compute child bounding boxes - Box child1Box; - Box child2Box; - for ( unsigned int i=0; iElementCount(); i++ ) { - Box eBox; - GetElementBounds( nodeElements[i], eBox.b ); - child2Box += eBox; - } - - // Split recursively - tNode->Split( child1ElemCount, child1Box, child2Box ); - SplitTempNode(tNode->GetChild1(),maxElementsPerNode); - SplitTempNode(tNode->GetChild2(),maxElementsPerNode); - } - - //! Recursively converts the temporary node data to NodeData. - unsigned int ConvertTempData( unsigned int nodeID, TempNode *tNode, unsigned int childIndex ) - { - if ( tNode->IsLeafNode() ) { - nodes[nodeID].SetLeafNode( tNode->GetBounds(), tNode->ElementCount(), tNode->ElementOffset() ); - return childIndex; - } else { - nodes[nodeID].SetInternalNode( tNode->GetBounds(), childIndex ); - unsigned int newChildIndex = ConvertTempData( childIndex, tNode->GetChild1(), childIndex+2 ); - return ConvertTempData( childIndex+1, tNode->GetChild2(), newChildIndex ); - } - } - - //! Called by the default implementation of FindSplit. - //! Splits the elements using the widest axis of the given bounding box. - unsigned int MeanSplit(unsigned int elementCount, unsigned int *nodeElements, float const *box, unsigned int maxElementsPerNode ) - { - if ( elementCount <= maxElementsPerNode ) return 0; - float d[3] = { box[3]-box[0], box[4]-box[1], box[5]-box[2] }; - unsigned int sd[3]; // split dimensions - sd[0] = d[0] >= d[1] ? ( d[0] >= d[2] ? 0 : 2 ) : ( d[1] >= d[2] ? 1 : 2 ); - sd[1] = (sd[0]+1) % 3; - sd[2] = (sd[0]+2) % 3; - if ( d[sd[1]] < d[sd[2]] ) { int t=sd[1]; sd[1]=sd[2]; sd[2]=t; } - - unsigned int child1ElemCount = 0; - for ( int s=0; s<3; s++ ) { - unsigned int splitDim = sd[s]; - float splitPos = 0.5f * ( box[splitDim] + box[splitDim+3] ); - unsigned int i=0, j=elementCount; - while ( i 0 ) { - child1ElemCount = i; - break; - } - } - - return child1ElemCount; - } - - ///////////////////////////////////////////////////////////////////////////////// -}; - -//------------------------------------------------------------------------------- - -#ifdef _CY_TRIMESH_H_INCLUDED_ - -//! Bounding Volume Hierarchy for triangular meshes (TriMesh) - -class BVHTriMesh : public BVH -{ -public: - //!@name Constructors - BVHTriMesh() : mesh(0) {} - BVHTriMesh( TriMesh const *m ) { SetMesh(m); } - - //! Sets the mesh pointer and builds the BVH structure. - void SetMesh( TriMesh const *m, unsigned int maxElementsPerNode=CY_BVH_MAX_ELEMENT_COUNT ) - { - mesh = m; - Clear(); - Build(mesh->NF(),maxElementsPerNode); - } - -protected: - //! Sets box as the i^th element's bounding box. - virtual void GetElementBounds(unsigned int i, float box[6]) const - { - TriMesh::TriFace const &f = mesh->F(i); - cyVec3f p = mesh->V( f.v[0] ); - box[0]=box[3]=p.x; box[1]=box[4]=p.y; box[2]=box[5]=p.z; - for ( int j=1; j<3; j++ ) { // for each triangle - cyVec3f p = mesh->V( f.v[j] ); - for ( int k=0; k<3; k++ ) { // for each dimension - if ( box[k] > p[k] ) box[k] = p[k]; - if ( box[k+3] < p[k] ) box[k+3] = p[k]; - } - } - } - - //! Returns the center of the i^th element in the given dimension. - virtual float GetElementCenter(unsigned int i, int dim) const - { - TriMesh::TriFace const &f = mesh->F(i); - return ( mesh->V(f.v[0])[dim] + mesh->V(f.v[1])[dim] + mesh->V(f.v[2])[dim] ) / 3.0f; - } - -private: - TriMesh const *mesh; -}; - -#endif - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::BVH cyBVH; //!< Bounding Volume Hierarchy class - -#ifdef _CY_TRIMESH_H_INCLUDED_ -typedef cy::BVHTriMesh cyBVHTriMesh; //!< BVH hierarchy for triangular meshes (TriMesh) -#endif - -//------------------------------------------------------------------------------- - -#endif - +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyBVH.h +//! \author Cem Yuksel +//! +//! \brief Bounding Volume Hierarchy class. +//! +//! BVH is a storage class for Bounding Volume Hierarchies. +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_BVH_H_INCLUDED_ +#define _CY_BVH_H_INCLUDED_ + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +#ifndef CY_BVH_ELEMENT_COUNT_BITS +#define CY_BVH_ELEMENT_COUNT_BITS 3 //!< Determines the number of bits needed to represent the maximum number of elements in a node (8) +#endif + +#ifndef CY_BVH_MAX_ELEMENT_COUNT +#define CY_BVH_MAX_ELEMENT_COUNT (1< CY_BVH_MAX_ELEMENT_COUNT ) maxElementsPerNode = CY_BVH_MAX_ELEMENT_COUNT; + elements = new unsigned int[numElements]; + for ( unsigned int i=0; iGetNumNodes(); + nodes = new Node[ numNodes+1 ]; + ConvertTempData( 1, tempRoot, 2 ); + delete tempRoot; + } + + ///////////////////////////////////////////////////////////////////////////////// + +protected: + + ///////////////////////////////////////////////////////////////////////////////// + //@ Methods to be implemented by sub-classes + ///////////////////////////////////////////////////////////////////////////////// + + virtual void GetElementBounds(unsigned int i, float box[6] ) const=0; //!< Sets box as the i^th element's bounding box. + virtual float GetElementCenter(unsigned int i, int dimension) const=0; //!< Returns the center of the i^th element in the given dimension + + ///////////////////////////////////////////////////////////////////////////////// + //@ Building method that can be overloaded + ///////////////////////////////////////////////////////////////////////////////// + + //! Sorts the given elements of a temporary node while building the BVH hierarchy, + //! such that first N elements are to be assigned to the first child and the + //! remaining elements are to be assigned to the second child node, then returns N. + //! Returns zero, if the node is not to be split. + //! The default implementation splits the temporary node down the middle of the + //! widest axis of its bounding box. + virtual unsigned int FindSplit( unsigned int elementCount, unsigned int *elements, float const *box, unsigned int maxElementsPerNode ) + { + return MeanSplit(elementCount,elements,box,maxElementsPerNode); + } + + ///////////////////////////////////////////////////////////////////////////////// + +private: + + ///////////////////////////////////////////////////////////////////////////////// + //@ Internal storage + ///////////////////////////////////////////////////////////////////////////////// + + struct Box + { + float b[6]; + Box() { Init(); } + Box( Box const &box ) { for(int i=0; i<6; i++) b[i]=box.b[i]; } + void Init() { b[0]=b[1]=b[2]=1e30f; b[3]=b[4]=b[5]=-1e30f; } + void operator += ( Box const &box ) { for(int i=0; i<3; i++) { if(b[i]>box.b[i])b[i]=box.b[i]; if(b[i+3]>_CY_BVH_ELEMENT_OFFSET_BITS)&_CY_BVH_ELEMENT_COUNT_MASK)+1; } //!< returns the number of elements in this node (must be leaf node) + bool IsLeafNode () const { return (data&_CY_BVH_LEAF_BIT_MASK)>0; } //!< returns true if this is a leaf node + float const * GetBounds () const { return box.b; } //!< returns the bounding box of the node + private: + Box box; //!< bounding box of the node + unsigned int data; //!< node data bits that keep the leaf node flag and the child node index or element count and element offset. + }; + + Node *nodes; //!< the tree structure that keeps all the node data (nodeData[0] is not used for cache coherency) + unsigned int *elements; //!< indices of all elements in all nodes + + ///////////////////////////////////////////////////////////////////////////////// + //@ Internal methods for building the BVH tree + ///////////////////////////////////////////////////////////////////////////////// + + //! Temporary node class used for building the hierarchy and then converted to NodeData. + class TempNode + { + public: + TempNode( unsigned int count, unsigned int offset, Box const &boundBox) : child1(0), child2(0), elementCount(count), elementOffset(offset), box(boundBox) {} + ~TempNode() { if ( child1 ) delete child1; if ( child2 ) delete child2; } + + void Split( unsigned int child1ElementCount, Box const &child1Box, Box const &child2Box ) + { + child1 = new TempNode(child1ElementCount,elementOffset,child1Box); + child2 = new TempNode(ElementCount()-child1ElementCount,elementOffset+child1ElementCount,child2Box); + } + unsigned int GetNumNodes() const + { + unsigned int n = 1; + if ( child1 ) n += child1->GetNumNodes(); + if ( child2 ) n += child2->GetNumNodes(); + return n; + } + bool IsLeafNode() const { return child1==0; } + unsigned int ElementCount () const { return elementCount; } + unsigned int ElementOffset() const { return elementOffset; } + TempNode* GetChild1() { return child1; } + TempNode* GetChild2() { return child2; } + Box const & GetBounds() const { return box; } + private: + TempNode *child1, *child2; + Box box; + unsigned int elementCount; + unsigned int elementOffset; + }; + + //! Recursively splits the given temporary node. + void SplitTempNode(TempNode *tNode, unsigned int maxElementsPerNode) + { + float const *box = tNode->GetBounds().b; + unsigned int *nodeElements = &elements[tNode->ElementOffset()]; + unsigned int child1ElemCount = FindSplit(tNode->ElementCount(),nodeElements,box,maxElementsPerNode); + + // If the FindSplit call does not return a valid split position + if ( child1ElemCount == 0 || child1ElemCount >= tNode->ElementCount() ) { + // if we must split anyway + if ( tNode->ElementCount() > CY_BVH_MAX_ELEMENT_COUNT ) { + // we split in half arbitrarily. + child1ElemCount = tNode->ElementCount() / 2; + } else { + // otherwise, we reached a leaf node and no more split is necessary. + return; + } + } + + // Compute child bounding boxes + Box child1Box; + Box child2Box; + for ( unsigned int i=0; iElementCount(); i++ ) { + Box eBox; + GetElementBounds( nodeElements[i], eBox.b ); + child2Box += eBox; + } + + // Split recursively + tNode->Split( child1ElemCount, child1Box, child2Box ); + SplitTempNode(tNode->GetChild1(),maxElementsPerNode); + SplitTempNode(tNode->GetChild2(),maxElementsPerNode); + } + + //! Recursively converts the temporary node data to NodeData. + unsigned int ConvertTempData( unsigned int nodeID, TempNode *tNode, unsigned int childIndex ) + { + if ( tNode->IsLeafNode() ) { + nodes[nodeID].SetLeafNode( tNode->GetBounds(), tNode->ElementCount(), tNode->ElementOffset() ); + return childIndex; + } else { + nodes[nodeID].SetInternalNode( tNode->GetBounds(), childIndex ); + unsigned int newChildIndex = ConvertTempData( childIndex, tNode->GetChild1(), childIndex+2 ); + return ConvertTempData( childIndex+1, tNode->GetChild2(), newChildIndex ); + } + } + + //! Called by the default implementation of FindSplit. + //! Splits the elements using the widest axis of the given bounding box. + unsigned int MeanSplit(unsigned int elementCount, unsigned int *nodeElements, float const *box, unsigned int maxElementsPerNode ) + { + if ( elementCount <= maxElementsPerNode ) return 0; + float d[3] = { box[3]-box[0], box[4]-box[1], box[5]-box[2] }; + unsigned int sd[3]; // split dimensions + sd[0] = d[0] >= d[1] ? ( d[0] >= d[2] ? 0 : 2 ) : ( d[1] >= d[2] ? 1 : 2 ); + sd[1] = (sd[0]+1) % 3; + sd[2] = (sd[0]+2) % 3; + if ( d[sd[1]] < d[sd[2]] ) { int t=sd[1]; sd[1]=sd[2]; sd[2]=t; } + + unsigned int child1ElemCount = 0; + for ( int s=0; s<3; s++ ) { + unsigned int splitDim = sd[s]; + float splitPos = 0.5f * ( box[splitDim] + box[splitDim+3] ); + unsigned int i=0, j=elementCount; + while ( i 0 ) { + child1ElemCount = i; + break; + } + } + + return child1ElemCount; + } + + ///////////////////////////////////////////////////////////////////////////////// +}; + +//------------------------------------------------------------------------------- + +#ifdef _CY_TRIMESH_H_INCLUDED_ + +//! Bounding Volume Hierarchy for triangular meshes (TriMesh) + +class BVHTriMesh : public BVH +{ +public: + //!@name Constructors + BVHTriMesh() : mesh(0) {} + BVHTriMesh( TriMesh const *m ) { SetMesh(m); } + + //! Sets the mesh pointer and builds the BVH structure. + void SetMesh( TriMesh const *m, unsigned int maxElementsPerNode=CY_BVH_MAX_ELEMENT_COUNT ) + { + mesh = m; + Clear(); + Build(mesh->NF(),maxElementsPerNode); + } + +protected: + //! Sets box as the i^th element's bounding box. + virtual void GetElementBounds(unsigned int i, float box[6]) const + { + TriMesh::TriFace const &f = mesh->F(i); + cyVec3f p = mesh->V( f.v[0] ); + box[0]=box[3]=p.x; box[1]=box[4]=p.y; box[2]=box[5]=p.z; + for ( int j=1; j<3; j++ ) { // for each triangle + cyVec3f p = mesh->V( f.v[j] ); + for ( int k=0; k<3; k++ ) { // for each dimension + if ( box[k] > p[k] ) box[k] = p[k]; + if ( box[k+3] < p[k] ) box[k+3] = p[k]; + } + } + } + + //! Returns the center of the i^th element in the given dimension. + virtual float GetElementCenter(unsigned int i, int dim) const + { + TriMesh::TriFace const &f = mesh->F(i); + return ( mesh->V(f.v[0])[dim] + mesh->V(f.v[1])[dim] + mesh->V(f.v[2])[dim] ) / 3.0f; + } + +private: + TriMesh const *mesh; +}; + +#endif + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::BVH cyBVH; //!< Bounding Volume Hierarchy class + +#ifdef _CY_TRIMESH_H_INCLUDED_ +typedef cy::BVHTriMesh cyBVHTriMesh; //!< BVH hierarchy for triangular meshes (TriMesh) +#endif + +//------------------------------------------------------------------------------- + +#endif + diff --git a/cyColor.h b/include/cyColor.h similarity index 98% rename from cyColor.h rename to include/cyColor.h index 82392a6..4dae6ae 100644 --- a/cyColor.h +++ b/include/cyColor.h @@ -1,354 +1,354 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyColor.h -//! \author Cem Yuksel -//! -//! \brief Color classes. -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_COLOR_H_INCLUDED_ -#define _CY_COLOR_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyCore.h" - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -class ColorA; -class Color24; -class Color32; - -//------------------------------------------------------------------------------- - -//! RGB color class with 3 float components - -class Color -{ - friend Color operator+( float const& v, Color const &c ) { return c+v; } //!< Addition with a constant - friend Color operator-( float const& v, Color const &c ) { return -(c-v); } //!< Subtraction from a constant - friend Color operator*( float const& v, Color const &c ) { return c*v; } //!< Multiplication with a constant - -public: - - //!@name Color components - float r, g, b; - - //!@name Constructors - Color() CY_CLASS_FUNCTION_DEFAULT - Color( Color const &c ) : r(c.r), g(c.g), b(c.b) {} - explicit Color( float _r, float _g, float _b ) : r(_r), g(_g), b(_b) {} - explicit Color( float const *c ) : r(c[0]), g(c[1]), b(c[2]) {} - explicit Color( float rgb ) : r(rgb), g(rgb), b(rgb) {} - explicit Color( ColorA const &c ); - explicit Color( Color24 const &c ); - explicit Color( Color32 const &c ); - - //!@name Set & Get value functions - void SetBlack() { r=0.0f; g=0.0f; b=0.0f; } //!< Sets r, g and b components as zero - void SetWhite() { r=1.0f; g=1.0f; b=1.0f; } //!< Sets r, g and b components as one - void Set ( float _r, float _g, float _b ) { r=_r; g=_g; b=_b; } //!< Sets r, g and b components as given - void Set ( float const *v ) { r=v[0]; g=v[1]; b=v[2]; } //!< Sets r, g and b components using the values in the given array - void GetValue( float *v ) const { v[0]=r; v[1]=g; v[2]=b; } //!< Puts r, g and b values into the array - - //!@name Gray-scale functions - float Sum () const { return r + g + b; } - float Gray () const { return Sum() / 3.0f; } - float Luma1 () const { return 0.299f *r + 0.587f *g + 0.114f *b; } - float Luma2 () const { return 0.2126f*r + 0.7152f*g + 0.0722f*b; } - bool IsBlack() const { return r==0.0f && g==0.0f && b==0.0f; } //!< Returns true if all components are exactly zero - float Min () const { return rg ? (r>b ? r : b) : (g>b ? g : b); } - - //!@name Limit functions - void Clamp ( float limitMin=0.0f, float limitMax=1.0f ) { ClampMin(limitMin); ClampMax(limitMax); } - void ClampMin( float limitMin=0.0f ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); } - void ClampMax( float limitMax=1.0f ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); } - void Abs() { r = std::abs(r); g = std::abs(g); b = std::abs(b); } - - //!@name Unary operators - Color operator - () const { return Color(-r,-g,-b); } - - //!@name Binary operators - Color operator + ( Color const &c ) const { return Color(r+c.r, g+c.g, b+c.b); } - Color operator - ( Color const &c ) const { return Color(r-c.r, g-c.g, b-c.b); } - Color operator * ( Color const &c ) const { return Color(r*c.r, g*c.g, b*c.b); } - Color operator / ( Color const &c ) const { return Color(r/c.r, g/c.g, b/c.b); } - Color operator + ( float const &n ) const { return Color(r+n, g+n, b+n); } - Color operator - ( float const &n ) const { return Color(r-n, g-n, b-n); } - Color operator * ( float const &n ) const { return Color(r*n, g*n, b*n); } - Color operator / ( float const &n ) const { return Color(r/n, g/n, b/n); } - - //!@name Assignment operators - Color& operator += ( Color const &c ) { r+=c.r; g+=c.g; b+=c.b; return *this; } - Color& operator -= ( Color const &c ) { r-=c.r; g-=c.g; b-=c.b; return *this; } - Color& operator *= ( Color const &c ) { r*=c.r; g*=c.g; b*=c.b; return *this; } - Color& operator /= ( Color const &c ) { r/=c.r; g/=c.g; b/=c.b; return *this; } - Color& operator += ( float const &n ) { r+=n; g+=n; b+=n; return *this; } - Color& operator -= ( float const &n ) { r-=n; g-=n; b-=n; return *this; } - Color& operator *= ( float const &n ) { r*=n; g*=n; b*=n; return *this; } - Color& operator /= ( float const &n ) { r/=n; g/=n; b/=n; return *this; } - - //!@name Test operators - bool operator == ( Color const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) ); } - bool operator != ( Color const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) ); } - - //!@name Access operators - float& operator [] ( int i ) { return (&r)[i]; } - float operator [] ( int i ) const { return (&r)[i]; } - - //!@name Static Methods - static Color Black() { return Color(0.0f,0.0f,0.0f); } //!< Returns a black color - static Color White() { return Color(1.0f,1.0f,1.0f); } //!< Returns a white color -}; - -//------------------------------------------------------------------------------- - -//! RGBA color class with 4 float components - -class ColorA -{ - friend ColorA operator + ( float const &v, ColorA const &c ) { return c+v; } //!< Addition with a constant - friend ColorA operator - ( float const &v, ColorA const &c ) { return -(c-v); } //!< Subtraction from a constant - friend ColorA operator * ( float const &v, ColorA const &c ) { return c*v; } //!< Multiplication with a constant - -public: - - //!@name Color components - float r, g, b, a; - - //!@name Constructors - ColorA() CY_CLASS_FUNCTION_DEFAULT - ColorA( ColorA const &c ) : r(c.r), g(c.g), b(c.b), a(c.a) {} - explicit ColorA( float _r, float _g, float _b, float _a=1 ) : r(_r), g(_g), b(_b), a(_a) {} - explicit ColorA( float const *c ) : r(c[0]), g(c[1]), b(c[2]), a(c[3]) {} - explicit ColorA( float rgb, float _a=1 ) : r(rgb), g(rgb), b(rgb), a(_a) {} - explicit ColorA( Color const &c, float _a=1 ) : r(c.r), g(c.g), b(c.b), a(_a) {} - explicit ColorA( Color24 const &c, float _a=1 ); - explicit ColorA( Color32 const &c ); - - //!@name Set & Get value functions - void SetBlack( float alpha=1.0f ) { r=0.0f; g=0.0f; b=0.0f; a=alpha; } //!< Sets r, g, and b components as zero and a component as given - void SetWhite( float alpha=1.0f ) { r=0.0f; g=0.0f; b=0.0f; a=alpha; } //!< Sets r, g, and b components as one and a component as given - void Set ( float _r, float _g, float _b, float _a=1 ) { r=_r; g=_g; b=_b; a=_a; } //!< Sets r, g, b and a components as given - void Set ( float const *v ) { r=v[0]; g=v[1]; b=v[2]; a=v[3]; } //!< Sets r, g, b and a components using the values in the given array - void GetValue( float *v ) const { v[0]=r; v[1]=g; v[2]=b; v[3]=a; } //!< Puts r, g, b and a values into the array - - //!@name Gray-scale functions - float Sum () const { return r + g + b; } - float Gray () const { return Sum() / 3.0f; } - float Luma1 () const { return 0.299f *r + 0.587f *g + 0.114f *b; } - float Luma2 () const { return 0.2126f*r + 0.7152f*g + 0.0722f*b; } - bool IsBlack() const { return r==0.0f && g==0.0f && b==0.0f; } //!< Returns true if the r, g, and b components are exactly zero - float Min () const { float mrg = rg ? r : g; float mba = b>a ? b : a; return mrg>mba ? mrg : mba; } - - //!@name Limit functions - void Clamp ( float limitMin=0.0f, float limitMax=1.0f ) { ClampMin(limitMin); ClampMax(limitMax); } - void ClampMin( float limitMin=0.0f ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); a=cy::Max(a,limitMin); } - void ClampMax( float limitMax=1.0f ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); a=cy::Min(a,limitMax); } - void Abs() { r = std::abs(r); g = std::abs(g); b = std::abs(b); a = std::abs(a); } - - //!@name Unary operators - ColorA operator - () const { return ColorA(-r,-g,-b,-a); } - - //!@name Binary operators - ColorA operator + ( ColorA const &c ) const { return ColorA(r+c.r, g+c.g, b+c.b, a+c.a); } - ColorA operator - ( ColorA const &c ) const { return ColorA(r-c.r, g-c.g, b-c.b, a-c.a); } - ColorA operator * ( ColorA const &c ) const { return ColorA(r*c.r, g*c.g, b*c.b, a*c.a); } - ColorA operator / ( ColorA const &c ) const { return ColorA(r/c.r, g/c.g, b/c.b, a/c.a); } - ColorA operator + ( float const &n ) const { return ColorA(r+n, g+n, b+n, a+n); } - ColorA operator - ( float const &n ) const { return ColorA(r-n, g-n, b-n, a-n); } - ColorA operator * ( float const &n ) const { return ColorA(r*n, g*n, b*n, a*n); } - ColorA operator / ( float const &n ) const { return ColorA(r/n, g/n, b/n, a/n); } - - //!@name Assignment operators - ColorA& operator += ( ColorA const &c ) { r+=c.r; g+=c.g; b+=c.b; a+=c.a; return *this; } - ColorA& operator -= ( ColorA const &c ) { r-=c.r; g-=c.g; b-=c.b; a-=c.a; return *this; } - ColorA& operator *= ( ColorA const &c ) { r*=c.r; g*=c.g; b*=c.b; a*=c.a; return *this; } - ColorA& operator /= ( ColorA const &c ) { r/=c.r; g/=c.g; b/=c.b; a/=c.a; return *this; } - ColorA& operator += ( float const &n ) { r+=n; g+=n; b+=n; a+=n; return *this; } - ColorA& operator -= ( float const &n ) { r-=n; g-=n; b-=n; a-=n; return *this; } - ColorA& operator *= ( float const &n ) { r*=n; g*=n; b*=n; a*=n; return *this; } - ColorA& operator /= ( float const &n ) { r/=n; g/=n; b/=n; a/=n; return *this; } - - //!@name Test operators - bool operator == ( ColorA const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) && (c.a==a) ); } - bool operator != ( ColorA const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) || (c.a!=a) ); } - - //!@name Access operators - float& operator [] ( int i ) { return (&r)[i]; } - float operator [] ( int i ) const { return (&r)[i]; } - - //!@name Static Methods - static ColorA Black( float alpha=1.0f ) { return ColorA(0.0f,0.0f,0.0f,alpha); } //!< Returns a black color - static ColorA White( float alpha=1.0f ) { return ColorA(1.0f,1.0f,1.0f,alpha); } //!< Returns a white color -}; - -//------------------------------------------------------------------------------- - -//! 24-bit RGB color class with 3 unsigned byte components - -class Color24 -{ -public: - - //!@name Color components - uint8_t r, g, b; - - //!@name Constructors - Color24() CY_CLASS_FUNCTION_DEFAULT - Color24( Color24 const &c ) : r(c.r), g(c.g), b(c.b) {} - explicit Color24( uint8_t _r, uint8_t _g, uint8_t _b ) : r(_r), g(_g), b(_b) {} - explicit Color24( Color const &c ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); } - explicit Color24( ColorA const &c ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); } - explicit Color24( Color32 const &c ); - - //!@name Conversion Methods - Color ToColor () const { return Color (r/255.0f,g/255.0f,b/255.0f); } - ColorA ToColorA() const { return ColorA(r/255.0f,g/255.0f,b/255.0f,1.0f); } - - //!@name Set & Get value functions - void SetBlack() { r= 0; g= 0; b= 0; } //!< Sets r, g, and b components as zero - void SetWhite() { r=255; g=255; b=255; } //!< Sets r, g, and b components as 255 - void Set ( uint8_t _r, uint8_t _g, uint8_t _b ) { r=_r; g=_g; b=_b; } //!< Sets r, g, and b components as given - void Set ( uint8_t const *v ) { r=v[0]; g=v[1]; b=v[2]; } //!< Sets r, g, and b components using the values in the given array - void GetValue( uint8_t *v ) const { v[0]=r; v[1]=g; v[2]=b; } //!< Puts r, g, and b values into the array - - //!@name Gray-scale functions - int Sum () const { return int(r) + int(g) + int(b); } - uint8_t Gray () const { return uint8_t( (Sum()+1) / 3 ); } - bool IsBlack() const { return r==0 && g==0 && b==0; } //!< Returns true if all components are exactly zero - uint8_t Min () const { return rg ? (r>b ? r : b) : (g>b ? g : b); } - - //!@name Limit functions - void Clamp ( uint8_t limitMin= 0, uint8_t limitMax=255 ) { ClampMin(limitMin); ClampMax(limitMax); } - void ClampMin( uint8_t limitMin= 0 ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); } - void ClampMax( uint8_t limitMax=255 ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); } - - //!@name Test operators - bool operator == ( Color24 const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) ); } - bool operator != ( Color24 const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) ); } - - //!@name Access operators - uint8_t& operator [] ( int i ) { return (&r)[i]; } - uint8_t operator [] ( int i ) const { return (&r)[i]; } - - //!@name Static Methods - static Color24 Black() { return Color24( 0, 0, 0); } //!< Returns a black color - static Color24 White() { return Color24(255,255,255); } //!< Returns a white color - -protected: - static uint8_t FloatToByte(float r) { return ClampInt(int(r*255+0.5f)); } - static uint8_t ClampInt(int v) { return v<0 ? 0 : (v>255 ? 255 : v); } -}; - -//------------------------------------------------------------------------------- - -//! 32-bit RGBA color class with 4 unsigned byte components - -class Color32 -{ -public: - - //!@name Color components - uint8_t r, g, b, a; - - //!@name Constructors - Color32() CY_CLASS_FUNCTION_DEFAULT - Color32( Color32 const &c ) : r(c.r), g(c.g), b(c.b), a(c.a) {} - explicit Color32( uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a=255 ) : r(_r), g(_g), b(_b), a(_a) {} - explicit Color32( Color const &c, float _a=1.0f ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); a=FloatToByte( _a); } - explicit Color32( ColorA const &c ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); a=FloatToByte(c.a); } - explicit Color32( Color24 const &c, uint8_t _a=255 ) : r(c.r), g(c.g), b(c.b), a(_a) {} - - //!@name Conversion Methods - Color ToColor () const { return Color (r/255.0f,g/255.0f,b/255.0f); } - ColorA ToColorA() const { return ColorA(r/255.0f,g/255.0f,b/255.0f,a/255.0f); } - - //!@name Set & Get value functions - void SetBlack( uint8_t _a=255 ) { r= 0; g= 0; b= 0; a=_a; } //!< Sets r, g, and b components as zero and a component as given - void SetWhite( uint8_t _a=255 ) { r=255; g=255; b=255; a=_a; } //!< Sets r, g, and b components as 255 and a component as given - void Set ( uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a ) { r=_r; g=_g; b=_b; a=_a; } //!< Sets r, g, b and a components as given - void Set ( uint8_t const *v ) { r=v[0]; g=v[1]; b=v[2]; a=v[3]; } //!< Sets r, g, b and a components using the values in the given array - void GetValue( uint8_t *v ) const { v[0]=r; v[1]=g; v[2]=b; v[3]=a; } //!< Puts r, g, b and a values into the array - - //!@name Gray-scale functions - int Sum () const { return int(r) + int(g) + int(b); } - uint8_t Gray () const { return uint8_t( (Sum()+1) / 3 ); } - bool IsBlack() const { return r==0 && g==0 && b==0; } //!< Returns true if the r, g, and b components are exactly zero - uint8_t Min () const { uint8_t mrg = rg ? r : g; uint8_t mba = b>a ? b : a; return mrg>mba ? mrg : mba; } - - //!@name Limit functions - void Clamp ( uint8_t limitMin= 0, uint8_t limitMax=255 ) { ClampMin(limitMin); ClampMax(limitMax); } - void ClampMin( uint8_t limitMin= 0 ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); a=cy::Max(a,limitMin); } - void ClampMax( uint8_t limitMax=255 ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); a=cy::Min(a,limitMax); } - - //!@name Test operators - bool operator == ( Color32 const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) && (c.a==a) ); } - bool operator != ( Color32 const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) || (c.a!=a) ); } - - //!@name Access operators - uint8_t& operator [] ( int i ) { return (&r)[i]; } - uint8_t operator [] ( int i ) const { return (&r)[i]; } - - //!@name Static Methods - static Color32 Black( uint8_t alpha=255 ) { return Color32( 0, 0, 0,alpha); } //!< Returns a black color - static Color32 White( uint8_t alpha=255 ) { return Color32(255,255,255,alpha); } //!< Returns a white color - -protected: - static uint8_t FloatToByte(float r) { return ClampInt(int(r*255+0.5f)); } - static uint8_t ClampInt(int v) { return v<0 ? 0 : (v>255 ? 255 : v); } -}; - -//------------------------------------------------------------------------------- - -inline Color ::Color ( ColorA const &c ) : r(c.r), g(c.g), b(c.b) {} -inline Color ::Color ( Color24 const &c ) { *this = c.ToColor(); } -inline Color ::Color ( Color32 const &c ) { *this = c.ToColor(); } -inline ColorA ::ColorA ( Color24 const &c, float alpha ) { Color rgb = c.ToColor(); r = rgb.r; g = rgb.g; b = rgb.b; a = alpha; } -inline ColorA ::ColorA ( Color32 const &c ) { *this = c.ToColorA(); } -inline Color24::Color24( Color32 const &c ) : r(c.r), g(c.g), b(c.b) {} - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::Color cyColor; //!< RGB color class with 3 float components -typedef cy::ColorA cyColorA; //!< RGBA color class with 4 float components -typedef cy::Color24 cyColor24; //!< 24-bit RGB color class with 3 unsigned byte components -typedef cy::Color32 cyColor32; //!< 32-bit RGBA color class with 4 unsigned byte components - -//------------------------------------------------------------------------------- - -#endif - +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyColor.h +//! \author Cem Yuksel +//! +//! \brief Color classes. +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_COLOR_H_INCLUDED_ +#define _CY_COLOR_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyCore.h" + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +class ColorA; +class Color24; +class Color32; + +//------------------------------------------------------------------------------- + +//! RGB color class with 3 float components + +class Color +{ + friend Color operator+( float const& v, Color const &c ) { return c+v; } //!< Addition with a constant + friend Color operator-( float const& v, Color const &c ) { return -(c-v); } //!< Subtraction from a constant + friend Color operator*( float const& v, Color const &c ) { return c*v; } //!< Multiplication with a constant + +public: + + //!@name Color components + float r, g, b; + + //!@name Constructors + Color() CY_CLASS_FUNCTION_DEFAULT + Color( Color const &c ) : r(c.r), g(c.g), b(c.b) {} + explicit Color( float _r, float _g, float _b ) : r(_r), g(_g), b(_b) {} + explicit Color( float const *c ) : r(c[0]), g(c[1]), b(c[2]) {} + explicit Color( float rgb ) : r(rgb), g(rgb), b(rgb) {} + explicit Color( ColorA const &c ); + explicit Color( Color24 const &c ); + explicit Color( Color32 const &c ); + + //!@name Set & Get value functions + void SetBlack() { r=0.0f; g=0.0f; b=0.0f; } //!< Sets r, g and b components as zero + void SetWhite() { r=1.0f; g=1.0f; b=1.0f; } //!< Sets r, g and b components as one + void Set ( float _r, float _g, float _b ) { r=_r; g=_g; b=_b; } //!< Sets r, g and b components as given + void Set ( float const *v ) { r=v[0]; g=v[1]; b=v[2]; } //!< Sets r, g and b components using the values in the given array + void GetValue( float *v ) const { v[0]=r; v[1]=g; v[2]=b; } //!< Puts r, g and b values into the array + + //!@name Gray-scale functions + float Sum () const { return r + g + b; } + float Gray () const { return Sum() / 3.0f; } + float Luma1 () const { return 0.299f *r + 0.587f *g + 0.114f *b; } + float Luma2 () const { return 0.2126f*r + 0.7152f*g + 0.0722f*b; } + bool IsBlack() const { return r==0.0f && g==0.0f && b==0.0f; } //!< Returns true if all components are exactly zero + float Min () const { return rg ? (r>b ? r : b) : (g>b ? g : b); } + + //!@name Limit functions + void Clamp ( float limitMin=0.0f, float limitMax=1.0f ) { ClampMin(limitMin); ClampMax(limitMax); } + void ClampMin( float limitMin=0.0f ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); } + void ClampMax( float limitMax=1.0f ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); } + void Abs() { r = std::abs(r); g = std::abs(g); b = std::abs(b); } + + //!@name Unary operators + Color operator - () const { return Color(-r,-g,-b); } + + //!@name Binary operators + Color operator + ( Color const &c ) const { return Color(r+c.r, g+c.g, b+c.b); } + Color operator - ( Color const &c ) const { return Color(r-c.r, g-c.g, b-c.b); } + Color operator * ( Color const &c ) const { return Color(r*c.r, g*c.g, b*c.b); } + Color operator / ( Color const &c ) const { return Color(r/c.r, g/c.g, b/c.b); } + Color operator + ( float const &n ) const { return Color(r+n, g+n, b+n); } + Color operator - ( float const &n ) const { return Color(r-n, g-n, b-n); } + Color operator * ( float const &n ) const { return Color(r*n, g*n, b*n); } + Color operator / ( float const &n ) const { return Color(r/n, g/n, b/n); } + + //!@name Assignment operators + Color& operator += ( Color const &c ) { r+=c.r; g+=c.g; b+=c.b; return *this; } + Color& operator -= ( Color const &c ) { r-=c.r; g-=c.g; b-=c.b; return *this; } + Color& operator *= ( Color const &c ) { r*=c.r; g*=c.g; b*=c.b; return *this; } + Color& operator /= ( Color const &c ) { r/=c.r; g/=c.g; b/=c.b; return *this; } + Color& operator += ( float const &n ) { r+=n; g+=n; b+=n; return *this; } + Color& operator -= ( float const &n ) { r-=n; g-=n; b-=n; return *this; } + Color& operator *= ( float const &n ) { r*=n; g*=n; b*=n; return *this; } + Color& operator /= ( float const &n ) { r/=n; g/=n; b/=n; return *this; } + + //!@name Test operators + bool operator == ( Color const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) ); } + bool operator != ( Color const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) ); } + + //!@name Access operators + float& operator [] ( int i ) { return (&r)[i]; } + float operator [] ( int i ) const { return (&r)[i]; } + + //!@name Static Methods + static Color Black() { return Color(0.0f,0.0f,0.0f); } //!< Returns a black color + static Color White() { return Color(1.0f,1.0f,1.0f); } //!< Returns a white color +}; + +//------------------------------------------------------------------------------- + +//! RGBA color class with 4 float components + +class ColorA +{ + friend ColorA operator + ( float const &v, ColorA const &c ) { return c+v; } //!< Addition with a constant + friend ColorA operator - ( float const &v, ColorA const &c ) { return -(c-v); } //!< Subtraction from a constant + friend ColorA operator * ( float const &v, ColorA const &c ) { return c*v; } //!< Multiplication with a constant + +public: + + //!@name Color components + float r, g, b, a; + + //!@name Constructors + ColorA() CY_CLASS_FUNCTION_DEFAULT + ColorA( ColorA const &c ) : r(c.r), g(c.g), b(c.b), a(c.a) {} + explicit ColorA( float _r, float _g, float _b, float _a=1 ) : r(_r), g(_g), b(_b), a(_a) {} + explicit ColorA( float const *c ) : r(c[0]), g(c[1]), b(c[2]), a(c[3]) {} + explicit ColorA( float rgb, float _a=1 ) : r(rgb), g(rgb), b(rgb), a(_a) {} + explicit ColorA( Color const &c, float _a=1 ) : r(c.r), g(c.g), b(c.b), a(_a) {} + explicit ColorA( Color24 const &c, float _a=1 ); + explicit ColorA( Color32 const &c ); + + //!@name Set & Get value functions + void SetBlack( float alpha=1.0f ) { r=0.0f; g=0.0f; b=0.0f; a=alpha; } //!< Sets r, g, and b components as zero and a component as given + void SetWhite( float alpha=1.0f ) { r=0.0f; g=0.0f; b=0.0f; a=alpha; } //!< Sets r, g, and b components as one and a component as given + void Set ( float _r, float _g, float _b, float _a=1 ) { r=_r; g=_g; b=_b; a=_a; } //!< Sets r, g, b and a components as given + void Set ( float const *v ) { r=v[0]; g=v[1]; b=v[2]; a=v[3]; } //!< Sets r, g, b and a components using the values in the given array + void GetValue( float *v ) const { v[0]=r; v[1]=g; v[2]=b; v[3]=a; } //!< Puts r, g, b and a values into the array + + //!@name Gray-scale functions + float Sum () const { return r + g + b; } + float Gray () const { return Sum() / 3.0f; } + float Luma1 () const { return 0.299f *r + 0.587f *g + 0.114f *b; } + float Luma2 () const { return 0.2126f*r + 0.7152f*g + 0.0722f*b; } + bool IsBlack() const { return r==0.0f && g==0.0f && b==0.0f; } //!< Returns true if the r, g, and b components are exactly zero + float Min () const { float mrg = rg ? r : g; float mba = b>a ? b : a; return mrg>mba ? mrg : mba; } + + //!@name Limit functions + void Clamp ( float limitMin=0.0f, float limitMax=1.0f ) { ClampMin(limitMin); ClampMax(limitMax); } + void ClampMin( float limitMin=0.0f ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); a=cy::Max(a,limitMin); } + void ClampMax( float limitMax=1.0f ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); a=cy::Min(a,limitMax); } + void Abs() { r = std::abs(r); g = std::abs(g); b = std::abs(b); a = std::abs(a); } + + //!@name Unary operators + ColorA operator - () const { return ColorA(-r,-g,-b,-a); } + + //!@name Binary operators + ColorA operator + ( ColorA const &c ) const { return ColorA(r+c.r, g+c.g, b+c.b, a+c.a); } + ColorA operator - ( ColorA const &c ) const { return ColorA(r-c.r, g-c.g, b-c.b, a-c.a); } + ColorA operator * ( ColorA const &c ) const { return ColorA(r*c.r, g*c.g, b*c.b, a*c.a); } + ColorA operator / ( ColorA const &c ) const { return ColorA(r/c.r, g/c.g, b/c.b, a/c.a); } + ColorA operator + ( float const &n ) const { return ColorA(r+n, g+n, b+n, a+n); } + ColorA operator - ( float const &n ) const { return ColorA(r-n, g-n, b-n, a-n); } + ColorA operator * ( float const &n ) const { return ColorA(r*n, g*n, b*n, a*n); } + ColorA operator / ( float const &n ) const { return ColorA(r/n, g/n, b/n, a/n); } + + //!@name Assignment operators + ColorA& operator += ( ColorA const &c ) { r+=c.r; g+=c.g; b+=c.b; a+=c.a; return *this; } + ColorA& operator -= ( ColorA const &c ) { r-=c.r; g-=c.g; b-=c.b; a-=c.a; return *this; } + ColorA& operator *= ( ColorA const &c ) { r*=c.r; g*=c.g; b*=c.b; a*=c.a; return *this; } + ColorA& operator /= ( ColorA const &c ) { r/=c.r; g/=c.g; b/=c.b; a/=c.a; return *this; } + ColorA& operator += ( float const &n ) { r+=n; g+=n; b+=n; a+=n; return *this; } + ColorA& operator -= ( float const &n ) { r-=n; g-=n; b-=n; a-=n; return *this; } + ColorA& operator *= ( float const &n ) { r*=n; g*=n; b*=n; a*=n; return *this; } + ColorA& operator /= ( float const &n ) { r/=n; g/=n; b/=n; a/=n; return *this; } + + //!@name Test operators + bool operator == ( ColorA const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) && (c.a==a) ); } + bool operator != ( ColorA const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) || (c.a!=a) ); } + + //!@name Access operators + float& operator [] ( int i ) { return (&r)[i]; } + float operator [] ( int i ) const { return (&r)[i]; } + + //!@name Static Methods + static ColorA Black( float alpha=1.0f ) { return ColorA(0.0f,0.0f,0.0f,alpha); } //!< Returns a black color + static ColorA White( float alpha=1.0f ) { return ColorA(1.0f,1.0f,1.0f,alpha); } //!< Returns a white color +}; + +//------------------------------------------------------------------------------- + +//! 24-bit RGB color class with 3 unsigned byte components + +class Color24 +{ +public: + + //!@name Color components + uint8_t r, g, b; + + //!@name Constructors + Color24() CY_CLASS_FUNCTION_DEFAULT + Color24( Color24 const &c ) : r(c.r), g(c.g), b(c.b) {} + explicit Color24( uint8_t _r, uint8_t _g, uint8_t _b ) : r(_r), g(_g), b(_b) {} + explicit Color24( Color const &c ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); } + explicit Color24( ColorA const &c ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); } + explicit Color24( Color32 const &c ); + + //!@name Conversion Methods + Color ToColor () const { return Color (r/255.0f,g/255.0f,b/255.0f); } + ColorA ToColorA() const { return ColorA(r/255.0f,g/255.0f,b/255.0f,1.0f); } + + //!@name Set & Get value functions + void SetBlack() { r= 0; g= 0; b= 0; } //!< Sets r, g, and b components as zero + void SetWhite() { r=255; g=255; b=255; } //!< Sets r, g, and b components as 255 + void Set ( uint8_t _r, uint8_t _g, uint8_t _b ) { r=_r; g=_g; b=_b; } //!< Sets r, g, and b components as given + void Set ( uint8_t const *v ) { r=v[0]; g=v[1]; b=v[2]; } //!< Sets r, g, and b components using the values in the given array + void GetValue( uint8_t *v ) const { v[0]=r; v[1]=g; v[2]=b; } //!< Puts r, g, and b values into the array + + //!@name Gray-scale functions + int Sum () const { return int(r) + int(g) + int(b); } + uint8_t Gray () const { return uint8_t( (Sum()+1) / 3 ); } + bool IsBlack() const { return r==0 && g==0 && b==0; } //!< Returns true if all components are exactly zero + uint8_t Min () const { return rg ? (r>b ? r : b) : (g>b ? g : b); } + + //!@name Limit functions + void Clamp ( uint8_t limitMin= 0, uint8_t limitMax=255 ) { ClampMin(limitMin); ClampMax(limitMax); } + void ClampMin( uint8_t limitMin= 0 ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); } + void ClampMax( uint8_t limitMax=255 ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); } + + //!@name Test operators + bool operator == ( Color24 const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) ); } + bool operator != ( Color24 const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) ); } + + //!@name Access operators + uint8_t& operator [] ( int i ) { return (&r)[i]; } + uint8_t operator [] ( int i ) const { return (&r)[i]; } + + //!@name Static Methods + static Color24 Black() { return Color24( 0, 0, 0); } //!< Returns a black color + static Color24 White() { return Color24(255,255,255); } //!< Returns a white color + +protected: + static uint8_t FloatToByte(float r) { return ClampInt(int(r*255+0.5f)); } + static uint8_t ClampInt(int v) { return v<0 ? 0 : (v>255 ? 255 : v); } +}; + +//------------------------------------------------------------------------------- + +//! 32-bit RGBA color class with 4 unsigned byte components + +class Color32 +{ +public: + + //!@name Color components + uint8_t r, g, b, a; + + //!@name Constructors + Color32() CY_CLASS_FUNCTION_DEFAULT + Color32( Color32 const &c ) : r(c.r), g(c.g), b(c.b), a(c.a) {} + explicit Color32( uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a=255 ) : r(_r), g(_g), b(_b), a(_a) {} + explicit Color32( Color const &c, float _a=1.0f ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); a=FloatToByte( _a); } + explicit Color32( ColorA const &c ) { r=FloatToByte(c.r); g=FloatToByte(c.g); b=FloatToByte(c.b); a=FloatToByte(c.a); } + explicit Color32( Color24 const &c, uint8_t _a=255 ) : r(c.r), g(c.g), b(c.b), a(_a) {} + + //!@name Conversion Methods + Color ToColor () const { return Color (r/255.0f,g/255.0f,b/255.0f); } + ColorA ToColorA() const { return ColorA(r/255.0f,g/255.0f,b/255.0f,a/255.0f); } + + //!@name Set & Get value functions + void SetBlack( uint8_t _a=255 ) { r= 0; g= 0; b= 0; a=_a; } //!< Sets r, g, and b components as zero and a component as given + void SetWhite( uint8_t _a=255 ) { r=255; g=255; b=255; a=_a; } //!< Sets r, g, and b components as 255 and a component as given + void Set ( uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a ) { r=_r; g=_g; b=_b; a=_a; } //!< Sets r, g, b and a components as given + void Set ( uint8_t const *v ) { r=v[0]; g=v[1]; b=v[2]; a=v[3]; } //!< Sets r, g, b and a components using the values in the given array + void GetValue( uint8_t *v ) const { v[0]=r; v[1]=g; v[2]=b; v[3]=a; } //!< Puts r, g, b and a values into the array + + //!@name Gray-scale functions + int Sum () const { return int(r) + int(g) + int(b); } + uint8_t Gray () const { return uint8_t( (Sum()+1) / 3 ); } + bool IsBlack() const { return r==0 && g==0 && b==0; } //!< Returns true if the r, g, and b components are exactly zero + uint8_t Min () const { uint8_t mrg = rg ? r : g; uint8_t mba = b>a ? b : a; return mrg>mba ? mrg : mba; } + + //!@name Limit functions + void Clamp ( uint8_t limitMin= 0, uint8_t limitMax=255 ) { ClampMin(limitMin); ClampMax(limitMax); } + void ClampMin( uint8_t limitMin= 0 ) { r=cy::Max(r,limitMin); g=cy::Max(g,limitMin); b=cy::Max(b,limitMin); a=cy::Max(a,limitMin); } + void ClampMax( uint8_t limitMax=255 ) { r=cy::Min(r,limitMax); g=cy::Min(g,limitMax); b=cy::Min(b,limitMax); a=cy::Min(a,limitMax); } + + //!@name Test operators + bool operator == ( Color32 const &c ) const { return ( (c.r==r) && (c.g==g) && (c.b==b) && (c.a==a) ); } + bool operator != ( Color32 const &c ) const { return ( (c.r!=r) || (c.g!=g) || (c.b!=b) || (c.a!=a) ); } + + //!@name Access operators + uint8_t& operator [] ( int i ) { return (&r)[i]; } + uint8_t operator [] ( int i ) const { return (&r)[i]; } + + //!@name Static Methods + static Color32 Black( uint8_t alpha=255 ) { return Color32( 0, 0, 0,alpha); } //!< Returns a black color + static Color32 White( uint8_t alpha=255 ) { return Color32(255,255,255,alpha); } //!< Returns a white color + +protected: + static uint8_t FloatToByte(float r) { return ClampInt(int(r*255+0.5f)); } + static uint8_t ClampInt(int v) { return v<0 ? 0 : (v>255 ? 255 : v); } +}; + +//------------------------------------------------------------------------------- + +inline Color ::Color ( ColorA const &c ) : r(c.r), g(c.g), b(c.b) {} +inline Color ::Color ( Color24 const &c ) { *this = c.ToColor(); } +inline Color ::Color ( Color32 const &c ) { *this = c.ToColor(); } +inline ColorA ::ColorA ( Color24 const &c, float alpha ) { Color rgb = c.ToColor(); r = rgb.r; g = rgb.g; b = rgb.b; a = alpha; } +inline ColorA ::ColorA ( Color32 const &c ) { *this = c.ToColorA(); } +inline Color24::Color24( Color32 const &c ) : r(c.r), g(c.g), b(c.b) {} + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::Color cyColor; //!< RGB color class with 3 float components +typedef cy::ColorA cyColorA; //!< RGBA color class with 4 float components +typedef cy::Color24 cyColor24; //!< 24-bit RGB color class with 3 unsigned byte components +typedef cy::Color32 cyColor32; //!< 32-bit RGBA color class with 4 unsigned byte components + +//------------------------------------------------------------------------------- + +#endif + diff --git a/cyCore.h b/include/cyCore.h similarity index 100% rename from cyCore.h rename to include/cyCore.h diff --git a/cyGL.h b/include/cyGL.h similarity index 100% rename from cyGL.h rename to include/cyGL.h diff --git a/cyHairFile.h b/include/cyHairFile.h similarity index 97% rename from cyHairFile.h rename to include/cyHairFile.h index 5027cd1..112d234 100644 --- a/cyHairFile.h +++ b/include/cyHairFile.h @@ -1,420 +1,420 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyHairFile.h -//! \author Cem Yuksel -//! -//! \brief A class for the HAIR file type -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_HAIR_FILE_H_INCLUDED_ -#define _CY_HAIR_FILE_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyCore.h" - -//------------------------------------------------------------------------------- - -_CY_CRT_SECURE_NO_WARNINGS - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -#define _CY_HAIR_FILE_SEGMENTS_BIT 1 -#define _CY_HAIR_FILE_POINTS_BIT 2 -#define _CY_HAIR_FILE_THICKNESS_BIT 4 -#define _CY_HAIR_FILE_TRANSPARENCY_BIT 8 -#define _CY_HAIR_FILE_COLORS_BIT 16 - -#define _CY_HAIR_FILE_INFO_SIZE 88 - -// File read errors -#define CY_HAIR_FILE_ERROR_CANT_OPEN_FILE -1 //!< Error code cannot open file -#define CY_HAIR_FILE_ERROR_CANT_READ_HEADER -2 //!< Error code cannot read header -#define CY_HAIR_FILE_ERROR_WRONG_SIGNATURE -3 //!< Error code wrong signature -#define CY_HAIR_FILE_ERROR_READING_SEGMENTS -4 //!< Error code failed reading segments -#define CY_HAIR_FILE_ERROR_READING_POINTS -5 //!< Error code failed reading points -#define CY_HAIR_FILE_ERROR_READING_THICKNESS -6 //!< Error code failed reading thickness -#define CY_HAIR_FILE_ERROR_READING_TRANSPARENCY -7 //!< Error code failed reading transparency -#define CY_HAIR_FILE_ERROR_READING_COLORS -8 //!< Error code failed reading colors - -//------------------------------------------------------------------------------- - -//! HAIR file class - -class HairFile -{ -public: - HairFile() : segments(nullptr), points(nullptr), thickness(nullptr), transparency(nullptr), colors(nullptr) { Initialize(); } - ~HairFile() { Initialize(); } - - //! Hair file header - struct Header - { - char signature[4]; //!< This should be "HAIR" - unsigned int hair_count; //!< number of hair strands - unsigned int point_count; //!< total number of points of all strands - unsigned int arrays; //!< bit array of data in the file - - unsigned int d_segments; //!< default number of segments of each strand - float d_thickness; //!< default thickness of hair strands - float d_transparency; //!< default transparency of hair strands - float d_color[3]; //!< default color of hair strands - - char info[_CY_HAIR_FILE_INFO_SIZE]; //!< information about the file - }; - - ////////////////////////////////////////////////////////////////////////// - //!@name Constant Data Access Methods - - Header const & GetHeader () const { return header; } //!< Use this method to access header data. - unsigned short const * GetSegmentsArray () const { return segments; } //!< Returns segments array (segment count for each hair strand). - float const * GetPointsArray () const { return points; } //!< Returns points array (xyz coordinates of each hair point). - float const * GetThicknessArray () const { return thickness; } //!< Returns thickness array (thickness at each hair point}. - float const * GetTransparencyArray() const { return transparency; } //!< Returns transparency array (transparency at each hair point). - float const * GetColorsArray () const { return colors; } //!< Returns colors array (rgb color at each hair point). - - - ////////////////////////////////////////////////////////////////////////// - //!@name Data Access Methods - - unsigned short* GetSegmentsArray () { return segments; } //!< Returns segments array (segment count for each hair strand). - float* GetPointsArray () { return points; } //!< Returns points array (xyz coordinates of each hair point). - float* GetThicknessArray () { return thickness; } //!< Returns thickness array (thickness at each hair point}. - float* GetTransparencyArray() { return transparency; } //!< Returns transparency array (transparency at each hair point). - float* GetColorsArray () { return colors; } //!< Returns colors array (rgb color at each hair point). - - - ////////////////////////////////////////////////////////////////////////// - //!@name Methods for Setting Array Sizes - - //! Deletes all arrays and initializes the header data. - void Initialize() - { - if ( segments ) delete [] segments; - if ( points ) delete [] points; - if ( colors ) delete [] colors; - if ( thickness ) delete [] thickness; - if ( transparency ) delete [] transparency; - header.signature[0] = 'H'; - header.signature[1] = 'A'; - header.signature[2] = 'I'; - header.signature[3] = 'R'; - header.hair_count = 0; - header.point_count = 0; - header.arrays = 0; // no arrays - header.d_segments = 0; - header.d_thickness = 1.0f; - header.d_transparency = 0.0f; - header.d_color[0] = 1.0f; - header.d_color[1] = 1.0f; - header.d_color[2] = 1.0f; - memset( header.info, '\0', _CY_HAIR_FILE_INFO_SIZE ); - } - - //! Sets the hair count, re-allocates segments array if necessary. - void SetHairCount( int count ) - { - header.hair_count = count; - if ( segments ) { - delete [] segments; - segments = new unsigned short[ header.hair_count ]; - } - } - - // Sets the point count, re-allocates points, thickness, transparency, and colors arrays if necessary. - void SetPointCount( int count ) - { - header.point_count = count; - if ( points ) { - delete [] points; - points = new float[ header.point_count*3 ]; - } - if ( thickness ) { - delete [] thickness; - thickness = new float[ header.point_count ]; - } - if ( transparency ) { - delete [] transparency; - transparency = new float[ header.point_count ]; - } - if ( colors ) { - delete [] colors; - colors = new float[ header.point_count*3 ]; - } - } - - //! Use this function to allocate/delete arrays. - //! Before you call this method set hair count and point count. - //! Note that a valid HAIR file should always have points array. - void SetArrays( int array_types ) - { - header.arrays = array_types; - if ( (header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) && !segments ) { segments = new unsigned short[header.hair_count]; } - if ( !(header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) && segments ) { delete [] segments; segments=nullptr; } - if ( (header.arrays & _CY_HAIR_FILE_POINTS_BIT ) && !points ) { points = new float[header.point_count*3]; } - if ( !(header.arrays & _CY_HAIR_FILE_POINTS_BIT ) && points ) { delete [] points; points=nullptr; } - if ( (header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) && !thickness ) { thickness = new float[header.point_count]; } - if ( !(header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) && thickness ) { delete [] thickness; thickness=nullptr; } - if ( (header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT) && !transparency ) { transparency = new float[header.point_count]; } - if ( !(header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT) && transparency ) { delete [] transparency; transparency=nullptr; } - if ( (header.arrays & _CY_HAIR_FILE_COLORS_BIT ) && !colors ) { colors = new float[header.point_count*3]; } - if ( !(header.arrays & _CY_HAIR_FILE_COLORS_BIT ) && colors ) { delete [] colors; colors=nullptr; } - } - - //! Sets default number of segments for all hair strands, which is used if segments array does not exist. - void SetDefaultSegmentCount( int s ) { header.d_segments = s; } - - //! Sets default hair strand thickness, which is used if thickness array does not exist. - void SetDefaultThickness( float t ) { header.d_thickness = t; } - - //! Sets default hair strand transparency, which is used if transparency array does not exist. - void SetDefaultTransparency( float t ) { header.d_transparency = t; } - - //! Sets default hair color, which is used if color array does not exist. - void SetDefaultColor( float r, float g, float b ) { header.d_color[0]=r; header.d_color[1]=g; header.d_color[2]=b; } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Load and Save Methods - - //! Loads hair data from the given HAIR file. - int LoadFromFile( char const *filename ) - { - Initialize(); - - FILE *fp; - fp = fopen( filename, "rb" ); - if ( fp == nullptr ) return CY_HAIR_FILE_ERROR_CANT_OPEN_FILE; - - // read the header - size_t headread = fread( &header, sizeof(Header), 1, fp ); - - #define _CY_FAILED_RETURN(errorno) { Initialize(); fclose( fp ); return errorno; } - - - // Check if header is correctly read - if ( headread < 1 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_CANT_READ_HEADER); - - // Check if this is a hair file - if ( strncmp( header.signature, "HAIR", 4) != 0 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_WRONG_SIGNATURE); - - // Read segments array - if ( header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) { - segments = new unsigned short[ header.hair_count ]; - size_t readcount = fread( segments, sizeof(unsigned short), header.hair_count, fp ); - if ( readcount < header.hair_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_SEGMENTS); - } - - // Read points array - if ( header.arrays & _CY_HAIR_FILE_POINTS_BIT ) { - points = new float[ header.point_count*3 ]; - size_t readcount = fread( points, sizeof(float), header.point_count*3, fp ); - if ( readcount < header.point_count*3 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_POINTS); - } - - // Read thickness array - if ( header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) { - thickness = new float[ header.point_count ]; - size_t readcount = fread( thickness, sizeof(float), header.point_count, fp ); - if ( readcount < header.point_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_THICKNESS); - } - - // Read thickness array - if ( header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT ) { - transparency = new float[ header.point_count ]; - size_t readcount = fread( transparency, sizeof(float), header.point_count, fp ); - if ( readcount < header.point_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_TRANSPARENCY); - } - - // Read colors array - if ( header.arrays & _CY_HAIR_FILE_COLORS_BIT ) { - colors = new float[ header.point_count*3 ]; - size_t readcount = fread( colors, sizeof(float), header.point_count*3, fp ); - if ( readcount < header.point_count*3 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_COLORS); - } - - fclose( fp ); - - return header.hair_count; - } - - //! Saves hair data to the given HAIR file. - int SaveToFile( char const *filename ) const - { - FILE *fp; - fp = fopen( filename, "wb" ); - if ( fp == nullptr ) return -1; - - // Write header - fwrite( &header, sizeof(Header), 1, fp ); - - // Write arrays - if ( header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) fwrite( segments, sizeof(unsigned short), header.hair_count, fp ); - if ( header.arrays & _CY_HAIR_FILE_POINTS_BIT ) fwrite( points, sizeof(float), header.point_count*3, fp ); - if ( header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) fwrite( thickness, sizeof(float), header.point_count, fp ); - if ( header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT ) fwrite( transparency, sizeof(float), header.point_count, fp ); - if ( header.arrays & _CY_HAIR_FILE_COLORS_BIT ) fwrite( colors, sizeof(float), header.point_count*3, fp ); - - fclose( fp ); - - return header.hair_count; - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Other Methods - - //! Fills the given direction array with normalized directions using the points array. - //! Call this function if you need strand directions for shading. - //! The given array dir should be allocated as an array of size 3 times point count. - //! Returns point count, returns zero if fails. - int FillDirectionArray( float *dir ) - { - if ( dir==nullptr || header.point_count<=0 || points==nullptr ) return 0; - - int p = 0; // point index - for ( unsigned int i=0; i 1 ) { - // direction at point1 - float len0, len1; - ComputeDirection( &dir[(p+1)*3], len0, len1, &points[p*3], &points[(p+1)*3], &points[(p+2)*3] ); - - // direction at point0 - float d0[3]; - d0[0] = points[(p+1)*3] - dir[(p+1)*3] *len0*0.3333f - points[p*3]; - d0[1] = points[(p+1)*3+1] - dir[(p+1)*3+1]*len0*0.3333f - points[p*3+1]; - d0[2] = points[(p+1)*3+2] - dir[(p+1)*3+2]*len0*0.3333f - points[p*3+2]; - float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2]; - float d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f; - dir[p*3] = d0[0] / d0len; - dir[p*3+1] = d0[1] / d0len; - dir[p*3+2] = d0[2] / d0len; - - // We computed the first 2 points - p += 2; - - // Compute the direction for the rest - for ( int t=2; t 0 ) ? (float) sqrt(d0lensq) : 1.0f; - dir[p*3] = d0[0] / d0len; - dir[p*3+1] = d0[1] / d0len; - dir[p*3+2] = d0[2] / d0len; - p++; - - } else if ( s > 0 ) { - // if it has a single segment - float d0[3]; - d0[0] = points[(p+1)*3] - points[p*3]; - d0[1] = points[(p+1)*3+1] - points[p*3+1]; - d0[2] = points[(p+1)*3+2] - points[p*3+2]; - float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2]; - float d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f; - dir[p*3] = d0[0] / d0len; - dir[p*3+1] = d0[1] / d0len; - dir[p*3+2] = d0[2] / d0len; - dir[(p+1)*3] = dir[p*3]; - dir[(p+1)*3+1] = dir[p*3+1]; - dir[(p+1)*3+2] = dir[p*3+2]; - p += 2; - } - //*/ - } - return p; - } - - -private: - ////////////////////////////////////////////////////////////////////////// - //!@name Private Variables and Methods - - Header header; - unsigned short *segments; - float *points; - float *thickness; - float *transparency; - float *colors; - - // Given point before (p0) and after (p2), computes the direction (d) at p1. - float ComputeDirection( float *d, float &d0len, float &d1len, float const *p0, float const *p1, float const *p2 ) - { - // line from p0 to p1 - float d0[3]; - d0[0] = p1[0] - p0[0]; - d0[1] = p1[1] - p0[1]; - d0[2] = p1[2] - p0[2]; - float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2]; - d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f; - - // line from p1 to p2 - float d1[3]; - d1[0] = p2[0] - p1[0]; - d1[1] = p2[1] - p1[1]; - d1[2] = p2[2] - p1[2]; - float d1lensq = d1[0]*d1[0] + d1[1]*d1[1] + d1[2]*d1[2]; - d1len = ( d1lensq > 0 ) ? (float) sqrt(d1lensq) : 1.0f; - - // make sure that d0 and d1 has the same length - d0[0] *= d1len / d0len; - d0[1] *= d1len / d0len; - d0[2] *= d1len / d0len; - - // direction at p1 - d[0] = d0[0] + d1[0]; - d[1] = d0[1] + d1[1]; - d[2] = d0[2] + d1[2]; - float dlensq = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; - float dlen = ( dlensq > 0 ) ? (float) sqrt(dlensq) : 1.0f; - d[0] /= dlen; - d[1] /= dlen; - d[2] /= dlen; - - return d0len; - } -}; - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::HairFile cyHairFile; //!< HAIR file class - -//------------------------------------------------------------------------------- - -_CY_CRT_SECURE_RESUME_WARNINGS -#endif +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyHairFile.h +//! \author Cem Yuksel +//! +//! \brief A class for the HAIR file type +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_HAIR_FILE_H_INCLUDED_ +#define _CY_HAIR_FILE_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyCore.h" + +//------------------------------------------------------------------------------- + +_CY_CRT_SECURE_NO_WARNINGS + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +#define _CY_HAIR_FILE_SEGMENTS_BIT 1 +#define _CY_HAIR_FILE_POINTS_BIT 2 +#define _CY_HAIR_FILE_THICKNESS_BIT 4 +#define _CY_HAIR_FILE_TRANSPARENCY_BIT 8 +#define _CY_HAIR_FILE_COLORS_BIT 16 + +#define _CY_HAIR_FILE_INFO_SIZE 88 + +// File read errors +#define CY_HAIR_FILE_ERROR_CANT_OPEN_FILE -1 //!< Error code cannot open file +#define CY_HAIR_FILE_ERROR_CANT_READ_HEADER -2 //!< Error code cannot read header +#define CY_HAIR_FILE_ERROR_WRONG_SIGNATURE -3 //!< Error code wrong signature +#define CY_HAIR_FILE_ERROR_READING_SEGMENTS -4 //!< Error code failed reading segments +#define CY_HAIR_FILE_ERROR_READING_POINTS -5 //!< Error code failed reading points +#define CY_HAIR_FILE_ERROR_READING_THICKNESS -6 //!< Error code failed reading thickness +#define CY_HAIR_FILE_ERROR_READING_TRANSPARENCY -7 //!< Error code failed reading transparency +#define CY_HAIR_FILE_ERROR_READING_COLORS -8 //!< Error code failed reading colors + +//------------------------------------------------------------------------------- + +//! HAIR file class + +class HairFile +{ +public: + HairFile() : segments(nullptr), points(nullptr), thickness(nullptr), transparency(nullptr), colors(nullptr) { Initialize(); } + ~HairFile() { Initialize(); } + + //! Hair file header + struct Header + { + char signature[4]; //!< This should be "HAIR" + unsigned int hair_count; //!< number of hair strands + unsigned int point_count; //!< total number of points of all strands + unsigned int arrays; //!< bit array of data in the file + + unsigned int d_segments; //!< default number of segments of each strand + float d_thickness; //!< default thickness of hair strands + float d_transparency; //!< default transparency of hair strands + float d_color[3]; //!< default color of hair strands + + char info[_CY_HAIR_FILE_INFO_SIZE]; //!< information about the file + }; + + ////////////////////////////////////////////////////////////////////////// + //!@name Constant Data Access Methods + + Header const & GetHeader () const { return header; } //!< Use this method to access header data. + unsigned short const * GetSegmentsArray () const { return segments; } //!< Returns segments array (segment count for each hair strand). + float const * GetPointsArray () const { return points; } //!< Returns points array (xyz coordinates of each hair point). + float const * GetThicknessArray () const { return thickness; } //!< Returns thickness array (thickness at each hair point}. + float const * GetTransparencyArray() const { return transparency; } //!< Returns transparency array (transparency at each hair point). + float const * GetColorsArray () const { return colors; } //!< Returns colors array (rgb color at each hair point). + + + ////////////////////////////////////////////////////////////////////////// + //!@name Data Access Methods + + unsigned short* GetSegmentsArray () { return segments; } //!< Returns segments array (segment count for each hair strand). + float* GetPointsArray () { return points; } //!< Returns points array (xyz coordinates of each hair point). + float* GetThicknessArray () { return thickness; } //!< Returns thickness array (thickness at each hair point}. + float* GetTransparencyArray() { return transparency; } //!< Returns transparency array (transparency at each hair point). + float* GetColorsArray () { return colors; } //!< Returns colors array (rgb color at each hair point). + + + ////////////////////////////////////////////////////////////////////////// + //!@name Methods for Setting Array Sizes + + //! Deletes all arrays and initializes the header data. + void Initialize() + { + if ( segments ) delete [] segments; + if ( points ) delete [] points; + if ( colors ) delete [] colors; + if ( thickness ) delete [] thickness; + if ( transparency ) delete [] transparency; + header.signature[0] = 'H'; + header.signature[1] = 'A'; + header.signature[2] = 'I'; + header.signature[3] = 'R'; + header.hair_count = 0; + header.point_count = 0; + header.arrays = 0; // no arrays + header.d_segments = 0; + header.d_thickness = 1.0f; + header.d_transparency = 0.0f; + header.d_color[0] = 1.0f; + header.d_color[1] = 1.0f; + header.d_color[2] = 1.0f; + memset( header.info, '\0', _CY_HAIR_FILE_INFO_SIZE ); + } + + //! Sets the hair count, re-allocates segments array if necessary. + void SetHairCount( int count ) + { + header.hair_count = count; + if ( segments ) { + delete [] segments; + segments = new unsigned short[ header.hair_count ]; + } + } + + // Sets the point count, re-allocates points, thickness, transparency, and colors arrays if necessary. + void SetPointCount( int count ) + { + header.point_count = count; + if ( points ) { + delete [] points; + points = new float[ header.point_count*3 ]; + } + if ( thickness ) { + delete [] thickness; + thickness = new float[ header.point_count ]; + } + if ( transparency ) { + delete [] transparency; + transparency = new float[ header.point_count ]; + } + if ( colors ) { + delete [] colors; + colors = new float[ header.point_count*3 ]; + } + } + + //! Use this function to allocate/delete arrays. + //! Before you call this method set hair count and point count. + //! Note that a valid HAIR file should always have points array. + void SetArrays( int array_types ) + { + header.arrays = array_types; + if ( (header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) && !segments ) { segments = new unsigned short[header.hair_count]; } + if ( !(header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) && segments ) { delete [] segments; segments=nullptr; } + if ( (header.arrays & _CY_HAIR_FILE_POINTS_BIT ) && !points ) { points = new float[header.point_count*3]; } + if ( !(header.arrays & _CY_HAIR_FILE_POINTS_BIT ) && points ) { delete [] points; points=nullptr; } + if ( (header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) && !thickness ) { thickness = new float[header.point_count]; } + if ( !(header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) && thickness ) { delete [] thickness; thickness=nullptr; } + if ( (header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT) && !transparency ) { transparency = new float[header.point_count]; } + if ( !(header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT) && transparency ) { delete [] transparency; transparency=nullptr; } + if ( (header.arrays & _CY_HAIR_FILE_COLORS_BIT ) && !colors ) { colors = new float[header.point_count*3]; } + if ( !(header.arrays & _CY_HAIR_FILE_COLORS_BIT ) && colors ) { delete [] colors; colors=nullptr; } + } + + //! Sets default number of segments for all hair strands, which is used if segments array does not exist. + void SetDefaultSegmentCount( int s ) { header.d_segments = s; } + + //! Sets default hair strand thickness, which is used if thickness array does not exist. + void SetDefaultThickness( float t ) { header.d_thickness = t; } + + //! Sets default hair strand transparency, which is used if transparency array does not exist. + void SetDefaultTransparency( float t ) { header.d_transparency = t; } + + //! Sets default hair color, which is used if color array does not exist. + void SetDefaultColor( float r, float g, float b ) { header.d_color[0]=r; header.d_color[1]=g; header.d_color[2]=b; } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Load and Save Methods + + //! Loads hair data from the given HAIR file. + int LoadFromFile( char const *filename ) + { + Initialize(); + + FILE *fp; + fp = fopen( filename, "rb" ); + if ( fp == nullptr ) return CY_HAIR_FILE_ERROR_CANT_OPEN_FILE; + + // read the header + size_t headread = fread( &header, sizeof(Header), 1, fp ); + + #define _CY_FAILED_RETURN(errorno) { Initialize(); fclose( fp ); return errorno; } + + + // Check if header is correctly read + if ( headread < 1 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_CANT_READ_HEADER); + + // Check if this is a hair file + if ( strncmp( header.signature, "HAIR", 4) != 0 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_WRONG_SIGNATURE); + + // Read segments array + if ( header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) { + segments = new unsigned short[ header.hair_count ]; + size_t readcount = fread( segments, sizeof(unsigned short), header.hair_count, fp ); + if ( readcount < header.hair_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_SEGMENTS); + } + + // Read points array + if ( header.arrays & _CY_HAIR_FILE_POINTS_BIT ) { + points = new float[ header.point_count*3 ]; + size_t readcount = fread( points, sizeof(float), header.point_count*3, fp ); + if ( readcount < header.point_count*3 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_POINTS); + } + + // Read thickness array + if ( header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) { + thickness = new float[ header.point_count ]; + size_t readcount = fread( thickness, sizeof(float), header.point_count, fp ); + if ( readcount < header.point_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_THICKNESS); + } + + // Read thickness array + if ( header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT ) { + transparency = new float[ header.point_count ]; + size_t readcount = fread( transparency, sizeof(float), header.point_count, fp ); + if ( readcount < header.point_count ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_TRANSPARENCY); + } + + // Read colors array + if ( header.arrays & _CY_HAIR_FILE_COLORS_BIT ) { + colors = new float[ header.point_count*3 ]; + size_t readcount = fread( colors, sizeof(float), header.point_count*3, fp ); + if ( readcount < header.point_count*3 ) _CY_FAILED_RETURN(CY_HAIR_FILE_ERROR_READING_COLORS); + } + + fclose( fp ); + + return header.hair_count; + } + + //! Saves hair data to the given HAIR file. + int SaveToFile( char const *filename ) const + { + FILE *fp; + fp = fopen( filename, "wb" ); + if ( fp == nullptr ) return -1; + + // Write header + fwrite( &header, sizeof(Header), 1, fp ); + + // Write arrays + if ( header.arrays & _CY_HAIR_FILE_SEGMENTS_BIT ) fwrite( segments, sizeof(unsigned short), header.hair_count, fp ); + if ( header.arrays & _CY_HAIR_FILE_POINTS_BIT ) fwrite( points, sizeof(float), header.point_count*3, fp ); + if ( header.arrays & _CY_HAIR_FILE_THICKNESS_BIT ) fwrite( thickness, sizeof(float), header.point_count, fp ); + if ( header.arrays & _CY_HAIR_FILE_TRANSPARENCY_BIT ) fwrite( transparency, sizeof(float), header.point_count, fp ); + if ( header.arrays & _CY_HAIR_FILE_COLORS_BIT ) fwrite( colors, sizeof(float), header.point_count*3, fp ); + + fclose( fp ); + + return header.hair_count; + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Other Methods + + //! Fills the given direction array with normalized directions using the points array. + //! Call this function if you need strand directions for shading. + //! The given array dir should be allocated as an array of size 3 times point count. + //! Returns point count, returns zero if fails. + int FillDirectionArray( float *dir ) + { + if ( dir==nullptr || header.point_count<=0 || points==nullptr ) return 0; + + int p = 0; // point index + for ( unsigned int i=0; i 1 ) { + // direction at point1 + float len0, len1; + ComputeDirection( &dir[(p+1)*3], len0, len1, &points[p*3], &points[(p+1)*3], &points[(p+2)*3] ); + + // direction at point0 + float d0[3]; + d0[0] = points[(p+1)*3] - dir[(p+1)*3] *len0*0.3333f - points[p*3]; + d0[1] = points[(p+1)*3+1] - dir[(p+1)*3+1]*len0*0.3333f - points[p*3+1]; + d0[2] = points[(p+1)*3+2] - dir[(p+1)*3+2]*len0*0.3333f - points[p*3+2]; + float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2]; + float d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f; + dir[p*3] = d0[0] / d0len; + dir[p*3+1] = d0[1] / d0len; + dir[p*3+2] = d0[2] / d0len; + + // We computed the first 2 points + p += 2; + + // Compute the direction for the rest + for ( int t=2; t 0 ) ? (float) sqrt(d0lensq) : 1.0f; + dir[p*3] = d0[0] / d0len; + dir[p*3+1] = d0[1] / d0len; + dir[p*3+2] = d0[2] / d0len; + p++; + + } else if ( s > 0 ) { + // if it has a single segment + float d0[3]; + d0[0] = points[(p+1)*3] - points[p*3]; + d0[1] = points[(p+1)*3+1] - points[p*3+1]; + d0[2] = points[(p+1)*3+2] - points[p*3+2]; + float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2]; + float d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f; + dir[p*3] = d0[0] / d0len; + dir[p*3+1] = d0[1] / d0len; + dir[p*3+2] = d0[2] / d0len; + dir[(p+1)*3] = dir[p*3]; + dir[(p+1)*3+1] = dir[p*3+1]; + dir[(p+1)*3+2] = dir[p*3+2]; + p += 2; + } + //*/ + } + return p; + } + + +private: + ////////////////////////////////////////////////////////////////////////// + //!@name Private Variables and Methods + + Header header; + unsigned short *segments; + float *points; + float *thickness; + float *transparency; + float *colors; + + // Given point before (p0) and after (p2), computes the direction (d) at p1. + float ComputeDirection( float *d, float &d0len, float &d1len, float const *p0, float const *p1, float const *p2 ) + { + // line from p0 to p1 + float d0[3]; + d0[0] = p1[0] - p0[0]; + d0[1] = p1[1] - p0[1]; + d0[2] = p1[2] - p0[2]; + float d0lensq = d0[0]*d0[0] + d0[1]*d0[1] + d0[2]*d0[2]; + d0len = ( d0lensq > 0 ) ? (float) sqrt(d0lensq) : 1.0f; + + // line from p1 to p2 + float d1[3]; + d1[0] = p2[0] - p1[0]; + d1[1] = p2[1] - p1[1]; + d1[2] = p2[2] - p1[2]; + float d1lensq = d1[0]*d1[0] + d1[1]*d1[1] + d1[2]*d1[2]; + d1len = ( d1lensq > 0 ) ? (float) sqrt(d1lensq) : 1.0f; + + // make sure that d0 and d1 has the same length + d0[0] *= d1len / d0len; + d0[1] *= d1len / d0len; + d0[2] *= d1len / d0len; + + // direction at p1 + d[0] = d0[0] + d1[0]; + d[1] = d0[1] + d1[1]; + d[2] = d0[2] + d1[2]; + float dlensq = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; + float dlen = ( dlensq > 0 ) ? (float) sqrt(dlensq) : 1.0f; + d[0] /= dlen; + d[1] /= dlen; + d[2] /= dlen; + + return d0len; + } +}; + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::HairFile cyHairFile; //!< HAIR file class + +//------------------------------------------------------------------------------- + +_CY_CRT_SECURE_RESUME_WARNINGS +#endif diff --git a/cyHeap.h b/include/cyHeap.h similarity index 100% rename from cyHeap.h rename to include/cyHeap.h diff --git a/cyIPoint.h b/include/cyIPoint.h similarity index 100% rename from cyIPoint.h rename to include/cyIPoint.h diff --git a/cyIVector.h b/include/cyIVector.h similarity index 100% rename from cyIVector.h rename to include/cyIVector.h diff --git a/cyLightingGrid.h b/include/cyLightingGrid.h similarity index 100% rename from cyLightingGrid.h rename to include/cyLightingGrid.h diff --git a/cyMatrix.h b/include/cyMatrix.h similarity index 98% rename from cyMatrix.h rename to include/cyMatrix.h index 5b93502..91a34d7 100644 --- a/cyMatrix.h +++ b/include/cyMatrix.h @@ -1,2420 +1,2420 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyMatrix.h -//! \author Cem Yuksel -//! -//! \brief 2x2, 3x3, 3x4, and 4x4 matrix classes -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_MATRIX_H_INCLUDED_ -#define _CY_MATRIX_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyVector.h" - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -// Forward declarations -//! \cond HIDDEN_SYMBOLS -template class Matrix3; -template class Matrix34; -template class Matrix4; -//! \endcond - -//------------------------------------------------------------------------------- - -#define _CY_VEC_DEFAULT_ERROR_TOLERANCE 0.0001 - -//------------------------------------------------------------------------------- - -// The macros below help the MSVC compiler with auto-vectorization -#define _CY_FORi(start,end,loop) _CY_IVDEP_FOR ( int i=(start); i<(end); ++i ) { loop; } -#define _CY_FORi0(end,loop) _CY_FORi(0,end,loop) -#define _CY_FOR_4i(loop) _CY_FORi0(4,loop) -#define _CY_FOR_8i(loop) _CY_FOR_4i(loop) _CY_FORi(4,8,loop) -#define _CY_FOR_9i(loop) _CY_FOR_8i(loop) { int i=8; loop; } -#define _CY_FOR_12i(loop) _CY_FOR_8i(loop) _CY_FORi( 8,12,loop) -#define _CY_FOR_16i(loop) _CY_FOR_12i(loop) _CY_FORi(12,16,loop) - -//------------------------------------------------------------------------------- - -//! 2x2 matrix class. -//! -//! Its data stores 4-value array of column-major matrix elements. -//! You can use Matrix2 with Vec2 to transform 2D points. - -template -class Matrix2 -{ - CY_NODISCARD friend Matrix2 operator * ( T value, Matrix2 const &right ) { Matrix2 r; _CY_FOR_4i( r.cell[i] = value * right.cell[i] ); return r; } //!< multiply matrix by a value - CY_NODISCARD friend Matrix2 operator + ( T value, Matrix2 const &right ) { return Matrix2(value+right.cell[0], right.cell[2], right.cell[1],value+right.cell[3]); } //!< add a value times identity matrix to a matrix - CY_NODISCARD friend Matrix2 operator - ( T value, Matrix2 const &right ) { return Matrix2(value-right.cell[0],-right.cell[2],-right.cell[1],value-right.cell[3]); } //!< subtract matrix from a value times identity matrix - CY_NODISCARD friend Matrix2 Inverse( Matrix2 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix - -public: - - //! Elements of the matrix are column-major: \n - //! | 0 2 | \n - //! | 1 3 | \n -#ifdef __cpp_unrestricted_unions - union { - T cell[4]; - Vec2 column[2]; // column vectors - }; -#else - T cell[4]; -#endif - - ////////////////////////////////////////////////////////////////////////// - //!@name Constructors - - Matrix2() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor - template explicit Matrix2( const Matrix2 &matrix ) { MemConvert(cell,matrix.cell,4); } //!< Copy constructor for different types - explicit Matrix2( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 4 values - explicit Matrix2( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v - explicit Matrix2( Vec2 const &x, Vec2 const &y ) { Set(x,y); } //!< Initialize the matrix using two vectors as columns - explicit Matrix2( Matrix3 const &m ); - explicit Matrix2( Matrix34 const &m ); - explicit Matrix2( Matrix4 const &m ); - - //! Constructor using row-major order for initialization - Matrix2( T c00, T c01, - T c10, T c11 ) - { - cell[0] = c00; cell[2] = c01; - cell[1] = c10; cell[3] = c11; - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set & Get Methods - - void Zero () { MemClear(cell,4); } //!< Set all the values as zero - bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero (); } //!< Returns true if the matrix is exactly zero - bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite(); } //!< Returns true if all components are finite real numbers. - void Get( T * restrict values ) { MemCopy(values,cell,4); } //!< Copies the matrix cell to the given values array of size 4 - void Set( T const * restrict values ) { MemCopy(cell,values,4); } //!< Set Matrix using an array of 4 values - void Set( Vec2 const &x, Vec2 const &y ) { x.Get(cell); y.Get(cell+2); } //!< Set Matrix using two vectors as columns - void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix - void SetTensorProduct( Vec2 const &v0, Vec2 const &v1 ) //!< Sets the matrix as the tensor product (outer product) of two vectors - { - _CY_IVDEP_FOR ( int i=0; i<2; ++i ) cell[ i] = v0[i] * v1.x; - _CY_IVDEP_FOR ( int i=0; i<2; ++i ) cell[2+i] = v0[i] * v1.y; - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Affine transformations - - //! Sets a uniform scale matrix - void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale); } - //! Sets a scale matrix - void SetScale( T scaleX, T scaleY ) { cell[0]=scaleX; cell[1]=0; cell[2]=0; cell[3]=scaleY;} - //! Sets a scale matrix - void SetScale( Vec2 const &scale ) { SetScale(scale.x,scale.y); } - //! Set a rotation matrix by angle - void SetRotation( T angle ) { SetRotation( std::sin(angle), std::cos(angle) ); } - //! Set a rotation matrix by cos and sin of angle - void SetRotation( T sinAngle, T cosAngle ) { cell[0]=cosAngle; cell[1]=-sinAngle; cell[2]=sinAngle; cell[3]=cosAngle; } - //! Sets a Cartesian coordinate frame using the given x direction. x must be a unit vector. - void SetCartesianFrameX( Vec2 const &x ) { Set( x, x.GetPerpendicular() ); } - //! Sets a Cartesian coordinate frame using the given y direction. y must be a unit vector. - void SetCartesianFrameY( Vec2 const &y ) { Set( -y.GetPerpendicular(), y ); } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set Row, Column, or Diagonal - - void SetRow ( int ri, T x, T y ) { cell[ri]=x; cell[ri+2]=y; } //!< Sets a row of the matrix - void SetRow ( int ri, Vec2 const &v ) { SetRow(ri,v.x,v.y); } //!< Sets a row of the matrix - void SetColumn ( int ci, T x, T y ) { Column(ci).Set(x,y); } //!< Sets a column of the matrix - void SetColumn ( int ci, Vec2 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix - void SetDiagonal( T xx, T yy ) { cell[0]=xx; cell[3]=yy; } //!< Sets the diagonal values of the matrix - void SetDiagonal( Vec2 const &p ) { SetDiagonal( p.x, p.y ); } //!< Sets the diagonal values of the matrix - void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1]); } //!< Sets the diagonal values of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Row, Column, or Diagonal - -#ifdef __cpp_unrestricted_unions - CY_NODISCARD Vec2 * Columns() { return column; } - CY_NODISCARD Vec2 const * Columns() const { return column; } - CY_NODISCARD Vec2 & Column ( int ci ) { return column[ci]; } - CY_NODISCARD Vec2 const & Column ( int ci ) const { return column[ci]; } -#else - CY_NODISCARD Vec2 * Columns() { return ((Vec2*)cell); } - CY_NODISCARD Vec2 const * Columns() const { return ((Vec2*)cell); } - CY_NODISCARD Vec2 & Column ( int ci ) { return Columns()[ci]; } - CY_NODISCARD Vec2 const & Column ( int ci ) const { return Columns()[ci]; } -#endif - CY_NODISCARD Vec2 GetRow ( int ri ) const { return Vec2( cell[ri], cell[ri+2] ); } //!< Returns a row of the matrix - CY_NODISCARD Vec2 GetDiagonal() const { return Vec2( cell[0], cell[3] ); } //!< Returns the diagonal of the matrix - CY_NODISCARD Matrix2 GetRotation() const { Matrix2 s, r; GetComponents(s,r); return r; } //!< Returns the rotation portion of the transformation - - //! Returns the scale portion of the transformation. - //! The returned matrix is symmetric, but not necessarily diagonal, and it can include non-uniform scale. - CY_NODISCARD Matrix2 GetScale() const - { - Matrix2 trns = GetTranspose(); - Matrix2 u2 = *this * trns; - Vec2 v0, v1; - u2.GetEigenvectors( v0, v1 ); - Matrix2 v(v0,v1); - Matrix2 vt = v.GetTranspose(); - Matrix2 d2 = vt * (*this) * v; // the result is a diagonal matrix - Vec2 diag = d2.GetDiagonal(); - Matrix2 d; - d.SetScale(diag); - return v * d * vt; - } - - //! Returns the average scale factor - CY_NODISCARD T GetAvrgScale() const - { - T det = cell[0]*cell[3]-cell[2]*cell[1]; - T s = Sqrt( std::abs(det) ); - return det >= 0 ? s : -s; - } - - void GetComponents( Matrix2 &scale, Matrix2 &rotation ) const { scale = GetScale(); rotation = *this * scale.GetInverse(); } //!< Returns separate transformation components - - ////////////////////////////////////////////////////////////////////////// - //!@name Comparison Operators - - CY_NODISCARD bool operator == ( Matrix2 const &right ) const { _CY_FOR_4i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal - CY_NODISCARD bool operator != ( Matrix2 const &right ) const { _CY_FOR_4i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal - - - ////////////////////////////////////////////////////////////////////////// - //!@name Access Operators - - CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<2 && ci>=0 && ci<2 ); return cell[ ci*2 + ri ]; } //!< subscript operator - CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<2 && ci>=0 && ci<2 ); return cell[ ci*2 + ri ]; } //!< constant subscript operator - CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<4 ); return cell[i]; } //!< subscript operator - CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<4 ); return cell[i]; } //!< constant subscript operator - - ////////////////////////////////////////////////////////////////////////// - //!@name Unary and Binary Operators - - // Unary operators - CY_NODISCARD Matrix2 operator - () const { Matrix2 r; _CY_FOR_4i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix - - // Binary operators - CY_NODISCARD Matrix2 operator * ( T const value ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value - CY_NODISCARD Matrix2 operator / ( T const value ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value - CY_NODISCARD Matrix2 operator + ( Matrix2 const &right ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices - CY_NODISCARD Matrix2 operator - ( Matrix2 const &right ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix2 from another - CY_NODISCARD Matrix2 operator * ( Matrix2 const &right ) const //!< multiply a matrix with another - { - Matrix2 r; - r[0] = cell[0] * right.cell[0] + cell[2] * right.cell[1]; - r[1] = cell[1] * right.cell[0] + cell[3] * right.cell[1]; - r[2] = cell[0] * right.cell[2] + cell[2] * right.cell[3]; - r[3] = cell[1] * right.cell[2] + cell[3] * right.cell[3]; - return r; - } - CY_NODISCARD Vec2 operator * ( Vec2 const &p ) const { return Vec2( p.x*cell[0] + p.y*cell[2], p.x*cell[1] + p.y*cell[3] ); } - - CY_NODISCARD Matrix2 operator + ( T value ) const { Matrix2 r=*this; r.cell[0]+=value; r.cell[3]+=value; return r; } //!< add a value times identity matrix - CY_NODISCARD Matrix2 operator - ( T value ) const { Matrix2 r=*this; r.cell[0]-=value; r.cell[3]-=value; return r; } //!< subtract a value times identity matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Assignment Operators - - Matrix2 const & operator += ( Matrix2 const &right ) { _CY_FOR_4i( cell[i] += right.cell[i] ); return *this; } //!< add two Matrices modify this - Matrix2 const & operator -= ( Matrix2 const &right ) { _CY_FOR_4i( cell[i] -= right.cell[i] ); return *this; } //!< subtract one Matrix2 from another matrix and modify this matrix - Matrix2 const & operator *= ( Matrix2 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix - Matrix2 const & operator *= ( T const value ) { _CY_FOR_4i( cell[i] *= value ); return *this; } //!< multiply a matrix with a value modify this matrix - Matrix2 const & operator /= ( T const value ) { _CY_FOR_4i( cell[i] /= value ); return *this; } //!< divide the matrix by a value modify the this matrix - Matrix2 const & operator += ( T const value ) { cell[0]+=value; cell[3]+=value; return *this; } //!< add a value times identity matrix - Matrix2 const & operator -= ( T const value ) { cell[0]-=value; cell[3]-=value; return *this; } //!< subtract a value times identity matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Other Methods - - void Transpose() { T tmp=cell[0]; cell[0]=cell[3]; cell[3]=tmp; } //!< Transpose this matrix - CY_NODISCARD Matrix2 GetTranspose() const //!< Returns the transpose of this matrix - { - Matrix2 m; - m.cell[0] = cell[0]; m.cell[1] = cell[2]; - m.cell[2] = cell[1]; m.cell[3] = cell[3]; - return m; - } - - //! Multiply the give vector with the transpose of the matrix - CY_NODISCARD Vec2 TransposeMult( Vec2 const &p ) const { return Vec2( p.x*cell[0] + p.y*cell[1], p.x*cell[2] + p.y*cell[3] ); } - - CY_NODISCARD Matrix2 TransposeMult( Matrix2 const & right ) const //!< Multiply a matrix by the transpose of this one (i.e. this^T * right). - { - Matrix2 r; - r[0] = cell[0] * right.cell[0] + cell[1] * right.cell[1]; - r[1] = cell[2] * right.cell[0] + cell[3] * right.cell[1]; - r[2] = cell[0] * right.cell[2] + cell[1] * right.cell[3]; - r[3] = cell[2] * right.cell[2] + cell[3] * right.cell[3]; - return r; - } - CY_NODISCARD Matrix2 MultTranspose( Matrix2 const & right ) const //!< Multiply the transpose of a matrix by this one (i.e. this * right^T). - { - Matrix2 r; - r[0] = cell[0] * right.cell[0] + cell[2] * right.cell[2]; - r[1] = cell[1] * right.cell[0] + cell[3] * right.cell[2]; - r[2] = cell[0] * right.cell[1] + cell[2] * right.cell[3]; - r[3] = cell[1] * right.cell[1] + cell[3] * right.cell[3]; - return r; - } - - CY_NODISCARD Matrix2 TransposeMultSelf() const { return TransposeMult(*this); } //!< Multiply the transpose of this matrix with itself (i.e. this^T * this). - CY_NODISCARD Matrix2 MultSelfTranspose() const { return MultTranspose(*this); } //!< Multiply the matrix with its transpose (i.e. this * this^T). - - CY_NODISCARD T GetTrace() const { return cell[0] + cell[3]; } //!< return the Trace of this matrix - - CY_NODISCARD T GetDeterminant() const { return cell[0]*cell[3]-cell[2]*cell[1]; } //!< Get the determinant of this matrix - - void Invert() //!< Invert this matrix - { - T det = GetDeterminant(); - T cell3 = cell[0] / det; - cell[0] = cell[3] / det; - cell[1] = -cell[1] / det; - cell[2] = -cell[2] / det; - cell[3] = cell3; - } - CY_NODISCARD Matrix2 GetInverse() const //!< Get the inverse of this matrix - { - T det = GetDeterminant(); - Matrix2 inv; - inv.cell[0] = cell[3] / det; - inv.cell[1] = -cell[1] / det; - inv.cell[2] = -cell[2] / det; - inv.cell[3] = cell[0] / det; - return inv; - } - - //! Removes the scale component of the matrix by normalizing each column. - //! The resulting matrix can contain shear, if it originally contained non-uniform scale and rotation. - void Normalize() { Column(0).Normalize(); Column(1).Normalize(); } - - //! Orthogonalizes the matrix and removes the scale component, preserving the x direction - void OrthogonalizeX() - { - Column(0).Normalize(); - Column(1) -= Column(0) * (Column(1) % Column(0)); - Column(1).Normalize(); - } - //! Orthogonalizes the matrix and removes the scale component, preserving the y direction - void OrthogonalizeY() - { - Column(1).Normalize(); - Column(0) -= Column(1) * (Column(0) % Column(1)); - Column(0).Normalize(); - } - - //! Returns if the matrix is identity within the given error tollerance. - bool IsIdentity( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const { return std::abs(cell[0] - T(1)) < tollerance && std::abs(cell[1]) < tollerance && std::abs(cell[2]) < tollerance && std::abs(cell[3] - T(1)) < tollerance; } - - //! Returns if the matrix is symmetric within the given error tollerance. - bool IsSymmetric( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const { return std::abs(cell[0] - cell[2]) < tollerance; } - - //! Returns if the matrix is diagonal. - bool IsDiagonal( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const { return std::abs(cell[1]) + std::abs(cell[2]) < tollerance*2; } - - //! Returns the eigenvalues of the matrix. - //! The eigenvalues are ordered, such that the first one is larger. - CY_NODISCARD Vec2 GetEigenvalues() const - { - T t = GetTrace(); - T d = GetDeterminant(); - T a = t*t*T(0.25) - d; - T s = SqrtSafe(a); - Vec2 lambda; - lambda.x = t * T(0.5) + s; - lambda.y = t * T(0.5) - s; - return lambda; - } - - //! Returns the eigenvalues and sets the given vectors as the eigenvectors of the matrix. - //! The eigenvalues are ordered, such that the first one is larger. - //! The given tollerance is used for checking whether the eigenvalues are the same. - Vec2 GetEigenvectors( Vec2 &evec0, Vec2 &evec1, T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - Vec2 lambda = GetEigenvalues(); - if ( std::abs(lambda.x - lambda.y) < tollerance ) { - evec0 = Column(0); - evec1 = Column(1); - } else { - Matrix2 v0( cell[0]-lambda.y, cell[1], cell[2], cell[3]-lambda.y ); - Matrix2 v1( cell[0]-lambda.x, cell[1], cell[2], cell[3]-lambda.x ); - evec0 = v0.Column(0) + v0.Column(1); - evec1 = v1.Column(0) + v1.Column(1); - } - return lambda; - } - - //! Singular value decomposition (SVD). - //! Returns the SVD of the matrix, where U and V are orthogonal matrices and - //! S is the diagonal elements of a diagonal matrix (including zeros), - //! such that this matrix A = U S V^T. - void SingularValueDecomposition( Matrix2 &U, Vec2 &S, Matrix2 &V ) - { - Matrix2 AAT = MultSelfTranspose(); - Vec2 lambda = AAT.GetEigenvectors( U.Column(0), U.Column(1) ); - S = (lambda.Abs()).Sqrt(); - U.Normalize(); - Matrix2 ATA = TransposeMultSelf(); - AAT.GetEigenvectors( V.Column(0), V.Column(1) ); - V.Normalize(); - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Static Methods - - //! Returns an identity matrix - CY_NODISCARD static Matrix2 Identity() { T c[] = { 1,0, 0,1 }; return Matrix2(c); } - //! Returns a rotation matrix about the given axis by angle in radians - CY_NODISCARD static Matrix2 Rotation( T angle ) { Matrix2 m; m.SetRotation(angle); return m; } - //! Returns a uniform scale matrix - CY_NODISCARD static Matrix2 Scale( T uniformScale ) { Matrix2 m; m.SetScale(uniformScale); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix2 Scale( T scaleX, T scaleY ) { Matrix2 m; m.SetScale(scaleX,scaleY); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix2 Scale( Vec2 const &scale ) { Matrix2 m; m.SetScale(scale); return m; } - //! Returns the tensor product (outer product) matrix of two vectors - CY_NODISCARD static Matrix2 TensorProduct( Vec2 const &v0, Vec2 const &v1 ) { Matrix2 m; m.SetTensorProduct(v0,v1); return m; } - - ////////////////////////////////////////////////////////////////////////// -}; - -//------------------------------------------------------------------------------- - -#ifdef CY_NONVECTORIZED_MATRIX3 -# define _CY_INIT_MATRIX3_VECTORIZATION const int N = 3; T const *cell_6 = cell + 6; -#else -# define _CY_INIT_MATRIX3_VECTORIZATION const int N = 4; T cell_6[4] = { cell[6], cell[7], cell[8], cell[8] }; -#endif - -//------------------------------------------------------------------------------- - -//! 3x3 matrix class. -//! -//! Its data stores 9-value array of column-major matrix elements. -//! You can use Matrix3 with Vec3 to transform 3D points. - -template -class Matrix3 -{ - CY_NODISCARD friend Matrix3 operator * ( T value, Matrix3 const &right ) { Matrix3 r; _CY_FOR_9i( r.cell[i] = value * right.cell[i] ); return r; } //!< multiply matrix by a value - CY_NODISCARD friend Matrix3 operator + ( T value, Matrix3 const &right ) { Matrix3 r= right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< add a value times identity matrix to a matrix - CY_NODISCARD friend Matrix3 operator - ( T value, Matrix3 const &right ) { Matrix3 r=-right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< subtract a matrix from a value times identity matrix - CY_NODISCARD friend Matrix3 Inverse( Matrix3 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix - -public: - - //! Elements of the matrix are column-major: \n - //! | 0 3 6 | \n - //! | 1 4 7 | \n - //! | 2 5 8 | \n -#ifdef __cpp_unrestricted_unions - union { - T cell[9]; - Vec3 column[3]; // column vectors - }; -#else - T cell[9]; -#endif - - ////////////////////////////////////////////////////////////////////////// - //!@name Constructors - - Matrix3() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor - template explicit Matrix3( Matrix3 const &matrix ) { MemConvert(cell,matrix.cell,9); } //!< Copy constructor for different types - explicit Matrix3( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 9 values - explicit Matrix3( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v - explicit Matrix3( Vec3 const &x, Vec3 const &y, Vec3 const &z ) { Set(x,y,z); } //!< Initialize the matrix using x,y,z vectors as columns - explicit Matrix3( Matrix2 const &m ) { Column(0).Set(m.Column(0),0); Column(1).Set(m.Column(1),0); Column(2).Set(0,0,1); } - explicit Matrix3( Matrix34 const &m ); - explicit Matrix3( Matrix4 const &m ); - - //! Constructor using row-major order for initialization - Matrix3( T c00, T c01, T c02, - T c10, T c11, T c12, - T c20, T c21, T c22 ) - { - cell[0] = c00; cell[3] = c01; cell[6] = c02; - cell[1] = c10; cell[4] = c11; cell[7] = c12; - cell[2] = c20; cell[5] = c21; cell[8] = c22; - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set & Get Methods - - void Zero () { MemClear(cell,9); } //!< Set all the values as zero - bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero () && Column(2).IsZero (); } //!< Returns true if the matrix is exactly zero - bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite() && Column(2).IsFinite(); } //!< Returns true if all components are finite real numbers. - void Get( T * restrict values ) { MemCopy(values,cell,9); } //!< Copies the matrix cell to the given values array of size 9 - void Set( T const * restrict values ) { MemCopy(cell,values,9); } //!< Set matrix using an array of 9 values - void Set( Vec3 const &x, Vec3 const &y, Vec3 const &z ) { Column(0)=x; Column(1)=y; Column(2)=z; } //!< Set matrix using x,y,z vectors as columns - void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix - void SetTensorProduct( Vec3 const &v0, Vec3 const &v1 ) //!< Sets the matrix as the tensor product (outer product) of two vectors - { - _CY_IVDEP_FOR ( int i=0; i<3; ++i ) cell[ i] = v0[i] * v1.x; - _CY_IVDEP_FOR ( int i=0; i<3; ++i ) cell[3+i] = v0[i] * v1.y; - _CY_IVDEP_FOR ( int i=0; i<3; ++i ) cell[6+i] = v0[i] * v1.z; - } - //! Matrix representation of the cross product ( a x b) - void SetCrossProd( Vec3 const &p ) { cell[0]=T(0); cell[1]=p.z; cell[2]=-p.y; cell[3]=-p.z; cell[4]=T(0); cell[5]=p.x; cell[6]=p.y; cell[7]=-p.x; cell[8]=T(0); } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Affine transformations - - //! Sets a uniform scale matrix - void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale,uniformScale); } - //! Sets a scale matrix - void SetScale( T scaleX, T scaleY, T scaleZ ) - { - cell[0] = scaleX; cell[1] = 0; cell[2]=0; - cell[3] = 0; cell[4] = scaleY; cell[5]=0; - cell[6] = 0; cell[7] = 0; cell[8]=scaleZ; - } - //! Sets a scale matrix - void SetScale( Vec3 const &scale ) { SetScale(scale.x,scale.y,scale.z); } - //! Set as rotation matrix around x axis - void SetRotationX( T angle ) { SetRotationX( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around x axis by cos and sin of angle - void SetRotationX( T sinAngle, T cosAngle ) - { - cell[0] = T(1); cell[1] = T(0); cell[2] = T(0); - cell[3] = T(0); cell[4] = cosAngle; cell[5] = sinAngle; - cell[6] = T(0); cell[7] = -sinAngle; cell[8] = cosAngle; - } - //! Set as rotation matrix around y axis - void SetRotationY( T angle ) { SetRotationY( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around y axis by cos and sin of angle - void SetRotationY( T sinAngle, T cosAngle ) - { - cell[0] = cosAngle; cell[1] = T(0); cell[2] = -sinAngle; - cell[3] = T(0); cell[4] = T(1); cell[5] = T(0); - cell[6] = sinAngle; cell[7] = T(0); cell[8] = cosAngle; - } - //! Set as rotation matrix around z axis - void SetRotationZ( T angle ) { SetRotationZ( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around z axis by cos and sin of angle - void SetRotationZ( T sinAngle, T cosAngle ) - { - cell[0] = cosAngle; cell[1] = sinAngle; cell[2] = T(0); - cell[3] = -sinAngle; cell[4] = cosAngle; cell[5] = T(0); - cell[6] = T(0); cell[7] = T(0); cell[8] = T(1); - } - //! Set as rotation matrix around x, y, and then z axes ( Rz * Ry * Rx ) - void SetRotationXYZ( T angleX, T angleY, T angleZ ) - { - T sx = std::sin(angleX); - T cx = std::cos(angleX); - T sy = std::sin(angleY); - T cy = std::cos(angleY); - T sz = std::sin(angleZ); - T cz = std::cos(angleZ); - cell[0] = cy*cz; cell[1] = cy*sz; cell[2] =-sy; - cell[3] = cz*sx*sy - cx*sz; cell[4] = cx*cz + sx*sy*sz; cell[5] = cy*sx; - cell[6] = cx*cz*sy + sx*sz; cell[7] =-cz*sx + cx*sy*sz; cell[8] = cx*cy; - } - //! Set as rotation matrix around z, y, and then x axes ( Rx * Ry * Rz ) - void SetRotationZYX( T angleX, T angleY, T angleZ ) - { - T sx = std::sin(angleX); - T cx = std::cos(angleX); - T sy = std::sin(angleY); - T cy = std::cos(angleY); - T sz = std::sin(angleZ); - T cz = std::cos(angleZ); - cell[0] = cy*cz; cell[1] = cx*sz + sx*sy*cz; cell[2] = sx*sz - cx*sy*cz; - cell[3] = -cy*sz; cell[4] = cx*cz - sx*sy*sz; cell[5] = sx*cz + cx*sy*sz; - cell[6] = sy; cell[7] = -sx*cy; cell[8] = cx*cy; - } - //! Set a rotation matrix about the given axis by angle - void SetRotation( Vec3 const &axis, T angle ) { SetRotation(axis,std::sin(angle),std::cos(angle)); } - //! Set a rotation matrix about the given axis by cos and sin of angle - void SetRotation( Vec3 const &axis, T sinAngle, T cosAngle ) - { - T t = T(1) - cosAngle; - Vec3 a = t * axis; - T txy = a.x * axis.y; - T txz = a.x * axis.z; - T tyz = a.y * axis.z; - Vec3 s = sinAngle * axis; - cell[ 0] = a.x * axis.x + cosAngle; cell[ 1] = txy + s.z; cell[ 2] = txz - s.y; - cell[ 3] = txy - s.z; cell[ 4] = a.y * axis.y + cosAngle; cell[ 5] = tyz + s.x; - cell[ 6] = txz + s.y; cell[ 7] = tyz - s.x; cell[ 8] = a.z * axis.z + cosAngle; - } - //! Set a rotation matrix that sets [from] unit vector to [to] unit vector - void SetRotation( Vec3 const &from, Vec3 const &to ) - { - assert( from.IsFinite() && to.IsUnit() ); - Vec3 axis = from.Cross(to); - T s = axis.Length(); - if ( s < T(0.000001) ) SetIdentity(); - else { - T c = from.Dot(to); - SetRotation(axis/s, s, c); - } - } - //! Set view matrix using position, target and approximate up vector - void SetView( Vec3 const &target, Vec3 const &up ) - { - Vec3 f = target; - f.Normalize(); - Vec3 s = f.Cross(up); - s.Normalize(); - Vec3 u = s.Cross(f); - cell[0] = s.x; cell[1] = u.x; cell[2] = -f.x; - cell[3] = s.y; cell[4] = u.y; cell[5] = -f.y; - cell[6] = s.z; cell[7] = u.z; cell[8] = -f.z; - } - //! Sets a Cartesian coordinate frame using the given x direction and an approximate y direction. x must be a unit vector. - void SetCartesianFrameXY( Vec3 const &x, Vec3 const &y_approx ) { Vec3 z = x.Cross(y_approx); z.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z); } - //! Sets a Cartesian coordinate frame using the given x direction and an approximate z direction. x must be a unit vector. - void SetCartesianFrameXZ( Vec3 const &x, Vec3 const &z_approx ) { Vec3 y = z_approx.Cross(x); y.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z); } - //! Sets a Cartesian coordinate frame using the given y direction and an approximate x direction. y must be a unit vector. - void SetCartesianFrameYX( Vec3 const &y, Vec3 const &x_approx ) { Vec3 z = x_approx.Cross(y); z.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z); } - //! Sets a Cartesian coordinate frame using the given y direction and an approximate z direction. y must be a unit vector. - void SetCartesianFrameYZ( Vec3 const &y, Vec3 const &z_approx ) { Vec3 x = y.Cross(z_approx); x.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z); } - //! Sets a Cartesian coordinate frame using the given z direction and an approximate x direction. z must be a unit vector. - void SetCartesianFrameZX( Vec3 const &z, Vec3 const &x_approx ) { Vec3 y = z.Cross(x_approx); y.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z); } - //! Sets a Cartesian coordinate frame using the given z direction and an approximate y direction. z must be a unit vector. - void SetCartesianFrameZY( Vec3 const &z, Vec3 const &y_approx ) { Vec3 x = y_approx.Cross(z); x.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z); } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set Row, Column, or Diagonal - - void SetRow ( int ri, T x, T y, T z ) { cell[ri]=x; cell[ri+3]=y; cell[ri+6]=z; } //!< Sets a row of the matrix - void SetRow ( int ri, Vec3 const &v ) { SetRow(ri,v.x,v.y,v.z); } //!< Sets a row of the matrix - void SetColumn ( int ci, T x, T y, T z ) { Column(ci).Set(x,y,z); } //!< Sets a column of the matrix - void SetColumn ( int ci, Vec3 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix - void SetDiagonal( T xx, T yy, T zz ) { cell[0]=xx; cell[4]=yy; cell[8]=zz; } //!< Sets the diagonal values of the matrix - void SetDiagonal( Vec3 const &p ) { SetDiagonal( p.x, p.y, p.z ); } //!< Sets the diagonal values of the matrix - void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1],values[2]); } //!< Sets the diagonal values of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Row, Column, or Diagonal - -#ifdef __cpp_unrestricted_unions - CY_NODISCARD Vec3 * Columns() { return column; } - CY_NODISCARD Vec3 const * Columns() const { return column; } - CY_NODISCARD Vec3 & Column ( int ci ) { return column[ci]; } - CY_NODISCARD Vec3 const & Column ( int ci ) const { return column[ci]; } -#else - CY_NODISCARD Vec3 * Columns() { return ((Vec3*)cell); } - CY_NODISCARD Vec3 const * Columns() const { return ((Vec3*)cell); } - CY_NODISCARD Vec3 & Column ( int ci ) { return Columns()[ci]; } - CY_NODISCARD Vec3 const & Column ( int ci ) const { return Columns()[ci]; } -#endif - CY_NODISCARD Vec3 GetRow ( int ri ) const { return Vec3( cell[ri], cell[ri+3], cell[ri+6] ); } //!< Returns a row of the matrix - CY_NODISCARD Vec3 GetDiagonal() const { return Vec3( cell[0], cell[4], cell[8] ); } //!< Returns the diagonal of the matrix - CY_NODISCARD Matrix3 GetRotation() const { Matrix3 s, r; GetComponents(s,r); return r; } //!< Returns the rotation portion of the transformation - - //! Returns the scale portion of the transformation. - //! The returned matrix is symmetric, but not necessarily diagonal, and it can include non-uniform scale. - CY_NODISCARD Matrix3 GetScale() const - { - Matrix3 trns = GetTranspose(); - Matrix3 u2 = *this * trns; - Vec3 v0, v1, v2; - u2.GetEigenvectors( v0, v1, v2 ); - Matrix3 v(v0,v1,v2); - Matrix3 vt = v.GetTranspose(); - Matrix3 d2 = vt * (*this) * v; // the result is a diagonal matrix - Vec3 diag = d2.GetDiagonal(); - Matrix3 d; - d.SetScale(diag); - return v * d * vt; - } - - //! Returns the average scale factor - CY_NODISCARD T GetAvrgScale() const - { - T det = cell[0] * ( cell[4] * cell[8] - cell[5] * cell[7] ) + - cell[1] * ( cell[5] * cell[6] - cell[3] * cell[8] ) + - cell[2] * ( cell[3] * cell[7] - cell[4] * cell[6] ); - T s = std::pow( std::abs(det), T(1)/T(3) ); - return det >= 0 ? s : -s; - } - - void GetComponents( Matrix3 &scale, Matrix3 &rotation ) const { scale = GetScale(); rotation = *this * scale.GetInverse(); } //!< Returns separate transformation components - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Sub-matrix cell - - CY_NODISCARD Matrix2 GetSubMatrix2() const { Matrix2 m; MemCopy(m.cell,cell,2); MemCopy(m.cell+2,cell+3,2); return m; } //!< Returns the 2x2 portion of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Comparison Operators - - CY_NODISCARD bool operator == ( Matrix3 const &right ) const { _CY_FOR_9i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal - CY_NODISCARD bool operator != ( Matrix3 const &right ) const { _CY_FOR_9i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal - - - ////////////////////////////////////////////////////////////////////////// - //!@name Access Operators - - CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<3 && ci>=0 && ci<3 ); return cell[ ci*3 + ri ]; } //!< subscript operator - CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<3 && ci>=0 && ci<3 ); return cell[ ci*3 + ri ]; } //!< constant subscript operator - CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<9 ); return cell[i]; } //!< subscript operator - CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<9 ); return cell[i]; } //!< constant subscript operator - - - ////////////////////////////////////////////////////////////////////////// - //!@name Unary and Binary Operators - - // Unary operators - CY_NODISCARD Matrix3 operator - () const { Matrix3 r; _CY_FOR_9i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix - - // Binary operators - CY_NODISCARD Matrix3 operator * ( T const value ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value - CY_NODISCARD Matrix3 operator / ( T const value ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value - CY_NODISCARD Matrix3 operator + ( Matrix3 const &right ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices - CY_NODISCARD Matrix3 operator - ( Matrix3 const &right ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix3 from another - - CY_NODISCARD Matrix3 operator * ( Matrix3 const &right ) const //!< multiply a matrix with another - { - _CY_INIT_MATRIX3_VECTORIZATION; - Matrix3 rm; - for ( int i=0; i<9; i+=3 ) { - T a[4], b[4], c[4], d[4], r[4]; - _CY_IVDEP_FOR ( int j=0; j operator * ( Vec3 const &p ) const - { - _CY_INIT_MATRIX3_VECTORIZATION; - //return Vec3( p.x*cell[0] + p.y*cell[3] + p.z*cell[6], - // p.x*cell[1] + p.y*cell[4] + p.z*cell[7], - // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] ); - T a[4], b[4], c[4], d[4]; - Vec3 r; - _CY_IVDEP_FOR ( int i=0; i const &diag ) const { return AddDiagonal(diag.x,diag.y,diag.z); } //!< Adds a diagonal matrix to this matrix and returns the result. - CY_NODISCARD Matrix3 AddIdentity( T scale=T(1) ) const { return AddDiagonal( scale, scale, scale ); } //!< Adds a scaled identity matrix to this matrix and returns the result. - - void Transpose() //!< Transpose this matrix - { - for ( int i = 1; i < 3; ++i ) { - for ( int j = 0; j < i; j++) { - T temp = cell[i * 3 + j]; - cell[i * 3 + j] = cell[j * 3 + i]; - cell[j * 3 + i] = temp; - } - } - } - CY_NODISCARD Matrix3 GetTranspose() const //!< Return the transpose of this matrix - { - Matrix3 m; - m.cell[0] = cell[0]; m.cell[1] = cell[3]; m.cell[2] = cell[6]; - m.cell[3] = cell[1]; m.cell[4] = cell[4]; m.cell[5] = cell[7]; - m.cell[6] = cell[2]; m.cell[7] = cell[5]; m.cell[8] = cell[8]; - return m; - } - - //! Multiply the give vector with the transpose of the matrix - CY_NODISCARD Vec3 TransposeMult( Vec3 const &p ) const - { - return Vec3( p.x*cell[0] + p.y*cell[1] + p.z*cell[2], - p.x*cell[3] + p.y*cell[4] + p.z*cell[5], - p.x*cell[6] + p.y*cell[7] + p.z*cell[8] ); - } - - CY_NODISCARD Matrix3 TransposeMult( Matrix3 const & right ) const //!< Multiply a matrix by the transpose of this one (i.e. this^T * right). - { - Matrix3 r; - for ( int i=0, k=0; i<3; ++i ) { - for ( int j=0; j<3; ++j, ++k ) { - r.cell[k] = Column(j).Dot( right.Column(i) ); - } - } - return r; - } - CY_NODISCARD Matrix3 MultTranspose( Matrix3 const & right ) const //!< Multiply the transpose of a matrix by this one (i.e. this * right^T). - { - _CY_INIT_MATRIX3_VECTORIZATION; - Matrix3 rm; - for ( int i=0; i<3; ++i ) { - T a[4], b[4], c[4], d[4], r[4]; - _CY_IVDEP_FOR ( int j=0; j GetEigenvalues( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - Vec3 lambda; - if ( IsDiagonal(tollerance) ) { - lambda = GetDiagonal(); // diagonal matrix, so the eigenvalues are the same as the diagonal elements. - } else { - T q = GetTrace() / 3; - Matrix3 m = AddIdentity(-q); - Matrix3 m2 = m * m; - T p = Sqrt( m2.GetTrace() / T(6) ); - Matrix3 B = m / p; - T d_2 = B.GetDeterminant() * T(0.5); - T a = d_2 < T(-1) ? Pi()/3 : ( d_2 > T(1) ? T(0) : ACosSafe(d_2)/3 ); // only guaranteed to work for symmetric matrices - Vec3 b; - b.x = 2*std::cos( a ); - b.y = 2*std::cos( a + Pi()*(T(2)/T(3)) ); - b.z = 2*std::cos( a + Pi()*(T(4)/T(3)) ); - lambda = b*p + q; - } - return lambda; - } - - //! Returns the eigenvalues and sets the given vector as the eigenvectors of the matrix. - //! The eigenvalues are ordered, such that the first one is the largest. - //! The given tollerance is used for checking whether the eigenvalues are the same. - Vec3 GetEigenvectors( Vec3 &evec0, Vec3 &evec1, Vec3 &evec2, T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - static auto setVectors = [&]( Vec3 &e0, Vec3 &e1, Vec3 &e2, Matrix3 const &v20, Matrix3 const &v12, Matrix3 const &v01 ) { - int i = 0; - Matrix3 v2 = v20 * v12; - e2 = v2.Column(0) + v2.Column(1) + v2.Column(2); - if ( (e2 ^ v01.Column(0)).LengthSquared() < tollerance ) { - e0 = v01.Column(1); - e1 = v01.Column(2); - } else { - e0 = v01.Column(0); - e1 = v01.Column( ( (e2 ^ v01.Column(1)).LengthSquared() < tollerance ) ? 2 : 1 ); - } - }; - - Vec3 lambda = GetEigenvalues(tollerance); - bool same01 = std::abs(lambda.x - lambda.y) < tollerance; - bool same12 = std::abs(lambda.y - lambda.z) < tollerance; - bool same02 = std::abs(lambda.x - lambda.z) < tollerance; - if ( same01 & same12 ) { - // All eigenvalues are the same, so, assuming that the matrix is normal, it must be scaled identity. - evec0 = Column(0); - evec1 = Column(1); - evec2 = Column(2); - } else { - Matrix3 v12 = AddIdentity( -lambda.x ); - Matrix3 v20 = AddIdentity( -lambda.y ); - Matrix3 v01 = AddIdentity( -lambda.z ); - char same = char(same01) | char(same12)*char(2) | char(same02)*char(3); // only one of them can be true here - switch (same) { - default: case 0: { - Matrix3 v0 = v01 * v20; - Matrix3 v1 = v12 * v01; - Matrix3 v2 = v20 * v12; - evec0 = v0.Column(0) + v0.Column(1) + v0.Column(2); - evec1 = v1.Column(0) + v1.Column(1) + v1.Column(2); - evec2 = v2.Column(0) + v2.Column(1) + v2.Column(2); - } - break; - case 1: setVectors( evec0, evec1, evec2, v20, v12, v01 ); break; - case 2: setVectors( evec1, evec2, evec0, v01, v20, v12 ); break; - case 3: setVectors( evec0, evec2, evec1, v12, v01, v20 ); break; - } - } - return lambda; - } - - //! Singular value decomposition (SVD) - //! Returns the SVD of the matrix, where U and V are orthogonal matrices and - //! S is the diagonal elements of a diagonal matrix (including zeros), - //! such that this matrix A = U S V^T. - //! The given tollerance is used for checking whether the eigenvalues are the same. - void SingularValueDecomposition( Matrix3 &U, Vec3 &S, Matrix3 &V, T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) - { - Matrix3 AAT = MultSelfTranspose(); - Vec3 lambda = AAT.GetEigenvectors( U.Column(0), U.Column(1), U.Column(2), tollerance ); - S = (lambda.Abs()).Sqrt(); - U.Normalize(); - Matrix3 ATA = TransposeMultSelf(); - AAT.GetEigenvectors( V.Column(0), V.Column(1), V.Column(2), tollerance ); - V.Normalize(); - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Static Methods - - //! Returns an identity matrix - CY_NODISCARD static Matrix3 Identity() { T c[] = { 1,0,0, 0,1,0, 0,0,1 }; return Matrix3(c); } - //! Returns a view matrix using position, target and approximate up vector - CY_NODISCARD static Matrix3 View( Vec3 const &target, Vec3 const &up ) { Matrix3 m; m.SetView(target,up); return m; } - //! Returns a rotation matrix around x axis by angle in radians - CY_NODISCARD static Matrix3 RotationX( T angle ) { Matrix3 m; m.SetRotationX(angle); return m; } - //! Returns a rotation matrix around y axis by angle in radians - CY_NODISCARD static Matrix3 RotationY( T angle ) { Matrix3 m; m.SetRotationY(angle); return m; } - //! Returns a rotation matrix around z axis by angle in radians - CY_NODISCARD static Matrix3 RotationZ( T angle ) { Matrix3 m; m.SetRotationZ(angle); return m; } - //! Returns a rotation matrix around x, y, and then z axes by angle in radians (Rz * Ry * Rx) - CY_NODISCARD static Matrix3 RotationXYZ( T angleX, T angleY, T angleZ ) { Matrix3 m; m.SetRotationXYZ(angleX,angleY,angleZ); return m; } - //! Returns a rotation matrix around z, y, and then x axes by angle in radians (Rx * Ry * Rz) - CY_NODISCARD static Matrix3 RotationZYX( T angleX, T angleY, T angleZ ) { Matrix3 m; m.SetRotationZYX(angleX,angleY,angleZ); return m; } - //! Returns a rotation matrix about the given axis by angle in radians - CY_NODISCARD static Matrix3 Rotation( Vec3 const &axis, T angle ) { Matrix3 m; m.SetRotation(axis,angle); return m; } - //! Returns a rotation matrix that sets [from] unit vector to [to] unit vector - CY_NODISCARD static Matrix3 Rotation( Vec3 const &from, Vec3 const &to ) { Matrix3 m; m.SetRotation(from,to); return m; } - //! Returns a uniform scale matrix - CY_NODISCARD static Matrix3 Scale( T uniformScale ) { Matrix3 m; m.SetScale(uniformScale); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix3 Scale( T scaleX, T scaleY, T scaleZ ) { Matrix3 m; m.SetScale(scaleX,scaleY,scaleZ); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix3 Scale( Vec3 const &scale ) { Matrix3 m; m.SetScale(scale); return m; } - //! Returns the tensor product (outer product) matrix of two vectors - CY_NODISCARD static Matrix3 TensorProduct( Vec3 const &v0, Vec3 const &v1 ) { Matrix3 m; m.SetTensorProduct(v0,v1); return m; } - //! Returns the matrix representation of cross product ( a x b ) - CY_NODISCARD static Matrix3 MatrixCrossProd( Vec3 const &a ) { Matrix3 m; m.SetCrossProd(a); return m; } - - ////////////////////////////////////////////////////////////////////////// -}; - -//------------------------------------------------------------------------------- - -#ifdef CY_NONVECTORIZED_MATRIX3 -# define _CY_INIT_MATRIX34_VECTORIZATION const int N = 3; T const *cell_9 = cell + 9; -#else -# define _CY_INIT_MATRIX34_VECTORIZATION const int N = 4; T cell_9[4] = { cell[9], cell[10], cell[11], cell[11] }; -#endif - -//------------------------------------------------------------------------------- - -//! 3x4 matrix class. -//! -//! Its data stores 12-value array of column-major matrix elements. -//! I chose column-major format to be compatible with OpenGL -//! You can use Matrix34 with Vec3 and Vec4 -//! to transform 3D and 4D points. - -template -class Matrix34 -{ - CY_NODISCARD friend Matrix34 operator * ( T value, Matrix34 const &right ) { Matrix34 r; _CY_FOR_12i( r.cell[i]=value*right.cell[i] ); return r; } //!< multiply matrix by a value - CY_NODISCARD friend Matrix34 operator + ( T value, Matrix34 const &right ) { Matrix34 r= right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< add a value times identity matrix to a matrix - CY_NODISCARD friend Matrix34 operator - ( T value, Matrix34 const &right ) { Matrix34 r=-right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< subtract a matrix from a value times identity matrix - CY_NODISCARD friend Matrix34 Inverse( Matrix34 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix - -public: - - //! Elements of the matrix are column-major: \n - //! | 0 3 6 9 | \n - //! | 1 4 7 10 | \n - //! | 2 5 8 11 | \n -#ifdef __cpp_unrestricted_unions - union { - T cell[12]; - Vec3 column[4]; // column vectors - }; -#else - T cell[12]; -#endif - - - ////////////////////////////////////////////////////////////////////////// - //!@name Constructors - - Matrix34() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor - template explicit Matrix34( Matrix34 const &matrix ) { MemConvert(cell,matrix.cell,12); } //!< Copy constructor for different types - explicit Matrix34( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 9 values - explicit Matrix34( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v - explicit Matrix34( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Set(x,y,z,pos); } //!< Initialize the matrix using x,y,z vectors and coordinate center - explicit Matrix34( Matrix3 const &m ) { MemCopy(cell,m.cell,9); Column(3).Zero(); } - explicit Matrix34( Matrix3 const &m, Vec3 const &pos ) { MemCopy(cell,m.cell,9); Column(3)=pos; } - explicit Matrix34( Matrix2 const &m ) { Column(0)=Vec3(m.Column(0)); Column(1)=Vec3(m.Column(1)); Column(2).Set(0,0,1); Column(3).Zero(); } - explicit Matrix34( Matrix4 const &m ); - - //! Constructor using row-major order for initialization - Matrix34( T c00, T c01, T c02, T c03, - T c10, T c11, T c12, T c13, - T c20, T c21, T c22, T c23 ) - { - cell[ 0] = c00; cell[ 3] = c01; cell[ 6] = c02; cell[ 9] = c03; - cell[ 1] = c10; cell[ 4] = c11; cell[ 7] = c12; cell[10] = c13; - cell[ 2] = c20; cell[ 5] = c21; cell[ 8] = c22; cell[11] = c23; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Set & Get Methods - - void Zero () { MemClear(cell,12); } //!< Set all the values as zero - bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero () && Column(2).IsZero () && Column(3).IsZero (); } //!< Returns true if the matrix is exactly zero - bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite() && Column(2).IsFinite() && Column(3).IsFinite(); } //!< Returns true if all components are finite real numbers. - void Get( T * restrict values ) { MemCopy(values,cell,12); } //!< Copies the matrix cell to the given values array of size 12 - void Set( T const * restrict values ) { MemCopy(cell,values,12); } //!< Set Matrix using an array of 12 values - void Set( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Column(0)=x; Column(1)=y; Column(2)=z; Column(3)=pos; } //!< Set matrix using x,y,z vectors and coordinate center - void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Affine transformations - - //! Sets a uniform scale matrix - void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale,uniformScale); } - //! Sets a scale matrix - void SetScale( T scaleX, T scaleY, T scaleZ ) - { - Zero(); - cell[0] = scaleX; - cell[4] = scaleY; - cell[8] = scaleZ; - } - //! Sets a scale matrix - void SetScale( Vec3 const &scale ) { SetScale(scale.x,scale.y,scale.z); } - //! Set as rotation matrix around x axis - void SetRotationX( T angle ) { SetRotationX( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around x axis by cos and sin of angle - void SetRotationX( T sinAngle, T cosAngle ) - { - cell[0] = T(1); cell[1] = T(0); cell[2] = T(0); - cell[3] = T(0); cell[4] = cosAngle; cell[5] = sinAngle; - cell[6] = T(0); cell[7] = -sinAngle; cell[8] = cosAngle; - MemClear(cell+9,3); - } - //! Set as rotation matrix around y axis - void SetRotationY( T angle ) { SetRotationY( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around y axis by cos and sin of angle - void SetRotationY( T sinAngle, T cosAngle ) - { - cell[0] = cosAngle; cell[1] = T(0); cell[2] = -sinAngle; - cell[3] = T(0); cell[4] = T(1); cell[5] = T(0); - cell[6] = sinAngle; cell[7] = T(0); cell[8] = cosAngle; - MemClear(cell+9,3); - } - //! Set as rotation matrix around z axis - void SetRotationZ( T angle ) { SetRotationZ( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around z axis by cos and sin of angle - void SetRotationZ( T sinAngle, T cosAngle ) - { - cell[0] = cosAngle; cell[1] = sinAngle; cell[2] = T(0); - cell[3] = -sinAngle; cell[4] = cosAngle; cell[5] = T(0); - cell[6] = T(0); cell[7] = T(0); cell[8] = T(1); - MemClear(cell+9,3); - } - //! Set as rotation matrix around x, y, and then z axes ( Rz * Ry * Rx ) - void SetRotationXYZ( T angleX, T angleY, T angleZ ) - { - T sx = std::sin(angleX); - T cx = std::cos(angleX); - T sy = std::sin(angleY); - T cy = std::cos(angleY); - T sz = std::sin(angleZ); - T cz = std::cos(angleZ); - cell[0] = cy*cz; cell[1] = cy*sz; cell[2] =-sy; - cell[3] = cz*sx*sy - cx*sz; cell[4] = cx*cz + sx*sy*sz; cell[5] = cy*sx; - cell[6] = cx*cz*sy + sx*sz; cell[7] =-cz*sx + cx*sy*sz; cell[8] = cx*cy; - MemClear(cell+9,3); - } - //! Set as rotation matrix around z, y, and then x axes ( Rx * Ry * Rz ) - void SetRotationZYX( T angleX, T angleY, T angleZ ) - { - T sx = std::sin(angleX); - T cx = std::cos(angleX); - T sy = std::sin(angleY); - T cy = std::cos(angleY); - T sz = std::sin(angleZ); - T cz = std::cos(angleZ); - cell[0] = cy*cz; cell[1] = cx*sz + sx*sy*cz; cell[2] = sx*sz - cx*sy*cz; - cell[3] =-cy*sz; cell[4] = cx*cz - sx*sy*sz; cell[5] = sx*cz + cx*sy*sz; - cell[6] = sy; cell[7] =-sx*cy; cell[8] = cx*cy; - MemClear(cell+9,3); - } - //! Set a rotation matrix about the given axis by angle - void SetRotation( Vec3 const &axis, T angle ) { SetRotation(axis,std::sin(angle),std::cos(angle)); } - //! Set a rotation matrix about the given axis by cos and sin of angle - void SetRotation( Vec3 const &axis, T sinAngle, T cosAngle ) - { - T t = T(1) - cosAngle; - Vec3 a = t * axis; - T txy = a.x * axis.y; - T txz = a.x * axis.z; - T tyz = a.y * axis.z; - Vec3 s = sinAngle * axis; - cell[ 0] = a.x * axis.x + cosAngle; cell[ 1] = txy + s.z; cell[ 2] = txz - s.y; - cell[ 3] = txy - s.z; cell[ 4] = a.y * axis.y + cosAngle; cell[ 5] = tyz + s.x; - cell[ 6] = txz + s.y; cell[ 7] = tyz - s.x; cell[ 8] = a.z * axis.z + cosAngle; - MemClear(cell+9,3); - } - //! Set a rotation matrix that sets [from] unit vector to [to] unit vector - void SetRotation( Vec3 const &from, Vec3 const &to ) - { - T c = from.Dot(to); - if ( c > T(0.9999999) ) SetIdentity(); - else { - T s = Sqrt(T(1) - c*c); - Vec3 axis = from.Cross(to).GetNormalized(); - SetRotation(axis, s, c); - } - } - //! Sets a translation matrix with no rotation or scale - void SetTranslation( Vec3 const &move ) { Column(0).Set(1,0,0); Column(1).Set(0,1,0); Column(2).Set(0,0,1); Column(3)=move; } - //! Adds a translation to the matrix - void AddTranslation( Vec3 const &move ) { Column(3) += move; } - //! Sets the translation component of the matrix - void SetTranslationComponent( Vec3 const &move ) { Column(3) = move; } - //! Sets the translation component of the matrix to zero - void SetNoTranslation() { Column(3).Set(0,0,0); } - //! Set view matrix using position, target and approximate up vector - void SetView( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) - { - Vec3 f = target - pos; - f.Normalize(); - Vec3 s = f.Cross(up); - s.Normalize(); - Vec3 u = s.Cross(f); - cell[ 0]=s.x; cell[ 1]=u.x; cell[ 2]=-f.x; - cell[ 3]=s.y; cell[ 4]=u.y; cell[ 5]=-f.y; - cell[ 6]=s.z; cell[ 7]=u.z; cell[ 8]=-f.z; - cell[ 9]= -s % pos; - cell[10]= -u % pos; - cell[11]= f % pos; - } - //! Sets a Cartesian coordinate frame using the given x direction, an approximate y direction, and a translation. x must be a unit vector. - void SetCartesianFrameXY( Vec3 const &x, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x.Cross(y_approx); z.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given x direction, an approximate z direction, and a translation. x must be a unit vector. - void SetCartesianFrameXZ( Vec3 const &x, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z_approx.Cross(x); y.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given y direction, an approximate x direction, and a translation. y must be a unit vector. - void SetCartesianFrameYX( Vec3 const &y, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x_approx.Cross(y); z.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given y direction, an approximate z direction, and a translation. y must be a unit vector. - void SetCartesianFrameYZ( Vec3 const &y, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y.Cross(z_approx); x.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given z direction, an approximate x direction, and a translation. z must be a unit vector. - void SetCartesianFrameZX( Vec3 const &z, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z.Cross(x_approx); y.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given z direction, an approximate y direction, and a translation. z must be a unit vector. - void SetCartesianFrameZY( Vec3 const &z, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y_approx.Cross(z); x.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set Row, Column, or Diagonal - - void SetRow ( int ri, T x, T y, T z, T w ) { cell[ri]=x; cell[ri+3]=y; cell[ri+6]=z; cell[ri+9]=w; } //!< Sets a row of the matrix - void SetRow ( int ri, Vec4 const &v ) { SetRow(ri,v.x,v.y,v.z,v.w); } //!< Sets a row of the matrix - void SetColumn ( int ci, T x, T y, T z ) { Column(ci).Set(x,y,z); } //!< Sets a column of the matrix - void SetColumn ( int ci, Vec3 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix - void SetDiagonal( T xx, T yy, T zz ) { cell[0]=xx; cell[4]=yy; cell[8]=zz; } //!< Sets the diagonal values of the matrix - void SetDiagonal( Vec3 const &p ) { SetDiagonal( p.x, p.y, p.z ); } //!< Sets the diagonal values of the matrix - void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1],values[2]); } //!< Sets the diagonal values of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Row, Column, or Diagonal - -#ifdef __cpp_unrestricted_unions - CY_NODISCARD Vec3 * Columns() { return column; } - CY_NODISCARD Vec3 const * Columns() const { return column; } - CY_NODISCARD Vec3 & Column ( int ci ) { return column[ci]; } - CY_NODISCARD Vec3 const & Column ( int ci ) const { return column[ci]; } -#else - CY_NODISCARD Vec3 * Columns() { return ((Vec3*)cell); } - CY_NODISCARD Vec3 const * Columns() const { return ((Vec3*)cell); } - CY_NODISCARD Vec3 & Column ( int ci ) { return Columns()[ci]; } - CY_NODISCARD Vec3 const & Column ( int ci ) const { return Columns()[ci]; } -#endif - CY_NODISCARD Vec4 GetRow ( int ri ) const { return Vec4( cell[ri], cell[ri+3], cell[ri+6], cell[ri+9] ); } //!< Returns a row of the matrix - CY_NODISCARD Vec3 GetDiagonal() const { return Vec3( cell[0], cell[4], cell[8] ); } //!< Returns the diagonal of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Sub-matrix cell - - CY_NODISCARD Matrix3 GetSubMatrix3 () const { Matrix3 m; MemCopy(m.cell,cell,9); return m; } //!< Returns the 3x3 portion of the matrix - CY_NODISCARD Matrix2 GetSubMatrix2 () const { Matrix2 m; MemCopy(m.cell,cell,2); MemCopy(m.cell+2,cell+3,2); return m; } //!< Returns the 2x2 portion of the matrix - CY_NODISCARD Vec3 GetTranslation() const { return Column(3); } //!< Returns the translation component of the matrix - CY_NODISCARD Matrix3 GetRotation () const { Matrix3 m(*this); return m.GetRotation(); } //!< Returns the rotation portion of the transformation - CY_NODISCARD Matrix3 GetScale () const { Matrix3 m(*this); return m.GetScale (); } //!< Returns the scale portion of the transformation. - - //! Returns the average scale factor of the 3 by 3 sub-matrix - T GetAvrgScale() const - { - T det = cell[0] * ( cell[4] * cell[8] - cell[5] * cell[7] ) + - cell[1] * ( cell[5] * cell[6] - cell[3] * cell[8] ) + - cell[2] * ( cell[3] * cell[7] - cell[4] * cell[6] ); - T s = std::pow( std::abs(det), T(1)/T(3) ); - return det >= 0 ? s : -s; - } - - void GetComponents( Matrix3 &scale, Matrix3 &rotation, Vec3 &translation ) const { Matrix3 m(*this); m.GetComponents(scale,rotation); translation=GetTranslation(); } //!< Returns separate transformation components - - ////////////////////////////////////////////////////////////////////////// - //!@name Comparison Operators - - CY_NODISCARD bool operator == ( Matrix34 const &right ) const { _CY_FOR_12i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal - CY_NODISCARD bool operator != ( Matrix34 const &right ) const { _CY_FOR_12i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal - - - ////////////////////////////////////////////////////////////////////////// - //!@name Access Operators - - CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<3 && ci>=0 && ci<4 ); return cell[ ci*3 + ri ]; } //!< subscript operator - CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<3 && ci>=0 && ci<4 ); return cell[ ci*3 + ri ]; } //!< constant subscript operator - CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<12 ); return cell[i]; } //!< subscript operator - CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<12 ); return cell[i]; } //!< constant subscript operator - - - ////////////////////////////////////////////////////////////////////////// - //!@name Unary and Binary Operators - - // Unary operators - CY_NODISCARD Matrix34 operator - () const { Matrix34 r; _CY_FOR_12i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix - - // Binary operators - CY_NODISCARD Matrix34 operator * ( T const value ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value - CY_NODISCARD Matrix34 operator / ( T const value ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value - CY_NODISCARD Matrix34 operator + ( Matrix34 const &right ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices - CY_NODISCARD Matrix34 operator - ( Matrix34 const &right ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix4 from another - CY_NODISCARD Matrix34 operator * ( Matrix34 const &right ) const //!< multiply a matrix with another - { - _CY_INIT_MATRIX34_VECTORIZATION; - Matrix34 rm; - T *rd = rm.cell; - for ( int i=0; i<12; i+=3, rd+=3 ) { - T a[4], b[4], c[4], d[4], r[4]; - _CY_IVDEP_FOR ( int k=0; k const &right ) const //!< multiply a matrix with another - { - _CY_INIT_MATRIX34_VECTORIZATION; - Matrix34 rm; - T *rd = rm.cell; - for ( int i=0; i<9; i+=3, rd+=3 ) { - T a[4], b[4], c[4], d[4], r[4]; - _CY_IVDEP_FOR ( int k=0; k operator * ( Vec3 const &p ) const - { - _CY_INIT_MATRIX34_VECTORIZATION; - //return Vec3( p.x*cell[0] + p.y*cell[3] + p.z*cell[6] + cell[ 9], - // p.x*cell[1] + p.y*cell[4] + p.z*cell[7] + cell[10], - // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] + cell[11] ); - T a[4], b[4], c[4], d[4], e[4], r[4]; - _CY_IVDEP_FOR ( int i=0; i(r); - } - CY_NODISCARD Vec4 operator * ( Vec4 const &p ) const - { - _CY_INIT_MATRIX34_VECTORIZATION; - //return Vec4( p.x*cell[0] + p.y*cell[3] + p.z*cell[6] + p.w*cell[ 9], - // p.x*cell[1] + p.y*cell[4] + p.z*cell[7] + p.w*cell[10], - // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] + p.w*cell[11], - // 0 + 0 + 0 + p.w ); - Vec4 r; - T a[4], b[4], c[4], d[4], e[4], f[4]; - _CY_IVDEP_FOR ( int i=0; i VectorTransform( Vec3 const &p ) const - { - _CY_INIT_MATRIX34_VECTORIZATION; - //return Vec3( p.x*cell[0] + p.y*cell[3] + p.z*cell[6], - // p.x*cell[1] + p.y*cell[4] + p.z*cell[7], - // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] ); - T a[4], b[4], c[4], d[4], r[4]; - _CY_IVDEP_FOR ( int i=0; i(r); - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Assignment Operators - - Matrix34 const & operator += ( Matrix34 const &right ) { _CY_FOR_12i( cell[i] += right.cell[i] ); return *this; } //!< add two Matrices modify this - Matrix34 const & operator -= ( Matrix34 const &right ) { _CY_FOR_12i( cell[i] -= right.cell[i] ); return *this; } //!< subtract one Matrix4 from another matrix and modify this matrix - Matrix34 const & operator *= ( Matrix34 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix - Matrix34 const & operator *= ( Matrix3 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix - Matrix34 const & operator *= ( T const value ) { _CY_FOR_12i( cell[i] *= value ); return *this; } //!< multiply a matrix with a value modify this matrix - Matrix34 const & operator /= ( T const value ) { _CY_FOR_12i( cell[i] /= value ); return *this; } //!< divide the matrix by a value modify the this matrix - Matrix34 const & operator += ( T const value ) { cell[0]+=value; cell[4]+=value; cell[8]+=value; return *this; } //!< add a value times identity matrix - Matrix34 const & operator -= ( T const value ) { cell[0]-=value; cell[4]-=value; cell[8]-=value; return *this; } //!< subtract a value times identity matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Other Methods - - //! Transpose this matrix - void Transpose() - { - for ( int i=1; i<3; ++i ) { - for ( int j=0; j GetTranspose() const; //!< Returns the transpose of this matrix - - //! Multiply the give vector with the transpose of the matrix - CY_NODISCARD Vec4 TransposeMult( Vec3 const &p ) const - { - return Vec4( p.x*cell[ 0] + p.y*cell[ 1] + p.z*cell[ 2], - p.x*cell[ 3] + p.y*cell[ 4] + p.z*cell[ 5], - p.x*cell[ 6] + p.y*cell[ 7] + p.z*cell[ 8], - p.x*cell[ 9] + p.y*cell[10] + p.z*cell[11] + T(1) ); - } - - //! Multiply the give vector with the transpose of the matrix - CY_NODISCARD Vec4 TransposeMult( Vec4 const &p ) const - { - return Vec4( p.x*cell[ 0] + p.y*cell[ 1] + p.z*cell[ 2], - p.x*cell[ 3] + p.y*cell[ 4] + p.z*cell[ 5], - p.x*cell[ 6] + p.y*cell[ 7] + p.z*cell[ 8], - p.x*cell[ 9] + p.y*cell[10] + p.z*cell[11] + p.w ); - } - - CY_NODISCARD T GetDeterminant() const //!< Get the determinant of this matrix - { - // 0 (4 8 - 5 7) + 1 (5 6 - 3 8) + 2 (3 7 - 4 6) - return cell[0] * ( cell[4] * cell[8] - cell[5] * cell[7] ) + - cell[1] * ( cell[5] * cell[6] - cell[3] * cell[8] ) + - cell[2] * ( cell[3] * cell[7] - cell[4] * cell[6] ); - } - void Invert() { *this = GetInverse(); } //!< Invert this matrix - CY_NODISCARD Matrix34 GetInverse() const //!< Get the inverse of this matrix - { - // (4 8 - 5 7) (5 6 - 3 8) (3 7 - 4 6) (3 (8 10 - 7 11) + 4 (6 11 - 8 9) + 5 (7 9 - 6 10)) - // (2 7 - 1 8) (0 8 - 2 6) (1 6 - 0 7) (0 (7 11 - 8 10) + 1 (8 9 - 6 11) + 2 (6 10 - 7 9)) / det - // (1 5 - 2 4) (2 3 - 0 5) (0 4 - 1 3) (0 (5 10 - 4 11) + 1 (3 11 - 5 9) + 2 (4 9 - 3 10)) - - Matrix34 inverse; - - T data_8_10__7_11 = cell[8] * cell[10] - cell[7] * cell[11]; - T data_6_11__8__9 = cell[6] * cell[11] - cell[8] * cell[ 9]; - T data_7__9__6_10 = cell[7] * cell[ 9] - cell[6] * cell[10]; - - inverse.cell[ 0] = (cell[4]*cell[8] - cell[5]*cell[7]); - inverse.cell[ 1] = (cell[2]*cell[7] - cell[1]*cell[8]); - inverse.cell[ 2] = (cell[1]*cell[5] - cell[2]*cell[4]); - - inverse.cell[ 3] = (cell[5]*cell[6] - cell[3]*cell[8]); - inverse.cell[ 4] = (cell[0]*cell[8] - cell[2]*cell[6]); - inverse.cell[ 5] = (cell[2]*cell[3] - cell[0]*cell[5]); - - inverse.cell[ 6] = (cell[3]*cell[7] - cell[4]*cell[6]); - inverse.cell[ 7] = (cell[1]*cell[6] - cell[0]*cell[7]); - inverse.cell[ 8] = (cell[0]*cell[4] - cell[1]*cell[3]); - - inverse.cell[ 9] = cell[3] * data_8_10__7_11 + cell[4] * data_6_11__8__9 + cell[5] * data_7__9__6_10; - inverse.cell[10] = cell[0] *-data_8_10__7_11 + cell[1] *-data_6_11__8__9 + cell[2] *-data_7__9__6_10; - inverse.cell[11] = cell[0] * (cell[5] * cell[10] - cell[4] * cell[11]) + - cell[1] * (cell[3] * cell[11] - cell[5] * cell[ 9]) + - cell[2] * (cell[4] * cell[ 9] - cell[3] * cell[10]); - - T det = cell[0] * inverse.cell[0] + cell[1] * inverse.cell[3] + cell[2] * inverse.cell[6]; - return inverse / det; - } - - //! Removes the scale component of the matrix by normalizing the first three columns. - //! The resulting matrix can contain shear, if it originally contained non-uniform scale and rotation. - void Normalize() { Column(0).Normalize(); Column(1).Normalize(); Column(2).Normalize(); } - - //! Orthogonalizes the matrix and removes the scale component, preserving the x direction - void OrthogonalizeX() - { - Column(0).Normalize(); - Column(1) -= Column(0) * (Column(1) % Column(0)); - Column(1).Normalize(); - Column(2) -= Column(0) * (Column(2) % Column(0)); - Column(2) -= Column(1) * (Column(2) % Column(1)); - Column(2).Normalize(); - } - //! Orthogonalizes the matrix and removes the scale component, preserving the y direction - void OrthogonalizeY() - { - Column(1).Normalize(); - Column(0) -= Column(1) * (Column(0) % Column(1)); - Column(0).Normalize(); - Column(2) -= Column(1) * (Column(2) % Column(1)); - Column(2) -= Column(0) * (Column(2) % Column(0)); - Column(2).Normalize(); - } - //! Orthogonalizes the matrix and removes the scale component, preserving the z direction - void OrthogonalizeZ() - { - Column(2).Normalize(); - Column(0) -= Column(2) * (Column(0) % Column(2)); - Column(0).Normalize(); - Column(1) -= Column(2) * (Column(1) % Column(2)); - Column(1) -= Column(0) * (Column(1) % Column(0)); - Column(1).Normalize(); - } - - //! Returns if the matrix is identity within the given error tollerance. - bool IsIdentity( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - return std::abs(cell[0]-T(1)) < tollerance && std::abs(cell[ 1]) < tollerance && std::abs(cell[ 2]) < tollerance && - std::abs(cell[3]) < tollerance && std::abs(cell[ 4]-T(1)) < tollerance && std::abs(cell[ 5]) < tollerance && - std::abs(cell[6]) < tollerance && std::abs(cell[ 7]) < tollerance && std::abs(cell[ 8]-T(1)) < tollerance && - std::abs(cell[9]) < tollerance && std::abs(cell[10]) < tollerance && std::abs(cell[11]) < tollerance; - } - - //! Returns if the matrix is symmetric within the given error tollerance. - bool IsSymmetric( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - return std::abs(cell[ 1] - cell[3]) < tollerance && - std::abs(cell[ 2] - cell[6]) < tollerance && - std::abs(cell[ 5] - cell[7]) < tollerance && - std::abs(cell[ 9]) < tollerance && - std::abs(cell[10]) < tollerance && - std::abs(cell[11]) < tollerance; - } - - //! Returns if the matrix is diagonal. - bool IsDiagonal( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - return std::abs(cell[ 1]) + std::abs(cell[ 2]) - + std::abs(cell[ 3]) + std::abs(cell[ 5]) - + std::abs(cell[ 6]) + std::abs(cell[ 7]) - + std::abs(cell[ 9]) + std::abs(cell[10]) + std::abs(cell[11]) < tollerance*9; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Static Methods - - //! Returns an identity matrix - CY_NODISCARD static Matrix34 Identity() { T c[] = { 1,0,0, 0,1,0, 0,0,1, 0,0,0 }; return Matrix34(c); } - //! Returns a view matrix using position, target and approximate up vector - CY_NODISCARD static Matrix34 View( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) { Matrix34 m; m.SetView(pos,target,up); return m; } - //! Returns a rotation matrix around x axis by angle in radians - CY_NODISCARD static Matrix34 RotationX( T angle ) { Matrix34 m; m.SetRotationX(angle); return m; } - //! Returns a rotation matrix around y axis by angle in radians - CY_NODISCARD static Matrix34 RotationY( T angle ) { Matrix34 m; m.SetRotationY(angle); return m; } - //! Returns a rotation matrix around z axis by angle in radians - CY_NODISCARD static Matrix34 RotationZ( T angle ) { Matrix34 m; m.SetRotationZ(angle); return m; } - //! Returns a rotation matrix around x, y, and then z axes by angle in radians (Rz * Ry * Rx) - CY_NODISCARD static Matrix34 RotationXYZ( T angleX, T angleY, T angleZ ) { Matrix34 m; m.SetRotationXYZ(angleX,angleY,angleZ); return m; } - //! Returns a rotation matrix around z, y, and then x axes by angle in radians (Rx * Ry * Rz) - CY_NODISCARD static Matrix34 RotationZYX( T angleX, T angleY, T angleZ ) { Matrix34 m; m.SetRotationZYX(angleX,angleY,angleZ); return m; } - //! Returns a rotation matrix about the given axis by angle in radians - CY_NODISCARD static Matrix34 Rotation( Vec3 const &axis, T angle ) { Matrix34 m; m.SetRotation(axis,angle); return m; } - //! Returns a rotation matrix that sets [from] unit vector to [to] unit vector - CY_NODISCARD static Matrix34 Rotation( Vec3 const &from, Vec3 const &to ) { Matrix34 m; m.SetRotation(from,to); return m; } - //! Returns a uniform scale matrix - CY_NODISCARD static Matrix34 Scale( T uniformScale ) { Matrix34 m; m.SetScale(uniformScale); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix34 Scale( T scaleX, T scaleY, T scaleZ ) { Matrix34 m; m.SetScale(scaleX,scaleY,scaleZ); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix34 Scale( Vec3 const &scale ) { Matrix34 m; m.SetScale(scale); return m; } - //! Returns a translation matrix with no rotation or scale - CY_NODISCARD static Matrix34 Translation( Vec3 const &move ) { Matrix34 m; m.SetTranslation(move); return m; } - - - ////////////////////////////////////////////////////////////////////////// -}; - - -//------------------------------------------------------------------------------- - -//! 4x4 matrix class. -//! -//! Its data stores 16-value array of column-major matrix elements. -//! I chose column-major format to be compatible with OpenGL -//! You can use Matrix4 with Vec3 and Vec4 -//! to transform 3D and 4D points. - -template -class Matrix4 -{ - CY_NODISCARD friend Matrix4 operator * ( T value, Matrix4 const &right ) { Matrix4 r; _CY_FOR_16i( r.cell[i]=value*right.cell[i] ); return r; } //!< multiply matrix by a value - CY_NODISCARD friend Matrix4 Inverse( Matrix4 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix - - //! multiply a 4x4 matrix with a 3x4 matrix, treating it as a 4x4 matrix with last row 0,0,0,1 - CY_NODISCARD friend Matrix4 operator * ( Matrix34 const &left, Matrix4 const &right ) - { - Matrix4 rm; - for ( int i=0; i<16; i+=4 ) { - T a[4], b[4], c[4], d[4], e[4], f[4], r[4]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) a[j] = left.cell[ j] * right.cell[i ]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) b[j] = left.cell[3+j] * right.cell[i+1]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) c[j] = left.cell[6+j] * right.cell[i+2]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) d[j] = left.cell[9+j] * right.cell[i+3]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) e[j] = a[j] + b[j]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) f[j] = c[j] + d[j]; - _CY_IVDEP_FOR ( int j=0; j<3; ++j ) r[j] = e[j] + f[j]; - r[3] = right.cell[i+3]; - MemCopy( rm.cell+i, r, 4 ); - } - return rm; - } - -public: - - //! Elements of the matrix are column-major: \n - //! | 0 4 8 12 | \n - //! | 1 5 9 13 | \n - //! | 2 6 10 14 | \n - //! | 3 7 11 15 | \n -#ifdef __cpp_unrestricted_unions - struct ColVec3 { - Vec3 v; - T s; - void Set( Vec3 const &_v, T _s ) { v=_v; s=_s; } - }; // column vector plus scalar - union { - T cell [16]; - Vec4 column[4]; // column vectors - ColVec3 col3 [4]; // column vectors plus scalars - }; -#else - T cell [16]; -#endif - - - ////////////////////////////////////////////////////////////////////////// - //!@name Constructors - - Matrix4() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor - template explicit Matrix4( Matrix4 const &matrix ) { MemConvert(cell,matrix.cell,16); } //!< Copy constructor for different types - explicit Matrix4( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 9 values - explicit Matrix4( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v - explicit Matrix4( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Set(x,y,z,pos); } //!< Initialize the matrix using x,y,z vectors and coordinate center - explicit Matrix4( Vec4 const &x, Vec4 const &y, Vec4 const &z, Vec4 const &w ) { Set(x,y,z,w); } //!< Initialize the matrix using x,y,z vectors as columns - explicit Matrix4( Matrix34 const &m ) { Column(0).Set(m.Column(0),T(0)); Column(1).Set(m.Column(1),T(0)); Column(2).Set(m.Column(2),T(0)); Column(3).Set(m.Column(3),T(1)); } - explicit Matrix4( Matrix3 const &m ) { Column(0).Set(m.Column(0),T(0)); Column(1).Set(m.Column(1),T(0)); Column(2).Set(m.Column(2),T(0)); Column(3).Set(0,0,0,1); } - explicit Matrix4( Matrix2 const &m ) { Column(0).Set(m.Column(0),T(0),T(0)); Column(1).Set(m.Column(1),T(0),T(0)); Column(2).Set(0,0,1,0); Column(3).Set(0,0,0,1); } - explicit Matrix4( Matrix3 const &m, Vec3 const &pos ) { Column(0).Set(m.Column(0),T(0)); Column(1).Set(m.Column(1),T(0)); Column(2).Set(m.Column(2),T(0)); Column(3).Set(pos,T(1)); } - - //! Constructor using row-major order for initialization - Matrix4( T c00, T c01, T c02, T c03, - T c10, T c11, T c12, T c13, - T c20, T c21, T c22, T c23, - T c30, T c31, T c32, T c33 ) - { - cell[ 0] = c00; cell[ 4] = c01; cell[ 8] = c02; cell[12] = c03; - cell[ 1] = c10; cell[ 5] = c11; cell[ 9] = c12; cell[13] = c13; - cell[ 2] = c20; cell[ 6] = c21; cell[10] = c22; cell[14] = c23; - cell[ 3] = c30; cell[ 7] = c31; cell[11] = c32; cell[15] = c33; - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set & Get Methods - - void Zero () { MemClear(cell,16); } //!< Set all the values as zero - bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero () && Column(2).IsZero () && Column(3).IsZero (); } //!< Returns true if the matrix is exactly zero - bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite() && Column(2).IsFinite() && Column(3).IsFinite(); } //!< Returns true if all components are finite real numbers. - void Get( T * restrict values ) { MemCopy(values,cell,16); } //!< Copies the matrix cell to the given values array of size 16 - void Set( T const * restrict values ) { MemCopy(cell,values,16); } //!< Set Matrix using an array of 16 values - void Set( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Column(0).Set(x,T(0)); Column(1).Set(y,T(0)); Column(2).Set(z,T(0)); Column(3).Set(pos,T(1)); } //!< Set matrix using x,y,z column vectors and coordinate center - void Set( Vec4 const &x, Vec4 const &y, Vec4 const &z, Vec4 const &w ) { Column(0)=x; Column(1)=y; Column(2)=z; Column(3)=w; } //!< Set matrix using x,y,z,w column vectors - void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix - void SetTensorProduct( Vec4 const &v0, Vec4 const &v1 ) //!< Sets the matrix as the tensor product (outer product) of two vectors - { - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[ i] = v0[i] * v1.x; // cell[0]=v0.x*v1.x; cell[4]=v0.x*v1.y; cell[ 8]=v0.x*v1.z; cell[12]=v0.x*v1.w; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[ 4+i] = v0[i] * v1.y; // cell[1]=v0.y*v1.x; cell[5]=v0.y*v1.y; cell[ 9]=v0.y*v1.z; cell[13]=v0.y*v1.w; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[ 8+i] = v0[i] * v1.z; // cell[2]=v0.z*v1.x; cell[6]=v0.z*v1.y; cell[10]=v0.z*v1.z; cell[14]=v0.z*v1.w; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[12+i] = v0[i] * v1.w; // cell[3]=v0.w*v1.x; cell[7]=v0.w*v1.y; cell[11]=v0.w*v1.z; cell[15]=v0.w*v1.w; - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Affine transformations - - //! Sets a uniform scale matrix - void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale,uniformScale); } - //! Sets a scale matrix - void SetScale( T scaleX, T scaleY, T scaleZ, T scaleW=T(1) ) - { - Zero(); - cell[ 0] = scaleX; - cell[ 5] = scaleY; - cell[10] = scaleZ; - cell[15] = scaleW; - } - //! Sets a scale matrix - void SetScale( Vec3 const &scale ) { SetScale(scale.x,scale.y,scale.z); } - //! Set as rotation matrix around x axis - void SetRotationX( T angle ) { SetRotationX( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around x axis by cos and sin of angle - void SetRotationX( T sinAngle, T cosAngle ) - { - cell[ 0] = T(1); cell[ 1] = T(0); cell[ 2] = T(0); cell[ 3] = T(0); - cell[ 4] = T(0); cell[ 5] = cosAngle; cell[ 6] = sinAngle; cell[ 7] = T(0); - cell[ 8] = T(0); cell[ 9] = -sinAngle; cell[10] = cosAngle; - MemClear(cell+11,4); - cell[15] = T(1); - } - //! Set as rotation matrix around y axis - void SetRotationY( T angle ) { SetRotationY( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around y axis by cos and sin of angle - void SetRotationY( T sinAngle, T cosAngle ) - { - cell[ 0] = cosAngle; cell[ 1] = T(0); cell[ 2] = -sinAngle; cell[ 3] = T(0); - cell[ 4] = T(0); cell[ 5] = T(1); cell[ 6] = T(0); cell[ 7] = T(0); - cell[ 8] = sinAngle; cell[ 9] = T(0); cell[10] = cosAngle; - MemClear(cell+11,4); - cell[15] = T(1); - } - //! Set as rotation matrix around z axis - void SetRotationZ( T angle ) { SetRotationZ( std::sin(angle), std::cos(angle) ); } - //! Set as rotation matrix around z axis by cos and sin of angle - void SetRotationZ( T sinAngle, T cosAngle ) - { - cell[ 0] = cosAngle; cell[ 1] = sinAngle; cell[ 2] = T(0); cell[ 3] = T(0); - cell[ 4] = -sinAngle; cell[ 5] = cosAngle; cell[ 6] = T(0); cell[ 7] = T(0); - cell[ 8] = T(0); cell[ 9] = T(0); cell[10] = T(1); - MemClear(cell+11,4); - cell[15] = T(1); - } - //! Set as rotation matrix around x, y, and then z axes ( Rz * Ry * Rx ) - void SetRotationXYZ( T angleX, T angleY, T angleZ ) - { - T sx = std::sin(angleX); - T cx = std::cos(angleX); - T sy = std::sin(angleY); - T cy = std::cos(angleY); - T sz = std::sin(angleZ); - T cz = std::cos(angleZ); - cell[ 0] = cy*cz; cell[ 1] = cy*sz; cell[ 2] =-sy; cell[ 3] = T(0); - cell[ 4] = cz*sx*sy - cx*sz; cell[ 5] = cx*cz + sx*sy*sz; cell[ 6] = cy*sx; cell[ 7] = T(0); - cell[ 8] = cx*cz*sy + sx*sz; cell[ 9] =-cz*sx + cx*sy*sz; cell[10] = cx*cy; - MemClear(cell+11,4); - cell[15] = T(1); - } - //! Set as rotation matrix around z, y, and then x axes ( Rx * Ry * Rz ) - void SetRotationZYX( T angleX, T angleY, T angleZ ) - { - T sx = std::sin(angleX); - T cx = std::cos(angleX); - T sy = std::sin(angleY); - T cy = std::cos(angleY); - T sz = std::sin(angleZ); - T cz = std::cos(angleZ); - cell[ 0] = cy*cz; cell[ 1] = cx*sz + sx*sy*cz; cell[ 2] = sx*sz - cx*sy*cz; cell[ 3] = T(0); - cell[ 4] =-cy*sz; cell[ 5] = cx*cz - sx*sy*sz; cell[ 6] = sx*cz + cx*sy*sz; cell[ 7] = T(0); - cell[ 8] = sy; cell[ 9] =-sx*cy; cell[10] = cx*cy; - MemClear(cell+11,4); - cell[15] = T(1); - } - //! Set a rotation matrix about the given axis by angle - void SetRotation( Vec3 const &axis, T angle ) { SetRotation(axis,std::sin(angle),std::cos(angle)); } - //! Set a rotation matrix about the given axis by cos and sin of angle - void SetRotation( Vec3 const &axis, T sinAngle, T cosAngle ) - { - T t = T(1) - cosAngle; - Vec3 a = t * axis; - T txy = a.x * axis.y; - T txz = a.x * axis.z; - T tyz = a.y * axis.z; - Vec3 s = sinAngle * axis; - cell[ 0] = a.x * axis.x + cosAngle; cell[ 1] = txy + s.z; cell[ 2] = txz - s.y; cell[ 3] = T(0); - cell[ 4] = txy - s.z; cell[ 5] = a.y * axis.y + cosAngle; cell[ 6] = tyz + s.x; cell[ 7] = T(0); - cell[ 8] = txz + s.y; cell[ 9] = tyz - s.x; cell[10] = a.z * axis.z + cosAngle; - MemClear(cell+11,4); - cell[15] = T(1); - } - //! Set a rotation matrix that sets [from] unit vector to [to] unit vector - void SetRotation( Vec3 const &from, Vec3 const &to ) - { - T c = from.Dot(to); - if ( c > T(0.9999999) ) SetIdentity(); - else { - T s = Sqrt(T(1) - c*c); - Vec3 axis = from.Cross(to).GetNormalized(); - SetRotation(axis, s, c); - } - } - //! Sets a translation matrix with no rotation or scale - void SetTranslation( Vec3 const &move ) { Column(0).Set(1,0,0,0); Column(1).Set(0,1,0,0); Column(2).Set(0,0,1,0); Column(3).Set(move,1); } - //! Adds a translation to the matrix - void AddTranslation( Vec3 const &move ) { cell[12]+=move.x; cell[13]+=move.y; cell[14]+=move.z; } - //! Sets the translation component of the matrix - void SetTranslationComponent( Vec3 const &move ) { cell[12]=move.x; cell[13]=move.y; cell[14]=move.z; } - //! Sets the translation component of the matrix to zero - void SetNoTranslation() { cell[12]=0; cell[13]=0; cell[14]=0; } - //! Set view matrix using position, target and approximate up vector - void SetView( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) - { - Vec3 f = target - pos; - f.Normalize(); - Vec3 s = f.Cross(up); - s.Normalize(); - Vec3 u = s.Cross(f); - cell[ 0]=s.x; cell[ 1]=u.x; cell[ 2]=-f.x; cell[ 3]=T(0); - cell[ 4]=s.y; cell[ 5]=u.y; cell[ 6]=-f.y; cell[ 7]=T(0); - cell[ 8]=s.z; cell[ 9]=u.z; cell[10]=-f.z; cell[11]=T(0); - cell[12]= -s % pos; - cell[13]= -u % pos; - cell[14]= f % pos; - cell[15]=T(1); - } - //! Sets a Cartesian coordinate frame using the given x direction, an approximate y direction, and a translation. x must be a unit vector. - void SetCartesianFrameXY( Vec3 const &x, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x.Cross(y_approx); z.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given x direction, an approximate z direction, and a translation. x must be a unit vector. - void SetCartesianFrameXZ( Vec3 const &x, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z_approx.Cross(x); y.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given y direction, an approximate x direction, and a translation. y must be a unit vector. - void SetCartesianFrameYX( Vec3 const &y, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x_approx.Cross(y); z.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given y direction, an approximate z direction, and a translation. y must be a unit vector. - void SetCartesianFrameYZ( Vec3 const &y, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y.Cross(z_approx); x.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given z direction, an approximate x direction, and a translation. z must be a unit vector. - void SetCartesianFrameZX( Vec3 const &z, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z.Cross(x_approx); y.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } - //! Sets a Cartesian coordinate frame using the given z direction, an approximate y direction, and a translation. z must be a unit vector. - void SetCartesianFrameZY( Vec3 const &z, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y_approx.Cross(z); x.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } - //! Set a project matrix with field of view in radians - void SetPerspective( T fov, T aspect, T znear, T zfar ) { SetPerspectiveTan(std::tan(fov*T(0.5)),aspect,znear,zfar); } - //! Set a project matrix with the tangent of the half field of view (tan_fov_2) - void SetPerspectiveTan( T tan_fov_2, T aspect, T znear, T zfar ) - { - T yScale = T(1) / tan_fov_2; - T xScale = yScale / aspect; - T zdif = znear - zfar; - Column(0).Set(xScale,0,0,0); - Column(1).Set(0,yScale,0,0); - Column(2).Set(0,0,(zfar+znear)/zdif,-1); - Column(3).Set(0,0,(2*zfar*znear)/zdif,0); - } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Set Row, Column, or Diagonal - - void SetRow ( int ri, T x, T y, T z, T w ) { cell[ri]=x; cell[ri+4]=y; cell[ri+8]=z; cell[ri+12]=w; } //!< Sets a row of the matrix - void SetRow ( int ri, Vec4 const &v ) { SetRow(ri,v.x,v.y,v.z,v.w); } //!< Sets a row of the matrix - void SetColumn ( int ci, T x, T y, T z, T w ) { Column(ci).Set(x,y,z,w); } //!< Sets a column of the matrix - void SetColumn ( int ci, Vec4 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix - void SetDiagonal( T xx, T yy, T zz, T ww=1 ) { cell[0]=xx; cell[5]=yy; cell[10]=zz; cell[15]=ww; } //!< Sets the diagonal values of the matrix - void SetDiagonal( Vec4 const &p ) { SetDiagonal( p.x, p.y, p.z, p.w ); } //!< Sets the diagonal values of the matrix - void SetDiagonal( Vec3 const &p ) { SetDiagonal( p.x, p.y, p.z, T(1) ); } //!< Sets the diagonal values of the matrix - void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1],values[2],values[3]); } //!< Sets the 4 diagonal values of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Row, Column, or Diagonal - -#ifdef __cpp_unrestricted_unions - CY_NODISCARD Vec4 * Columns() { return column; } - CY_NODISCARD Vec4 const * Columns() const { return column; } - CY_NODISCARD Vec4 & Column ( int ci ) { return column[ci]; } - CY_NODISCARD Vec4 const & Column ( int ci ) const { return column[ci]; } - CY_NODISCARD Vec3 & Column3( int ci ) { return col3[ci].v; } - CY_NODISCARD Vec3 const & Column3( int ci ) const { return col3[ci].v; } -#else - CY_NODISCARD Vec4 * Columns() { return ((Vec4*)cell); } - CY_NODISCARD Vec4 const * Columns() const { return ((Vec4*)cell); } - CY_NODISCARD Vec4 & Column ( int ci ) { return Columns()[ci]; } - CY_NODISCARD Vec4 const & Column ( int ci ) const { return Columns()[ci]; } - CY_NODISCARD Vec3 & Column3( int ci ) { return (Vec3 &)cell[ci*4]; } - CY_NODISCARD Vec3 const & Column3( int ci ) const { return (Vec3 const &)cell[ci*4]; } -#endif - CY_NODISCARD Vec4 GetRow ( int ri ) const { return Vec4( cell[ri], cell[ri+4], cell[ri+8], cell[ri+12] ); } //!< Returns a row of the matrix - CY_NODISCARD Vec4 GetDiagonal() const { return Vec4( cell[0], cell[5], cell[10], cell[15] ); } //!< Returns the diagonal of the matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Get Sub-matrix cell - - CY_NODISCARD Matrix34 GetSubMatrix34() const { Matrix34 m; MemCopy(m.cell,cell,3); MemCopy(m.cell+3,cell+4,3); MemCopy(m.cell+6,cell+8,3); MemCopy(m.cell+9,cell+12,3); return m; } //!< Returns the 3x4 portion of the matrix - CY_NODISCARD Matrix3 GetSubMatrix3 () const { Matrix3 m; MemCopy(m.cell,cell,3); MemCopy(m.cell+3,cell+4,3); MemCopy(m.cell+6,cell+8,3); return m; } //!< Returns the 3x3 portion of the matrix - CY_NODISCARD Matrix2 GetSubMatrix2 () const { Matrix2 m; MemCopy(m.cell,cell,2); MemCopy(m.cell+2,cell+4,2); return m; } //!< Returns the 2x2 portion of the matrix - CY_NODISCARD Vec3 GetTranslation() const { return Vec3(cell+12); } //!< Returns the translation component of the matrix - CY_NODISCARD Matrix3 GetRotation () const { Matrix3 m(*this); return m.GetRotation(); } //!< Returns the rotation portion of the transformation - CY_NODISCARD Matrix3 GetScale () const { Matrix3 m(*this); return m.GetScale (); } //!< Returns the scale portion of the transformation. - - //! Returns the average scale factor of the 3 by 3 sub-matrix - CY_NODISCARD T GetAvrgScale() const - { - T det = cell[0] * ( cell[5] * cell[10] - cell[6] * cell[ 9] ) + - cell[1] * ( cell[6] * cell[ 8] - cell[4] * cell[10] ) + - cell[2] * ( cell[4] * cell[ 9] - cell[5] * cell[ 8] ); - T s = std::pow( std::abs(det), T(1)/T(3) ); - return det >= 0 ? s : -s; - } - - void GetComponents( Matrix3 &scale, Matrix3 &rotation, Vec3 &translation ) const { Matrix3 m(*this); m.GetComponents(scale,rotation); translation=GetTranslation(); } //!< Returns separate transformation components - - ////////////////////////////////////////////////////////////////////////// - //!@name Comparison Operators - - CY_NODISCARD bool operator == ( Matrix4 const &right ) const { _CY_FOR_16i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal - CY_NODISCARD bool operator != ( Matrix4 const &right ) const { _CY_FOR_16i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal - - - ////////////////////////////////////////////////////////////////////////// - //!@name Access Operators - - CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<4 && ci>=0 && ci<4 ); return cell[ ci*4 + ri ]; } //!< subscript operator - CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<4 && ci>=0 && ci<4 ); return cell[ ci*4 + ri ]; } //!< constant subscript operator - CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<16 ); return cell[i]; } //!< subscript operator - CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<16 ); return cell[i]; } //!< constant subscript operator - - - ////////////////////////////////////////////////////////////////////////// - //!@name Unary and Binary Operators - - // Unary operators - CY_NODISCARD Matrix4 operator - () const { Matrix4 r; _CY_FOR_16i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix - - // Binary operators - CY_NODISCARD Matrix4 operator * ( T const value ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value - CY_NODISCARD Matrix4 operator / ( T const value ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value - CY_NODISCARD Matrix4 operator + ( Matrix4 const &right ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices - CY_NODISCARD Matrix4 operator - ( Matrix4 const &right ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix4 from another - CY_NODISCARD Matrix4 operator * ( Matrix4 const &right ) const //!< multiply a matrix with another - { - Matrix4 rm; - for ( int i=0; i<16; i+=4 ) { - T a[4], b[4], c[4], d[4], e[4], f[4], r[4]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) a[j] = cell[ j] * right.cell[i ]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) b[j] = cell[ 4+j] * right.cell[i+1]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) c[j] = cell[ 8+j] * right.cell[i+2]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = cell[12+j] * right.cell[i+3]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) e[j] = a[j] + b[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) f[j] = c[j] + d[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = e[j] + f[j]; - MemCopy( rm.cell+i, r, 4 ); - } - return rm; - } - CY_NODISCARD Matrix4 operator * ( Matrix34 const &right ) const //!< multiply a matrix with another - { - T a[4], b[4], c[4], d[4], e[4], r[4]; - Matrix4 rm; - T *rd = rm.cell; - for ( int i=0; i<9; i+=3, rd+=4 ) { - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) a[k] = cell[ k] * right.cell[i ]; - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) b[k] = cell[4+k] * right.cell[i+1]; - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) c[k] = cell[8+k] * right.cell[i+2]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = a[j] + b[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = d[j] + c[j]; - MemCopy( rd, r, 4 ); - } - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) a[k] = cell[ k] * right.cell[ 9]; - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) b[k] = cell[4+k] * right.cell[10]; - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) c[k] = cell[8+k] * right.cell[11]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = a[j] + b[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) e[j] = c[j] + cell[12+j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = d[j] + e[j]; - MemCopy( rd, r, 4 ); - return rm; - } - CY_NODISCARD Matrix4 operator * ( Matrix3 const &right ) const //!< multiply a matrix with another - { - T a[4], b[4], c[4], d[4], r[4]; - Matrix4 rm; - T *rd = rm.cell; - for ( int i=0; i<9; i+=3, rd+=4 ) { - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) a[k] = cell[ k] * right.cell[i ]; - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) b[k] = cell[4+k] * right.cell[i+1]; - _CY_IVDEP_FOR ( int k=0; k<4; ++k ) c[k] = cell[8+k] * right.cell[i+2]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = a[j] + b[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = d[j] + c[j]; - MemCopy( rd, r, 4 ); - } - MemCopy( rm.cell+12, cell+12, 4 ); - return rm; - } - CY_NODISCARD Vec4 operator * ( Vec3 const &p ) const - { - //return Vec4( p.x*cell[0] + p.y*cell[4] + p.z*cell[ 8] + cell[12], - // p.x*cell[1] + p.y*cell[5] + p.z*cell[ 9] + cell[13], - // p.x*cell[2] + p.y*cell[6] + p.z*cell[10] + cell[14], - // p.x*cell[3] + p.y*cell[7] + p.z*cell[11] + cell[15] ); - Vec4 r; - T a[4], b[4], c[4], d[4], e[4]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = p.x * cell[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = p.y * cell[4+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = p.z * cell[8+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = a[i] + b[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) e[i] = c[i] + cell[12+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) r[i] = d[i] + e[i]; - return r; - } - CY_NODISCARD Vec4 operator * ( Vec4 const &p ) const - { - //return Vec4( p.x*cell[0] + p.y*cell[4] + p.z*cell[ 8] + p.w*cell[12], - // p.x*cell[1] + p.y*cell[5] + p.z*cell[ 9] + p.w*cell[13], - // p.x*cell[2] + p.y*cell[6] + p.z*cell[10] + p.w*cell[14], - // p.x*cell[3] + p.y*cell[7] + p.z*cell[11] + p.w*cell[15] ); - Vec4 r; - T a[4], b[4], c[4], d[4], e[4], f[4]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = p.x * cell[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = p.y * cell[4+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = p.z * cell[8+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = p.w * cell[12+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) e[i] = a[i] + b[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) f[i] = c[i] + d[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) r[i] = e[i] + f[i]; - return r; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name 3D Vector Transform Methods - - //! Transforms the vector by multiplying it with the matrix, ignoring the translation component. - CY_NODISCARD Vec4 VectorTransform( Vec3 const &p ) const - { - //return Vec4( p.x*cell[0] + p.y*cell[4] + p.z*cell[ 8], - // p.x*cell[1] + p.y*cell[5] + p.z*cell[ 9], - // p.x*cell[2] + p.y*cell[6] + p.z*cell[10], - // p.x*cell[3] + p.y*cell[7] + p.z*cell[11] ); - Vec4 r; - T a[4], b[4], c[4], d[4]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = p.x * cell[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = p.y * cell[4+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = p.z * cell[8+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = a[i] + b[i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) r[i] = d[i] + c[i]; - return r; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Assignment Operators - - Matrix4 const & operator += ( Matrix4 const &right ) { _CY_FOR_16i( cell[i] += right.cell[i] ); return *this; } //!< add two Matrices modify this - Matrix4 const & operator -= ( Matrix4 const &right ) { _CY_FOR_16i( cell[i] -= right.cell[i] ); return *this; } //!< subtract one Matrix4 from another matrix and modify this matrix - Matrix4 const & operator *= ( Matrix4 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix - Matrix4 const & operator *= ( Matrix34 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix - Matrix4 const & operator *= ( Matrix3 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix - Matrix4 const & operator *= ( T const value ) { _CY_FOR_16i( cell[i] *= value ); return *this; } //!< multiply a matrix with a value modify this matrix - Matrix4 const & operator /= ( T const value ) { _CY_FOR_16i( cell[i] /= value ); return *this; } //!< divide the matrix by a value modify the this matrix - - - ////////////////////////////////////////////////////////////////////////// - //!@name Other Methods - - void Transpose() //!< Transpose this matrix - { - for ( int i = 1; i < 4; ++i ) { - for ( int j = 0; j < i; j++) { - T temp = cell[i * 4 + j]; - cell[i * 4 + j] = cell[j * 4 + i]; - cell[j * 4 + i] = temp; - } - } - } - CY_NODISCARD Matrix4 GetTranspose() const //!< Return the transpose of this matrix - { - Matrix4 m; - m.cell[ 0] = cell[0]; m.cell[ 1] = cell[4]; m.cell[ 2] = cell[ 8]; m.cell[ 3] = cell[12]; - m.cell[ 4] = cell[1]; m.cell[ 5] = cell[5]; m.cell[ 6] = cell[ 9]; m.cell[ 7] = cell[13]; - m.cell[ 8] = cell[2]; m.cell[ 9] = cell[6]; m.cell[10] = cell[10]; m.cell[11] = cell[14]; - m.cell[12] = cell[3]; m.cell[13] = cell[7]; m.cell[14] = cell[11]; m.cell[15] = cell[15]; - return m; - } - - //! Multiply the give vector with the transpose of the matrix - CY_NODISCARD Vec4 TransposeMult( Vec3 const &p ) const { return TransposeMult( Vec4(p.x, p.y, p.z, T(1)) ); } - - //! Multiply the give vector with the transpose of the matrix - CY_NODISCARD Vec4 TransposeMult( Vec4 const &p ) const - { - //return Vec4( p.x*cell[ 0] + p.y*cell[ 1] + p.z*cell[ 2] + p.w*cell[ 3], - // p.x*cell[ 4] + p.y*cell[ 5] + p.z*cell[ 6] + p.w*cell[ 7], - // p.x*cell[ 8] + p.y*cell[ 9] + p.z*cell[10] + p.w*cell[11], - // p.x*cell[12] + p.y*cell[13] + p.z*cell[14] + p.w*cell[15] ); - T a[4], b[4], c[4], d[4]; - T const *pd = p.Elements(); - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = pd[i] * cell[ i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = pd[i] * cell[ 4+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = pd[i] * cell[ 8+i]; - _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = pd[i] * cell[12+i]; - Vec4 rr; - rr.x = a[0] + a[1] + a[2] + a[3]; - rr.y = b[0] + b[1] + b[2] + b[3]; - rr.z = c[0] + c[1] + c[2] + c[3]; - rr.w = d[0] + d[1] + d[2] + d[3]; - return rr; - } - - CY_NODISCARD Matrix4 TransposeMult( Matrix4 const & right ) const //!< Multiply a matrix by the transpose of this one (i.e. this^T * right). - { - Matrix4 r; - for ( int i=0, k=0; i<3; ++i ) { - for ( int j=0; j<3; ++j, ++k ) { - r.cell[k] = Column(j).Dot( right.Column(i) ); - } - } - return r; - } - CY_NODISCARD Matrix4 MultTranspose( Matrix4 const & right ) const //!< Multiply the transpose of a matrix by this one (i.e. this * right^T). - { - Matrix4 rm; - T* rd = rm.cell; - for ( int i=0; i<4; ++i, rd+=4 ) { - T a[4], b[4], c[4], d[4], e[4], f[4], r[4]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) a[j] = cell[j] * right.cell[i]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) b[j] = cell[4+j] * right.cell[i+ 4]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) c[j] = cell[8+j] * right.cell[i+ 8]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = cell[12+j] * right.cell[i+12]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) e[j] = a[j] + b[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) f[j] = c[j] + d[j]; - _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = e[j] + f[j]; - MemCopy( rd, r, 4 ); - } - return rm; - } - - CY_NODISCARD Matrix4 TransposeMultSelf() const { return TransposeMult(*this); } //!< Multiply the transpose of this matrix with itself (i.e. this^T * this). - CY_NODISCARD Matrix4 MultSelfTranspose() const { return MultTranspose(*this); } //!< Multiply the matrix with its transpose (i.e. this * this^T). - - CY_NODISCARD T GetTrace() const { return cell[0]+cell[5]+cell[10]+cell[15]; } - - CY_NODISCARD T GetDeterminant() const //!< Get the determinant of this matrix - { - // 0 ( 5 ( 10 15 - 11 14) + 6 ( 11 13 - 9 15) + 7 ( 9 14 - 10 13)) + - // 1 ( 4 ( 11 14 - 10 15) + 6 ( 8 15 - 11 12) + 7 ( 10 12 - 8 14)) + - // 2 ( 4 ( 9 15 - 11 13) + 5 ( 11 12 - 8 15) + 7 ( 8 13 - 9 12)) + - // 3 ( 4 ( 10 13 - 9 14) + 5 ( 8 14 - 10 12) + 6 ( 9 12 - 8 13)) - - T data_11_14__10_15 = cell[11] * cell[14] - cell[10] * cell[15]; - T data__9_15__11_13 = cell[ 9] * cell[15] - cell[11] * cell[13]; - T data_10_13___9_14 = cell[10] * cell[13] - cell[ 9] * cell[14]; - T data_11_12___8_15 = cell[11] * cell[12] - cell[ 8] * cell[15]; - T data__8_14__10_12 = cell[ 8] * cell[14] - cell[10] * cell[12]; - T data__9_12___8_13 = cell[ 9] * cell[12] - cell[ 8] * cell[13]; - return cell[0] * ( cell[5] * (-data_11_14__10_15 ) + cell[6] * (-data__9_15__11_13 ) + cell[7] * (-data_10_13___9_14 ) ) + - cell[1] * ( cell[4] * ( data_11_14__10_15 ) + cell[6] * (-data_11_12___8_15 ) + cell[7] * (-data__8_14__10_12 ) ) + - cell[2] * ( cell[4] * ( data__9_15__11_13 ) + cell[5] * ( data_11_12___8_15 ) + cell[7] * (-data__9_12___8_13 ) ) + - cell[3] * ( cell[4] * ( data_10_13___9_14 ) + cell[5] * ( data__8_14__10_12 ) + cell[6] * ( data__9_12___8_13 ) ); - } - - void Invert() { *this = GetInverse(); } //!< Invert this matrix - CY_NODISCARD Matrix4 GetInverse() const //!< Get the inverse of this matrix - { - // 5 ( 10 15 - 11 14 ) + 6 ( 11 13 - 9 15 ) + 7 ( 9 14 - 10 13 ) - // 1 ( 11 14 - 10 15 ) + 2 ( 9 15 - 11 13 ) + 3 ( 10 13 - 9 14 ) - // 1 ( 6 15 - 7 14 ) + 2 ( 7 13 - 5 15 ) + 3 ( 5 14 - 6 13 ) - // 1 ( 7 10 - 6 11 ) + 2 ( 5 11 - 7 9 ) + 3 ( 6 9 - 5 10 ) - // - // 4 ( 11 14 - 10 15 ) + 6 ( 8 15 - 11 12 ) + 7 ( 10 12 - 8 14 ) - // 0 ( 10 15 - 11 14 ) + 2 ( 11 12 - 8 15 ) + 3 ( 8 14 - 10 12 ) - // 0 ( 7 14 - 6 15 ) + 2 ( 4 15 - 7 12 ) + 3 ( 6 12 - 4 14 ) / det - // 0 ( 6 11 - 7 10 ) + 2 ( 8 7 - 4 11 ) + 3 ( 4 10 - 6 8 ) - // - // 4 ( 9 15 - 11 13 ) + 5 ( 11 12 - 8 15 ) + 7 ( 8 13 - 9 12 ) - // 0 ( 11 13 - 9 15 ) + 1 ( 8 15 - 11 12 ) + 3 ( 9 12 - 8 13 ) - // 0 ( 5 15 - 7 13 ) + 1 ( 7 12 - 4 15 ) + 3 ( 4 13 - 5 12 ) - // 0 ( 7 9 - 5 11 ) + 1 ( 4 11 - 7 8 ) + 3 ( 5 8 - 4 9 ) - // - // 4 ( 10 13 - 9 14 ) + 5 ( 8 14 - 10 12 ) + 6 ( 9 12 - 8 13 ) - // 0 ( 9 14 - 10 13 ) + 1 ( 10 12 - 8 14 ) + 2 ( 8 13 - 9 12 ) - // 0 ( 6 13 - 5 14 ) + 1 ( 4 14 - 6 12 ) + 2 ( 5 12 - 4 13 ) - // 0 ( 5 10 - 6 9 ) + 1 ( 6 8 - 4 10 ) + 2 ( 4 9 - 5 8 ) - - Matrix4 inverse; - - T data_11_14__10_15 = cell[11] * cell[14] - cell[10] * cell[15]; - T data_10_15__11_14 = cell[10] * cell[15] - cell[11] * cell[14]; - T data__7_14___6_15 = cell[ 7] * cell[14] - cell[ 6] * cell[15]; - T data__6_11___7_10 = cell[ 6] * cell[11] - cell[ 7] * cell[10]; - - T data__9_15__11_13 = cell[ 9] * cell[15] - cell[11] * cell[13]; - T data_11_13___9_15 = cell[11] * cell[13] - cell[ 9] * cell[15]; - T data__5_15___7_13 = cell[ 5] * cell[15] - cell[ 7] * cell[13]; - T data__7__9___5_11 = cell[ 7] * cell[ 9] - cell[ 5] * cell[11]; - - T data_10_13___9_14 = cell[10] * cell[13] - cell[ 9] * cell[14]; - T data__9_14__10_13 = cell[ 9] * cell[14] - cell[10] * cell[13]; - T data__6_13___5_14 = cell[ 6] * cell[13] - cell[ 5] * cell[14]; - T data__5_10___6__9 = cell[ 5] * cell[10] - cell[ 6] * cell[ 9]; - - T data_11_12___8_15 = cell[11] * cell[12] - cell[ 8] * cell[15]; - T data__8_15__11_12 = cell[ 8] * cell[15] - cell[11] * cell[12]; - T data__7_12___4_15 = cell[ 7] * cell[12] - cell[ 4] * cell[15]; - T data__4_11___7__8 = cell[ 4] * cell[11] - cell[ 7] * cell[ 8]; - - T data__8_14__10_12 = cell[ 8] * cell[14] - cell[10] * cell[12]; - T data_10_12___8_14 = cell[10] * cell[12] - cell[ 8] * cell[14]; - T data__4_14___6_12 = cell[ 4] * cell[14] - cell[ 6] * cell[12]; - T data__6__8___4_10 = cell[ 6] * cell[ 8] - cell[ 4] * cell[10]; - - T data__9_12___8_13 = cell[ 9] * cell[12] - cell[ 8] * cell[13]; - T data__8_13___9_12 = cell[ 8] * cell[13] - cell[ 9] * cell[12]; - T data__5_12___4_13 = cell[ 5] * cell[12] - cell[ 4] * cell[13]; - T data__4__9___5__8 = cell[ 4] * cell[ 9] - cell[ 5] * cell[ 8]; - - inverse.cell[ 0] = cell[5] * (-data_11_14__10_15) + cell[6] * (-data__9_15__11_13) + cell[7] * (-data_10_13___9_14); - inverse.cell[ 1] = cell[1] * (-data_10_15__11_14) + cell[2] * (-data_11_13___9_15) + cell[3] * (-data__9_14__10_13); - inverse.cell[ 2] = cell[1] * (-data__7_14___6_15) + cell[2] * (-data__5_15___7_13) + cell[3] * (-data__6_13___5_14); - inverse.cell[ 3] = cell[1] * (-data__6_11___7_10) + cell[2] * (-data__7__9___5_11) + cell[3] * (-data__5_10___6__9); - - inverse.cell[ 4] = cell[4] * ( data_11_14__10_15) + cell[6] * (-data_11_12___8_15) + cell[7] * (-data__8_14__10_12); - inverse.cell[ 5] = cell[0] * ( data_10_15__11_14) + cell[2] * (-data__8_15__11_12) + cell[3] * (-data_10_12___8_14); - inverse.cell[ 6] = cell[0] * ( data__7_14___6_15) + cell[2] * (-data__7_12___4_15) + cell[3] * (-data__4_14___6_12); - inverse.cell[ 7] = cell[0] * ( data__6_11___7_10) + cell[2] * (-data__4_11___7__8) + cell[3] * (-data__6__8___4_10); - - inverse.cell[ 8] = cell[4] * ( data__9_15__11_13) + cell[5] * ( data_11_12___8_15) + cell[7] * (-data__9_12___8_13); - inverse.cell[ 9] = cell[0] * ( data_11_13___9_15) + cell[1] * ( data__8_15__11_12) + cell[3] * (-data__8_13___9_12); - inverse.cell[10] = cell[0] * ( data__5_15___7_13) + cell[1] * ( data__7_12___4_15) + cell[3] * (-data__5_12___4_13); - inverse.cell[11] = cell[0] * ( data__7__9___5_11) + cell[1] * ( data__4_11___7__8) + cell[3] * (-data__4__9___5__8); - - inverse.cell[12] = cell[4] * ( data_10_13___9_14) + cell[5] * ( data__8_14__10_12) + cell[6] * ( data__9_12___8_13); - inverse.cell[13] = cell[0] * ( data__9_14__10_13) + cell[1] * ( data_10_12___8_14) + cell[2] * ( data__8_13___9_12); - inverse.cell[14] = cell[0] * ( data__6_13___5_14) + cell[1] * ( data__4_14___6_12) + cell[2] * ( data__5_12___4_13); - inverse.cell[15] = cell[0] * ( data__5_10___6__9) + cell[1] * ( data__6__8___4_10) + cell[2] * ( data__4__9___5__8); - - T det = cell[0] * inverse.cell[0] + cell[1] * inverse.cell[4] + cell[2] * inverse.cell[8] + cell[3] * inverse.cell[12]; - return inverse / det; - } - - //! Removes the scale component of the matrix by normalizing each column of the 3x3 sub-matrix. - //! The resulting matrix can contain shear, if it originally contained non-uniform scale and rotation. - void Normalize() { Column3(0).Normalize(); Column3(0).Normalize(); Column3(0).Normalize(); } - - //! Orthogonalizes the matrix and removes the scale component, preserving the x direction - void OrthogonalizeX() - { - Column3(0).Normalize(); - Column3(1) -= Column3(0) * (Column3(1) % Column3(0)); - Column3(1).Normalize(); - Column3(2) -= Column3(0) * (Column3(2) % Column3(0)); - Column3(2) -= Column3(1) * (Column3(2) % Column3(1)); - Column3(2).Normalize(); - } - //! Orthogonalizes the matrix and removes the scale component, preserving the y direction - void OrthogonalizeY() - { - Column3(1).Normalize(); - Column3(0) -= Column3(1) * (Column3(0) % Column3(1)); - Column3(0).Normalize(); - Column3(2) -= Column3(1) * (Column3(2) % Column3(1)); - Column3(2) -= Column3(0) * (Column3(2) % Column3(0)); - Column3(2).Normalize(); - } - //! Orthogonalizes the matrix and removes the scale component, preserving the z direction - void OrthogonalizeZ() - { - Column3(2).Normalize(); - Column3(0) -= Column3(2) * (Column3(0) % Column3(2)); - Column3(0).Normalize(); - Column3(1) -= Column3(2) * (Column3(1) % Column3(2)); - Column3(1) -= Column3(0) * (Column3(1) % Column3(0)); - Column3(1).Normalize(); - } - - //! Returns if the matrix is identity within the given error tollerance. - CY_NODISCARD bool IsIdentity( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - return std::abs(cell[ 0]-T(1)) < tollerance && std::abs(cell[ 1]) < tollerance && std::abs(cell[ 2]) < tollerance && std::abs(cell[ 3]) < tollerance && - std::abs(cell[ 4]) < tollerance && std::abs(cell[ 5]-T(1)) < tollerance && std::abs(cell[ 6]) < tollerance && std::abs(cell[ 7]) < tollerance && - std::abs(cell[ 8]) < tollerance && std::abs(cell[ 9]) < tollerance && std::abs(cell[10]-T(1)) < tollerance && std::abs(cell[11]) < tollerance && - std::abs(cell[12]) < tollerance && std::abs(cell[13]) < tollerance && std::abs(cell[14]) < tollerance && std::abs(cell[15]-T(1)) < tollerance; - } - - //! Returns if the matrix is symmetric within the given error tollerance. - CY_NODISCARD bool IsSymmetric( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - return std::abs(cell[ 1] - cell[ 4]) < tollerance && - std::abs(cell[ 2] - cell[ 8]) < tollerance && - std::abs(cell[ 3] - cell[12]) < tollerance && - std::abs(cell[ 6] - cell[ 9]) < tollerance && - std::abs(cell[ 7] - cell[13]) < tollerance && - std::abs(cell[11] - cell[14]) < tollerance; - } - - //! Returns if the matrix is diagonal. - CY_NODISCARD bool IsDiagonal( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const - { - return std::abs(cell[ 1]) + std::abs(cell[ 2]) + std::abs(cell[ 3]) - + std::abs(cell[ 4]) + std::abs(cell[ 6]) + std::abs(cell[ 7]) - + std::abs(cell[ 8]) + std::abs(cell[ 9]) + std::abs(cell[11]) - + std::abs(cell[12]) + std::abs(cell[13]) + std::abs(cell[14]) < tollerance*12; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Static Methods - - //! Returns an identity matrix - CY_NODISCARD static Matrix4 Identity() { T c[] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; return Matrix4(c); } - //! Returns a view matrix using position, target and approximate up vector - CY_NODISCARD static Matrix4 View( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) { Matrix4 m; m.SetView(pos,target,up); return m; } - //! Returns a rotation matrix around x axis by angle in radians - CY_NODISCARD static Matrix4 RotationX( T angle ) { Matrix4 m; m.SetRotationX(angle); return m; } - //! Returns a rotation matrix around y axis by angle in radians - CY_NODISCARD static Matrix4 RotationY( T angle ) { Matrix4 m; m.SetRotationY(angle); return m; } - //! Returns a rotation matrix around z axis by angle in radians - CY_NODISCARD static Matrix4 RotationZ( T angle ) { Matrix4 m; m.SetRotationZ(angle); return m; } - //! Returns a rotation matrix about the given axis by angle in radians - CY_NODISCARD static Matrix4 Rotation( Vec3 const &axis, T angle ) { Matrix4 m; m.SetRotation(axis,angle); return m; } - //! Returns a rotation matrix that sets [from] unit vector to [to] unit vector - CY_NODISCARD static Matrix4 Rotation( Vec3 const &from, Vec3 const &to ) { Matrix4 m; m.SetRotation(from,to); return m; } - //! Returns a rotation matrix around x, y, and then z axes by angle in radians (Rz * Ry * Rx) - CY_NODISCARD static Matrix4 RotationXYZ( T angleX, T angleY, T angleZ ) { Matrix4 m; m.SetRotationXYZ(angleX,angleY,angleZ); return m; } - //! Returns a rotation matrix around z, y, and then x axes by angle in radians (Rx * Ry * Rz) - CY_NODISCARD static Matrix4 RotationZYX( T angleX, T angleY, T angleZ ) { Matrix4 m; m.SetRotationZYX(angleX,angleY,angleZ); return m; } - //! Returns a uniform scale matrix - CY_NODISCARD static Matrix4 Scale( T uniformScale ) { Matrix4 m; m.SetScale(uniformScale); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix4 Scale( T scaleX, T scaleY, T scaleZ, T scaleW=T(1) ) { Matrix4 m; m.SetScale(scaleX,scaleY,scaleZ,scaleW); return m; } - //! Returns a scale matrix - CY_NODISCARD static Matrix4 Scale( Vec3 const &scale ) { Matrix4 m; m.SetScale(scale); return m; } - //! Returns a translation matrix with no rotation or scale - CY_NODISCARD static Matrix4 Translation( Vec3 const &move ) { Matrix4 m; m.SetTranslation(move); return m; } - //! Returns a project matrix with field of view in radians - CY_NODISCARD static Matrix4 Perspective( T fov, T aspect, T znear, T zfar ) { Matrix4 m; m.SetPerspective(fov,aspect,znear,zfar); return m; } - //! Returns a project matrix with the tangent of the half field of view (tan_fov_2) - CY_NODISCARD static Matrix4 PerspectiveTan( T tan_fov_2, T aspect, T znear, T zfar ) { Matrix4 m; m.SetPerspectiveTan(tan_fov_2,aspect,znear,zfar); return m; } - //! Returns the tensor product (outer product) matrix of two vectors - CY_NODISCARD static Matrix4 TensorProduct( Vec4 const &v0, Vec4 const &v1 ) { Matrix4 m; m.SetTensorProduct(v0,v1); return m; } - - ////////////////////////////////////////////////////////////////////////// -}; - -//------------------------------------------------------------------------------- - -template inline Matrix2 operator & ( Vec2 const &v0, Vec2 const &v1 ) { Matrix2 r; r.SetTensorProduct(v0,v1); return r; } //!< tensor product (outer product) of two vectors -template inline Matrix3 operator & ( Vec3 const &v0, Vec3 const &v1 ) { Matrix3 r; r.SetTensorProduct(v0,v1); return r; } //!< tensor product (outer product) of two vectors -template inline Matrix4 operator & ( Vec4 const &v0, Vec4 const &v1 ) { Matrix4 r; r.SetTensorProduct(v0,v1); return r; } //!< tensor product (outer product) of two vectors - -//------------------------------------------------------------------------------- - -// Definitions of the conversion constructors -template Matrix2 ::Matrix2 ( Matrix3 const &m ) { MemCopy(cell,m.cell,2); MemCopy(cell+2,m.cell+3,2); } -template Matrix2 ::Matrix2 ( Matrix34 const &m ) { MemCopy(cell,m.cell,2); MemCopy(cell+2,m.cell+3,2); } -template Matrix2 ::Matrix2 ( Matrix4 const &m ) { MemCopy(cell,m.cell,2); MemCopy(cell+2,m.cell+4,2); } -template Matrix3 ::Matrix3 ( Matrix34 const &m ) { MemCopy(cell,m.cell,9); } -template Matrix3 ::Matrix3 ( Matrix4 const &m ) { MemCopy(cell,m.cell,3); MemCopy(cell+3,m.cell+4,3); MemCopy(cell+6,m.cell+8,3); } -template Matrix34::Matrix34( Matrix4 const &m ) { MemCopy(cell,m.cell,3); MemCopy(cell+3,m.cell+4,3); MemCopy(cell+6,m.cell+8,3); MemCopy(cell+9,m.cell+12,3); } - -template inline Matrix4 Matrix34::GetTranspose() const -{ - Matrix4 m; - m.cell[ 0] = cell[0]; m.cell[ 1] = cell[3]; m.cell[ 2] = cell[ 6]; m.cell[ 3] = cell[ 9]; - m.cell[ 4] = cell[1]; m.cell[ 5] = cell[4]; m.cell[ 6] = cell[ 7]; m.cell[ 7] = cell[10]; - m.cell[ 8] = cell[2]; m.cell[ 9] = cell[5]; m.cell[10] = cell[ 8]; m.cell[11] = cell[11]; - m.cell[12] = T(0); m.cell[13] = T(0); m.cell[14] = T(0); m.cell[15] = T(1); - return m; -} - -//------------------------------------------------------------------------------- - -typedef Matrix2 Matrix2f; //!< Single precision (float) 2x2 Matrix class -typedef Matrix3 Matrix3f; //!< Single precision (float) 3x3 Matrix class -typedef Matrix34 Matrix34f; //!< Single precision (float) 3x4 Matrix class -typedef Matrix4 Matrix4f; //!< Single precision (float) 4x4 Matrix class - -typedef Matrix2 Matrix2d; //!< Double precision (double) 2x2 Matrix class -typedef Matrix3 Matrix3d; //!< Double precision (double) 3x3 Matrix class -typedef Matrix34 Matrix34d; //!< Double precision (double) 3x4 Matrix class -typedef Matrix4 Matrix4d; //!< Double precision (double) 4x4 Matrix class - -//------------------------------------------------------------------------------- -} // namespace hf -//------------------------------------------------------------------------------- - -typedef cy::Matrix2f cyMatrix2f; //!< Single precision (float) 2x2 Matrix class -typedef cy::Matrix3f cyMatrix3f; //!< Single precision (float) 3x3 Matrix class -typedef cy::Matrix34f cyMatrix34f; //!< Single precision (float) 3x4 Matrix class -typedef cy::Matrix4f cyMatrix4f; //!< Single precision (float) 4x4 Matrix class - -typedef cy::Matrix2d cyMatrix2d; //!< Double precision (double) 2x2 Matrix class -typedef cy::Matrix3d cyMatrix3d; //!< Double precision (double) 3x3 Matrix class -typedef cy::Matrix34d cyMatrix34d; //!< Double precision (double) 3x4 Matrix class -typedef cy::Matrix4d cyMatrix4d; //!< Double precision (double) 4x4 Matrix class - -//------------------------------------------------------------------------------- - -#endif +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyMatrix.h +//! \author Cem Yuksel +//! +//! \brief 2x2, 3x3, 3x4, and 4x4 matrix classes +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_MATRIX_H_INCLUDED_ +#define _CY_MATRIX_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyVector.h" + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +// Forward declarations +//! \cond HIDDEN_SYMBOLS +template class Matrix3; +template class Matrix34; +template class Matrix4; +//! \endcond + +//------------------------------------------------------------------------------- + +#define _CY_VEC_DEFAULT_ERROR_TOLERANCE 0.0001 + +//------------------------------------------------------------------------------- + +// The macros below help the MSVC compiler with auto-vectorization +#define _CY_FORi(start,end,loop) _CY_IVDEP_FOR ( int i=(start); i<(end); ++i ) { loop; } +#define _CY_FORi0(end,loop) _CY_FORi(0,end,loop) +#define _CY_FOR_4i(loop) _CY_FORi0(4,loop) +#define _CY_FOR_8i(loop) _CY_FOR_4i(loop) _CY_FORi(4,8,loop) +#define _CY_FOR_9i(loop) _CY_FOR_8i(loop) { int i=8; loop; } +#define _CY_FOR_12i(loop) _CY_FOR_8i(loop) _CY_FORi( 8,12,loop) +#define _CY_FOR_16i(loop) _CY_FOR_12i(loop) _CY_FORi(12,16,loop) + +//------------------------------------------------------------------------------- + +//! 2x2 matrix class. +//! +//! Its data stores 4-value array of column-major matrix elements. +//! You can use Matrix2 with Vec2 to transform 2D points. + +template +class Matrix2 +{ + CY_NODISCARD friend Matrix2 operator * ( T value, Matrix2 const &right ) { Matrix2 r; _CY_FOR_4i( r.cell[i] = value * right.cell[i] ); return r; } //!< multiply matrix by a value + CY_NODISCARD friend Matrix2 operator + ( T value, Matrix2 const &right ) { return Matrix2(value+right.cell[0], right.cell[2], right.cell[1],value+right.cell[3]); } //!< add a value times identity matrix to a matrix + CY_NODISCARD friend Matrix2 operator - ( T value, Matrix2 const &right ) { return Matrix2(value-right.cell[0],-right.cell[2],-right.cell[1],value-right.cell[3]); } //!< subtract matrix from a value times identity matrix + CY_NODISCARD friend Matrix2 Inverse( Matrix2 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix + +public: + + //! Elements of the matrix are column-major: \n + //! | 0 2 | \n + //! | 1 3 | \n +#ifdef __cpp_unrestricted_unions + union { + T cell[4]; + Vec2 column[2]; // column vectors + }; +#else + T cell[4]; +#endif + + ////////////////////////////////////////////////////////////////////////// + //!@name Constructors + + Matrix2() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor + template explicit Matrix2( const Matrix2 &matrix ) { MemConvert(cell,matrix.cell,4); } //!< Copy constructor for different types + explicit Matrix2( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 4 values + explicit Matrix2( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v + explicit Matrix2( Vec2 const &x, Vec2 const &y ) { Set(x,y); } //!< Initialize the matrix using two vectors as columns + explicit Matrix2( Matrix3 const &m ); + explicit Matrix2( Matrix34 const &m ); + explicit Matrix2( Matrix4 const &m ); + + //! Constructor using row-major order for initialization + Matrix2( T c00, T c01, + T c10, T c11 ) + { + cell[0] = c00; cell[2] = c01; + cell[1] = c10; cell[3] = c11; + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set & Get Methods + + void Zero () { MemClear(cell,4); } //!< Set all the values as zero + bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero (); } //!< Returns true if the matrix is exactly zero + bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite(); } //!< Returns true if all components are finite real numbers. + void Get( T * restrict values ) { MemCopy(values,cell,4); } //!< Copies the matrix cell to the given values array of size 4 + void Set( T const * restrict values ) { MemCopy(cell,values,4); } //!< Set Matrix using an array of 4 values + void Set( Vec2 const &x, Vec2 const &y ) { x.Get(cell); y.Get(cell+2); } //!< Set Matrix using two vectors as columns + void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix + void SetTensorProduct( Vec2 const &v0, Vec2 const &v1 ) //!< Sets the matrix as the tensor product (outer product) of two vectors + { + _CY_IVDEP_FOR ( int i=0; i<2; ++i ) cell[ i] = v0[i] * v1.x; + _CY_IVDEP_FOR ( int i=0; i<2; ++i ) cell[2+i] = v0[i] * v1.y; + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Affine transformations + + //! Sets a uniform scale matrix + void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale); } + //! Sets a scale matrix + void SetScale( T scaleX, T scaleY ) { cell[0]=scaleX; cell[1]=0; cell[2]=0; cell[3]=scaleY;} + //! Sets a scale matrix + void SetScale( Vec2 const &scale ) { SetScale(scale.x,scale.y); } + //! Set a rotation matrix by angle + void SetRotation( T angle ) { SetRotation( std::sin(angle), std::cos(angle) ); } + //! Set a rotation matrix by cos and sin of angle + void SetRotation( T sinAngle, T cosAngle ) { cell[0]=cosAngle; cell[1]=-sinAngle; cell[2]=sinAngle; cell[3]=cosAngle; } + //! Sets a Cartesian coordinate frame using the given x direction. x must be a unit vector. + void SetCartesianFrameX( Vec2 const &x ) { Set( x, x.GetPerpendicular() ); } + //! Sets a Cartesian coordinate frame using the given y direction. y must be a unit vector. + void SetCartesianFrameY( Vec2 const &y ) { Set( -y.GetPerpendicular(), y ); } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set Row, Column, or Diagonal + + void SetRow ( int ri, T x, T y ) { cell[ri]=x; cell[ri+2]=y; } //!< Sets a row of the matrix + void SetRow ( int ri, Vec2 const &v ) { SetRow(ri,v.x,v.y); } //!< Sets a row of the matrix + void SetColumn ( int ci, T x, T y ) { Column(ci).Set(x,y); } //!< Sets a column of the matrix + void SetColumn ( int ci, Vec2 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix + void SetDiagonal( T xx, T yy ) { cell[0]=xx; cell[3]=yy; } //!< Sets the diagonal values of the matrix + void SetDiagonal( Vec2 const &p ) { SetDiagonal( p.x, p.y ); } //!< Sets the diagonal values of the matrix + void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1]); } //!< Sets the diagonal values of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Row, Column, or Diagonal + +#ifdef __cpp_unrestricted_unions + CY_NODISCARD Vec2 * Columns() { return column; } + CY_NODISCARD Vec2 const * Columns() const { return column; } + CY_NODISCARD Vec2 & Column ( int ci ) { return column[ci]; } + CY_NODISCARD Vec2 const & Column ( int ci ) const { return column[ci]; } +#else + CY_NODISCARD Vec2 * Columns() { return ((Vec2*)cell); } + CY_NODISCARD Vec2 const * Columns() const { return ((Vec2*)cell); } + CY_NODISCARD Vec2 & Column ( int ci ) { return Columns()[ci]; } + CY_NODISCARD Vec2 const & Column ( int ci ) const { return Columns()[ci]; } +#endif + CY_NODISCARD Vec2 GetRow ( int ri ) const { return Vec2( cell[ri], cell[ri+2] ); } //!< Returns a row of the matrix + CY_NODISCARD Vec2 GetDiagonal() const { return Vec2( cell[0], cell[3] ); } //!< Returns the diagonal of the matrix + CY_NODISCARD Matrix2 GetRotation() const { Matrix2 s, r; GetComponents(s,r); return r; } //!< Returns the rotation portion of the transformation + + //! Returns the scale portion of the transformation. + //! The returned matrix is symmetric, but not necessarily diagonal, and it can include non-uniform scale. + CY_NODISCARD Matrix2 GetScale() const + { + Matrix2 trns = GetTranspose(); + Matrix2 u2 = *this * trns; + Vec2 v0, v1; + u2.GetEigenvectors( v0, v1 ); + Matrix2 v(v0,v1); + Matrix2 vt = v.GetTranspose(); + Matrix2 d2 = vt * (*this) * v; // the result is a diagonal matrix + Vec2 diag = d2.GetDiagonal(); + Matrix2 d; + d.SetScale(diag); + return v * d * vt; + } + + //! Returns the average scale factor + CY_NODISCARD T GetAvrgScale() const + { + T det = cell[0]*cell[3]-cell[2]*cell[1]; + T s = Sqrt( std::abs(det) ); + return det >= 0 ? s : -s; + } + + void GetComponents( Matrix2 &scale, Matrix2 &rotation ) const { scale = GetScale(); rotation = *this * scale.GetInverse(); } //!< Returns separate transformation components + + ////////////////////////////////////////////////////////////////////////// + //!@name Comparison Operators + + CY_NODISCARD bool operator == ( Matrix2 const &right ) const { _CY_FOR_4i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal + CY_NODISCARD bool operator != ( Matrix2 const &right ) const { _CY_FOR_4i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal + + + ////////////////////////////////////////////////////////////////////////// + //!@name Access Operators + + CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<2 && ci>=0 && ci<2 ); return cell[ ci*2 + ri ]; } //!< subscript operator + CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<2 && ci>=0 && ci<2 ); return cell[ ci*2 + ri ]; } //!< constant subscript operator + CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<4 ); return cell[i]; } //!< subscript operator + CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<4 ); return cell[i]; } //!< constant subscript operator + + ////////////////////////////////////////////////////////////////////////// + //!@name Unary and Binary Operators + + // Unary operators + CY_NODISCARD Matrix2 operator - () const { Matrix2 r; _CY_FOR_4i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix + + // Binary operators + CY_NODISCARD Matrix2 operator * ( T const value ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value + CY_NODISCARD Matrix2 operator / ( T const value ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value + CY_NODISCARD Matrix2 operator + ( Matrix2 const &right ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices + CY_NODISCARD Matrix2 operator - ( Matrix2 const &right ) const { Matrix2 r; _CY_FOR_4i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix2 from another + CY_NODISCARD Matrix2 operator * ( Matrix2 const &right ) const //!< multiply a matrix with another + { + Matrix2 r; + r[0] = cell[0] * right.cell[0] + cell[2] * right.cell[1]; + r[1] = cell[1] * right.cell[0] + cell[3] * right.cell[1]; + r[2] = cell[0] * right.cell[2] + cell[2] * right.cell[3]; + r[3] = cell[1] * right.cell[2] + cell[3] * right.cell[3]; + return r; + } + CY_NODISCARD Vec2 operator * ( Vec2 const &p ) const { return Vec2( p.x*cell[0] + p.y*cell[2], p.x*cell[1] + p.y*cell[3] ); } + + CY_NODISCARD Matrix2 operator + ( T value ) const { Matrix2 r=*this; r.cell[0]+=value; r.cell[3]+=value; return r; } //!< add a value times identity matrix + CY_NODISCARD Matrix2 operator - ( T value ) const { Matrix2 r=*this; r.cell[0]-=value; r.cell[3]-=value; return r; } //!< subtract a value times identity matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Assignment Operators + + Matrix2 const & operator += ( Matrix2 const &right ) { _CY_FOR_4i( cell[i] += right.cell[i] ); return *this; } //!< add two Matrices modify this + Matrix2 const & operator -= ( Matrix2 const &right ) { _CY_FOR_4i( cell[i] -= right.cell[i] ); return *this; } //!< subtract one Matrix2 from another matrix and modify this matrix + Matrix2 const & operator *= ( Matrix2 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix + Matrix2 const & operator *= ( T const value ) { _CY_FOR_4i( cell[i] *= value ); return *this; } //!< multiply a matrix with a value modify this matrix + Matrix2 const & operator /= ( T const value ) { _CY_FOR_4i( cell[i] /= value ); return *this; } //!< divide the matrix by a value modify the this matrix + Matrix2 const & operator += ( T const value ) { cell[0]+=value; cell[3]+=value; return *this; } //!< add a value times identity matrix + Matrix2 const & operator -= ( T const value ) { cell[0]-=value; cell[3]-=value; return *this; } //!< subtract a value times identity matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Other Methods + + void Transpose() { T tmp=cell[0]; cell[0]=cell[3]; cell[3]=tmp; } //!< Transpose this matrix + CY_NODISCARD Matrix2 GetTranspose() const //!< Returns the transpose of this matrix + { + Matrix2 m; + m.cell[0] = cell[0]; m.cell[1] = cell[2]; + m.cell[2] = cell[1]; m.cell[3] = cell[3]; + return m; + } + + //! Multiply the give vector with the transpose of the matrix + CY_NODISCARD Vec2 TransposeMult( Vec2 const &p ) const { return Vec2( p.x*cell[0] + p.y*cell[1], p.x*cell[2] + p.y*cell[3] ); } + + CY_NODISCARD Matrix2 TransposeMult( Matrix2 const & right ) const //!< Multiply a matrix by the transpose of this one (i.e. this^T * right). + { + Matrix2 r; + r[0] = cell[0] * right.cell[0] + cell[1] * right.cell[1]; + r[1] = cell[2] * right.cell[0] + cell[3] * right.cell[1]; + r[2] = cell[0] * right.cell[2] + cell[1] * right.cell[3]; + r[3] = cell[2] * right.cell[2] + cell[3] * right.cell[3]; + return r; + } + CY_NODISCARD Matrix2 MultTranspose( Matrix2 const & right ) const //!< Multiply the transpose of a matrix by this one (i.e. this * right^T). + { + Matrix2 r; + r[0] = cell[0] * right.cell[0] + cell[2] * right.cell[2]; + r[1] = cell[1] * right.cell[0] + cell[3] * right.cell[2]; + r[2] = cell[0] * right.cell[1] + cell[2] * right.cell[3]; + r[3] = cell[1] * right.cell[1] + cell[3] * right.cell[3]; + return r; + } + + CY_NODISCARD Matrix2 TransposeMultSelf() const { return TransposeMult(*this); } //!< Multiply the transpose of this matrix with itself (i.e. this^T * this). + CY_NODISCARD Matrix2 MultSelfTranspose() const { return MultTranspose(*this); } //!< Multiply the matrix with its transpose (i.e. this * this^T). + + CY_NODISCARD T GetTrace() const { return cell[0] + cell[3]; } //!< return the Trace of this matrix + + CY_NODISCARD T GetDeterminant() const { return cell[0]*cell[3]-cell[2]*cell[1]; } //!< Get the determinant of this matrix + + void Invert() //!< Invert this matrix + { + T det = GetDeterminant(); + T cell3 = cell[0] / det; + cell[0] = cell[3] / det; + cell[1] = -cell[1] / det; + cell[2] = -cell[2] / det; + cell[3] = cell3; + } + CY_NODISCARD Matrix2 GetInverse() const //!< Get the inverse of this matrix + { + T det = GetDeterminant(); + Matrix2 inv; + inv.cell[0] = cell[3] / det; + inv.cell[1] = -cell[1] / det; + inv.cell[2] = -cell[2] / det; + inv.cell[3] = cell[0] / det; + return inv; + } + + //! Removes the scale component of the matrix by normalizing each column. + //! The resulting matrix can contain shear, if it originally contained non-uniform scale and rotation. + void Normalize() { Column(0).Normalize(); Column(1).Normalize(); } + + //! Orthogonalizes the matrix and removes the scale component, preserving the x direction + void OrthogonalizeX() + { + Column(0).Normalize(); + Column(1) -= Column(0) * (Column(1) % Column(0)); + Column(1).Normalize(); + } + //! Orthogonalizes the matrix and removes the scale component, preserving the y direction + void OrthogonalizeY() + { + Column(1).Normalize(); + Column(0) -= Column(1) * (Column(0) % Column(1)); + Column(0).Normalize(); + } + + //! Returns if the matrix is identity within the given error tollerance. + bool IsIdentity( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const { return std::abs(cell[0] - T(1)) < tollerance && std::abs(cell[1]) < tollerance && std::abs(cell[2]) < tollerance && std::abs(cell[3] - T(1)) < tollerance; } + + //! Returns if the matrix is symmetric within the given error tollerance. + bool IsSymmetric( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const { return std::abs(cell[0] - cell[2]) < tollerance; } + + //! Returns if the matrix is diagonal. + bool IsDiagonal( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const { return std::abs(cell[1]) + std::abs(cell[2]) < tollerance*2; } + + //! Returns the eigenvalues of the matrix. + //! The eigenvalues are ordered, such that the first one is larger. + CY_NODISCARD Vec2 GetEigenvalues() const + { + T t = GetTrace(); + T d = GetDeterminant(); + T a = t*t*T(0.25) - d; + T s = SqrtSafe(a); + Vec2 lambda; + lambda.x = t * T(0.5) + s; + lambda.y = t * T(0.5) - s; + return lambda; + } + + //! Returns the eigenvalues and sets the given vectors as the eigenvectors of the matrix. + //! The eigenvalues are ordered, such that the first one is larger. + //! The given tollerance is used for checking whether the eigenvalues are the same. + Vec2 GetEigenvectors( Vec2 &evec0, Vec2 &evec1, T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + Vec2 lambda = GetEigenvalues(); + if ( std::abs(lambda.x - lambda.y) < tollerance ) { + evec0 = Column(0); + evec1 = Column(1); + } else { + Matrix2 v0( cell[0]-lambda.y, cell[1], cell[2], cell[3]-lambda.y ); + Matrix2 v1( cell[0]-lambda.x, cell[1], cell[2], cell[3]-lambda.x ); + evec0 = v0.Column(0) + v0.Column(1); + evec1 = v1.Column(0) + v1.Column(1); + } + return lambda; + } + + //! Singular value decomposition (SVD). + //! Returns the SVD of the matrix, where U and V are orthogonal matrices and + //! S is the diagonal elements of a diagonal matrix (including zeros), + //! such that this matrix A = U S V^T. + void SingularValueDecomposition( Matrix2 &U, Vec2 &S, Matrix2 &V ) + { + Matrix2 AAT = MultSelfTranspose(); + Vec2 lambda = AAT.GetEigenvectors( U.Column(0), U.Column(1) ); + S = (lambda.Abs()).Sqrt(); + U.Normalize(); + Matrix2 ATA = TransposeMultSelf(); + AAT.GetEigenvectors( V.Column(0), V.Column(1) ); + V.Normalize(); + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Static Methods + + //! Returns an identity matrix + CY_NODISCARD static Matrix2 Identity() { T c[] = { 1,0, 0,1 }; return Matrix2(c); } + //! Returns a rotation matrix about the given axis by angle in radians + CY_NODISCARD static Matrix2 Rotation( T angle ) { Matrix2 m; m.SetRotation(angle); return m; } + //! Returns a uniform scale matrix + CY_NODISCARD static Matrix2 Scale( T uniformScale ) { Matrix2 m; m.SetScale(uniformScale); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix2 Scale( T scaleX, T scaleY ) { Matrix2 m; m.SetScale(scaleX,scaleY); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix2 Scale( Vec2 const &scale ) { Matrix2 m; m.SetScale(scale); return m; } + //! Returns the tensor product (outer product) matrix of two vectors + CY_NODISCARD static Matrix2 TensorProduct( Vec2 const &v0, Vec2 const &v1 ) { Matrix2 m; m.SetTensorProduct(v0,v1); return m; } + + ////////////////////////////////////////////////////////////////////////// +}; + +//------------------------------------------------------------------------------- + +#ifdef CY_NONVECTORIZED_MATRIX3 +# define _CY_INIT_MATRIX3_VECTORIZATION const int N = 3; T const *cell_6 = cell + 6; +#else +# define _CY_INIT_MATRIX3_VECTORIZATION const int N = 4; T cell_6[4] = { cell[6], cell[7], cell[8], cell[8] }; +#endif + +//------------------------------------------------------------------------------- + +//! 3x3 matrix class. +//! +//! Its data stores 9-value array of column-major matrix elements. +//! You can use Matrix3 with Vec3 to transform 3D points. + +template +class Matrix3 +{ + CY_NODISCARD friend Matrix3 operator * ( T value, Matrix3 const &right ) { Matrix3 r; _CY_FOR_9i( r.cell[i] = value * right.cell[i] ); return r; } //!< multiply matrix by a value + CY_NODISCARD friend Matrix3 operator + ( T value, Matrix3 const &right ) { Matrix3 r= right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< add a value times identity matrix to a matrix + CY_NODISCARD friend Matrix3 operator - ( T value, Matrix3 const &right ) { Matrix3 r=-right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< subtract a matrix from a value times identity matrix + CY_NODISCARD friend Matrix3 Inverse( Matrix3 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix + +public: + + //! Elements of the matrix are column-major: \n + //! | 0 3 6 | \n + //! | 1 4 7 | \n + //! | 2 5 8 | \n +#ifdef __cpp_unrestricted_unions + union { + T cell[9]; + Vec3 column[3]; // column vectors + }; +#else + T cell[9]; +#endif + + ////////////////////////////////////////////////////////////////////////// + //!@name Constructors + + Matrix3() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor + template explicit Matrix3( Matrix3 const &matrix ) { MemConvert(cell,matrix.cell,9); } //!< Copy constructor for different types + explicit Matrix3( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 9 values + explicit Matrix3( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v + explicit Matrix3( Vec3 const &x, Vec3 const &y, Vec3 const &z ) { Set(x,y,z); } //!< Initialize the matrix using x,y,z vectors as columns + explicit Matrix3( Matrix2 const &m ) { Column(0).Set(m.Column(0),0); Column(1).Set(m.Column(1),0); Column(2).Set(0,0,1); } + explicit Matrix3( Matrix34 const &m ); + explicit Matrix3( Matrix4 const &m ); + + //! Constructor using row-major order for initialization + Matrix3( T c00, T c01, T c02, + T c10, T c11, T c12, + T c20, T c21, T c22 ) + { + cell[0] = c00; cell[3] = c01; cell[6] = c02; + cell[1] = c10; cell[4] = c11; cell[7] = c12; + cell[2] = c20; cell[5] = c21; cell[8] = c22; + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set & Get Methods + + void Zero () { MemClear(cell,9); } //!< Set all the values as zero + bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero () && Column(2).IsZero (); } //!< Returns true if the matrix is exactly zero + bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite() && Column(2).IsFinite(); } //!< Returns true if all components are finite real numbers. + void Get( T * restrict values ) { MemCopy(values,cell,9); } //!< Copies the matrix cell to the given values array of size 9 + void Set( T const * restrict values ) { MemCopy(cell,values,9); } //!< Set matrix using an array of 9 values + void Set( Vec3 const &x, Vec3 const &y, Vec3 const &z ) { Column(0)=x; Column(1)=y; Column(2)=z; } //!< Set matrix using x,y,z vectors as columns + void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix + void SetTensorProduct( Vec3 const &v0, Vec3 const &v1 ) //!< Sets the matrix as the tensor product (outer product) of two vectors + { + _CY_IVDEP_FOR ( int i=0; i<3; ++i ) cell[ i] = v0[i] * v1.x; + _CY_IVDEP_FOR ( int i=0; i<3; ++i ) cell[3+i] = v0[i] * v1.y; + _CY_IVDEP_FOR ( int i=0; i<3; ++i ) cell[6+i] = v0[i] * v1.z; + } + //! Matrix representation of the cross product ( a x b) + void SetCrossProd( Vec3 const &p ) { cell[0]=T(0); cell[1]=p.z; cell[2]=-p.y; cell[3]=-p.z; cell[4]=T(0); cell[5]=p.x; cell[6]=p.y; cell[7]=-p.x; cell[8]=T(0); } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Affine transformations + + //! Sets a uniform scale matrix + void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale,uniformScale); } + //! Sets a scale matrix + void SetScale( T scaleX, T scaleY, T scaleZ ) + { + cell[0] = scaleX; cell[1] = 0; cell[2]=0; + cell[3] = 0; cell[4] = scaleY; cell[5]=0; + cell[6] = 0; cell[7] = 0; cell[8]=scaleZ; + } + //! Sets a scale matrix + void SetScale( Vec3 const &scale ) { SetScale(scale.x,scale.y,scale.z); } + //! Set as rotation matrix around x axis + void SetRotationX( T angle ) { SetRotationX( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around x axis by cos and sin of angle + void SetRotationX( T sinAngle, T cosAngle ) + { + cell[0] = T(1); cell[1] = T(0); cell[2] = T(0); + cell[3] = T(0); cell[4] = cosAngle; cell[5] = sinAngle; + cell[6] = T(0); cell[7] = -sinAngle; cell[8] = cosAngle; + } + //! Set as rotation matrix around y axis + void SetRotationY( T angle ) { SetRotationY( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around y axis by cos and sin of angle + void SetRotationY( T sinAngle, T cosAngle ) + { + cell[0] = cosAngle; cell[1] = T(0); cell[2] = -sinAngle; + cell[3] = T(0); cell[4] = T(1); cell[5] = T(0); + cell[6] = sinAngle; cell[7] = T(0); cell[8] = cosAngle; + } + //! Set as rotation matrix around z axis + void SetRotationZ( T angle ) { SetRotationZ( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around z axis by cos and sin of angle + void SetRotationZ( T sinAngle, T cosAngle ) + { + cell[0] = cosAngle; cell[1] = sinAngle; cell[2] = T(0); + cell[3] = -sinAngle; cell[4] = cosAngle; cell[5] = T(0); + cell[6] = T(0); cell[7] = T(0); cell[8] = T(1); + } + //! Set as rotation matrix around x, y, and then z axes ( Rz * Ry * Rx ) + void SetRotationXYZ( T angleX, T angleY, T angleZ ) + { + T sx = std::sin(angleX); + T cx = std::cos(angleX); + T sy = std::sin(angleY); + T cy = std::cos(angleY); + T sz = std::sin(angleZ); + T cz = std::cos(angleZ); + cell[0] = cy*cz; cell[1] = cy*sz; cell[2] =-sy; + cell[3] = cz*sx*sy - cx*sz; cell[4] = cx*cz + sx*sy*sz; cell[5] = cy*sx; + cell[6] = cx*cz*sy + sx*sz; cell[7] =-cz*sx + cx*sy*sz; cell[8] = cx*cy; + } + //! Set as rotation matrix around z, y, and then x axes ( Rx * Ry * Rz ) + void SetRotationZYX( T angleX, T angleY, T angleZ ) + { + T sx = std::sin(angleX); + T cx = std::cos(angleX); + T sy = std::sin(angleY); + T cy = std::cos(angleY); + T sz = std::sin(angleZ); + T cz = std::cos(angleZ); + cell[0] = cy*cz; cell[1] = cx*sz + sx*sy*cz; cell[2] = sx*sz - cx*sy*cz; + cell[3] = -cy*sz; cell[4] = cx*cz - sx*sy*sz; cell[5] = sx*cz + cx*sy*sz; + cell[6] = sy; cell[7] = -sx*cy; cell[8] = cx*cy; + } + //! Set a rotation matrix about the given axis by angle + void SetRotation( Vec3 const &axis, T angle ) { SetRotation(axis,std::sin(angle),std::cos(angle)); } + //! Set a rotation matrix about the given axis by cos and sin of angle + void SetRotation( Vec3 const &axis, T sinAngle, T cosAngle ) + { + T t = T(1) - cosAngle; + Vec3 a = t * axis; + T txy = a.x * axis.y; + T txz = a.x * axis.z; + T tyz = a.y * axis.z; + Vec3 s = sinAngle * axis; + cell[ 0] = a.x * axis.x + cosAngle; cell[ 1] = txy + s.z; cell[ 2] = txz - s.y; + cell[ 3] = txy - s.z; cell[ 4] = a.y * axis.y + cosAngle; cell[ 5] = tyz + s.x; + cell[ 6] = txz + s.y; cell[ 7] = tyz - s.x; cell[ 8] = a.z * axis.z + cosAngle; + } + //! Set a rotation matrix that sets [from] unit vector to [to] unit vector + void SetRotation( Vec3 const &from, Vec3 const &to ) + { + assert( from.IsFinite() && to.IsUnit() ); + Vec3 axis = from.Cross(to); + T s = axis.Length(); + if ( s < T(0.000001) ) SetIdentity(); + else { + T c = from.Dot(to); + SetRotation(axis/s, s, c); + } + } + //! Set view matrix using position, target and approximate up vector + void SetView( Vec3 const &target, Vec3 const &up ) + { + Vec3 f = target; + f.Normalize(); + Vec3 s = f.Cross(up); + s.Normalize(); + Vec3 u = s.Cross(f); + cell[0] = s.x; cell[1] = u.x; cell[2] = -f.x; + cell[3] = s.y; cell[4] = u.y; cell[5] = -f.y; + cell[6] = s.z; cell[7] = u.z; cell[8] = -f.z; + } + //! Sets a Cartesian coordinate frame using the given x direction and an approximate y direction. x must be a unit vector. + void SetCartesianFrameXY( Vec3 const &x, Vec3 const &y_approx ) { Vec3 z = x.Cross(y_approx); z.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z); } + //! Sets a Cartesian coordinate frame using the given x direction and an approximate z direction. x must be a unit vector. + void SetCartesianFrameXZ( Vec3 const &x, Vec3 const &z_approx ) { Vec3 y = z_approx.Cross(x); y.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z); } + //! Sets a Cartesian coordinate frame using the given y direction and an approximate x direction. y must be a unit vector. + void SetCartesianFrameYX( Vec3 const &y, Vec3 const &x_approx ) { Vec3 z = x_approx.Cross(y); z.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z); } + //! Sets a Cartesian coordinate frame using the given y direction and an approximate z direction. y must be a unit vector. + void SetCartesianFrameYZ( Vec3 const &y, Vec3 const &z_approx ) { Vec3 x = y.Cross(z_approx); x.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z); } + //! Sets a Cartesian coordinate frame using the given z direction and an approximate x direction. z must be a unit vector. + void SetCartesianFrameZX( Vec3 const &z, Vec3 const &x_approx ) { Vec3 y = z.Cross(x_approx); y.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z); } + //! Sets a Cartesian coordinate frame using the given z direction and an approximate y direction. z must be a unit vector. + void SetCartesianFrameZY( Vec3 const &z, Vec3 const &y_approx ) { Vec3 x = y_approx.Cross(z); x.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z); } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set Row, Column, or Diagonal + + void SetRow ( int ri, T x, T y, T z ) { cell[ri]=x; cell[ri+3]=y; cell[ri+6]=z; } //!< Sets a row of the matrix + void SetRow ( int ri, Vec3 const &v ) { SetRow(ri,v.x,v.y,v.z); } //!< Sets a row of the matrix + void SetColumn ( int ci, T x, T y, T z ) { Column(ci).Set(x,y,z); } //!< Sets a column of the matrix + void SetColumn ( int ci, Vec3 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix + void SetDiagonal( T xx, T yy, T zz ) { cell[0]=xx; cell[4]=yy; cell[8]=zz; } //!< Sets the diagonal values of the matrix + void SetDiagonal( Vec3 const &p ) { SetDiagonal( p.x, p.y, p.z ); } //!< Sets the diagonal values of the matrix + void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1],values[2]); } //!< Sets the diagonal values of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Row, Column, or Diagonal + +#ifdef __cpp_unrestricted_unions + CY_NODISCARD Vec3 * Columns() { return column; } + CY_NODISCARD Vec3 const * Columns() const { return column; } + CY_NODISCARD Vec3 & Column ( int ci ) { return column[ci]; } + CY_NODISCARD Vec3 const & Column ( int ci ) const { return column[ci]; } +#else + CY_NODISCARD Vec3 * Columns() { return ((Vec3*)cell); } + CY_NODISCARD Vec3 const * Columns() const { return ((Vec3*)cell); } + CY_NODISCARD Vec3 & Column ( int ci ) { return Columns()[ci]; } + CY_NODISCARD Vec3 const & Column ( int ci ) const { return Columns()[ci]; } +#endif + CY_NODISCARD Vec3 GetRow ( int ri ) const { return Vec3( cell[ri], cell[ri+3], cell[ri+6] ); } //!< Returns a row of the matrix + CY_NODISCARD Vec3 GetDiagonal() const { return Vec3( cell[0], cell[4], cell[8] ); } //!< Returns the diagonal of the matrix + CY_NODISCARD Matrix3 GetRotation() const { Matrix3 s, r; GetComponents(s,r); return r; } //!< Returns the rotation portion of the transformation + + //! Returns the scale portion of the transformation. + //! The returned matrix is symmetric, but not necessarily diagonal, and it can include non-uniform scale. + CY_NODISCARD Matrix3 GetScale() const + { + Matrix3 trns = GetTranspose(); + Matrix3 u2 = *this * trns; + Vec3 v0, v1, v2; + u2.GetEigenvectors( v0, v1, v2 ); + Matrix3 v(v0,v1,v2); + Matrix3 vt = v.GetTranspose(); + Matrix3 d2 = vt * (*this) * v; // the result is a diagonal matrix + Vec3 diag = d2.GetDiagonal(); + Matrix3 d; + d.SetScale(diag); + return v * d * vt; + } + + //! Returns the average scale factor + CY_NODISCARD T GetAvrgScale() const + { + T det = cell[0] * ( cell[4] * cell[8] - cell[5] * cell[7] ) + + cell[1] * ( cell[5] * cell[6] - cell[3] * cell[8] ) + + cell[2] * ( cell[3] * cell[7] - cell[4] * cell[6] ); + T s = std::pow( std::abs(det), T(1)/T(3) ); + return det >= 0 ? s : -s; + } + + void GetComponents( Matrix3 &scale, Matrix3 &rotation ) const { scale = GetScale(); rotation = *this * scale.GetInverse(); } //!< Returns separate transformation components + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Sub-matrix cell + + CY_NODISCARD Matrix2 GetSubMatrix2() const { Matrix2 m; MemCopy(m.cell,cell,2); MemCopy(m.cell+2,cell+3,2); return m; } //!< Returns the 2x2 portion of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Comparison Operators + + CY_NODISCARD bool operator == ( Matrix3 const &right ) const { _CY_FOR_9i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal + CY_NODISCARD bool operator != ( Matrix3 const &right ) const { _CY_FOR_9i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal + + + ////////////////////////////////////////////////////////////////////////// + //!@name Access Operators + + CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<3 && ci>=0 && ci<3 ); return cell[ ci*3 + ri ]; } //!< subscript operator + CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<3 && ci>=0 && ci<3 ); return cell[ ci*3 + ri ]; } //!< constant subscript operator + CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<9 ); return cell[i]; } //!< subscript operator + CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<9 ); return cell[i]; } //!< constant subscript operator + + + ////////////////////////////////////////////////////////////////////////// + //!@name Unary and Binary Operators + + // Unary operators + CY_NODISCARD Matrix3 operator - () const { Matrix3 r; _CY_FOR_9i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix + + // Binary operators + CY_NODISCARD Matrix3 operator * ( T const value ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value + CY_NODISCARD Matrix3 operator / ( T const value ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value + CY_NODISCARD Matrix3 operator + ( Matrix3 const &right ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices + CY_NODISCARD Matrix3 operator - ( Matrix3 const &right ) const { Matrix3 r; _CY_FOR_9i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix3 from another + + CY_NODISCARD Matrix3 operator * ( Matrix3 const &right ) const //!< multiply a matrix with another + { + _CY_INIT_MATRIX3_VECTORIZATION; + Matrix3 rm; + for ( int i=0; i<9; i+=3 ) { + T a[4], b[4], c[4], d[4], r[4]; + _CY_IVDEP_FOR ( int j=0; j operator * ( Vec3 const &p ) const + { + _CY_INIT_MATRIX3_VECTORIZATION; + //return Vec3( p.x*cell[0] + p.y*cell[3] + p.z*cell[6], + // p.x*cell[1] + p.y*cell[4] + p.z*cell[7], + // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] ); + T a[4], b[4], c[4], d[4]; + Vec3 r; + _CY_IVDEP_FOR ( int i=0; i const &diag ) const { return AddDiagonal(diag.x,diag.y,diag.z); } //!< Adds a diagonal matrix to this matrix and returns the result. + CY_NODISCARD Matrix3 AddIdentity( T scale=T(1) ) const { return AddDiagonal( scale, scale, scale ); } //!< Adds a scaled identity matrix to this matrix and returns the result. + + void Transpose() //!< Transpose this matrix + { + for ( int i = 1; i < 3; ++i ) { + for ( int j = 0; j < i; j++) { + T temp = cell[i * 3 + j]; + cell[i * 3 + j] = cell[j * 3 + i]; + cell[j * 3 + i] = temp; + } + } + } + CY_NODISCARD Matrix3 GetTranspose() const //!< Return the transpose of this matrix + { + Matrix3 m; + m.cell[0] = cell[0]; m.cell[1] = cell[3]; m.cell[2] = cell[6]; + m.cell[3] = cell[1]; m.cell[4] = cell[4]; m.cell[5] = cell[7]; + m.cell[6] = cell[2]; m.cell[7] = cell[5]; m.cell[8] = cell[8]; + return m; + } + + //! Multiply the give vector with the transpose of the matrix + CY_NODISCARD Vec3 TransposeMult( Vec3 const &p ) const + { + return Vec3( p.x*cell[0] + p.y*cell[1] + p.z*cell[2], + p.x*cell[3] + p.y*cell[4] + p.z*cell[5], + p.x*cell[6] + p.y*cell[7] + p.z*cell[8] ); + } + + CY_NODISCARD Matrix3 TransposeMult( Matrix3 const & right ) const //!< Multiply a matrix by the transpose of this one (i.e. this^T * right). + { + Matrix3 r; + for ( int i=0, k=0; i<3; ++i ) { + for ( int j=0; j<3; ++j, ++k ) { + r.cell[k] = Column(j).Dot( right.Column(i) ); + } + } + return r; + } + CY_NODISCARD Matrix3 MultTranspose( Matrix3 const & right ) const //!< Multiply the transpose of a matrix by this one (i.e. this * right^T). + { + _CY_INIT_MATRIX3_VECTORIZATION; + Matrix3 rm; + for ( int i=0; i<3; ++i ) { + T a[4], b[4], c[4], d[4], r[4]; + _CY_IVDEP_FOR ( int j=0; j GetEigenvalues( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + Vec3 lambda; + if ( IsDiagonal(tollerance) ) { + lambda = GetDiagonal(); // diagonal matrix, so the eigenvalues are the same as the diagonal elements. + } else { + T q = GetTrace() / 3; + Matrix3 m = AddIdentity(-q); + Matrix3 m2 = m * m; + T p = Sqrt( m2.GetTrace() / T(6) ); + Matrix3 B = m / p; + T d_2 = B.GetDeterminant() * T(0.5); + T a = d_2 < T(-1) ? Pi()/3 : ( d_2 > T(1) ? T(0) : ACosSafe(d_2)/3 ); // only guaranteed to work for symmetric matrices + Vec3 b; + b.x = 2*std::cos( a ); + b.y = 2*std::cos( a + Pi()*(T(2)/T(3)) ); + b.z = 2*std::cos( a + Pi()*(T(4)/T(3)) ); + lambda = b*p + q; + } + return lambda; + } + + //! Returns the eigenvalues and sets the given vector as the eigenvectors of the matrix. + //! The eigenvalues are ordered, such that the first one is the largest. + //! The given tollerance is used for checking whether the eigenvalues are the same. + Vec3 GetEigenvectors( Vec3 &evec0, Vec3 &evec1, Vec3 &evec2, T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + static auto setVectors = [&]( Vec3 &e0, Vec3 &e1, Vec3 &e2, Matrix3 const &v20, Matrix3 const &v12, Matrix3 const &v01 ) { + int i = 0; + Matrix3 v2 = v20 * v12; + e2 = v2.Column(0) + v2.Column(1) + v2.Column(2); + if ( (e2 ^ v01.Column(0)).LengthSquared() < tollerance ) { + e0 = v01.Column(1); + e1 = v01.Column(2); + } else { + e0 = v01.Column(0); + e1 = v01.Column( ( (e2 ^ v01.Column(1)).LengthSquared() < tollerance ) ? 2 : 1 ); + } + }; + + Vec3 lambda = GetEigenvalues(tollerance); + bool same01 = std::abs(lambda.x - lambda.y) < tollerance; + bool same12 = std::abs(lambda.y - lambda.z) < tollerance; + bool same02 = std::abs(lambda.x - lambda.z) < tollerance; + if ( same01 & same12 ) { + // All eigenvalues are the same, so, assuming that the matrix is normal, it must be scaled identity. + evec0 = Column(0); + evec1 = Column(1); + evec2 = Column(2); + } else { + Matrix3 v12 = AddIdentity( -lambda.x ); + Matrix3 v20 = AddIdentity( -lambda.y ); + Matrix3 v01 = AddIdentity( -lambda.z ); + char same = char(same01) | char(same12)*char(2) | char(same02)*char(3); // only one of them can be true here + switch (same) { + default: case 0: { + Matrix3 v0 = v01 * v20; + Matrix3 v1 = v12 * v01; + Matrix3 v2 = v20 * v12; + evec0 = v0.Column(0) + v0.Column(1) + v0.Column(2); + evec1 = v1.Column(0) + v1.Column(1) + v1.Column(2); + evec2 = v2.Column(0) + v2.Column(1) + v2.Column(2); + } + break; + case 1: setVectors( evec0, evec1, evec2, v20, v12, v01 ); break; + case 2: setVectors( evec1, evec2, evec0, v01, v20, v12 ); break; + case 3: setVectors( evec0, evec2, evec1, v12, v01, v20 ); break; + } + } + return lambda; + } + + //! Singular value decomposition (SVD) + //! Returns the SVD of the matrix, where U and V are orthogonal matrices and + //! S is the diagonal elements of a diagonal matrix (including zeros), + //! such that this matrix A = U S V^T. + //! The given tollerance is used for checking whether the eigenvalues are the same. + void SingularValueDecomposition( Matrix3 &U, Vec3 &S, Matrix3 &V, T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) + { + Matrix3 AAT = MultSelfTranspose(); + Vec3 lambda = AAT.GetEigenvectors( U.Column(0), U.Column(1), U.Column(2), tollerance ); + S = (lambda.Abs()).Sqrt(); + U.Normalize(); + Matrix3 ATA = TransposeMultSelf(); + AAT.GetEigenvectors( V.Column(0), V.Column(1), V.Column(2), tollerance ); + V.Normalize(); + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Static Methods + + //! Returns an identity matrix + CY_NODISCARD static Matrix3 Identity() { T c[] = { 1,0,0, 0,1,0, 0,0,1 }; return Matrix3(c); } + //! Returns a view matrix using position, target and approximate up vector + CY_NODISCARD static Matrix3 View( Vec3 const &target, Vec3 const &up ) { Matrix3 m; m.SetView(target,up); return m; } + //! Returns a rotation matrix around x axis by angle in radians + CY_NODISCARD static Matrix3 RotationX( T angle ) { Matrix3 m; m.SetRotationX(angle); return m; } + //! Returns a rotation matrix around y axis by angle in radians + CY_NODISCARD static Matrix3 RotationY( T angle ) { Matrix3 m; m.SetRotationY(angle); return m; } + //! Returns a rotation matrix around z axis by angle in radians + CY_NODISCARD static Matrix3 RotationZ( T angle ) { Matrix3 m; m.SetRotationZ(angle); return m; } + //! Returns a rotation matrix around x, y, and then z axes by angle in radians (Rz * Ry * Rx) + CY_NODISCARD static Matrix3 RotationXYZ( T angleX, T angleY, T angleZ ) { Matrix3 m; m.SetRotationXYZ(angleX,angleY,angleZ); return m; } + //! Returns a rotation matrix around z, y, and then x axes by angle in radians (Rx * Ry * Rz) + CY_NODISCARD static Matrix3 RotationZYX( T angleX, T angleY, T angleZ ) { Matrix3 m; m.SetRotationZYX(angleX,angleY,angleZ); return m; } + //! Returns a rotation matrix about the given axis by angle in radians + CY_NODISCARD static Matrix3 Rotation( Vec3 const &axis, T angle ) { Matrix3 m; m.SetRotation(axis,angle); return m; } + //! Returns a rotation matrix that sets [from] unit vector to [to] unit vector + CY_NODISCARD static Matrix3 Rotation( Vec3 const &from, Vec3 const &to ) { Matrix3 m; m.SetRotation(from,to); return m; } + //! Returns a uniform scale matrix + CY_NODISCARD static Matrix3 Scale( T uniformScale ) { Matrix3 m; m.SetScale(uniformScale); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix3 Scale( T scaleX, T scaleY, T scaleZ ) { Matrix3 m; m.SetScale(scaleX,scaleY,scaleZ); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix3 Scale( Vec3 const &scale ) { Matrix3 m; m.SetScale(scale); return m; } + //! Returns the tensor product (outer product) matrix of two vectors + CY_NODISCARD static Matrix3 TensorProduct( Vec3 const &v0, Vec3 const &v1 ) { Matrix3 m; m.SetTensorProduct(v0,v1); return m; } + //! Returns the matrix representation of cross product ( a x b ) + CY_NODISCARD static Matrix3 MatrixCrossProd( Vec3 const &a ) { Matrix3 m; m.SetCrossProd(a); return m; } + + ////////////////////////////////////////////////////////////////////////// +}; + +//------------------------------------------------------------------------------- + +#ifdef CY_NONVECTORIZED_MATRIX3 +# define _CY_INIT_MATRIX34_VECTORIZATION const int N = 3; T const *cell_9 = cell + 9; +#else +# define _CY_INIT_MATRIX34_VECTORIZATION const int N = 4; T cell_9[4] = { cell[9], cell[10], cell[11], cell[11] }; +#endif + +//------------------------------------------------------------------------------- + +//! 3x4 matrix class. +//! +//! Its data stores 12-value array of column-major matrix elements. +//! I chose column-major format to be compatible with OpenGL +//! You can use Matrix34 with Vec3 and Vec4 +//! to transform 3D and 4D points. + +template +class Matrix34 +{ + CY_NODISCARD friend Matrix34 operator * ( T value, Matrix34 const &right ) { Matrix34 r; _CY_FOR_12i( r.cell[i]=value*right.cell[i] ); return r; } //!< multiply matrix by a value + CY_NODISCARD friend Matrix34 operator + ( T value, Matrix34 const &right ) { Matrix34 r= right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< add a value times identity matrix to a matrix + CY_NODISCARD friend Matrix34 operator - ( T value, Matrix34 const &right ) { Matrix34 r=-right; r.cell[0]+=value; r.cell[4]+=value; r.cell[8]+=value; return r; } //!< subtract a matrix from a value times identity matrix + CY_NODISCARD friend Matrix34 Inverse( Matrix34 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix + +public: + + //! Elements of the matrix are column-major: \n + //! | 0 3 6 9 | \n + //! | 1 4 7 10 | \n + //! | 2 5 8 11 | \n +#ifdef __cpp_unrestricted_unions + union { + T cell[12]; + Vec3 column[4]; // column vectors + }; +#else + T cell[12]; +#endif + + + ////////////////////////////////////////////////////////////////////////// + //!@name Constructors + + Matrix34() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor + template explicit Matrix34( Matrix34 const &matrix ) { MemConvert(cell,matrix.cell,12); } //!< Copy constructor for different types + explicit Matrix34( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 9 values + explicit Matrix34( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v + explicit Matrix34( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Set(x,y,z,pos); } //!< Initialize the matrix using x,y,z vectors and coordinate center + explicit Matrix34( Matrix3 const &m ) { MemCopy(cell,m.cell,9); Column(3).Zero(); } + explicit Matrix34( Matrix3 const &m, Vec3 const &pos ) { MemCopy(cell,m.cell,9); Column(3)=pos; } + explicit Matrix34( Matrix2 const &m ) { Column(0)=Vec3(m.Column(0)); Column(1)=Vec3(m.Column(1)); Column(2).Set(0,0,1); Column(3).Zero(); } + explicit Matrix34( Matrix4 const &m ); + + //! Constructor using row-major order for initialization + Matrix34( T c00, T c01, T c02, T c03, + T c10, T c11, T c12, T c13, + T c20, T c21, T c22, T c23 ) + { + cell[ 0] = c00; cell[ 3] = c01; cell[ 6] = c02; cell[ 9] = c03; + cell[ 1] = c10; cell[ 4] = c11; cell[ 7] = c12; cell[10] = c13; + cell[ 2] = c20; cell[ 5] = c21; cell[ 8] = c22; cell[11] = c23; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Set & Get Methods + + void Zero () { MemClear(cell,12); } //!< Set all the values as zero + bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero () && Column(2).IsZero () && Column(3).IsZero (); } //!< Returns true if the matrix is exactly zero + bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite() && Column(2).IsFinite() && Column(3).IsFinite(); } //!< Returns true if all components are finite real numbers. + void Get( T * restrict values ) { MemCopy(values,cell,12); } //!< Copies the matrix cell to the given values array of size 12 + void Set( T const * restrict values ) { MemCopy(cell,values,12); } //!< Set Matrix using an array of 12 values + void Set( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Column(0)=x; Column(1)=y; Column(2)=z; Column(3)=pos; } //!< Set matrix using x,y,z vectors and coordinate center + void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Affine transformations + + //! Sets a uniform scale matrix + void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale,uniformScale); } + //! Sets a scale matrix + void SetScale( T scaleX, T scaleY, T scaleZ ) + { + Zero(); + cell[0] = scaleX; + cell[4] = scaleY; + cell[8] = scaleZ; + } + //! Sets a scale matrix + void SetScale( Vec3 const &scale ) { SetScale(scale.x,scale.y,scale.z); } + //! Set as rotation matrix around x axis + void SetRotationX( T angle ) { SetRotationX( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around x axis by cos and sin of angle + void SetRotationX( T sinAngle, T cosAngle ) + { + cell[0] = T(1); cell[1] = T(0); cell[2] = T(0); + cell[3] = T(0); cell[4] = cosAngle; cell[5] = sinAngle; + cell[6] = T(0); cell[7] = -sinAngle; cell[8] = cosAngle; + MemClear(cell+9,3); + } + //! Set as rotation matrix around y axis + void SetRotationY( T angle ) { SetRotationY( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around y axis by cos and sin of angle + void SetRotationY( T sinAngle, T cosAngle ) + { + cell[0] = cosAngle; cell[1] = T(0); cell[2] = -sinAngle; + cell[3] = T(0); cell[4] = T(1); cell[5] = T(0); + cell[6] = sinAngle; cell[7] = T(0); cell[8] = cosAngle; + MemClear(cell+9,3); + } + //! Set as rotation matrix around z axis + void SetRotationZ( T angle ) { SetRotationZ( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around z axis by cos and sin of angle + void SetRotationZ( T sinAngle, T cosAngle ) + { + cell[0] = cosAngle; cell[1] = sinAngle; cell[2] = T(0); + cell[3] = -sinAngle; cell[4] = cosAngle; cell[5] = T(0); + cell[6] = T(0); cell[7] = T(0); cell[8] = T(1); + MemClear(cell+9,3); + } + //! Set as rotation matrix around x, y, and then z axes ( Rz * Ry * Rx ) + void SetRotationXYZ( T angleX, T angleY, T angleZ ) + { + T sx = std::sin(angleX); + T cx = std::cos(angleX); + T sy = std::sin(angleY); + T cy = std::cos(angleY); + T sz = std::sin(angleZ); + T cz = std::cos(angleZ); + cell[0] = cy*cz; cell[1] = cy*sz; cell[2] =-sy; + cell[3] = cz*sx*sy - cx*sz; cell[4] = cx*cz + sx*sy*sz; cell[5] = cy*sx; + cell[6] = cx*cz*sy + sx*sz; cell[7] =-cz*sx + cx*sy*sz; cell[8] = cx*cy; + MemClear(cell+9,3); + } + //! Set as rotation matrix around z, y, and then x axes ( Rx * Ry * Rz ) + void SetRotationZYX( T angleX, T angleY, T angleZ ) + { + T sx = std::sin(angleX); + T cx = std::cos(angleX); + T sy = std::sin(angleY); + T cy = std::cos(angleY); + T sz = std::sin(angleZ); + T cz = std::cos(angleZ); + cell[0] = cy*cz; cell[1] = cx*sz + sx*sy*cz; cell[2] = sx*sz - cx*sy*cz; + cell[3] =-cy*sz; cell[4] = cx*cz - sx*sy*sz; cell[5] = sx*cz + cx*sy*sz; + cell[6] = sy; cell[7] =-sx*cy; cell[8] = cx*cy; + MemClear(cell+9,3); + } + //! Set a rotation matrix about the given axis by angle + void SetRotation( Vec3 const &axis, T angle ) { SetRotation(axis,std::sin(angle),std::cos(angle)); } + //! Set a rotation matrix about the given axis by cos and sin of angle + void SetRotation( Vec3 const &axis, T sinAngle, T cosAngle ) + { + T t = T(1) - cosAngle; + Vec3 a = t * axis; + T txy = a.x * axis.y; + T txz = a.x * axis.z; + T tyz = a.y * axis.z; + Vec3 s = sinAngle * axis; + cell[ 0] = a.x * axis.x + cosAngle; cell[ 1] = txy + s.z; cell[ 2] = txz - s.y; + cell[ 3] = txy - s.z; cell[ 4] = a.y * axis.y + cosAngle; cell[ 5] = tyz + s.x; + cell[ 6] = txz + s.y; cell[ 7] = tyz - s.x; cell[ 8] = a.z * axis.z + cosAngle; + MemClear(cell+9,3); + } + //! Set a rotation matrix that sets [from] unit vector to [to] unit vector + void SetRotation( Vec3 const &from, Vec3 const &to ) + { + T c = from.Dot(to); + if ( c > T(0.9999999) ) SetIdentity(); + else { + T s = Sqrt(T(1) - c*c); + Vec3 axis = from.Cross(to).GetNormalized(); + SetRotation(axis, s, c); + } + } + //! Sets a translation matrix with no rotation or scale + void SetTranslation( Vec3 const &move ) { Column(0).Set(1,0,0); Column(1).Set(0,1,0); Column(2).Set(0,0,1); Column(3)=move; } + //! Adds a translation to the matrix + void AddTranslation( Vec3 const &move ) { Column(3) += move; } + //! Sets the translation component of the matrix + void SetTranslationComponent( Vec3 const &move ) { Column(3) = move; } + //! Sets the translation component of the matrix to zero + void SetNoTranslation() { Column(3).Set(0,0,0); } + //! Set view matrix using position, target and approximate up vector + void SetView( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) + { + Vec3 f = target - pos; + f.Normalize(); + Vec3 s = f.Cross(up); + s.Normalize(); + Vec3 u = s.Cross(f); + cell[ 0]=s.x; cell[ 1]=u.x; cell[ 2]=-f.x; + cell[ 3]=s.y; cell[ 4]=u.y; cell[ 5]=-f.y; + cell[ 6]=s.z; cell[ 7]=u.z; cell[ 8]=-f.z; + cell[ 9]= -s % pos; + cell[10]= -u % pos; + cell[11]= f % pos; + } + //! Sets a Cartesian coordinate frame using the given x direction, an approximate y direction, and a translation. x must be a unit vector. + void SetCartesianFrameXY( Vec3 const &x, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x.Cross(y_approx); z.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given x direction, an approximate z direction, and a translation. x must be a unit vector. + void SetCartesianFrameXZ( Vec3 const &x, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z_approx.Cross(x); y.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given y direction, an approximate x direction, and a translation. y must be a unit vector. + void SetCartesianFrameYX( Vec3 const &y, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x_approx.Cross(y); z.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given y direction, an approximate z direction, and a translation. y must be a unit vector. + void SetCartesianFrameYZ( Vec3 const &y, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y.Cross(z_approx); x.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given z direction, an approximate x direction, and a translation. z must be a unit vector. + void SetCartesianFrameZX( Vec3 const &z, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z.Cross(x_approx); y.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given z direction, an approximate y direction, and a translation. z must be a unit vector. + void SetCartesianFrameZY( Vec3 const &z, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y_approx.Cross(z); x.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set Row, Column, or Diagonal + + void SetRow ( int ri, T x, T y, T z, T w ) { cell[ri]=x; cell[ri+3]=y; cell[ri+6]=z; cell[ri+9]=w; } //!< Sets a row of the matrix + void SetRow ( int ri, Vec4 const &v ) { SetRow(ri,v.x,v.y,v.z,v.w); } //!< Sets a row of the matrix + void SetColumn ( int ci, T x, T y, T z ) { Column(ci).Set(x,y,z); } //!< Sets a column of the matrix + void SetColumn ( int ci, Vec3 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix + void SetDiagonal( T xx, T yy, T zz ) { cell[0]=xx; cell[4]=yy; cell[8]=zz; } //!< Sets the diagonal values of the matrix + void SetDiagonal( Vec3 const &p ) { SetDiagonal( p.x, p.y, p.z ); } //!< Sets the diagonal values of the matrix + void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1],values[2]); } //!< Sets the diagonal values of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Row, Column, or Diagonal + +#ifdef __cpp_unrestricted_unions + CY_NODISCARD Vec3 * Columns() { return column; } + CY_NODISCARD Vec3 const * Columns() const { return column; } + CY_NODISCARD Vec3 & Column ( int ci ) { return column[ci]; } + CY_NODISCARD Vec3 const & Column ( int ci ) const { return column[ci]; } +#else + CY_NODISCARD Vec3 * Columns() { return ((Vec3*)cell); } + CY_NODISCARD Vec3 const * Columns() const { return ((Vec3*)cell); } + CY_NODISCARD Vec3 & Column ( int ci ) { return Columns()[ci]; } + CY_NODISCARD Vec3 const & Column ( int ci ) const { return Columns()[ci]; } +#endif + CY_NODISCARD Vec4 GetRow ( int ri ) const { return Vec4( cell[ri], cell[ri+3], cell[ri+6], cell[ri+9] ); } //!< Returns a row of the matrix + CY_NODISCARD Vec3 GetDiagonal() const { return Vec3( cell[0], cell[4], cell[8] ); } //!< Returns the diagonal of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Sub-matrix cell + + CY_NODISCARD Matrix3 GetSubMatrix3 () const { Matrix3 m; MemCopy(m.cell,cell,9); return m; } //!< Returns the 3x3 portion of the matrix + CY_NODISCARD Matrix2 GetSubMatrix2 () const { Matrix2 m; MemCopy(m.cell,cell,2); MemCopy(m.cell+2,cell+3,2); return m; } //!< Returns the 2x2 portion of the matrix + CY_NODISCARD Vec3 GetTranslation() const { return Column(3); } //!< Returns the translation component of the matrix + CY_NODISCARD Matrix3 GetRotation () const { Matrix3 m(*this); return m.GetRotation(); } //!< Returns the rotation portion of the transformation + CY_NODISCARD Matrix3 GetScale () const { Matrix3 m(*this); return m.GetScale (); } //!< Returns the scale portion of the transformation. + + //! Returns the average scale factor of the 3 by 3 sub-matrix + T GetAvrgScale() const + { + T det = cell[0] * ( cell[4] * cell[8] - cell[5] * cell[7] ) + + cell[1] * ( cell[5] * cell[6] - cell[3] * cell[8] ) + + cell[2] * ( cell[3] * cell[7] - cell[4] * cell[6] ); + T s = std::pow( std::abs(det), T(1)/T(3) ); + return det >= 0 ? s : -s; + } + + void GetComponents( Matrix3 &scale, Matrix3 &rotation, Vec3 &translation ) const { Matrix3 m(*this); m.GetComponents(scale,rotation); translation=GetTranslation(); } //!< Returns separate transformation components + + ////////////////////////////////////////////////////////////////////////// + //!@name Comparison Operators + + CY_NODISCARD bool operator == ( Matrix34 const &right ) const { _CY_FOR_12i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal + CY_NODISCARD bool operator != ( Matrix34 const &right ) const { _CY_FOR_12i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal + + + ////////////////////////////////////////////////////////////////////////// + //!@name Access Operators + + CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<3 && ci>=0 && ci<4 ); return cell[ ci*3 + ri ]; } //!< subscript operator + CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<3 && ci>=0 && ci<4 ); return cell[ ci*3 + ri ]; } //!< constant subscript operator + CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<12 ); return cell[i]; } //!< subscript operator + CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<12 ); return cell[i]; } //!< constant subscript operator + + + ////////////////////////////////////////////////////////////////////////// + //!@name Unary and Binary Operators + + // Unary operators + CY_NODISCARD Matrix34 operator - () const { Matrix34 r; _CY_FOR_12i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix + + // Binary operators + CY_NODISCARD Matrix34 operator * ( T const value ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value + CY_NODISCARD Matrix34 operator / ( T const value ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value + CY_NODISCARD Matrix34 operator + ( Matrix34 const &right ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices + CY_NODISCARD Matrix34 operator - ( Matrix34 const &right ) const { Matrix34 r; _CY_FOR_12i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix4 from another + CY_NODISCARD Matrix34 operator * ( Matrix34 const &right ) const //!< multiply a matrix with another + { + _CY_INIT_MATRIX34_VECTORIZATION; + Matrix34 rm; + T *rd = rm.cell; + for ( int i=0; i<12; i+=3, rd+=3 ) { + T a[4], b[4], c[4], d[4], r[4]; + _CY_IVDEP_FOR ( int k=0; k const &right ) const //!< multiply a matrix with another + { + _CY_INIT_MATRIX34_VECTORIZATION; + Matrix34 rm; + T *rd = rm.cell; + for ( int i=0; i<9; i+=3, rd+=3 ) { + T a[4], b[4], c[4], d[4], r[4]; + _CY_IVDEP_FOR ( int k=0; k operator * ( Vec3 const &p ) const + { + _CY_INIT_MATRIX34_VECTORIZATION; + //return Vec3( p.x*cell[0] + p.y*cell[3] + p.z*cell[6] + cell[ 9], + // p.x*cell[1] + p.y*cell[4] + p.z*cell[7] + cell[10], + // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] + cell[11] ); + T a[4], b[4], c[4], d[4], e[4], r[4]; + _CY_IVDEP_FOR ( int i=0; i(r); + } + CY_NODISCARD Vec4 operator * ( Vec4 const &p ) const + { + _CY_INIT_MATRIX34_VECTORIZATION; + //return Vec4( p.x*cell[0] + p.y*cell[3] + p.z*cell[6] + p.w*cell[ 9], + // p.x*cell[1] + p.y*cell[4] + p.z*cell[7] + p.w*cell[10], + // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] + p.w*cell[11], + // 0 + 0 + 0 + p.w ); + Vec4 r; + T a[4], b[4], c[4], d[4], e[4], f[4]; + _CY_IVDEP_FOR ( int i=0; i VectorTransform( Vec3 const &p ) const + { + _CY_INIT_MATRIX34_VECTORIZATION; + //return Vec3( p.x*cell[0] + p.y*cell[3] + p.z*cell[6], + // p.x*cell[1] + p.y*cell[4] + p.z*cell[7], + // p.x*cell[2] + p.y*cell[5] + p.z*cell[8] ); + T a[4], b[4], c[4], d[4], r[4]; + _CY_IVDEP_FOR ( int i=0; i(r); + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Assignment Operators + + Matrix34 const & operator += ( Matrix34 const &right ) { _CY_FOR_12i( cell[i] += right.cell[i] ); return *this; } //!< add two Matrices modify this + Matrix34 const & operator -= ( Matrix34 const &right ) { _CY_FOR_12i( cell[i] -= right.cell[i] ); return *this; } //!< subtract one Matrix4 from another matrix and modify this matrix + Matrix34 const & operator *= ( Matrix34 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix + Matrix34 const & operator *= ( Matrix3 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix + Matrix34 const & operator *= ( T const value ) { _CY_FOR_12i( cell[i] *= value ); return *this; } //!< multiply a matrix with a value modify this matrix + Matrix34 const & operator /= ( T const value ) { _CY_FOR_12i( cell[i] /= value ); return *this; } //!< divide the matrix by a value modify the this matrix + Matrix34 const & operator += ( T const value ) { cell[0]+=value; cell[4]+=value; cell[8]+=value; return *this; } //!< add a value times identity matrix + Matrix34 const & operator -= ( T const value ) { cell[0]-=value; cell[4]-=value; cell[8]-=value; return *this; } //!< subtract a value times identity matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Other Methods + + //! Transpose this matrix + void Transpose() + { + for ( int i=1; i<3; ++i ) { + for ( int j=0; j GetTranspose() const; //!< Returns the transpose of this matrix + + //! Multiply the give vector with the transpose of the matrix + CY_NODISCARD Vec4 TransposeMult( Vec3 const &p ) const + { + return Vec4( p.x*cell[ 0] + p.y*cell[ 1] + p.z*cell[ 2], + p.x*cell[ 3] + p.y*cell[ 4] + p.z*cell[ 5], + p.x*cell[ 6] + p.y*cell[ 7] + p.z*cell[ 8], + p.x*cell[ 9] + p.y*cell[10] + p.z*cell[11] + T(1) ); + } + + //! Multiply the give vector with the transpose of the matrix + CY_NODISCARD Vec4 TransposeMult( Vec4 const &p ) const + { + return Vec4( p.x*cell[ 0] + p.y*cell[ 1] + p.z*cell[ 2], + p.x*cell[ 3] + p.y*cell[ 4] + p.z*cell[ 5], + p.x*cell[ 6] + p.y*cell[ 7] + p.z*cell[ 8], + p.x*cell[ 9] + p.y*cell[10] + p.z*cell[11] + p.w ); + } + + CY_NODISCARD T GetDeterminant() const //!< Get the determinant of this matrix + { + // 0 (4 8 - 5 7) + 1 (5 6 - 3 8) + 2 (3 7 - 4 6) + return cell[0] * ( cell[4] * cell[8] - cell[5] * cell[7] ) + + cell[1] * ( cell[5] * cell[6] - cell[3] * cell[8] ) + + cell[2] * ( cell[3] * cell[7] - cell[4] * cell[6] ); + } + void Invert() { *this = GetInverse(); } //!< Invert this matrix + CY_NODISCARD Matrix34 GetInverse() const //!< Get the inverse of this matrix + { + // (4 8 - 5 7) (5 6 - 3 8) (3 7 - 4 6) (3 (8 10 - 7 11) + 4 (6 11 - 8 9) + 5 (7 9 - 6 10)) + // (2 7 - 1 8) (0 8 - 2 6) (1 6 - 0 7) (0 (7 11 - 8 10) + 1 (8 9 - 6 11) + 2 (6 10 - 7 9)) / det + // (1 5 - 2 4) (2 3 - 0 5) (0 4 - 1 3) (0 (5 10 - 4 11) + 1 (3 11 - 5 9) + 2 (4 9 - 3 10)) + + Matrix34 inverse; + + T data_8_10__7_11 = cell[8] * cell[10] - cell[7] * cell[11]; + T data_6_11__8__9 = cell[6] * cell[11] - cell[8] * cell[ 9]; + T data_7__9__6_10 = cell[7] * cell[ 9] - cell[6] * cell[10]; + + inverse.cell[ 0] = (cell[4]*cell[8] - cell[5]*cell[7]); + inverse.cell[ 1] = (cell[2]*cell[7] - cell[1]*cell[8]); + inverse.cell[ 2] = (cell[1]*cell[5] - cell[2]*cell[4]); + + inverse.cell[ 3] = (cell[5]*cell[6] - cell[3]*cell[8]); + inverse.cell[ 4] = (cell[0]*cell[8] - cell[2]*cell[6]); + inverse.cell[ 5] = (cell[2]*cell[3] - cell[0]*cell[5]); + + inverse.cell[ 6] = (cell[3]*cell[7] - cell[4]*cell[6]); + inverse.cell[ 7] = (cell[1]*cell[6] - cell[0]*cell[7]); + inverse.cell[ 8] = (cell[0]*cell[4] - cell[1]*cell[3]); + + inverse.cell[ 9] = cell[3] * data_8_10__7_11 + cell[4] * data_6_11__8__9 + cell[5] * data_7__9__6_10; + inverse.cell[10] = cell[0] *-data_8_10__7_11 + cell[1] *-data_6_11__8__9 + cell[2] *-data_7__9__6_10; + inverse.cell[11] = cell[0] * (cell[5] * cell[10] - cell[4] * cell[11]) + + cell[1] * (cell[3] * cell[11] - cell[5] * cell[ 9]) + + cell[2] * (cell[4] * cell[ 9] - cell[3] * cell[10]); + + T det = cell[0] * inverse.cell[0] + cell[1] * inverse.cell[3] + cell[2] * inverse.cell[6]; + return inverse / det; + } + + //! Removes the scale component of the matrix by normalizing the first three columns. + //! The resulting matrix can contain shear, if it originally contained non-uniform scale and rotation. + void Normalize() { Column(0).Normalize(); Column(1).Normalize(); Column(2).Normalize(); } + + //! Orthogonalizes the matrix and removes the scale component, preserving the x direction + void OrthogonalizeX() + { + Column(0).Normalize(); + Column(1) -= Column(0) * (Column(1) % Column(0)); + Column(1).Normalize(); + Column(2) -= Column(0) * (Column(2) % Column(0)); + Column(2) -= Column(1) * (Column(2) % Column(1)); + Column(2).Normalize(); + } + //! Orthogonalizes the matrix and removes the scale component, preserving the y direction + void OrthogonalizeY() + { + Column(1).Normalize(); + Column(0) -= Column(1) * (Column(0) % Column(1)); + Column(0).Normalize(); + Column(2) -= Column(1) * (Column(2) % Column(1)); + Column(2) -= Column(0) * (Column(2) % Column(0)); + Column(2).Normalize(); + } + //! Orthogonalizes the matrix and removes the scale component, preserving the z direction + void OrthogonalizeZ() + { + Column(2).Normalize(); + Column(0) -= Column(2) * (Column(0) % Column(2)); + Column(0).Normalize(); + Column(1) -= Column(2) * (Column(1) % Column(2)); + Column(1) -= Column(0) * (Column(1) % Column(0)); + Column(1).Normalize(); + } + + //! Returns if the matrix is identity within the given error tollerance. + bool IsIdentity( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + return std::abs(cell[0]-T(1)) < tollerance && std::abs(cell[ 1]) < tollerance && std::abs(cell[ 2]) < tollerance && + std::abs(cell[3]) < tollerance && std::abs(cell[ 4]-T(1)) < tollerance && std::abs(cell[ 5]) < tollerance && + std::abs(cell[6]) < tollerance && std::abs(cell[ 7]) < tollerance && std::abs(cell[ 8]-T(1)) < tollerance && + std::abs(cell[9]) < tollerance && std::abs(cell[10]) < tollerance && std::abs(cell[11]) < tollerance; + } + + //! Returns if the matrix is symmetric within the given error tollerance. + bool IsSymmetric( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + return std::abs(cell[ 1] - cell[3]) < tollerance && + std::abs(cell[ 2] - cell[6]) < tollerance && + std::abs(cell[ 5] - cell[7]) < tollerance && + std::abs(cell[ 9]) < tollerance && + std::abs(cell[10]) < tollerance && + std::abs(cell[11]) < tollerance; + } + + //! Returns if the matrix is diagonal. + bool IsDiagonal( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + return std::abs(cell[ 1]) + std::abs(cell[ 2]) + + std::abs(cell[ 3]) + std::abs(cell[ 5]) + + std::abs(cell[ 6]) + std::abs(cell[ 7]) + + std::abs(cell[ 9]) + std::abs(cell[10]) + std::abs(cell[11]) < tollerance*9; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Static Methods + + //! Returns an identity matrix + CY_NODISCARD static Matrix34 Identity() { T c[] = { 1,0,0, 0,1,0, 0,0,1, 0,0,0 }; return Matrix34(c); } + //! Returns a view matrix using position, target and approximate up vector + CY_NODISCARD static Matrix34 View( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) { Matrix34 m; m.SetView(pos,target,up); return m; } + //! Returns a rotation matrix around x axis by angle in radians + CY_NODISCARD static Matrix34 RotationX( T angle ) { Matrix34 m; m.SetRotationX(angle); return m; } + //! Returns a rotation matrix around y axis by angle in radians + CY_NODISCARD static Matrix34 RotationY( T angle ) { Matrix34 m; m.SetRotationY(angle); return m; } + //! Returns a rotation matrix around z axis by angle in radians + CY_NODISCARD static Matrix34 RotationZ( T angle ) { Matrix34 m; m.SetRotationZ(angle); return m; } + //! Returns a rotation matrix around x, y, and then z axes by angle in radians (Rz * Ry * Rx) + CY_NODISCARD static Matrix34 RotationXYZ( T angleX, T angleY, T angleZ ) { Matrix34 m; m.SetRotationXYZ(angleX,angleY,angleZ); return m; } + //! Returns a rotation matrix around z, y, and then x axes by angle in radians (Rx * Ry * Rz) + CY_NODISCARD static Matrix34 RotationZYX( T angleX, T angleY, T angleZ ) { Matrix34 m; m.SetRotationZYX(angleX,angleY,angleZ); return m; } + //! Returns a rotation matrix about the given axis by angle in radians + CY_NODISCARD static Matrix34 Rotation( Vec3 const &axis, T angle ) { Matrix34 m; m.SetRotation(axis,angle); return m; } + //! Returns a rotation matrix that sets [from] unit vector to [to] unit vector + CY_NODISCARD static Matrix34 Rotation( Vec3 const &from, Vec3 const &to ) { Matrix34 m; m.SetRotation(from,to); return m; } + //! Returns a uniform scale matrix + CY_NODISCARD static Matrix34 Scale( T uniformScale ) { Matrix34 m; m.SetScale(uniformScale); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix34 Scale( T scaleX, T scaleY, T scaleZ ) { Matrix34 m; m.SetScale(scaleX,scaleY,scaleZ); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix34 Scale( Vec3 const &scale ) { Matrix34 m; m.SetScale(scale); return m; } + //! Returns a translation matrix with no rotation or scale + CY_NODISCARD static Matrix34 Translation( Vec3 const &move ) { Matrix34 m; m.SetTranslation(move); return m; } + + + ////////////////////////////////////////////////////////////////////////// +}; + + +//------------------------------------------------------------------------------- + +//! 4x4 matrix class. +//! +//! Its data stores 16-value array of column-major matrix elements. +//! I chose column-major format to be compatible with OpenGL +//! You can use Matrix4 with Vec3 and Vec4 +//! to transform 3D and 4D points. + +template +class Matrix4 +{ + CY_NODISCARD friend Matrix4 operator * ( T value, Matrix4 const &right ) { Matrix4 r; _CY_FOR_16i( r.cell[i]=value*right.cell[i] ); return r; } //!< multiply matrix by a value + CY_NODISCARD friend Matrix4 Inverse( Matrix4 const &m ) { return m.GetInverse(); } //!< return the inverse of the matrix + + //! multiply a 4x4 matrix with a 3x4 matrix, treating it as a 4x4 matrix with last row 0,0,0,1 + CY_NODISCARD friend Matrix4 operator * ( Matrix34 const &left, Matrix4 const &right ) + { + Matrix4 rm; + for ( int i=0; i<16; i+=4 ) { + T a[4], b[4], c[4], d[4], e[4], f[4], r[4]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) a[j] = left.cell[ j] * right.cell[i ]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) b[j] = left.cell[3+j] * right.cell[i+1]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) c[j] = left.cell[6+j] * right.cell[i+2]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) d[j] = left.cell[9+j] * right.cell[i+3]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) e[j] = a[j] + b[j]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) f[j] = c[j] + d[j]; + _CY_IVDEP_FOR ( int j=0; j<3; ++j ) r[j] = e[j] + f[j]; + r[3] = right.cell[i+3]; + MemCopy( rm.cell+i, r, 4 ); + } + return rm; + } + +public: + + //! Elements of the matrix are column-major: \n + //! | 0 4 8 12 | \n + //! | 1 5 9 13 | \n + //! | 2 6 10 14 | \n + //! | 3 7 11 15 | \n +#ifdef __cpp_unrestricted_unions + struct ColVec3 { + Vec3 v; + T s; + void Set( Vec3 const &_v, T _s ) { v=_v; s=_s; } + }; // column vector plus scalar + union { + T cell [16]; + Vec4 column[4]; // column vectors + ColVec3 col3 [4]; // column vectors plus scalars + }; +#else + T cell [16]; +#endif + + + ////////////////////////////////////////////////////////////////////////// + //!@name Constructors + + Matrix4() CY_CLASS_FUNCTION_DEFAULT //!< Default constructor + template explicit Matrix4( Matrix4 const &matrix ) { MemConvert(cell,matrix.cell,16); } //!< Copy constructor for different types + explicit Matrix4( T const * restrict values ) { Set(values); } //!< Initialize the matrix using an array of 9 values + explicit Matrix4( T v ) { SetScale(v); } //!< Initialize the matrix as identity scaled by v + explicit Matrix4( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Set(x,y,z,pos); } //!< Initialize the matrix using x,y,z vectors and coordinate center + explicit Matrix4( Vec4 const &x, Vec4 const &y, Vec4 const &z, Vec4 const &w ) { Set(x,y,z,w); } //!< Initialize the matrix using x,y,z vectors as columns + explicit Matrix4( Matrix34 const &m ) { Column(0).Set(m.Column(0),T(0)); Column(1).Set(m.Column(1),T(0)); Column(2).Set(m.Column(2),T(0)); Column(3).Set(m.Column(3),T(1)); } + explicit Matrix4( Matrix3 const &m ) { Column(0).Set(m.Column(0),T(0)); Column(1).Set(m.Column(1),T(0)); Column(2).Set(m.Column(2),T(0)); Column(3).Set(0,0,0,1); } + explicit Matrix4( Matrix2 const &m ) { Column(0).Set(m.Column(0),T(0),T(0)); Column(1).Set(m.Column(1),T(0),T(0)); Column(2).Set(0,0,1,0); Column(3).Set(0,0,0,1); } + explicit Matrix4( Matrix3 const &m, Vec3 const &pos ) { Column(0).Set(m.Column(0),T(0)); Column(1).Set(m.Column(1),T(0)); Column(2).Set(m.Column(2),T(0)); Column(3).Set(pos,T(1)); } + + //! Constructor using row-major order for initialization + Matrix4( T c00, T c01, T c02, T c03, + T c10, T c11, T c12, T c13, + T c20, T c21, T c22, T c23, + T c30, T c31, T c32, T c33 ) + { + cell[ 0] = c00; cell[ 4] = c01; cell[ 8] = c02; cell[12] = c03; + cell[ 1] = c10; cell[ 5] = c11; cell[ 9] = c12; cell[13] = c13; + cell[ 2] = c20; cell[ 6] = c21; cell[10] = c22; cell[14] = c23; + cell[ 3] = c30; cell[ 7] = c31; cell[11] = c32; cell[15] = c33; + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set & Get Methods + + void Zero () { MemClear(cell,16); } //!< Set all the values as zero + bool IsZero () const { return Column(0).IsZero () && Column(1).IsZero () && Column(2).IsZero () && Column(3).IsZero (); } //!< Returns true if the matrix is exactly zero + bool IsFinite() const { return Column(0).IsFinite() && Column(1).IsFinite() && Column(2).IsFinite() && Column(3).IsFinite(); } //!< Returns true if all components are finite real numbers. + void Get( T * restrict values ) { MemCopy(values,cell,16); } //!< Copies the matrix cell to the given values array of size 16 + void Set( T const * restrict values ) { MemCopy(cell,values,16); } //!< Set Matrix using an array of 16 values + void Set( Vec3 const &x, Vec3 const &y, Vec3 const &z, Vec3 const &pos ) { Column(0).Set(x,T(0)); Column(1).Set(y,T(0)); Column(2).Set(z,T(0)); Column(3).Set(pos,T(1)); } //!< Set matrix using x,y,z column vectors and coordinate center + void Set( Vec4 const &x, Vec4 const &y, Vec4 const &z, Vec4 const &w ) { Column(0)=x; Column(1)=y; Column(2)=z; Column(3)=w; } //!< Set matrix using x,y,z,w column vectors + void SetIdentity() { SetScale(T(1)); } //!< Converts the matrix to an identity matrix + void SetTensorProduct( Vec4 const &v0, Vec4 const &v1 ) //!< Sets the matrix as the tensor product (outer product) of two vectors + { + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[ i] = v0[i] * v1.x; // cell[0]=v0.x*v1.x; cell[4]=v0.x*v1.y; cell[ 8]=v0.x*v1.z; cell[12]=v0.x*v1.w; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[ 4+i] = v0[i] * v1.y; // cell[1]=v0.y*v1.x; cell[5]=v0.y*v1.y; cell[ 9]=v0.y*v1.z; cell[13]=v0.y*v1.w; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[ 8+i] = v0[i] * v1.z; // cell[2]=v0.z*v1.x; cell[6]=v0.z*v1.y; cell[10]=v0.z*v1.z; cell[14]=v0.z*v1.w; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) cell[12+i] = v0[i] * v1.w; // cell[3]=v0.w*v1.x; cell[7]=v0.w*v1.y; cell[11]=v0.w*v1.z; cell[15]=v0.w*v1.w; + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Affine transformations + + //! Sets a uniform scale matrix + void SetScale( T uniformScale ) { SetScale(uniformScale,uniformScale,uniformScale); } + //! Sets a scale matrix + void SetScale( T scaleX, T scaleY, T scaleZ, T scaleW=T(1) ) + { + Zero(); + cell[ 0] = scaleX; + cell[ 5] = scaleY; + cell[10] = scaleZ; + cell[15] = scaleW; + } + //! Sets a scale matrix + void SetScale( Vec3 const &scale ) { SetScale(scale.x,scale.y,scale.z); } + //! Set as rotation matrix around x axis + void SetRotationX( T angle ) { SetRotationX( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around x axis by cos and sin of angle + void SetRotationX( T sinAngle, T cosAngle ) + { + cell[ 0] = T(1); cell[ 1] = T(0); cell[ 2] = T(0); cell[ 3] = T(0); + cell[ 4] = T(0); cell[ 5] = cosAngle; cell[ 6] = sinAngle; cell[ 7] = T(0); + cell[ 8] = T(0); cell[ 9] = -sinAngle; cell[10] = cosAngle; + MemClear(cell+11,4); + cell[15] = T(1); + } + //! Set as rotation matrix around y axis + void SetRotationY( T angle ) { SetRotationY( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around y axis by cos and sin of angle + void SetRotationY( T sinAngle, T cosAngle ) + { + cell[ 0] = cosAngle; cell[ 1] = T(0); cell[ 2] = -sinAngle; cell[ 3] = T(0); + cell[ 4] = T(0); cell[ 5] = T(1); cell[ 6] = T(0); cell[ 7] = T(0); + cell[ 8] = sinAngle; cell[ 9] = T(0); cell[10] = cosAngle; + MemClear(cell+11,4); + cell[15] = T(1); + } + //! Set as rotation matrix around z axis + void SetRotationZ( T angle ) { SetRotationZ( std::sin(angle), std::cos(angle) ); } + //! Set as rotation matrix around z axis by cos and sin of angle + void SetRotationZ( T sinAngle, T cosAngle ) + { + cell[ 0] = cosAngle; cell[ 1] = sinAngle; cell[ 2] = T(0); cell[ 3] = T(0); + cell[ 4] = -sinAngle; cell[ 5] = cosAngle; cell[ 6] = T(0); cell[ 7] = T(0); + cell[ 8] = T(0); cell[ 9] = T(0); cell[10] = T(1); + MemClear(cell+11,4); + cell[15] = T(1); + } + //! Set as rotation matrix around x, y, and then z axes ( Rz * Ry * Rx ) + void SetRotationXYZ( T angleX, T angleY, T angleZ ) + { + T sx = std::sin(angleX); + T cx = std::cos(angleX); + T sy = std::sin(angleY); + T cy = std::cos(angleY); + T sz = std::sin(angleZ); + T cz = std::cos(angleZ); + cell[ 0] = cy*cz; cell[ 1] = cy*sz; cell[ 2] =-sy; cell[ 3] = T(0); + cell[ 4] = cz*sx*sy - cx*sz; cell[ 5] = cx*cz + sx*sy*sz; cell[ 6] = cy*sx; cell[ 7] = T(0); + cell[ 8] = cx*cz*sy + sx*sz; cell[ 9] =-cz*sx + cx*sy*sz; cell[10] = cx*cy; + MemClear(cell+11,4); + cell[15] = T(1); + } + //! Set as rotation matrix around z, y, and then x axes ( Rx * Ry * Rz ) + void SetRotationZYX( T angleX, T angleY, T angleZ ) + { + T sx = std::sin(angleX); + T cx = std::cos(angleX); + T sy = std::sin(angleY); + T cy = std::cos(angleY); + T sz = std::sin(angleZ); + T cz = std::cos(angleZ); + cell[ 0] = cy*cz; cell[ 1] = cx*sz + sx*sy*cz; cell[ 2] = sx*sz - cx*sy*cz; cell[ 3] = T(0); + cell[ 4] =-cy*sz; cell[ 5] = cx*cz - sx*sy*sz; cell[ 6] = sx*cz + cx*sy*sz; cell[ 7] = T(0); + cell[ 8] = sy; cell[ 9] =-sx*cy; cell[10] = cx*cy; + MemClear(cell+11,4); + cell[15] = T(1); + } + //! Set a rotation matrix about the given axis by angle + void SetRotation( Vec3 const &axis, T angle ) { SetRotation(axis,std::sin(angle),std::cos(angle)); } + //! Set a rotation matrix about the given axis by cos and sin of angle + void SetRotation( Vec3 const &axis, T sinAngle, T cosAngle ) + { + T t = T(1) - cosAngle; + Vec3 a = t * axis; + T txy = a.x * axis.y; + T txz = a.x * axis.z; + T tyz = a.y * axis.z; + Vec3 s = sinAngle * axis; + cell[ 0] = a.x * axis.x + cosAngle; cell[ 1] = txy + s.z; cell[ 2] = txz - s.y; cell[ 3] = T(0); + cell[ 4] = txy - s.z; cell[ 5] = a.y * axis.y + cosAngle; cell[ 6] = tyz + s.x; cell[ 7] = T(0); + cell[ 8] = txz + s.y; cell[ 9] = tyz - s.x; cell[10] = a.z * axis.z + cosAngle; + MemClear(cell+11,4); + cell[15] = T(1); + } + //! Set a rotation matrix that sets [from] unit vector to [to] unit vector + void SetRotation( Vec3 const &from, Vec3 const &to ) + { + T c = from.Dot(to); + if ( c > T(0.9999999) ) SetIdentity(); + else { + T s = Sqrt(T(1) - c*c); + Vec3 axis = from.Cross(to).GetNormalized(); + SetRotation(axis, s, c); + } + } + //! Sets a translation matrix with no rotation or scale + void SetTranslation( Vec3 const &move ) { Column(0).Set(1,0,0,0); Column(1).Set(0,1,0,0); Column(2).Set(0,0,1,0); Column(3).Set(move,1); } + //! Adds a translation to the matrix + void AddTranslation( Vec3 const &move ) { cell[12]+=move.x; cell[13]+=move.y; cell[14]+=move.z; } + //! Sets the translation component of the matrix + void SetTranslationComponent( Vec3 const &move ) { cell[12]=move.x; cell[13]=move.y; cell[14]=move.z; } + //! Sets the translation component of the matrix to zero + void SetNoTranslation() { cell[12]=0; cell[13]=0; cell[14]=0; } + //! Set view matrix using position, target and approximate up vector + void SetView( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) + { + Vec3 f = target - pos; + f.Normalize(); + Vec3 s = f.Cross(up); + s.Normalize(); + Vec3 u = s.Cross(f); + cell[ 0]=s.x; cell[ 1]=u.x; cell[ 2]=-f.x; cell[ 3]=T(0); + cell[ 4]=s.y; cell[ 5]=u.y; cell[ 6]=-f.y; cell[ 7]=T(0); + cell[ 8]=s.z; cell[ 9]=u.z; cell[10]=-f.z; cell[11]=T(0); + cell[12]= -s % pos; + cell[13]= -u % pos; + cell[14]= f % pos; + cell[15]=T(1); + } + //! Sets a Cartesian coordinate frame using the given x direction, an approximate y direction, and a translation. x must be a unit vector. + void SetCartesianFrameXY( Vec3 const &x, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x.Cross(y_approx); z.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given x direction, an approximate z direction, and a translation. x must be a unit vector. + void SetCartesianFrameXZ( Vec3 const &x, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z_approx.Cross(x); y.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given y direction, an approximate x direction, and a translation. y must be a unit vector. + void SetCartesianFrameYX( Vec3 const &y, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 z = x_approx.Cross(y); z.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given y direction, an approximate z direction, and a translation. y must be a unit vector. + void SetCartesianFrameYZ( Vec3 const &y, Vec3 const &z_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y.Cross(z_approx); x.Normalize(); Vec3 z=x.Cross(y); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given z direction, an approximate x direction, and a translation. z must be a unit vector. + void SetCartesianFrameZX( Vec3 const &z, Vec3 const &x_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 y = z.Cross(x_approx); y.Normalize(); Vec3 x=y.Cross(z); Set(x,y,z,trans); } + //! Sets a Cartesian coordinate frame using the given z direction, an approximate y direction, and a translation. z must be a unit vector. + void SetCartesianFrameZY( Vec3 const &z, Vec3 const &y_approx, Vec3 const &trans=Vec3(T(0),T(0),T(0)) ) { Vec3 x = y_approx.Cross(z); x.Normalize(); Vec3 y=z.Cross(x); Set(x,y,z,trans); } + //! Set a project matrix with field of view in radians + void SetPerspective( T fov, T aspect, T znear, T zfar ) { SetPerspectiveTan(std::tan(fov*T(0.5)),aspect,znear,zfar); } + //! Set a project matrix with the tangent of the half field of view (tan_fov_2) + void SetPerspectiveTan( T tan_fov_2, T aspect, T znear, T zfar ) + { + T yScale = T(1) / tan_fov_2; + T xScale = yScale / aspect; + T zdif = znear - zfar; + Column(0).Set(xScale,0,0,0); + Column(1).Set(0,yScale,0,0); + Column(2).Set(0,0,(zfar+znear)/zdif,-1); + Column(3).Set(0,0,(2*zfar*znear)/zdif,0); + } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Set Row, Column, or Diagonal + + void SetRow ( int ri, T x, T y, T z, T w ) { cell[ri]=x; cell[ri+4]=y; cell[ri+8]=z; cell[ri+12]=w; } //!< Sets a row of the matrix + void SetRow ( int ri, Vec4 const &v ) { SetRow(ri,v.x,v.y,v.z,v.w); } //!< Sets a row of the matrix + void SetColumn ( int ci, T x, T y, T z, T w ) { Column(ci).Set(x,y,z,w); } //!< Sets a column of the matrix + void SetColumn ( int ci, Vec4 const &v ) { Column(ci)=v; } //!< Sets a column of the matrix + void SetDiagonal( T xx, T yy, T zz, T ww=1 ) { cell[0]=xx; cell[5]=yy; cell[10]=zz; cell[15]=ww; } //!< Sets the diagonal values of the matrix + void SetDiagonal( Vec4 const &p ) { SetDiagonal( p.x, p.y, p.z, p.w ); } //!< Sets the diagonal values of the matrix + void SetDiagonal( Vec3 const &p ) { SetDiagonal( p.x, p.y, p.z, T(1) ); } //!< Sets the diagonal values of the matrix + void SetDiagonal( T const * restrict values ) { SetDiagonal(values[0],values[1],values[2],values[3]); } //!< Sets the 4 diagonal values of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Row, Column, or Diagonal + +#ifdef __cpp_unrestricted_unions + CY_NODISCARD Vec4 * Columns() { return column; } + CY_NODISCARD Vec4 const * Columns() const { return column; } + CY_NODISCARD Vec4 & Column ( int ci ) { return column[ci]; } + CY_NODISCARD Vec4 const & Column ( int ci ) const { return column[ci]; } + CY_NODISCARD Vec3 & Column3( int ci ) { return col3[ci].v; } + CY_NODISCARD Vec3 const & Column3( int ci ) const { return col3[ci].v; } +#else + CY_NODISCARD Vec4 * Columns() { return ((Vec4*)cell); } + CY_NODISCARD Vec4 const * Columns() const { return ((Vec4*)cell); } + CY_NODISCARD Vec4 & Column ( int ci ) { return Columns()[ci]; } + CY_NODISCARD Vec4 const & Column ( int ci ) const { return Columns()[ci]; } + CY_NODISCARD Vec3 & Column3( int ci ) { return (Vec3 &)cell[ci*4]; } + CY_NODISCARD Vec3 const & Column3( int ci ) const { return (Vec3 const &)cell[ci*4]; } +#endif + CY_NODISCARD Vec4 GetRow ( int ri ) const { return Vec4( cell[ri], cell[ri+4], cell[ri+8], cell[ri+12] ); } //!< Returns a row of the matrix + CY_NODISCARD Vec4 GetDiagonal() const { return Vec4( cell[0], cell[5], cell[10], cell[15] ); } //!< Returns the diagonal of the matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Get Sub-matrix cell + + CY_NODISCARD Matrix34 GetSubMatrix34() const { Matrix34 m; MemCopy(m.cell,cell,3); MemCopy(m.cell+3,cell+4,3); MemCopy(m.cell+6,cell+8,3); MemCopy(m.cell+9,cell+12,3); return m; } //!< Returns the 3x4 portion of the matrix + CY_NODISCARD Matrix3 GetSubMatrix3 () const { Matrix3 m; MemCopy(m.cell,cell,3); MemCopy(m.cell+3,cell+4,3); MemCopy(m.cell+6,cell+8,3); return m; } //!< Returns the 3x3 portion of the matrix + CY_NODISCARD Matrix2 GetSubMatrix2 () const { Matrix2 m; MemCopy(m.cell,cell,2); MemCopy(m.cell+2,cell+4,2); return m; } //!< Returns the 2x2 portion of the matrix + CY_NODISCARD Vec3 GetTranslation() const { return Vec3(cell+12); } //!< Returns the translation component of the matrix + CY_NODISCARD Matrix3 GetRotation () const { Matrix3 m(*this); return m.GetRotation(); } //!< Returns the rotation portion of the transformation + CY_NODISCARD Matrix3 GetScale () const { Matrix3 m(*this); return m.GetScale (); } //!< Returns the scale portion of the transformation. + + //! Returns the average scale factor of the 3 by 3 sub-matrix + CY_NODISCARD T GetAvrgScale() const + { + T det = cell[0] * ( cell[5] * cell[10] - cell[6] * cell[ 9] ) + + cell[1] * ( cell[6] * cell[ 8] - cell[4] * cell[10] ) + + cell[2] * ( cell[4] * cell[ 9] - cell[5] * cell[ 8] ); + T s = std::pow( std::abs(det), T(1)/T(3) ); + return det >= 0 ? s : -s; + } + + void GetComponents( Matrix3 &scale, Matrix3 &rotation, Vec3 &translation ) const { Matrix3 m(*this); m.GetComponents(scale,rotation); translation=GetTranslation(); } //!< Returns separate transformation components + + ////////////////////////////////////////////////////////////////////////// + //!@name Comparison Operators + + CY_NODISCARD bool operator == ( Matrix4 const &right ) const { _CY_FOR_16i( if ( cell[i] != right.cell[i] ) return false ); return true; } //!< compare equal + CY_NODISCARD bool operator != ( Matrix4 const &right ) const { _CY_FOR_16i( if ( cell[i] != right.cell[i] ) return true ); return false; } //!< compare not equal + + + ////////////////////////////////////////////////////////////////////////// + //!@name Access Operators + + CY_NODISCARD T& operator () ( int ri, int ci ) { assert( ri>=0 && ri<4 && ci>=0 && ci<4 ); return cell[ ci*4 + ri ]; } //!< subscript operator + CY_NODISCARD T const & operator () ( int ri, int ci ) const { assert( ri>=0 && ri<4 && ci>=0 && ci<4 ); return cell[ ci*4 + ri ]; } //!< constant subscript operator + CY_NODISCARD T& operator [] ( int i ) { assert( i>=0 && i<16 ); return cell[i]; } //!< subscript operator + CY_NODISCARD T const & operator [] ( int i ) const { assert( i>=0 && i<16 ); return cell[i]; } //!< constant subscript operator + + + ////////////////////////////////////////////////////////////////////////// + //!@name Unary and Binary Operators + + // Unary operators + CY_NODISCARD Matrix4 operator - () const { Matrix4 r; _CY_FOR_16i( r.cell[i] = -cell[i] ); return r; } //!< negative matrix + + // Binary operators + CY_NODISCARD Matrix4 operator * ( T const value ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] * value ); return r; } //!< multiply matrix by a value + CY_NODISCARD Matrix4 operator / ( T const value ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] / value ); return r; } //!< divide matrix by a value + CY_NODISCARD Matrix4 operator + ( Matrix4 const &right ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] + right.cell[i] ); return r; } //!< add two Matrices + CY_NODISCARD Matrix4 operator - ( Matrix4 const &right ) const { Matrix4 r; _CY_FOR_16i( r.cell[i] = cell[i] - right.cell[i] ); return r; } //!< subtract one Matrix4 from another + CY_NODISCARD Matrix4 operator * ( Matrix4 const &right ) const //!< multiply a matrix with another + { + Matrix4 rm; + for ( int i=0; i<16; i+=4 ) { + T a[4], b[4], c[4], d[4], e[4], f[4], r[4]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) a[j] = cell[ j] * right.cell[i ]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) b[j] = cell[ 4+j] * right.cell[i+1]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) c[j] = cell[ 8+j] * right.cell[i+2]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = cell[12+j] * right.cell[i+3]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) e[j] = a[j] + b[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) f[j] = c[j] + d[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = e[j] + f[j]; + MemCopy( rm.cell+i, r, 4 ); + } + return rm; + } + CY_NODISCARD Matrix4 operator * ( Matrix34 const &right ) const //!< multiply a matrix with another + { + T a[4], b[4], c[4], d[4], e[4], r[4]; + Matrix4 rm; + T *rd = rm.cell; + for ( int i=0; i<9; i+=3, rd+=4 ) { + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) a[k] = cell[ k] * right.cell[i ]; + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) b[k] = cell[4+k] * right.cell[i+1]; + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) c[k] = cell[8+k] * right.cell[i+2]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = a[j] + b[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = d[j] + c[j]; + MemCopy( rd, r, 4 ); + } + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) a[k] = cell[ k] * right.cell[ 9]; + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) b[k] = cell[4+k] * right.cell[10]; + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) c[k] = cell[8+k] * right.cell[11]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = a[j] + b[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) e[j] = c[j] + cell[12+j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = d[j] + e[j]; + MemCopy( rd, r, 4 ); + return rm; + } + CY_NODISCARD Matrix4 operator * ( Matrix3 const &right ) const //!< multiply a matrix with another + { + T a[4], b[4], c[4], d[4], r[4]; + Matrix4 rm; + T *rd = rm.cell; + for ( int i=0; i<9; i+=3, rd+=4 ) { + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) a[k] = cell[ k] * right.cell[i ]; + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) b[k] = cell[4+k] * right.cell[i+1]; + _CY_IVDEP_FOR ( int k=0; k<4; ++k ) c[k] = cell[8+k] * right.cell[i+2]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = a[j] + b[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = d[j] + c[j]; + MemCopy( rd, r, 4 ); + } + MemCopy( rm.cell+12, cell+12, 4 ); + return rm; + } + CY_NODISCARD Vec4 operator * ( Vec3 const &p ) const + { + //return Vec4( p.x*cell[0] + p.y*cell[4] + p.z*cell[ 8] + cell[12], + // p.x*cell[1] + p.y*cell[5] + p.z*cell[ 9] + cell[13], + // p.x*cell[2] + p.y*cell[6] + p.z*cell[10] + cell[14], + // p.x*cell[3] + p.y*cell[7] + p.z*cell[11] + cell[15] ); + Vec4 r; + T a[4], b[4], c[4], d[4], e[4]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = p.x * cell[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = p.y * cell[4+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = p.z * cell[8+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = a[i] + b[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) e[i] = c[i] + cell[12+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) r[i] = d[i] + e[i]; + return r; + } + CY_NODISCARD Vec4 operator * ( Vec4 const &p ) const + { + //return Vec4( p.x*cell[0] + p.y*cell[4] + p.z*cell[ 8] + p.w*cell[12], + // p.x*cell[1] + p.y*cell[5] + p.z*cell[ 9] + p.w*cell[13], + // p.x*cell[2] + p.y*cell[6] + p.z*cell[10] + p.w*cell[14], + // p.x*cell[3] + p.y*cell[7] + p.z*cell[11] + p.w*cell[15] ); + Vec4 r; + T a[4], b[4], c[4], d[4], e[4], f[4]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = p.x * cell[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = p.y * cell[4+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = p.z * cell[8+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = p.w * cell[12+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) e[i] = a[i] + b[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) f[i] = c[i] + d[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) r[i] = e[i] + f[i]; + return r; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name 3D Vector Transform Methods + + //! Transforms the vector by multiplying it with the matrix, ignoring the translation component. + CY_NODISCARD Vec4 VectorTransform( Vec3 const &p ) const + { + //return Vec4( p.x*cell[0] + p.y*cell[4] + p.z*cell[ 8], + // p.x*cell[1] + p.y*cell[5] + p.z*cell[ 9], + // p.x*cell[2] + p.y*cell[6] + p.z*cell[10], + // p.x*cell[3] + p.y*cell[7] + p.z*cell[11] ); + Vec4 r; + T a[4], b[4], c[4], d[4]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = p.x * cell[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = p.y * cell[4+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = p.z * cell[8+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = a[i] + b[i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) r[i] = d[i] + c[i]; + return r; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Assignment Operators + + Matrix4 const & operator += ( Matrix4 const &right ) { _CY_FOR_16i( cell[i] += right.cell[i] ); return *this; } //!< add two Matrices modify this + Matrix4 const & operator -= ( Matrix4 const &right ) { _CY_FOR_16i( cell[i] -= right.cell[i] ); return *this; } //!< subtract one Matrix4 from another matrix and modify this matrix + Matrix4 const & operator *= ( Matrix4 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix + Matrix4 const & operator *= ( Matrix34 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix + Matrix4 const & operator *= ( Matrix3 const &right ) { *this = operator*(right); return *this; } //!< multiply a matrix with another matrix and modify this matrix + Matrix4 const & operator *= ( T const value ) { _CY_FOR_16i( cell[i] *= value ); return *this; } //!< multiply a matrix with a value modify this matrix + Matrix4 const & operator /= ( T const value ) { _CY_FOR_16i( cell[i] /= value ); return *this; } //!< divide the matrix by a value modify the this matrix + + + ////////////////////////////////////////////////////////////////////////// + //!@name Other Methods + + void Transpose() //!< Transpose this matrix + { + for ( int i = 1; i < 4; ++i ) { + for ( int j = 0; j < i; j++) { + T temp = cell[i * 4 + j]; + cell[i * 4 + j] = cell[j * 4 + i]; + cell[j * 4 + i] = temp; + } + } + } + CY_NODISCARD Matrix4 GetTranspose() const //!< Return the transpose of this matrix + { + Matrix4 m; + m.cell[ 0] = cell[0]; m.cell[ 1] = cell[4]; m.cell[ 2] = cell[ 8]; m.cell[ 3] = cell[12]; + m.cell[ 4] = cell[1]; m.cell[ 5] = cell[5]; m.cell[ 6] = cell[ 9]; m.cell[ 7] = cell[13]; + m.cell[ 8] = cell[2]; m.cell[ 9] = cell[6]; m.cell[10] = cell[10]; m.cell[11] = cell[14]; + m.cell[12] = cell[3]; m.cell[13] = cell[7]; m.cell[14] = cell[11]; m.cell[15] = cell[15]; + return m; + } + + //! Multiply the give vector with the transpose of the matrix + CY_NODISCARD Vec4 TransposeMult( Vec3 const &p ) const { return TransposeMult( Vec4(p.x, p.y, p.z, T(1)) ); } + + //! Multiply the give vector with the transpose of the matrix + CY_NODISCARD Vec4 TransposeMult( Vec4 const &p ) const + { + //return Vec4( p.x*cell[ 0] + p.y*cell[ 1] + p.z*cell[ 2] + p.w*cell[ 3], + // p.x*cell[ 4] + p.y*cell[ 5] + p.z*cell[ 6] + p.w*cell[ 7], + // p.x*cell[ 8] + p.y*cell[ 9] + p.z*cell[10] + p.w*cell[11], + // p.x*cell[12] + p.y*cell[13] + p.z*cell[14] + p.w*cell[15] ); + T a[4], b[4], c[4], d[4]; + T const *pd = p.Elements(); + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) a[i] = pd[i] * cell[ i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) b[i] = pd[i] * cell[ 4+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) c[i] = pd[i] * cell[ 8+i]; + _CY_IVDEP_FOR ( int i=0; i<4; ++i ) d[i] = pd[i] * cell[12+i]; + Vec4 rr; + rr.x = a[0] + a[1] + a[2] + a[3]; + rr.y = b[0] + b[1] + b[2] + b[3]; + rr.z = c[0] + c[1] + c[2] + c[3]; + rr.w = d[0] + d[1] + d[2] + d[3]; + return rr; + } + + CY_NODISCARD Matrix4 TransposeMult( Matrix4 const & right ) const //!< Multiply a matrix by the transpose of this one (i.e. this^T * right). + { + Matrix4 r; + for ( int i=0, k=0; i<3; ++i ) { + for ( int j=0; j<3; ++j, ++k ) { + r.cell[k] = Column(j).Dot( right.Column(i) ); + } + } + return r; + } + CY_NODISCARD Matrix4 MultTranspose( Matrix4 const & right ) const //!< Multiply the transpose of a matrix by this one (i.e. this * right^T). + { + Matrix4 rm; + T* rd = rm.cell; + for ( int i=0; i<4; ++i, rd+=4 ) { + T a[4], b[4], c[4], d[4], e[4], f[4], r[4]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) a[j] = cell[j] * right.cell[i]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) b[j] = cell[4+j] * right.cell[i+ 4]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) c[j] = cell[8+j] * right.cell[i+ 8]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) d[j] = cell[12+j] * right.cell[i+12]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) e[j] = a[j] + b[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) f[j] = c[j] + d[j]; + _CY_IVDEP_FOR ( int j=0; j<4; ++j ) r[j] = e[j] + f[j]; + MemCopy( rd, r, 4 ); + } + return rm; + } + + CY_NODISCARD Matrix4 TransposeMultSelf() const { return TransposeMult(*this); } //!< Multiply the transpose of this matrix with itself (i.e. this^T * this). + CY_NODISCARD Matrix4 MultSelfTranspose() const { return MultTranspose(*this); } //!< Multiply the matrix with its transpose (i.e. this * this^T). + + CY_NODISCARD T GetTrace() const { return cell[0]+cell[5]+cell[10]+cell[15]; } + + CY_NODISCARD T GetDeterminant() const //!< Get the determinant of this matrix + { + // 0 ( 5 ( 10 15 - 11 14) + 6 ( 11 13 - 9 15) + 7 ( 9 14 - 10 13)) + + // 1 ( 4 ( 11 14 - 10 15) + 6 ( 8 15 - 11 12) + 7 ( 10 12 - 8 14)) + + // 2 ( 4 ( 9 15 - 11 13) + 5 ( 11 12 - 8 15) + 7 ( 8 13 - 9 12)) + + // 3 ( 4 ( 10 13 - 9 14) + 5 ( 8 14 - 10 12) + 6 ( 9 12 - 8 13)) + + T data_11_14__10_15 = cell[11] * cell[14] - cell[10] * cell[15]; + T data__9_15__11_13 = cell[ 9] * cell[15] - cell[11] * cell[13]; + T data_10_13___9_14 = cell[10] * cell[13] - cell[ 9] * cell[14]; + T data_11_12___8_15 = cell[11] * cell[12] - cell[ 8] * cell[15]; + T data__8_14__10_12 = cell[ 8] * cell[14] - cell[10] * cell[12]; + T data__9_12___8_13 = cell[ 9] * cell[12] - cell[ 8] * cell[13]; + return cell[0] * ( cell[5] * (-data_11_14__10_15 ) + cell[6] * (-data__9_15__11_13 ) + cell[7] * (-data_10_13___9_14 ) ) + + cell[1] * ( cell[4] * ( data_11_14__10_15 ) + cell[6] * (-data_11_12___8_15 ) + cell[7] * (-data__8_14__10_12 ) ) + + cell[2] * ( cell[4] * ( data__9_15__11_13 ) + cell[5] * ( data_11_12___8_15 ) + cell[7] * (-data__9_12___8_13 ) ) + + cell[3] * ( cell[4] * ( data_10_13___9_14 ) + cell[5] * ( data__8_14__10_12 ) + cell[6] * ( data__9_12___8_13 ) ); + } + + void Invert() { *this = GetInverse(); } //!< Invert this matrix + CY_NODISCARD Matrix4 GetInverse() const //!< Get the inverse of this matrix + { + // 5 ( 10 15 - 11 14 ) + 6 ( 11 13 - 9 15 ) + 7 ( 9 14 - 10 13 ) + // 1 ( 11 14 - 10 15 ) + 2 ( 9 15 - 11 13 ) + 3 ( 10 13 - 9 14 ) + // 1 ( 6 15 - 7 14 ) + 2 ( 7 13 - 5 15 ) + 3 ( 5 14 - 6 13 ) + // 1 ( 7 10 - 6 11 ) + 2 ( 5 11 - 7 9 ) + 3 ( 6 9 - 5 10 ) + // + // 4 ( 11 14 - 10 15 ) + 6 ( 8 15 - 11 12 ) + 7 ( 10 12 - 8 14 ) + // 0 ( 10 15 - 11 14 ) + 2 ( 11 12 - 8 15 ) + 3 ( 8 14 - 10 12 ) + // 0 ( 7 14 - 6 15 ) + 2 ( 4 15 - 7 12 ) + 3 ( 6 12 - 4 14 ) / det + // 0 ( 6 11 - 7 10 ) + 2 ( 8 7 - 4 11 ) + 3 ( 4 10 - 6 8 ) + // + // 4 ( 9 15 - 11 13 ) + 5 ( 11 12 - 8 15 ) + 7 ( 8 13 - 9 12 ) + // 0 ( 11 13 - 9 15 ) + 1 ( 8 15 - 11 12 ) + 3 ( 9 12 - 8 13 ) + // 0 ( 5 15 - 7 13 ) + 1 ( 7 12 - 4 15 ) + 3 ( 4 13 - 5 12 ) + // 0 ( 7 9 - 5 11 ) + 1 ( 4 11 - 7 8 ) + 3 ( 5 8 - 4 9 ) + // + // 4 ( 10 13 - 9 14 ) + 5 ( 8 14 - 10 12 ) + 6 ( 9 12 - 8 13 ) + // 0 ( 9 14 - 10 13 ) + 1 ( 10 12 - 8 14 ) + 2 ( 8 13 - 9 12 ) + // 0 ( 6 13 - 5 14 ) + 1 ( 4 14 - 6 12 ) + 2 ( 5 12 - 4 13 ) + // 0 ( 5 10 - 6 9 ) + 1 ( 6 8 - 4 10 ) + 2 ( 4 9 - 5 8 ) + + Matrix4 inverse; + + T data_11_14__10_15 = cell[11] * cell[14] - cell[10] * cell[15]; + T data_10_15__11_14 = cell[10] * cell[15] - cell[11] * cell[14]; + T data__7_14___6_15 = cell[ 7] * cell[14] - cell[ 6] * cell[15]; + T data__6_11___7_10 = cell[ 6] * cell[11] - cell[ 7] * cell[10]; + + T data__9_15__11_13 = cell[ 9] * cell[15] - cell[11] * cell[13]; + T data_11_13___9_15 = cell[11] * cell[13] - cell[ 9] * cell[15]; + T data__5_15___7_13 = cell[ 5] * cell[15] - cell[ 7] * cell[13]; + T data__7__9___5_11 = cell[ 7] * cell[ 9] - cell[ 5] * cell[11]; + + T data_10_13___9_14 = cell[10] * cell[13] - cell[ 9] * cell[14]; + T data__9_14__10_13 = cell[ 9] * cell[14] - cell[10] * cell[13]; + T data__6_13___5_14 = cell[ 6] * cell[13] - cell[ 5] * cell[14]; + T data__5_10___6__9 = cell[ 5] * cell[10] - cell[ 6] * cell[ 9]; + + T data_11_12___8_15 = cell[11] * cell[12] - cell[ 8] * cell[15]; + T data__8_15__11_12 = cell[ 8] * cell[15] - cell[11] * cell[12]; + T data__7_12___4_15 = cell[ 7] * cell[12] - cell[ 4] * cell[15]; + T data__4_11___7__8 = cell[ 4] * cell[11] - cell[ 7] * cell[ 8]; + + T data__8_14__10_12 = cell[ 8] * cell[14] - cell[10] * cell[12]; + T data_10_12___8_14 = cell[10] * cell[12] - cell[ 8] * cell[14]; + T data__4_14___6_12 = cell[ 4] * cell[14] - cell[ 6] * cell[12]; + T data__6__8___4_10 = cell[ 6] * cell[ 8] - cell[ 4] * cell[10]; + + T data__9_12___8_13 = cell[ 9] * cell[12] - cell[ 8] * cell[13]; + T data__8_13___9_12 = cell[ 8] * cell[13] - cell[ 9] * cell[12]; + T data__5_12___4_13 = cell[ 5] * cell[12] - cell[ 4] * cell[13]; + T data__4__9___5__8 = cell[ 4] * cell[ 9] - cell[ 5] * cell[ 8]; + + inverse.cell[ 0] = cell[5] * (-data_11_14__10_15) + cell[6] * (-data__9_15__11_13) + cell[7] * (-data_10_13___9_14); + inverse.cell[ 1] = cell[1] * (-data_10_15__11_14) + cell[2] * (-data_11_13___9_15) + cell[3] * (-data__9_14__10_13); + inverse.cell[ 2] = cell[1] * (-data__7_14___6_15) + cell[2] * (-data__5_15___7_13) + cell[3] * (-data__6_13___5_14); + inverse.cell[ 3] = cell[1] * (-data__6_11___7_10) + cell[2] * (-data__7__9___5_11) + cell[3] * (-data__5_10___6__9); + + inverse.cell[ 4] = cell[4] * ( data_11_14__10_15) + cell[6] * (-data_11_12___8_15) + cell[7] * (-data__8_14__10_12); + inverse.cell[ 5] = cell[0] * ( data_10_15__11_14) + cell[2] * (-data__8_15__11_12) + cell[3] * (-data_10_12___8_14); + inverse.cell[ 6] = cell[0] * ( data__7_14___6_15) + cell[2] * (-data__7_12___4_15) + cell[3] * (-data__4_14___6_12); + inverse.cell[ 7] = cell[0] * ( data__6_11___7_10) + cell[2] * (-data__4_11___7__8) + cell[3] * (-data__6__8___4_10); + + inverse.cell[ 8] = cell[4] * ( data__9_15__11_13) + cell[5] * ( data_11_12___8_15) + cell[7] * (-data__9_12___8_13); + inverse.cell[ 9] = cell[0] * ( data_11_13___9_15) + cell[1] * ( data__8_15__11_12) + cell[3] * (-data__8_13___9_12); + inverse.cell[10] = cell[0] * ( data__5_15___7_13) + cell[1] * ( data__7_12___4_15) + cell[3] * (-data__5_12___4_13); + inverse.cell[11] = cell[0] * ( data__7__9___5_11) + cell[1] * ( data__4_11___7__8) + cell[3] * (-data__4__9___5__8); + + inverse.cell[12] = cell[4] * ( data_10_13___9_14) + cell[5] * ( data__8_14__10_12) + cell[6] * ( data__9_12___8_13); + inverse.cell[13] = cell[0] * ( data__9_14__10_13) + cell[1] * ( data_10_12___8_14) + cell[2] * ( data__8_13___9_12); + inverse.cell[14] = cell[0] * ( data__6_13___5_14) + cell[1] * ( data__4_14___6_12) + cell[2] * ( data__5_12___4_13); + inverse.cell[15] = cell[0] * ( data__5_10___6__9) + cell[1] * ( data__6__8___4_10) + cell[2] * ( data__4__9___5__8); + + T det = cell[0] * inverse.cell[0] + cell[1] * inverse.cell[4] + cell[2] * inverse.cell[8] + cell[3] * inverse.cell[12]; + return inverse / det; + } + + //! Removes the scale component of the matrix by normalizing each column of the 3x3 sub-matrix. + //! The resulting matrix can contain shear, if it originally contained non-uniform scale and rotation. + void Normalize() { Column3(0).Normalize(); Column3(0).Normalize(); Column3(0).Normalize(); } + + //! Orthogonalizes the matrix and removes the scale component, preserving the x direction + void OrthogonalizeX() + { + Column3(0).Normalize(); + Column3(1) -= Column3(0) * (Column3(1) % Column3(0)); + Column3(1).Normalize(); + Column3(2) -= Column3(0) * (Column3(2) % Column3(0)); + Column3(2) -= Column3(1) * (Column3(2) % Column3(1)); + Column3(2).Normalize(); + } + //! Orthogonalizes the matrix and removes the scale component, preserving the y direction + void OrthogonalizeY() + { + Column3(1).Normalize(); + Column3(0) -= Column3(1) * (Column3(0) % Column3(1)); + Column3(0).Normalize(); + Column3(2) -= Column3(1) * (Column3(2) % Column3(1)); + Column3(2) -= Column3(0) * (Column3(2) % Column3(0)); + Column3(2).Normalize(); + } + //! Orthogonalizes the matrix and removes the scale component, preserving the z direction + void OrthogonalizeZ() + { + Column3(2).Normalize(); + Column3(0) -= Column3(2) * (Column3(0) % Column3(2)); + Column3(0).Normalize(); + Column3(1) -= Column3(2) * (Column3(1) % Column3(2)); + Column3(1) -= Column3(0) * (Column3(1) % Column3(0)); + Column3(1).Normalize(); + } + + //! Returns if the matrix is identity within the given error tollerance. + CY_NODISCARD bool IsIdentity( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + return std::abs(cell[ 0]-T(1)) < tollerance && std::abs(cell[ 1]) < tollerance && std::abs(cell[ 2]) < tollerance && std::abs(cell[ 3]) < tollerance && + std::abs(cell[ 4]) < tollerance && std::abs(cell[ 5]-T(1)) < tollerance && std::abs(cell[ 6]) < tollerance && std::abs(cell[ 7]) < tollerance && + std::abs(cell[ 8]) < tollerance && std::abs(cell[ 9]) < tollerance && std::abs(cell[10]-T(1)) < tollerance && std::abs(cell[11]) < tollerance && + std::abs(cell[12]) < tollerance && std::abs(cell[13]) < tollerance && std::abs(cell[14]) < tollerance && std::abs(cell[15]-T(1)) < tollerance; + } + + //! Returns if the matrix is symmetric within the given error tollerance. + CY_NODISCARD bool IsSymmetric( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + return std::abs(cell[ 1] - cell[ 4]) < tollerance && + std::abs(cell[ 2] - cell[ 8]) < tollerance && + std::abs(cell[ 3] - cell[12]) < tollerance && + std::abs(cell[ 6] - cell[ 9]) < tollerance && + std::abs(cell[ 7] - cell[13]) < tollerance && + std::abs(cell[11] - cell[14]) < tollerance; + } + + //! Returns if the matrix is diagonal. + CY_NODISCARD bool IsDiagonal( T tollerance=T(_CY_VEC_DEFAULT_ERROR_TOLERANCE) ) const + { + return std::abs(cell[ 1]) + std::abs(cell[ 2]) + std::abs(cell[ 3]) + + std::abs(cell[ 4]) + std::abs(cell[ 6]) + std::abs(cell[ 7]) + + std::abs(cell[ 8]) + std::abs(cell[ 9]) + std::abs(cell[11]) + + std::abs(cell[12]) + std::abs(cell[13]) + std::abs(cell[14]) < tollerance*12; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Static Methods + + //! Returns an identity matrix + CY_NODISCARD static Matrix4 Identity() { T c[] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; return Matrix4(c); } + //! Returns a view matrix using position, target and approximate up vector + CY_NODISCARD static Matrix4 View( Vec3 const &pos, Vec3 const &target, Vec3 const &up ) { Matrix4 m; m.SetView(pos,target,up); return m; } + //! Returns a rotation matrix around x axis by angle in radians + CY_NODISCARD static Matrix4 RotationX( T angle ) { Matrix4 m; m.SetRotationX(angle); return m; } + //! Returns a rotation matrix around y axis by angle in radians + CY_NODISCARD static Matrix4 RotationY( T angle ) { Matrix4 m; m.SetRotationY(angle); return m; } + //! Returns a rotation matrix around z axis by angle in radians + CY_NODISCARD static Matrix4 RotationZ( T angle ) { Matrix4 m; m.SetRotationZ(angle); return m; } + //! Returns a rotation matrix about the given axis by angle in radians + CY_NODISCARD static Matrix4 Rotation( Vec3 const &axis, T angle ) { Matrix4 m; m.SetRotation(axis,angle); return m; } + //! Returns a rotation matrix that sets [from] unit vector to [to] unit vector + CY_NODISCARD static Matrix4 Rotation( Vec3 const &from, Vec3 const &to ) { Matrix4 m; m.SetRotation(from,to); return m; } + //! Returns a rotation matrix around x, y, and then z axes by angle in radians (Rz * Ry * Rx) + CY_NODISCARD static Matrix4 RotationXYZ( T angleX, T angleY, T angleZ ) { Matrix4 m; m.SetRotationXYZ(angleX,angleY,angleZ); return m; } + //! Returns a rotation matrix around z, y, and then x axes by angle in radians (Rx * Ry * Rz) + CY_NODISCARD static Matrix4 RotationZYX( T angleX, T angleY, T angleZ ) { Matrix4 m; m.SetRotationZYX(angleX,angleY,angleZ); return m; } + //! Returns a uniform scale matrix + CY_NODISCARD static Matrix4 Scale( T uniformScale ) { Matrix4 m; m.SetScale(uniformScale); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix4 Scale( T scaleX, T scaleY, T scaleZ, T scaleW=T(1) ) { Matrix4 m; m.SetScale(scaleX,scaleY,scaleZ,scaleW); return m; } + //! Returns a scale matrix + CY_NODISCARD static Matrix4 Scale( Vec3 const &scale ) { Matrix4 m; m.SetScale(scale); return m; } + //! Returns a translation matrix with no rotation or scale + CY_NODISCARD static Matrix4 Translation( Vec3 const &move ) { Matrix4 m; m.SetTranslation(move); return m; } + //! Returns a project matrix with field of view in radians + CY_NODISCARD static Matrix4 Perspective( T fov, T aspect, T znear, T zfar ) { Matrix4 m; m.SetPerspective(fov,aspect,znear,zfar); return m; } + //! Returns a project matrix with the tangent of the half field of view (tan_fov_2) + CY_NODISCARD static Matrix4 PerspectiveTan( T tan_fov_2, T aspect, T znear, T zfar ) { Matrix4 m; m.SetPerspectiveTan(tan_fov_2,aspect,znear,zfar); return m; } + //! Returns the tensor product (outer product) matrix of two vectors + CY_NODISCARD static Matrix4 TensorProduct( Vec4 const &v0, Vec4 const &v1 ) { Matrix4 m; m.SetTensorProduct(v0,v1); return m; } + + ////////////////////////////////////////////////////////////////////////// +}; + +//------------------------------------------------------------------------------- + +template inline Matrix2 operator & ( Vec2 const &v0, Vec2 const &v1 ) { Matrix2 r; r.SetTensorProduct(v0,v1); return r; } //!< tensor product (outer product) of two vectors +template inline Matrix3 operator & ( Vec3 const &v0, Vec3 const &v1 ) { Matrix3 r; r.SetTensorProduct(v0,v1); return r; } //!< tensor product (outer product) of two vectors +template inline Matrix4 operator & ( Vec4 const &v0, Vec4 const &v1 ) { Matrix4 r; r.SetTensorProduct(v0,v1); return r; } //!< tensor product (outer product) of two vectors + +//------------------------------------------------------------------------------- + +// Definitions of the conversion constructors +template Matrix2 ::Matrix2 ( Matrix3 const &m ) { MemCopy(cell,m.cell,2); MemCopy(cell+2,m.cell+3,2); } +template Matrix2 ::Matrix2 ( Matrix34 const &m ) { MemCopy(cell,m.cell,2); MemCopy(cell+2,m.cell+3,2); } +template Matrix2 ::Matrix2 ( Matrix4 const &m ) { MemCopy(cell,m.cell,2); MemCopy(cell+2,m.cell+4,2); } +template Matrix3 ::Matrix3 ( Matrix34 const &m ) { MemCopy(cell,m.cell,9); } +template Matrix3 ::Matrix3 ( Matrix4 const &m ) { MemCopy(cell,m.cell,3); MemCopy(cell+3,m.cell+4,3); MemCopy(cell+6,m.cell+8,3); } +template Matrix34::Matrix34( Matrix4 const &m ) { MemCopy(cell,m.cell,3); MemCopy(cell+3,m.cell+4,3); MemCopy(cell+6,m.cell+8,3); MemCopy(cell+9,m.cell+12,3); } + +template inline Matrix4 Matrix34::GetTranspose() const +{ + Matrix4 m; + m.cell[ 0] = cell[0]; m.cell[ 1] = cell[3]; m.cell[ 2] = cell[ 6]; m.cell[ 3] = cell[ 9]; + m.cell[ 4] = cell[1]; m.cell[ 5] = cell[4]; m.cell[ 6] = cell[ 7]; m.cell[ 7] = cell[10]; + m.cell[ 8] = cell[2]; m.cell[ 9] = cell[5]; m.cell[10] = cell[ 8]; m.cell[11] = cell[11]; + m.cell[12] = T(0); m.cell[13] = T(0); m.cell[14] = T(0); m.cell[15] = T(1); + return m; +} + +//------------------------------------------------------------------------------- + +typedef Matrix2 Matrix2f; //!< Single precision (float) 2x2 Matrix class +typedef Matrix3 Matrix3f; //!< Single precision (float) 3x3 Matrix class +typedef Matrix34 Matrix34f; //!< Single precision (float) 3x4 Matrix class +typedef Matrix4 Matrix4f; //!< Single precision (float) 4x4 Matrix class + +typedef Matrix2 Matrix2d; //!< Double precision (double) 2x2 Matrix class +typedef Matrix3 Matrix3d; //!< Double precision (double) 3x3 Matrix class +typedef Matrix34 Matrix34d; //!< Double precision (double) 3x4 Matrix class +typedef Matrix4 Matrix4d; //!< Double precision (double) 4x4 Matrix class + +//------------------------------------------------------------------------------- +} // namespace hf +//------------------------------------------------------------------------------- + +typedef cy::Matrix2f cyMatrix2f; //!< Single precision (float) 2x2 Matrix class +typedef cy::Matrix3f cyMatrix3f; //!< Single precision (float) 3x3 Matrix class +typedef cy::Matrix34f cyMatrix34f; //!< Single precision (float) 3x4 Matrix class +typedef cy::Matrix4f cyMatrix4f; //!< Single precision (float) 4x4 Matrix class + +typedef cy::Matrix2d cyMatrix2d; //!< Double precision (double) 2x2 Matrix class +typedef cy::Matrix3d cyMatrix3d; //!< Double precision (double) 3x3 Matrix class +typedef cy::Matrix34d cyMatrix34d; //!< Double precision (double) 3x4 Matrix class +typedef cy::Matrix4d cyMatrix4d; //!< Double precision (double) 4x4 Matrix class + +//------------------------------------------------------------------------------- + +#endif diff --git a/cyPoint.h b/include/cyPoint.h similarity index 97% rename from cyPoint.h rename to include/cyPoint.h index a8ce492..0c61dfc 100644 --- a/cyPoint.h +++ b/include/cyPoint.h @@ -1,78 +1,78 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyPoint.h -//! \author Cem Yuksel -//! -//! \brief 2D, 3D, 4D, and ND point (vector) classes. This file is deprecated. -//! -//! This file provides backwards compatibility for vector classes. -//! It is deprecated. Use cyVector.h and classes in that header file instead. -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_POINT_H_INCLUDED_ -#define _CY_POINT_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyVector.h" - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -#define Point Vec //!< A general class for N-dimensional points (vectors). -#define Point2 Vec2 //!< 2D point (vector) class -#define Point3 Vec3 //!< 3D point (vector) class -#define Point4 Vec4 //!< 4D point (vector) class - -//------------------------------------------------------------------------------- - -typedef Point2 Point2f; //!< 2D point (vector) class with float type elements -typedef Point3 Point3f; //!< 3D point (vector) class with float type elements -typedef Point4 Point4f; //!< 4D point (vector) class with float type elements - -typedef Point2 Point2d; //!< 2D point (vector) class with double type elements -typedef Point3 Point3d; //!< 3D point (vector) class with double type elements -typedef Point4 Point4d; //!< 4D point (vector) class with double type elements - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::Point2f cyPoint2f; //!< 2D point (vector) class with float type elements -typedef cy::Point3f cyPoint3f; //!< 3D point (vector) class with float type elements -typedef cy::Point4f cyPoint4f; //!< 4D point (vector) class with float type elements - -typedef cy::Point2d cyPoint2d; //!< 2D point (vector) class with double type elements -typedef cy::Point3d cyPoint3d; //!< 3D point (vector) class with double type elements -typedef cy::Point4d cyPoint4d; //!< 4D point (vector) class with double type elements - -//------------------------------------------------------------------------------- - -#endif - +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyPoint.h +//! \author Cem Yuksel +//! +//! \brief 2D, 3D, 4D, and ND point (vector) classes. This file is deprecated. +//! +//! This file provides backwards compatibility for vector classes. +//! It is deprecated. Use cyVector.h and classes in that header file instead. +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_POINT_H_INCLUDED_ +#define _CY_POINT_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyVector.h" + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +#define Point Vec //!< A general class for N-dimensional points (vectors). +#define Point2 Vec2 //!< 2D point (vector) class +#define Point3 Vec3 //!< 3D point (vector) class +#define Point4 Vec4 //!< 4D point (vector) class + +//------------------------------------------------------------------------------- + +typedef Point2 Point2f; //!< 2D point (vector) class with float type elements +typedef Point3 Point3f; //!< 3D point (vector) class with float type elements +typedef Point4 Point4f; //!< 4D point (vector) class with float type elements + +typedef Point2 Point2d; //!< 2D point (vector) class with double type elements +typedef Point3 Point3d; //!< 3D point (vector) class with double type elements +typedef Point4 Point4d; //!< 4D point (vector) class with double type elements + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::Point2f cyPoint2f; //!< 2D point (vector) class with float type elements +typedef cy::Point3f cyPoint3f; //!< 3D point (vector) class with float type elements +typedef cy::Point4f cyPoint4f; //!< 4D point (vector) class with float type elements + +typedef cy::Point2d cyPoint2d; //!< 2D point (vector) class with double type elements +typedef cy::Point3d cyPoint3d; //!< 3D point (vector) class with double type elements +typedef cy::Point4d cyPoint4d; //!< 4D point (vector) class with double type elements + +//------------------------------------------------------------------------------- + +#endif + diff --git a/cyPointCloud.h b/include/cyPointCloud.h similarity index 100% rename from cyPointCloud.h rename to include/cyPointCloud.h diff --git a/cyQuat.h b/include/cyQuat.h similarity index 97% rename from cyQuat.h rename to include/cyQuat.h index 6298d78..5b1485b 100644 --- a/cyQuat.h +++ b/include/cyQuat.h @@ -1,160 +1,160 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyQuat.h -//! \author Cem Yuksel -//! -//! \brief Quaternion class -//! -//! This file includes a quaternion class that can be used to rotate 3D vectors. -//! It works with Vec3, Matrix3, and Matrix4 classes. -//! Special thanks to Can Yuksel for his contributions in writing this class. -//! -//------------------------------------------------------------------------------- -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_QUAT_H_INCLUDED_ -#define _CY_QUAT_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyVector.h" -#include "cyMatrix.h" - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -//! Quaternion class - -template -class Quat -{ - friend Quat operator*( T f, Quat const &q ) { return Quat( q.s*f, q.v*f); } -public: - T s; //!< scaler part - Vec3 v; //!< vector part - - //!@name Constructors - Quat() CY_CLASS_FUNCTION_DEFAULT - Quat( T _s, Vec3 const &_v ) : s(_s), v(_v) {} - Quat( T _s, T _x, T _y, T _z ) : s(_s), v(_x,_y,_z) {} - Quat( Quat const &q ) : s(q.s), v(q.v) {} - - //!@name Set & Get value functions - void Zero() { s=0; v.Zero(); } - void Reset() { s=1; v.Zero(); } //!< Sets the scalar part to 1 and vector part to zero vector. - void Set( T _s, Vec3 const &_v ) { s=_s; v=_v; } - void Set( T _s, T _x, T _y, T _z ) { s=_s; v.Set(_x,_y,_z); } - void Set( T *array ) { s=array[0]; v.Set(&array[1]); } - void SetRotation( T angle, Vec3 const &axis ) { s=cos(angle*0.5f); v=(T)sin(angle*0.5f)*(axis.GetNormalized()); } - void SetRotation( T angle, T axisX, T axisY, T axisZ ) { SetRotation( angle, Vec3(axisX,axisY,axisZ) ); } - void Get( T *array ) { array[0]=s; v.Get(&array[1]); } - T GetRotationAngle() { return 2.0f*(T)acos(s); } //!< Returns rotation angle in radiants - Vec3 GetRotationAxis () { return v.GetNormalized(); } - - //!@name Length and Normalize functions - void Normalize () { T f=1.0f/Length(); *this *= f; } - Quat GetNormalized() const { T f=1.0f/Length(); return *this*f; } - T LengthSquared() const { return s*s + v.LengthSquared(); } - T Length () const { return (T) sqrt(LengthSquared()); } - - //!@name Matrix conversion functions - void ToMatrix3( Matrix3 &m ) const { FillMatrix( m.cell, &m.cell[3], &m.cell[6] ); } - void ToMatrix4( Matrix4 &m ) const { FillMatrix( m.cell, &m.cell[4], &m.cell[8] ); m.cell[3]=m.cell[7]=m.cell[11]=m.cell[12]=m.cell[13]=m.cell[14]=0; m.cell[15]=1; } - Matrix3 ToMatrix3() const { Matrix3 m; ToMatrix3(m); return m; } - Matrix4 ToMatrix4() const { Matrix4 m; ToMatrix4(m); return m; } - - //!@name Unary operators - Quat operator - () const { return Quat(-s,-v); } - - //!@name Binary operators - Quat operator * ( Quat const &q ) const { return Quat( s*q.s - v.Dot(q.v), s*q.v + q.s*v + v.Cross(q.v)); } - Quat operator + ( Quat const &q ) const { return Quat( s + q.s, v + q.v ); } - Quat operator - ( Quat const &q ) const { return Quat( s - q.s, v - q.v ); } - Quat operator * ( T const &f ) const { return Quat( s*f, v*f); } - - //!@name Assignment operators - Quat& operator *= ( Quat const &q ) { Set( s*q.s - v.Dot(q.v), s*q.v + q.s*v + v.Cross(q.v)); return *this; } - Quat& operator += ( Quat const &q ) { s+=q.s; v+=q.v; return *this; } - Quat& operator -= ( Quat const &q ) { s-=q.s; v-=q.v; return *this; } - Quat& operator *= ( T const &f ) { s*=f; v*=f; return *this; } - - //!@name Test operators - int operator == ( Quat const &q ) const { return ( (q.s==s) && (q.v==v) ); } - int operator != ( Quat const &q ) const { return ( (q.s!=s) || (q.v!=v) ); } - - //!@name Vector rotations - //! Rotates the given vector using the quaternion. - //! Note that the quaternion must be a unit quaternion. - Vec3 GetRotatedVector( Vec3 const &p ) - { - T t2 = s*v.x; - T t3 = s*v.y; - T t4 = s*v.z; - T t5 = -v.x*v.x; - T t6 = v.x*v.y; - T t7 = v.x*v.z; - T t8 = -v.y*v.y; - T t9 = v.y*v.z; - T t10 = -v.z*v.z; - Vec3 pnew; - pnew.x = 2*( (t8 + t10)*p.x + (t6 - t4)*p.y + (t3 + t7)*p.z ) + p.x; - pnew.y = 2*( (t4 + t6)*p.x + (t5 + t10)*p.y + (t9 - t2)*p.z ) + p.y; - pnew.z = 2*( (t7 - t3)*p.x + (t2 + t9)*p.y + (t5 + t8)*p.z ) + p.z; - return pnew; - } - void RotateVector( Vec3 &p ) { p = GetRotatedVector(p); } - -private: - //! \internal - void FillMatrix( T *col1, T *col2, T *col3 ) const - { - col1[0] = s*s + v.x*v.x - v.y*v.y - v.z*v.z; - col1[1] = 2.0f*v.x*v.y + 2.0f*s*v.z; - col1[2] = 2.0f*v.x*v.z - 2.0f*s*v.y; - - col2[0] = 2.0f*v.x*v.y - 2.0f*s*v.z; - col2[1] = s*s - v.x*v.x + v.y*v.y - v.z*v.z; - col2[2] = 2.0f*v.y*v.z + 2.0f*s*v.x; - - col3[0] = 2.0f*v.x*v.z + 2.0f*s*v.y; - col3[1] = 2.0f*v.y*v.z - 2.0f*s*v.x; - col3[2] = s*s - v.x*v.x - v.y*v.y + v.z*v.z; - } -}; - -//------------------------------------------------------------------------------- - -typedef Quat Quatf; //!< Quaternion class with float elements -typedef Quat Quatd; //!< Quaternion class with double elements - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::Quatf cyQuatf; //!< Quaternion class with float elements -typedef cy::Quatd cyQuatd; //!< Quaternion class with double elements - -//------------------------------------------------------------------------------- - -#endif +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyQuat.h +//! \author Cem Yuksel +//! +//! \brief Quaternion class +//! +//! This file includes a quaternion class that can be used to rotate 3D vectors. +//! It works with Vec3, Matrix3, and Matrix4 classes. +//! Special thanks to Can Yuksel for his contributions in writing this class. +//! +//------------------------------------------------------------------------------- +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_QUAT_H_INCLUDED_ +#define _CY_QUAT_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyVector.h" +#include "cyMatrix.h" + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +//! Quaternion class + +template +class Quat +{ + friend Quat operator*( T f, Quat const &q ) { return Quat( q.s*f, q.v*f); } +public: + T s; //!< scaler part + Vec3 v; //!< vector part + + //!@name Constructors + Quat() CY_CLASS_FUNCTION_DEFAULT + Quat( T _s, Vec3 const &_v ) : s(_s), v(_v) {} + Quat( T _s, T _x, T _y, T _z ) : s(_s), v(_x,_y,_z) {} + Quat( Quat const &q ) : s(q.s), v(q.v) {} + + //!@name Set & Get value functions + void Zero() { s=0; v.Zero(); } + void Reset() { s=1; v.Zero(); } //!< Sets the scalar part to 1 and vector part to zero vector. + void Set( T _s, Vec3 const &_v ) { s=_s; v=_v; } + void Set( T _s, T _x, T _y, T _z ) { s=_s; v.Set(_x,_y,_z); } + void Set( T *array ) { s=array[0]; v.Set(&array[1]); } + void SetRotation( T angle, Vec3 const &axis ) { s=cos(angle*0.5f); v=(T)sin(angle*0.5f)*(axis.GetNormalized()); } + void SetRotation( T angle, T axisX, T axisY, T axisZ ) { SetRotation( angle, Vec3(axisX,axisY,axisZ) ); } + void Get( T *array ) { array[0]=s; v.Get(&array[1]); } + T GetRotationAngle() { return 2.0f*(T)acos(s); } //!< Returns rotation angle in radiants + Vec3 GetRotationAxis () { return v.GetNormalized(); } + + //!@name Length and Normalize functions + void Normalize () { T f=1.0f/Length(); *this *= f; } + Quat GetNormalized() const { T f=1.0f/Length(); return *this*f; } + T LengthSquared() const { return s*s + v.LengthSquared(); } + T Length () const { return (T) sqrt(LengthSquared()); } + + //!@name Matrix conversion functions + void ToMatrix3( Matrix3 &m ) const { FillMatrix( m.cell, &m.cell[3], &m.cell[6] ); } + void ToMatrix4( Matrix4 &m ) const { FillMatrix( m.cell, &m.cell[4], &m.cell[8] ); m.cell[3]=m.cell[7]=m.cell[11]=m.cell[12]=m.cell[13]=m.cell[14]=0; m.cell[15]=1; } + Matrix3 ToMatrix3() const { Matrix3 m; ToMatrix3(m); return m; } + Matrix4 ToMatrix4() const { Matrix4 m; ToMatrix4(m); return m; } + + //!@name Unary operators + Quat operator - () const { return Quat(-s,-v); } + + //!@name Binary operators + Quat operator * ( Quat const &q ) const { return Quat( s*q.s - v.Dot(q.v), s*q.v + q.s*v + v.Cross(q.v)); } + Quat operator + ( Quat const &q ) const { return Quat( s + q.s, v + q.v ); } + Quat operator - ( Quat const &q ) const { return Quat( s - q.s, v - q.v ); } + Quat operator * ( T const &f ) const { return Quat( s*f, v*f); } + + //!@name Assignment operators + Quat& operator *= ( Quat const &q ) { Set( s*q.s - v.Dot(q.v), s*q.v + q.s*v + v.Cross(q.v)); return *this; } + Quat& operator += ( Quat const &q ) { s+=q.s; v+=q.v; return *this; } + Quat& operator -= ( Quat const &q ) { s-=q.s; v-=q.v; return *this; } + Quat& operator *= ( T const &f ) { s*=f; v*=f; return *this; } + + //!@name Test operators + int operator == ( Quat const &q ) const { return ( (q.s==s) && (q.v==v) ); } + int operator != ( Quat const &q ) const { return ( (q.s!=s) || (q.v!=v) ); } + + //!@name Vector rotations + //! Rotates the given vector using the quaternion. + //! Note that the quaternion must be a unit quaternion. + Vec3 GetRotatedVector( Vec3 const &p ) + { + T t2 = s*v.x; + T t3 = s*v.y; + T t4 = s*v.z; + T t5 = -v.x*v.x; + T t6 = v.x*v.y; + T t7 = v.x*v.z; + T t8 = -v.y*v.y; + T t9 = v.y*v.z; + T t10 = -v.z*v.z; + Vec3 pnew; + pnew.x = 2*( (t8 + t10)*p.x + (t6 - t4)*p.y + (t3 + t7)*p.z ) + p.x; + pnew.y = 2*( (t4 + t6)*p.x + (t5 + t10)*p.y + (t9 - t2)*p.z ) + p.y; + pnew.z = 2*( (t7 - t3)*p.x + (t2 + t9)*p.y + (t5 + t8)*p.z ) + p.z; + return pnew; + } + void RotateVector( Vec3 &p ) { p = GetRotatedVector(p); } + +private: + //! \internal + void FillMatrix( T *col1, T *col2, T *col3 ) const + { + col1[0] = s*s + v.x*v.x - v.y*v.y - v.z*v.z; + col1[1] = 2.0f*v.x*v.y + 2.0f*s*v.z; + col1[2] = 2.0f*v.x*v.z - 2.0f*s*v.y; + + col2[0] = 2.0f*v.x*v.y - 2.0f*s*v.z; + col2[1] = s*s - v.x*v.x + v.y*v.y - v.z*v.z; + col2[2] = 2.0f*v.y*v.z + 2.0f*s*v.x; + + col3[0] = 2.0f*v.x*v.z + 2.0f*s*v.y; + col3[1] = 2.0f*v.y*v.z - 2.0f*s*v.x; + col3[2] = s*s - v.x*v.x - v.y*v.y + v.z*v.z; + } +}; + +//------------------------------------------------------------------------------- + +typedef Quat Quatf; //!< Quaternion class with float elements +typedef Quat Quatd; //!< Quaternion class with double elements + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::Quatf cyQuatf; //!< Quaternion class with float elements +typedef cy::Quatd cyQuatd; //!< Quaternion class with double elements + +//------------------------------------------------------------------------------- + +#endif diff --git a/cySampleElim.h b/include/cySampleElim.h similarity index 100% rename from cySampleElim.h rename to include/cySampleElim.h diff --git a/cySpatial.h b/include/cySpatial.h similarity index 97% rename from cySpatial.h rename to include/cySpatial.h index 6fcdfc9..75ec0d2 100644 --- a/cySpatial.h +++ b/include/cySpatial.h @@ -1,272 +1,272 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cySpatial.h -//! \author Cem Yuksel -//! -//! \brief Spatial vector algebra classes -//! -//! This file includes spatial vector algebra classes intended for the -//! implementation of Featherstone's articulated rigid body dynamics method. -//! SpatialVector6 class is both for spatial motion vectors and spatial -//! force vectors, SpatialTrans6 is a spatial matrix class for coordinate -//! transformations only, and SpatialMatrix6 is the general spatial -//! matrix class. -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_SPATIAL_H_INCLUDED_ -#define _CY_SPATIAL_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyVector.h" -#include "cyMatrix.h" - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -//! 6D spatial vector (for 3D). -//! -//! This class is both for spatial motion vectors and spatial force vectors. - -template -class SpatialVector6 -{ -public: - - //!@name Components - Vec3 a, b; - - //!@name Constructors - SpatialVector6() CY_CLASS_FUNCTION_DEFAULT - SpatialVector6( Vec3 const &p1, Vec3 const &p2 ) { Set(p1,p2); } - SpatialVector6( T a1, T a2, T a3, T b1, T b2, T b3 ) { Set(a1,a2,a3,b1,b2,b3); } - SpatialVector6( SpatialVector6 const &v ) { a=v.a; b=v.b; } - - //!@name Initialization methods - void Set( Vec3 const &p1, Vec3 const &p2 ) { a = p1; b = p2; } - void Set( T a1, T a2, T a3, T b1, T b2, T b3 ) { a.Set(a1,a2,a3); b.Set(b1,b2,b3); } - void Zero() { a.Zero(); b.Zero(); } - - //!@name Transpose methods - void SetTranspose() { Vec3 p=a; a=b; b=p; } - SpatialVector6 Transpose() const { return SpatialVector6( b, a ); } - - //!@name Unary operators - SpatialVector6 operator-() const { return SpatialVector6(-a,-b); } - - //!@name Binary operators - SpatialVector6 operator + ( SpatialVector6 const &s ) const { return SpatialVector6(a+s.a, b+s.b); } - SpatialVector6 operator - ( SpatialVector6 const &s ) const { return SpatialVector6(a-s.a, b-s.b); } - SpatialVector6 operator * ( T const &t ) const { return SpatialVector6( a*t, b*t ); } - - //! Scalar product of two vectors. - //! Note that one of the vectors should be motion vector ant the other should be a force vector. - //! Otherwise, scalar product is not defined in spatial vector algebra. - T operator * ( SpatialVector6 const &s ) const { return a.Dot(s.a) + b.Dot(s.b); } - - //!@name Assignment operators - void operator = ( SpatialVector6 const &v ) { a=v.a; b=v.b; } - void operator += ( SpatialVector6 const &s ) { a+=s.a; b+=s.b; } - void operator -= ( SpatialVector6 const &s ) { a-=s.a; b-=s.b; } - void operator *= ( T const &t ) { a*=t; b*=t; } - -}; - - -//------------------------------------------------------------------------------- - -//! 6D spatial matrix for coordinate transforms. -//! -//! This is a special case for SpatialMatrix6 class, -//! where the matrix represents a coordinate transformation. -//! In this case, instead of keeping a full 6x6 matrix values, -//! we can keep a 3x3 matrix for rotation, and a 3D point -//! for translation. This compact representation simplifies -//! some computations, therefore you should use this class -//! instead of SpatialMatrix6 whenever you represent -//! a coordinate transformation. However, for general matrix -//! operations, you have to use SpatialMatrix6. -//! - -template -class SpatialTrans6 -{ -public: - - // | R 0 | - // | -r x R R | - - Matrix3 R; //!< Rotation matrix - Vec3 r; //!< Transformation - - //!@name Constructors - SpatialTrans6() CY_CLASS_FUNCTION_DEFAULT - SpatialTrans6( SpatialTrans6 const &mat ) { R=mat.R; r=mat.r; } - SpatialTrans6( Matrix3 const &_R, Vec3 const &_r ) { Set(_R,_r); } - - //!@name Initialization methods - void Set( Matrix3 const &_R, Vec3 const &_r ) { R=_R; r=_r; } - void SetIdentity() { R.SetIdentity(); r.Zero(); } - - //!@name Unary operators - SpatialTrans6 operator - () const { return SpatialTrans6( -R, -r ); } - - - //!@name Binary operators - SpatialVector6 operator * ( SpatialVector6 const &p ) const { Vec3 Ra = R*p.a; return SpatialVector6( Ra, Matrix3::Scale(-r)*Ra + R*p.b ); } - - SpatialTrans6 operator * ( SpatialTrans6 const &mat ) const { return SpatialTrans6( R*mat.R, r + R*mat.r ); } - SpatialTrans6 operator + ( SpatialTrans6 const &mat ) const { return SpatialTrans6( R + mat.R, r + mat.r ); } - SpatialTrans6 operator - ( SpatialTrans6 const &mat ) const { return SpatialTrans6( R - mat.R, r - mat.r ); } - - SpatialTrans6 operator * ( T t ) const { return SpatialTrans6(R*t,r*t); } - SpatialTrans6 operator / ( T t ) const { T d=1.0f/t; return *this * d; } - - - //!@name Assignment operators - void operator *= ( SpatialTrans6 const &mat ) { *this = *this * mat; } - void operator += ( SpatialTrans6 const &mat ) { R+=mat.R; r+=mat.r; } - void operator -= ( SpatialTrans6 const &mat ) { R-=mat.R; r-=mat.r; } - void operator *= ( T const &t ) { *this = *this * t; } - -}; - -//------------------------------------------------------------------------------- - -//! 6D spatial matrix. -//! -//! This is the general class for 6D spatial matrices. -//! For representing coordinate transformation matrices -//! use SpatialTrans6 instead, since it is more efficient. -//! However, SpatialTrans6 cannot be used for general -//! matrix operations that do not correspond to a -//! coordinate transformation. - -template -class SpatialMatrix6 -{ -public: - - // | m[0] m[2] | - // | m[1] m[3] | - - Matrix3 m[4]; //!< Matrix data in column major order - - - //!@name Constructors - SpatialMatrix6() CY_CLASS_FUNCTION_DEFAULT - SpatialMatrix6( SpatialMatrix6 const &mat ) { m[0]=mat.m[0]; m[1]=mat.m[1]; m[2]=mat.m[2]; m[3]=mat.m[3]; } - explicit SpatialMatrix6( Matrix3 const &_R, Vec3 const &_r ) { Set(_R,_r); } - explicit SpatialMatrix6( Matrix3 const &m11, Matrix3 const &m21, Matrix3 const &m12, Matrix3 const &m22 ) { Set(m11,m21,m12,m22); } - explicit SpatialMatrix6( SpatialTrans6 const &tm ) { Set(tm); } - - - //!@name Initialization methods - void Set( Matrix3 const &_R, Vec3 const &_r ) { m[0]=m[3]=_R; m[1]=Matrix3::Scale(-_r)*_R; m[2].Zero(); } - void Set( Matrix3 const &m11, Matrix3 const &m21, Matrix3 const &m12, Matrix3 const &m22 ) { m[0]=m11; m[1]=m21; m[2]=m12; m[3]=m22; } - void Set( SpatialTrans6 const &tm ) { m[0]=m[3]=tm.R; m[1]=Matrix3::Scale(-tm.r)*tm.R; m[2].Zero(); } - - //! Sets the matrix as the outer product of two vectors. - void SetTensorProduct( SpatialVector6 const &p1, SpatialVector6 const &p2 ) - { - SetMatrix( m[0], p1.a, p2.a ); - SetMatrix( m[1], p1.b, p2.a ); - SetMatrix( m[2], p1.a, p2.b ); - SetMatrix( m[3], p1.b, p2.b ); - } - - void SetIdentity() { m[0].SetIdentity(); m[1].Zero(); m[2].Zero(); m[3].SetIdentity(); } - void Zero() { m[0].Zero(); m[1].Zero(); m[2].Zero(); m[3].Zero(); } - - - //!@name Unary operators - SpatialMatrix6 operator - () const { return SpatialMatrix6( -m[0], -m[1], -m[2], -m[3] ); } - - - //!@name Unary operators - - SpatialVector6 operator * ( SpatialVector6 const &p ) const { return SpatialVector6( m[0]*p.a + m[2]*p.b, m[1]*p.a + m[3]*p.b ); } - - SpatialMatrix6 operator * ( SpatialMatrix6 const &mat ) const { return SpatialMatrix6( m[0]*mat.m[0]+m[2]*mat.m[1], m[1]*mat.m[0]+m[3]*mat.m[1], m[0]*mat.m[2]+m[2]*mat.m[3], m[1]*mat.m[2]+m[3]*mat.m[3] ); } - SpatialMatrix6 operator + ( SpatialMatrix6 const &mat ) const { return SpatialMatrix6( m[0]+mat.m[0], m[1]+mat.m[1], m[2]+mat.m[2], m[3]+mat.m[3] ); } - SpatialMatrix6 operator - ( SpatialMatrix6 const &mat ) const { return SpatialMatrix6( m[0]-mat.m[0], m[1]-mat.m[1], m[2]-mat.m[2], m[3]-mat.m[3] ); } - - SpatialMatrix6 operator * ( T t ) const { return SpatialMatrix6(m[0]*t,m[1]*t,m[2]*t,m[3]*t); } - SpatialMatrix6 operator / ( T t ) const { T d=1.0f/t; return *this * d; } - - - //!@name Assignment operators - void operator *= ( SpatialMatrix6 const &mat ) { *this = *this * mat; } - void operator += ( SpatialMatrix6 const &mat ) { m[0]+=mat.m[0]; m[1]+=mat.m[1]; m[2]+=mat.m[2]; m[3]+=mat.m[3]; } - void operator -= ( SpatialMatrix6 const &mat ) { m[0]-=mat.m[0]; m[1]-=mat.m[1]; m[2]-=mat.m[2]; m[3]-=mat.m[3]; } - void operator *= ( T t ) { *this = *this * t; } - - -protected: - - //! \internal - - // Sets the given matrix as the outer product of the given two vectors. - void SetMatrix( Matrix3 &m, Vec3 const &p1, Vec3 const &p2 ) - { - T val[] = {p1.x * p2.x, p1.y * p2.x, p1.z * p2.x, p1.x * p2.y, p1.y * p2.y, p1.z * p2.y, p1.x * p2.z, p1.y * p2.z, p1.z * p2.z}; - m.Set( val ); - } - -}; - -//------------------------------------------------------------------------------- - -template inline SpatialMatrix6 operator & ( SpatialVector6 const &v0, SpatialVector6 const &v1 ) { Matrix2 buffer; buffer.SetTensorProduct(v0,v1); return buffer; } //!< tensor product (outer product) of two vectors - -//------------------------------------------------------------------------------- - -typedef SpatialVector6 SpatialVector6f; //!< 6D spatial vector (for 3D) with float type elements -typedef SpatialTrans6 SpatialTrans6f; //!< 6D spatial matrix for coordinate transforms with float type elements -typedef SpatialMatrix6 SpatialMatrix6f; //!< 6D spatial matrix with float type elements - -typedef SpatialVector6 SpatialVector6d; //!< 6D spatial vector (for 3D) with double type elements -typedef SpatialTrans6 SpatialTrans6d; //!< 6D spatial matrix for coordinate transforms with double type elements -typedef SpatialMatrix6 SpatialMatrix6d; //!< 6D spatial matrix with double type elements - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::SpatialVector6f cySpatialVector6f; //!< 6D spatial vector (for 3D) with float type elements -typedef cy::SpatialTrans6f cySpatialTrans6f; //!< 6D spatial matrix for coordinate transforms with float type elements -typedef cy::SpatialMatrix6f cySpatialMatrix6f; //!< 6D spatial matrix with float type elements - -typedef cy::SpatialVector6d cySpatialVector6d; //!< 6D spatial vector (for 3D) with double type elements -typedef cy::SpatialTrans6d cySpatialTrans6d; //!< 6D spatial matrix for coordinate transforms with double type elements -typedef cy::SpatialMatrix6d cySpatialMatrix6d; //!< 6D spatial matrix with double type elements - -//------------------------------------------------------------------------------- - -#endif +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cySpatial.h +//! \author Cem Yuksel +//! +//! \brief Spatial vector algebra classes +//! +//! This file includes spatial vector algebra classes intended for the +//! implementation of Featherstone's articulated rigid body dynamics method. +//! SpatialVector6 class is both for spatial motion vectors and spatial +//! force vectors, SpatialTrans6 is a spatial matrix class for coordinate +//! transformations only, and SpatialMatrix6 is the general spatial +//! matrix class. +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_SPATIAL_H_INCLUDED_ +#define _CY_SPATIAL_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyVector.h" +#include "cyMatrix.h" + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +//! 6D spatial vector (for 3D). +//! +//! This class is both for spatial motion vectors and spatial force vectors. + +template +class SpatialVector6 +{ +public: + + //!@name Components + Vec3 a, b; + + //!@name Constructors + SpatialVector6() CY_CLASS_FUNCTION_DEFAULT + SpatialVector6( Vec3 const &p1, Vec3 const &p2 ) { Set(p1,p2); } + SpatialVector6( T a1, T a2, T a3, T b1, T b2, T b3 ) { Set(a1,a2,a3,b1,b2,b3); } + SpatialVector6( SpatialVector6 const &v ) { a=v.a; b=v.b; } + + //!@name Initialization methods + void Set( Vec3 const &p1, Vec3 const &p2 ) { a = p1; b = p2; } + void Set( T a1, T a2, T a3, T b1, T b2, T b3 ) { a.Set(a1,a2,a3); b.Set(b1,b2,b3); } + void Zero() { a.Zero(); b.Zero(); } + + //!@name Transpose methods + void SetTranspose() { Vec3 p=a; a=b; b=p; } + SpatialVector6 Transpose() const { return SpatialVector6( b, a ); } + + //!@name Unary operators + SpatialVector6 operator-() const { return SpatialVector6(-a,-b); } + + //!@name Binary operators + SpatialVector6 operator + ( SpatialVector6 const &s ) const { return SpatialVector6(a+s.a, b+s.b); } + SpatialVector6 operator - ( SpatialVector6 const &s ) const { return SpatialVector6(a-s.a, b-s.b); } + SpatialVector6 operator * ( T const &t ) const { return SpatialVector6( a*t, b*t ); } + + //! Scalar product of two vectors. + //! Note that one of the vectors should be motion vector ant the other should be a force vector. + //! Otherwise, scalar product is not defined in spatial vector algebra. + T operator * ( SpatialVector6 const &s ) const { return a.Dot(s.a) + b.Dot(s.b); } + + //!@name Assignment operators + void operator = ( SpatialVector6 const &v ) { a=v.a; b=v.b; } + void operator += ( SpatialVector6 const &s ) { a+=s.a; b+=s.b; } + void operator -= ( SpatialVector6 const &s ) { a-=s.a; b-=s.b; } + void operator *= ( T const &t ) { a*=t; b*=t; } + +}; + + +//------------------------------------------------------------------------------- + +//! 6D spatial matrix for coordinate transforms. +//! +//! This is a special case for SpatialMatrix6 class, +//! where the matrix represents a coordinate transformation. +//! In this case, instead of keeping a full 6x6 matrix values, +//! we can keep a 3x3 matrix for rotation, and a 3D point +//! for translation. This compact representation simplifies +//! some computations, therefore you should use this class +//! instead of SpatialMatrix6 whenever you represent +//! a coordinate transformation. However, for general matrix +//! operations, you have to use SpatialMatrix6. +//! + +template +class SpatialTrans6 +{ +public: + + // | R 0 | + // | -r x R R | + + Matrix3 R; //!< Rotation matrix + Vec3 r; //!< Transformation + + //!@name Constructors + SpatialTrans6() CY_CLASS_FUNCTION_DEFAULT + SpatialTrans6( SpatialTrans6 const &mat ) { R=mat.R; r=mat.r; } + SpatialTrans6( Matrix3 const &_R, Vec3 const &_r ) { Set(_R,_r); } + + //!@name Initialization methods + void Set( Matrix3 const &_R, Vec3 const &_r ) { R=_R; r=_r; } + void SetIdentity() { R.SetIdentity(); r.Zero(); } + + //!@name Unary operators + SpatialTrans6 operator - () const { return SpatialTrans6( -R, -r ); } + + + //!@name Binary operators + SpatialVector6 operator * ( SpatialVector6 const &p ) const { Vec3 Ra = R*p.a; return SpatialVector6( Ra, Matrix3::Scale(-r)*Ra + R*p.b ); } + + SpatialTrans6 operator * ( SpatialTrans6 const &mat ) const { return SpatialTrans6( R*mat.R, r + R*mat.r ); } + SpatialTrans6 operator + ( SpatialTrans6 const &mat ) const { return SpatialTrans6( R + mat.R, r + mat.r ); } + SpatialTrans6 operator - ( SpatialTrans6 const &mat ) const { return SpatialTrans6( R - mat.R, r - mat.r ); } + + SpatialTrans6 operator * ( T t ) const { return SpatialTrans6(R*t,r*t); } + SpatialTrans6 operator / ( T t ) const { T d=1.0f/t; return *this * d; } + + + //!@name Assignment operators + void operator *= ( SpatialTrans6 const &mat ) { *this = *this * mat; } + void operator += ( SpatialTrans6 const &mat ) { R+=mat.R; r+=mat.r; } + void operator -= ( SpatialTrans6 const &mat ) { R-=mat.R; r-=mat.r; } + void operator *= ( T const &t ) { *this = *this * t; } + +}; + +//------------------------------------------------------------------------------- + +//! 6D spatial matrix. +//! +//! This is the general class for 6D spatial matrices. +//! For representing coordinate transformation matrices +//! use SpatialTrans6 instead, since it is more efficient. +//! However, SpatialTrans6 cannot be used for general +//! matrix operations that do not correspond to a +//! coordinate transformation. + +template +class SpatialMatrix6 +{ +public: + + // | m[0] m[2] | + // | m[1] m[3] | + + Matrix3 m[4]; //!< Matrix data in column major order + + + //!@name Constructors + SpatialMatrix6() CY_CLASS_FUNCTION_DEFAULT + SpatialMatrix6( SpatialMatrix6 const &mat ) { m[0]=mat.m[0]; m[1]=mat.m[1]; m[2]=mat.m[2]; m[3]=mat.m[3]; } + explicit SpatialMatrix6( Matrix3 const &_R, Vec3 const &_r ) { Set(_R,_r); } + explicit SpatialMatrix6( Matrix3 const &m11, Matrix3 const &m21, Matrix3 const &m12, Matrix3 const &m22 ) { Set(m11,m21,m12,m22); } + explicit SpatialMatrix6( SpatialTrans6 const &tm ) { Set(tm); } + + + //!@name Initialization methods + void Set( Matrix3 const &_R, Vec3 const &_r ) { m[0]=m[3]=_R; m[1]=Matrix3::Scale(-_r)*_R; m[2].Zero(); } + void Set( Matrix3 const &m11, Matrix3 const &m21, Matrix3 const &m12, Matrix3 const &m22 ) { m[0]=m11; m[1]=m21; m[2]=m12; m[3]=m22; } + void Set( SpatialTrans6 const &tm ) { m[0]=m[3]=tm.R; m[1]=Matrix3::Scale(-tm.r)*tm.R; m[2].Zero(); } + + //! Sets the matrix as the outer product of two vectors. + void SetTensorProduct( SpatialVector6 const &p1, SpatialVector6 const &p2 ) + { + SetMatrix( m[0], p1.a, p2.a ); + SetMatrix( m[1], p1.b, p2.a ); + SetMatrix( m[2], p1.a, p2.b ); + SetMatrix( m[3], p1.b, p2.b ); + } + + void SetIdentity() { m[0].SetIdentity(); m[1].Zero(); m[2].Zero(); m[3].SetIdentity(); } + void Zero() { m[0].Zero(); m[1].Zero(); m[2].Zero(); m[3].Zero(); } + + + //!@name Unary operators + SpatialMatrix6 operator - () const { return SpatialMatrix6( -m[0], -m[1], -m[2], -m[3] ); } + + + //!@name Unary operators + + SpatialVector6 operator * ( SpatialVector6 const &p ) const { return SpatialVector6( m[0]*p.a + m[2]*p.b, m[1]*p.a + m[3]*p.b ); } + + SpatialMatrix6 operator * ( SpatialMatrix6 const &mat ) const { return SpatialMatrix6( m[0]*mat.m[0]+m[2]*mat.m[1], m[1]*mat.m[0]+m[3]*mat.m[1], m[0]*mat.m[2]+m[2]*mat.m[3], m[1]*mat.m[2]+m[3]*mat.m[3] ); } + SpatialMatrix6 operator + ( SpatialMatrix6 const &mat ) const { return SpatialMatrix6( m[0]+mat.m[0], m[1]+mat.m[1], m[2]+mat.m[2], m[3]+mat.m[3] ); } + SpatialMatrix6 operator - ( SpatialMatrix6 const &mat ) const { return SpatialMatrix6( m[0]-mat.m[0], m[1]-mat.m[1], m[2]-mat.m[2], m[3]-mat.m[3] ); } + + SpatialMatrix6 operator * ( T t ) const { return SpatialMatrix6(m[0]*t,m[1]*t,m[2]*t,m[3]*t); } + SpatialMatrix6 operator / ( T t ) const { T d=1.0f/t; return *this * d; } + + + //!@name Assignment operators + void operator *= ( SpatialMatrix6 const &mat ) { *this = *this * mat; } + void operator += ( SpatialMatrix6 const &mat ) { m[0]+=mat.m[0]; m[1]+=mat.m[1]; m[2]+=mat.m[2]; m[3]+=mat.m[3]; } + void operator -= ( SpatialMatrix6 const &mat ) { m[0]-=mat.m[0]; m[1]-=mat.m[1]; m[2]-=mat.m[2]; m[3]-=mat.m[3]; } + void operator *= ( T t ) { *this = *this * t; } + + +protected: + + //! \internal + + // Sets the given matrix as the outer product of the given two vectors. + void SetMatrix( Matrix3 &m, Vec3 const &p1, Vec3 const &p2 ) + { + T val[] = {p1.x * p2.x, p1.y * p2.x, p1.z * p2.x, p1.x * p2.y, p1.y * p2.y, p1.z * p2.y, p1.x * p2.z, p1.y * p2.z, p1.z * p2.z}; + m.Set( val ); + } + +}; + +//------------------------------------------------------------------------------- + +template inline SpatialMatrix6 operator & ( SpatialVector6 const &v0, SpatialVector6 const &v1 ) { Matrix2 buffer; buffer.SetTensorProduct(v0,v1); return buffer; } //!< tensor product (outer product) of two vectors + +//------------------------------------------------------------------------------- + +typedef SpatialVector6 SpatialVector6f; //!< 6D spatial vector (for 3D) with float type elements +typedef SpatialTrans6 SpatialTrans6f; //!< 6D spatial matrix for coordinate transforms with float type elements +typedef SpatialMatrix6 SpatialMatrix6f; //!< 6D spatial matrix with float type elements + +typedef SpatialVector6 SpatialVector6d; //!< 6D spatial vector (for 3D) with double type elements +typedef SpatialTrans6 SpatialTrans6d; //!< 6D spatial matrix for coordinate transforms with double type elements +typedef SpatialMatrix6 SpatialMatrix6d; //!< 6D spatial matrix with double type elements + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::SpatialVector6f cySpatialVector6f; //!< 6D spatial vector (for 3D) with float type elements +typedef cy::SpatialTrans6f cySpatialTrans6f; //!< 6D spatial matrix for coordinate transforms with float type elements +typedef cy::SpatialMatrix6f cySpatialMatrix6f; //!< 6D spatial matrix with float type elements + +typedef cy::SpatialVector6d cySpatialVector6d; //!< 6D spatial vector (for 3D) with double type elements +typedef cy::SpatialTrans6d cySpatialTrans6d; //!< 6D spatial matrix for coordinate transforms with double type elements +typedef cy::SpatialMatrix6d cySpatialMatrix6d; //!< 6D spatial matrix with double type elements + +//------------------------------------------------------------------------------- + +#endif diff --git a/cyString.h b/include/cyString.h similarity index 96% rename from cyString.h rename to include/cyString.h index e80f293..f4b1e14 100644 --- a/cyString.h +++ b/include/cyString.h @@ -1,1063 +1,1063 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyString.h -//! \author Cem Yuksel -//! -//! \brief String class -//! -//! This file includes a general purpose string class for char arrays. -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_STRING_H_INCLUDED_ -#define _CY_STRING_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include -#include -#include -#include -#include "cyCore.h" - -//------------------------------------------------------------------------------- - -_CY_CRT_SECURE_NO_WARNINGS - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -//! A general-purpose string class for char arrays. -//! -//! This is a general purpose string class, which supports many useful string operations. -//! It has methods for numeric conversions, character and string search, -//! formating, editing, and file operations. - -class String -{ - -#ifdef _OSTREAM_ - //! Overloaded stream operator. It only works if you include iostream before this file. - friend std::ostream& operator << ( std::ostream &os, String const &str ) - { - os< 0 ) { - char *str = NewString(newLength); - int l = (length < newLength) ? length : newLength; - strncpy(str,string,l); - memset(str+l,' ',newLength-l); - ReplaceString( str, newLength ); - } else { - EmptyString(); - } - return length; - } - - //! Creates a string of length 'count' with the given character 'chr'. - void SetCharString( char chr, int count ) - { - SetStrLen( count ); - memset( string, chr, length ); - } - - //! Deletes 'count' number of characters from the array, starting from 'start'. - //! If 'count' is too big, deletes till the end of the string. - void Delete( int start, int count ) - { - if ( start > length || count <= 0 ) return; - int end = start + count; - if ( end > length ) { count -= end - length; end = length; } - length -= count; - char *string2 = NewString(length); - strncpy ( string2, string, start ); - strncpy ( string2+start, string+end, length - start ); - ReplaceString( string2 ); - } - - //! Inserts the given string to the given index. - void Insert( String const &str, int index ) - { - int count = length - index; - if ( count < 0 ) { index = length; count = 0; } - length += str.length; - char *string2 = NewString(length); - strncpy( string2, string, index ); - strncpy( string2+index, str.string, str.length ); - strncpy( string2+index+str.length, string+index, count ); - ReplaceString( string2 ); - } - - //! Deletes all carriage return characters. - //! Returns the number of characters deleted. - int DeleteCarriageReturns() { return DeleteChar('\r'); } - - //! Insert a carriage return character after every new line character - //! if it doesn't already exits. Returns the number of carriage return characters inserted. - int InsertCarriageReturns() - { - int nn = CountChar('\n'); - if ( nn == 0 ) return 0; - int nr = CountChar('\r'); - char *string2 = NewString( length + nn - nr ); - int i = length - 1; - int j = length + nn - nr - 1; - while ( j >= 0 ) { - bool needCR = false; - if ( string[i] == '\n' ) needCR = true; - string[j--] = string[i--]; - if ( needCR ) { - if ( i > 0 && string[i] == '\r' ) continue; - string[j--] = '\r'; - } - } - ReplaceString( string2, length + nn - nr ); - Shrink(); - return nn - nr; - - } - - //! Deletes all the characters in the string that are equal to the given character 'c'. - //! Returns the number of characters deleted. - int DeleteChar( char c ) - { - int n = 0; - char *str = strchr( string, c ); - while ( str != nullptr ) { - n++; - int count; - char *str2 = strchr( ++str, c ); - if ( str2 != nullptr ) count = int(str2 - str); - else count = int(string - str) + length + 1; - memmove( str-n, str, count ); - str = str2; - } - Shrink(); - return n; - } - - //! Deletes all the characters in the string that exits in the given set. - //! Returns the number of characters deleted. - int DeleteChars( String const &set ) - { - int n = 0; - char *str = strpbrk( string, set.string ); - while ( str != nullptr ) { - n++; - int count; - char *str2 = strpbrk( ++str, set.string ); - if ( str2 != nullptr ) count = int(str2 - str); - else count = int(string - str) + length + 1; - memmove( str-n, str, count ); - str = str2; - } - Shrink(); - return n; - } - - //! Reverses the string. - void Reverse() - { - for ( int i=0; i= 0; i-- ) { - int pos = set.GetPosition( string[i] ); - if ( pos >= 0 ) return i; - } - return -1; - } - - //! Searches the string starting from the beginning for a character that exists in the given set. - //! Returns the first position of a character from the set. - //! If not found, returns -1. - int SearchNextSet( int start, String const &set ) const - { - if ( start > length ) return -1; - int pos = (int) strcspn( string + start, set.string ); - if ( pos < length ) return pos + start; - else return -1; - } - - //! Returns the first position of the character. - //! If the character is not found, returns -1. - int GetPosition( char c ) const - { - char *cp = strchr( string, c ); - if ( cp != nullptr ) return int(cp - string); - else return -1; - } - - //! Returns the first position of the given string. - //! If the string is not found, returns -1. - int GetPosition( String const &str ) const - { - char *sub = strstr( string, str.GetString() ); - if ( sub != nullptr ) return int(sub - string); - else return -1; - } - - //! Returns the last position of the character. - //! If the character is not found, returns -1. - int GetLastPosition( char c ) const - { - char *cp = strrchr( string, c ); - if ( cp != nullptr ) return int(cp - string); - else return -1; - } - - //! Returns the last position of the given string. - //! If the string is not found, returns -1. - int GetLastPosition( String const &str ) const - { - String s(*this); - String str2(str); - s.Reverse(); - str2.Reverse(); - int pos = s.GetPosition(str2); - if ( pos >= 0 ) return length - pos - str.length; - else return -1; - } - - //! Returns the next position of the character. - //! If the character is not found, returns -1. - int GetNextPosition( int start, char c ) const - { - if ( start > length ) return -1; - char *cp = strchr( string+start, c ); - if ( cp != nullptr ) return int(cp - string); - else return -1; - } - - //! Returns the next position of the given string. - //! If the string is not found, returns -1. - int GetNextPosition( int start, String const &str ) const - { - if ( start > length ) return -1; - char *sub = strstr( string+start, str.GetString() ); - if ( sub != nullptr ) return int(sub - string); - else return -1; - } - - //! Returns the line number of the given position in the string - int GetLineNumber( int pos ) const { return CountChar('\n',0,pos) + 1; } - - //! Returns the number of lines in the string. - int GetNumLines() const { return CountChar('\n') + 1; } - - //! Returns the number of characters in the string that are equal to the given character 'c'. - int CountChar( char c ) const - { - int n = 0; - char *str = strchr( string, c ); - while ( str != nullptr ) { - n++; - str = strchr( str+1, c ); - } - return n; - } - - //! Returns the number of characters in the string that are equal to the given character 'c'.between start and end - int CountChar( char c, int start, int end ) const - { - int n = 0; - - if ( start > length ) return 0; - if ( end > length ) end = length; - if ( end < start ) return 0; - - char *str = string + start; - - str = strchr( str, c ); - while ( str != nullptr && str <= (string + end) ) { - n++; - str = strchr( str+1, c ); - } - return n; - } - - //! Returns the number of characters in the string that exists in the given character set. - int CountChars( String const &set ) const - { - return (int) strspn( string, set.string ); - } - - //! Returns the character of the string at the specified index. - char operator [] ( int index ) const { return string[index]; } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Comparison methods - - //! Checks if this string is the same as 'str'. - int operator == ( String const &str ) const { return ( Compare(str) == 0 ); } - - //! Checks if this string is not the same as 'str'. - int operator != ( String const &str ) const { return ( Compare(str) != 0 ); } - - //! Checks if this string is smaller than 'str'. - int operator < ( String const &str ) const { return ( Compare(str) < 0 ); } - - //! Checks if this string is smaller than or equal to 'str'. - int operator <= ( String const &str ) const { return ( Compare(str) <= 0 ); } - - //! Checks if this string is greater than 'str'. - int operator > ( String const &str ) const { return ( Compare(str) > 0 ); } - - //! Checks if this string is greater than or equal to 'str'. - int operator >= ( String const &str ) const { return ( Compare(str) >= 0 ); } - - //! Compares this string to 'str' (case sensitive). - //! Returns zero if the strings are the same, - //! smaller than zero if this string is smaller than 'str', - //! greater than zero if this string is greater than 'str'. - int Compare( String const &str ) const - { - if ( length == str.length ) { - if ( length > 0 ) return strcmp( string, str.string ); - else if ( str.length == 0 ) return 0; - else return -1; - } else return length - str.length; - } - - //! Compares this string to 'str' (case sensitive) limited to the first 'count' characters. - //! Returns zero if the strings are the same, - //! smaller than zero if this string is smaller than 'str', - //! greater than zero if this string is greater than 'str'. - int Compare( String const &str, int count ) const - { - return strncmp( string, str.string, count ); - } - - //! Compares this string to 'str' (case insensitive). - //! Returns zero if the strings are the same, - //! smaller than zero if this string is smaller than 'str', - //! greater than zero if this string is greater than 'str'. - int CompareIC( String const &str ) const - { - String str1(*this); - String str2(str); - str1.LowerCase(); - str2.LowerCase(); - return str1.Compare( str2 ); - } - - //! Compares this string to 'str' (case insensitive) limited to the first 'count' characters. - //! Returns zero if the strings are the same, - //! smaller than zero if this string is smaller than 'str', - //! greater than zero if this string is greater than 'str'. - int CompareIC( String const &str, int count ) const - { - String str1(*this); - String str2(str); - str1.LowerCase(); - str2.LowerCase(); - return str1.Compare( str2, count ); - } - - //! Returns if the char in the given position is a capital letter - int IsCapitalChar( int pos ) const - { - if ( string[pos] < 65 ) return false; - if ( string[pos] > 90 ) return false; - return true; - } - - //! Returns if the char in the given position is a lower case letter - int IsLowerCaseChar( int pos ) const - { - if ( string[pos] < 97 ) return false; - if ( string[pos] > 122 ) return false; - return true; - } - - //! Returns if the char in the given position is a numeric character - int IsNumericChar( int pos ) const - { - if ( string[pos] < 48 ) return false; - if ( string[pos] > 57 ) return false; - return true; - } - - //! Returns if the char in the given position is a lower case or capital letter - int IsAlphaChar( int pos ) const - { - if ( IsLowerCaseChar(pos) ) return true; - if ( IsCapitalChar(pos) ) return true; - return false; - } - - //! Returns if the char in the given position is a lower case or capital letter or a numeric character - int IsAlphaNumericChar( int pos ) const - { - if ( IsNumericChar(pos) ) return true; - if ( IsAlphaChar(pos) ) return true; - return false; - } - - //! Returns if the char in the given position is a lower case or capital letter, a numeric character or '_' - int IsNameChar( int pos ) const - { - if ( string[pos] == '-') return true; - else return IsAlphaNumericChar( pos ); - } - - //! Returns if the char in the given position is a space character - int IsSpaceChar( int pos ) const - { - switch ( string[pos] ) { - case ' ': - case '\t': - case '\n': - case '\r': - return true; - default: - return false; - } - } - - //! Returns if the char in the given position is a control char (including new line etc.) - int IsControlChar( int pos ) const - { - if ( string[pos] < 32 ) return true; - if ( string[pos] > 126 ) return true; - return false; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Append and substring - - //! Appends to the end of the string. - void Append( String const &str ) - { - int length2 = length + str.length; - char *string2 = NewString(length2); - strncpy(string2,string,length); - strncpy(string2+length,str.string,str.length); - ReplaceString( string2, length2 ); - } - - //! Appends to the end of the string and returns this string. - String& operator += ( String const &str ) { Append(str); return *this; } - - //! Appends two strings and returns the result - String operator + ( String const &right ) { - String r; - r.SetStrLen( length + right.length ); - strncpy( r.string, string, length ); - strncpy( r.string+length, right.string, right.length ); - return r; - } - - //! Converts the string to its sub-string starting from 'start' with length of 'count'. - //! If 'count' is too large, returns the sub-string till the end of the string. - void SubString( int start, int count ) - { - if ( start > length ) start = length; - int end = start + count; - if ( end > length ) { count -= end - length; end = length; } - length = count; - char *string2 = NewString(length); - strncpy( string2, string+start, length ); - ReplaceString( string2 ); - } - - //! Returns the sub-string from 'start' with the length of 'count'. - //! If 'count' is too big, returns the sub-string till the end of the string. - String GetSubString( int start, int count ) const - { - if ( start > length ) start = length; - int end = start + count; - if ( end > length ) { count -= end - length; end = length; } - String str(string+start,count); - return str; - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Conversion to numbers and number arrays - - //! Converts the string to int. - int ToInt() const { return atoi(string); } - - //! Converts the string to long. - long ToLong() const { return atol(string); } - - //! Converts the string to float. - float ToFloat() const { return (float) atof(string); } - - //! Converts the string to double. - double ToDouble() const { return atof(string); } - - //! Converts the string (ex: "23,43,14") to int array. - void ToIntArray(int n, int *v) const - { - int p1 = 0; - for ( int i=0; i 0 ) { - sub = GetSubString(p1,p2-p1); - p1 = p2+1; - } else { - sub = GetSubString(p1,length); - } - v[i] = sub.ToInt(); - } - } - - //! Converts the string to long. - void ToLongArray(int n, long *v) const - { - int p1 = 0; - for ( int i=0; i 0 ) { - sub = GetSubString(p1,p2-p1); - p1 = p2+1; - } else { - sub = GetSubString(p1,length); - } - v[i] = sub.ToLong(); - } - } - - //! Converts the string (ex: "23,43,14") to float array. - void ToFloatArray(int n, float *v) const - { - int p1 = 0; - for ( int i=0; i 0 ) { - sub = GetSubString(p1,p2-p1); - p1 = p2+1; - } else { - sub = GetSubString(p1,length); - } - v[i] = sub.ToFloat(); - } - } - - //! Converts the string (ex: "23,43,14") to double array. - void ToDoubleArray(int n, double *v) const - { - int p1 = 0; - for ( int i=0; i 0 ) { - sub = GetSubString(p1,p2-p1); - p1 = p2+1; - } else { - sub = GetSubString(p1,length); - } - v[i] = sub.ToDouble(); - } - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Trim and shrink - - //! Deletes empty characters from the beginning and end of the string. - void Trim() { TrimRight(); TrimLeft(); } - - //! Deletes empty characters from the beginning of the string. - void TrimLeft() - { - int i; - unsigned char *uchr = (unsigned char *) string; // unsigned to support extended ASCII characters - for ( i=0; i 32 && *uchr != 127 && *uchr != 255 ) break; - uchr++; - } - Delete(0,i); - } - - //! Deletes empty characters from the end of the string. - void TrimRight() - { - unsigned char *uchr = (unsigned char *) LastChar(); // unsigned to support extended ASCII characters - if ( uchr ) { - unsigned char *str = (unsigned char *) string; - for ( ; uchr >= str; uchr--) { - if ( *uchr > 32 && *uchr != 127 && *uchr != 255 ) break; - } - Delete( int(uchr-str)+1, length ); - } - } - - //! Deletes the rest of the string after the first null character. - void Shrink() - { - char *end = strchr(string,'\0'); - if ( end != nullptr ) { - int count = int(end - string); - if ( count < length ) SubString(0,count); - } - } - - ////////////////////////////////////////////////////////////////////////// - //!@name Case change - - //! Coverts the string to lower case. - void LowerCase() - { - for ( int i=0; i= 65 && string[i] <= 90 ) string[i] += 32; - } - - //! Coverts the string to upper case. - void UpperCase() - { - for ( int i=0; i= 97 && string[i] <= 122 ) string[i] -= 32; - } - - //! Coverts the string to swapped case. - void SwapCase() - { - for ( int i=0; i= 65 && string[i] <= 90 ) string[i] += 32; - else if ( string[i] >= 97 && string[i] <= 122 ) string[i] -= 32; - } - } - - //! Coverts the string to title case. - void TitleCase() - { - int wordstart = true; - for ( int i=0; i= 97 && string[i] <= 122 ) { - string[i] -= 32; - wordstart = false; - } - else if( string[i] >= 65 && string[i] <= 90 ) wordstart = false; - } else { - if ( string[i] >= 65 && string[i] <= 90 ) string[i] += 32; - else if( string[i] < 97 || string[i] > 122 ) wordstart = true; - } - } - } - - //! Returns the lower case version of the string. - String GetLowerCase() const { String str(*this); str.LowerCase(); return str; } - - //! Returns the upper case version of the string. - String GetUpperCase() const { String str(*this); str.UpperCase(); return str; } - - //! Returns the swapped case version of the string. - String GetSwapCase() const { String str(*this); str.SwapCase(); return str; } - - //! Returns the title case version of the string. - String GetTitleCase() const { String str(*this); str.TitleCase(); return str; } - - - ////////////////////////////////////////////////////////////////////////// - //!@name Load/save and file name methods - - //! Parses the string as file name string and returns path, filename. - void DecodeFileName( String &path, String &filename ) - { - int pos = ReverseSearchSet("\\/:"); - if ( pos >= 0 ) { - path = GetSubString(0,pos+1); - filename = GetSubString(pos+1,length); - } else { - path.EmptyString(); - filename.Set(*this); - } - } - - //! Parses the string as file name string and returns path, filename and extension. - void DecodeFileName( String &path, String &filename, String &extention ) - { - String fname; - DecodeFileName( path, fname ); - int pos = fname.GetLastPosition( '.' ); - if ( pos > 0 && pos < length - 1 ) { - filename = fname.GetSubString( 0, pos ); - extention = fname.GetSubString( pos+1, fname.length ); - } else { - filename.Set(fname); - extention.EmptyString(); - } - } - - //! Reads 'count' number of characters from the given file stream onto the string. - //! Returns final length of the string. - int LoadFromStream( FILE *stream, unsigned int count ) - { - SetStrLen(count); - if ( count ) { - count = (unsigned int) fread( string, 1, count, stream ); - string[count] = '\0'; - Shrink(); - } - return length; - } - - //! Loads the string from the file. Returns final length of the string. - int LoadFromFile( String const &filename ) - { - FILE *fp = fopen( filename.GetString(), "r" ); - if ( fp != nullptr ) { - int seek = fseek( fp, 0, SEEK_END ); - if ( seek == 0 ) { - int count = ftell(fp); - fseek( fp, 0, SEEK_SET ); - LoadFromStream( fp, count ); - fclose ( fp ); - return length; - } - } - EmptyString(); - return length; - } - - //! Writes string data to the given file stream. Returns the number of bytes written. - int SaveToStream( FILE *stream ) const - { - return (int) fwrite( string, 1, length, stream ); - } - - //! Saves the string to the text file. Returns the number of bytes written. - int SaveToFile( String const &filename ) const - { - FILE *fp = fopen( filename.GetString(), "w" ); - if ( fp != nullptr ) { - int count = SaveToStream( fp ); - fclose ( fp ); - return count; - } - return 0; - } - -private: - - //! \internal - ////////////////////////////////////////////////////////////////////////// - //!@name Internal methods - - char *string; // keeps the string data - int length; // keeps the length of the string (the actual length of the array is length +1) - - // Deletes string and allocates memory for new string with the given length. - // Returns the length of the string. - int SetStrLen( int newLength ) - { - if ( newLength < 0 || newLength == length ) return length; - ReplaceString( NewString(newLength), newLength ); - return length; - } - - // Deletes string data and sets as the given string. - void ReplaceString( char *str ) - { - DeleteString( string ); - string = str; - } - - // Deletes string data and sets as the given string and changes the length. - void ReplaceString( char *str, int len ) - { - DeleteString( string ); - string = str; - length = len; - } - - // Allocates memory for a string of given size and returns the new string. - // Sets the last character at [size] as null. - char* NewString( int size ) - { - char *str = new char[size+1]; - str[size] = '\0'; - return str; - } - - // Deletes allocated memory for a string. - void DeleteString( char *str ) - { - if ( str ) delete [] str; - } - - // Given a predicted size (should be greater than or equal to the final size) - // format and arguments list (args), formats the string. - void FormatString( int size, char const *format, va_list args ) - { - SetStrLen(size); - vsprintf( string, format, args ); - Shrink(); - } - -}; - -//------------------------------------------------------------------------------- -} // namespace cy -//------------------------------------------------------------------------------- - -typedef cy::String cyString; //!< String class for char arrays. - -//------------------------------------------------------------------------------- - -_CY_CRT_SECURE_RESUME_WARNINGS -#endif +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyString.h +//! \author Cem Yuksel +//! +//! \brief String class +//! +//! This file includes a general purpose string class for char arrays. +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_STRING_H_INCLUDED_ +#define _CY_STRING_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "cyCore.h" + +//------------------------------------------------------------------------------- + +_CY_CRT_SECURE_NO_WARNINGS + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +//! A general-purpose string class for char arrays. +//! +//! This is a general purpose string class, which supports many useful string operations. +//! It has methods for numeric conversions, character and string search, +//! formating, editing, and file operations. + +class String +{ + +#ifdef _OSTREAM_ + //! Overloaded stream operator. It only works if you include iostream before this file. + friend std::ostream& operator << ( std::ostream &os, String const &str ) + { + os< 0 ) { + char *str = NewString(newLength); + int l = (length < newLength) ? length : newLength; + strncpy(str,string,l); + memset(str+l,' ',newLength-l); + ReplaceString( str, newLength ); + } else { + EmptyString(); + } + return length; + } + + //! Creates a string of length 'count' with the given character 'chr'. + void SetCharString( char chr, int count ) + { + SetStrLen( count ); + memset( string, chr, length ); + } + + //! Deletes 'count' number of characters from the array, starting from 'start'. + //! If 'count' is too big, deletes till the end of the string. + void Delete( int start, int count ) + { + if ( start > length || count <= 0 ) return; + int end = start + count; + if ( end > length ) { count -= end - length; end = length; } + length -= count; + char *string2 = NewString(length); + strncpy ( string2, string, start ); + strncpy ( string2+start, string+end, length - start ); + ReplaceString( string2 ); + } + + //! Inserts the given string to the given index. + void Insert( String const &str, int index ) + { + int count = length - index; + if ( count < 0 ) { index = length; count = 0; } + length += str.length; + char *string2 = NewString(length); + strncpy( string2, string, index ); + strncpy( string2+index, str.string, str.length ); + strncpy( string2+index+str.length, string+index, count ); + ReplaceString( string2 ); + } + + //! Deletes all carriage return characters. + //! Returns the number of characters deleted. + int DeleteCarriageReturns() { return DeleteChar('\r'); } + + //! Insert a carriage return character after every new line character + //! if it doesn't already exits. Returns the number of carriage return characters inserted. + int InsertCarriageReturns() + { + int nn = CountChar('\n'); + if ( nn == 0 ) return 0; + int nr = CountChar('\r'); + char *string2 = NewString( length + nn - nr ); + int i = length - 1; + int j = length + nn - nr - 1; + while ( j >= 0 ) { + bool needCR = false; + if ( string[i] == '\n' ) needCR = true; + string[j--] = string[i--]; + if ( needCR ) { + if ( i > 0 && string[i] == '\r' ) continue; + string[j--] = '\r'; + } + } + ReplaceString( string2, length + nn - nr ); + Shrink(); + return nn - nr; + + } + + //! Deletes all the characters in the string that are equal to the given character 'c'. + //! Returns the number of characters deleted. + int DeleteChar( char c ) + { + int n = 0; + char *str = strchr( string, c ); + while ( str != nullptr ) { + n++; + int count; + char *str2 = strchr( ++str, c ); + if ( str2 != nullptr ) count = int(str2 - str); + else count = int(string - str) + length + 1; + memmove( str-n, str, count ); + str = str2; + } + Shrink(); + return n; + } + + //! Deletes all the characters in the string that exits in the given set. + //! Returns the number of characters deleted. + int DeleteChars( String const &set ) + { + int n = 0; + char *str = strpbrk( string, set.string ); + while ( str != nullptr ) { + n++; + int count; + char *str2 = strpbrk( ++str, set.string ); + if ( str2 != nullptr ) count = int(str2 - str); + else count = int(string - str) + length + 1; + memmove( str-n, str, count ); + str = str2; + } + Shrink(); + return n; + } + + //! Reverses the string. + void Reverse() + { + for ( int i=0; i= 0; i-- ) { + int pos = set.GetPosition( string[i] ); + if ( pos >= 0 ) return i; + } + return -1; + } + + //! Searches the string starting from the beginning for a character that exists in the given set. + //! Returns the first position of a character from the set. + //! If not found, returns -1. + int SearchNextSet( int start, String const &set ) const + { + if ( start > length ) return -1; + int pos = (int) strcspn( string + start, set.string ); + if ( pos < length ) return pos + start; + else return -1; + } + + //! Returns the first position of the character. + //! If the character is not found, returns -1. + int GetPosition( char c ) const + { + char *cp = strchr( string, c ); + if ( cp != nullptr ) return int(cp - string); + else return -1; + } + + //! Returns the first position of the given string. + //! If the string is not found, returns -1. + int GetPosition( String const &str ) const + { + char *sub = strstr( string, str.GetString() ); + if ( sub != nullptr ) return int(sub - string); + else return -1; + } + + //! Returns the last position of the character. + //! If the character is not found, returns -1. + int GetLastPosition( char c ) const + { + char *cp = strrchr( string, c ); + if ( cp != nullptr ) return int(cp - string); + else return -1; + } + + //! Returns the last position of the given string. + //! If the string is not found, returns -1. + int GetLastPosition( String const &str ) const + { + String s(*this); + String str2(str); + s.Reverse(); + str2.Reverse(); + int pos = s.GetPosition(str2); + if ( pos >= 0 ) return length - pos - str.length; + else return -1; + } + + //! Returns the next position of the character. + //! If the character is not found, returns -1. + int GetNextPosition( int start, char c ) const + { + if ( start > length ) return -1; + char *cp = strchr( string+start, c ); + if ( cp != nullptr ) return int(cp - string); + else return -1; + } + + //! Returns the next position of the given string. + //! If the string is not found, returns -1. + int GetNextPosition( int start, String const &str ) const + { + if ( start > length ) return -1; + char *sub = strstr( string+start, str.GetString() ); + if ( sub != nullptr ) return int(sub - string); + else return -1; + } + + //! Returns the line number of the given position in the string + int GetLineNumber( int pos ) const { return CountChar('\n',0,pos) + 1; } + + //! Returns the number of lines in the string. + int GetNumLines() const { return CountChar('\n') + 1; } + + //! Returns the number of characters in the string that are equal to the given character 'c'. + int CountChar( char c ) const + { + int n = 0; + char *str = strchr( string, c ); + while ( str != nullptr ) { + n++; + str = strchr( str+1, c ); + } + return n; + } + + //! Returns the number of characters in the string that are equal to the given character 'c'.between start and end + int CountChar( char c, int start, int end ) const + { + int n = 0; + + if ( start > length ) return 0; + if ( end > length ) end = length; + if ( end < start ) return 0; + + char *str = string + start; + + str = strchr( str, c ); + while ( str != nullptr && str <= (string + end) ) { + n++; + str = strchr( str+1, c ); + } + return n; + } + + //! Returns the number of characters in the string that exists in the given character set. + int CountChars( String const &set ) const + { + return (int) strspn( string, set.string ); + } + + //! Returns the character of the string at the specified index. + char operator [] ( int index ) const { return string[index]; } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Comparison methods + + //! Checks if this string is the same as 'str'. + int operator == ( String const &str ) const { return ( Compare(str) == 0 ); } + + //! Checks if this string is not the same as 'str'. + int operator != ( String const &str ) const { return ( Compare(str) != 0 ); } + + //! Checks if this string is smaller than 'str'. + int operator < ( String const &str ) const { return ( Compare(str) < 0 ); } + + //! Checks if this string is smaller than or equal to 'str'. + int operator <= ( String const &str ) const { return ( Compare(str) <= 0 ); } + + //! Checks if this string is greater than 'str'. + int operator > ( String const &str ) const { return ( Compare(str) > 0 ); } + + //! Checks if this string is greater than or equal to 'str'. + int operator >= ( String const &str ) const { return ( Compare(str) >= 0 ); } + + //! Compares this string to 'str' (case sensitive). + //! Returns zero if the strings are the same, + //! smaller than zero if this string is smaller than 'str', + //! greater than zero if this string is greater than 'str'. + int Compare( String const &str ) const + { + if ( length == str.length ) { + if ( length > 0 ) return strcmp( string, str.string ); + else if ( str.length == 0 ) return 0; + else return -1; + } else return length - str.length; + } + + //! Compares this string to 'str' (case sensitive) limited to the first 'count' characters. + //! Returns zero if the strings are the same, + //! smaller than zero if this string is smaller than 'str', + //! greater than zero if this string is greater than 'str'. + int Compare( String const &str, int count ) const + { + return strncmp( string, str.string, count ); + } + + //! Compares this string to 'str' (case insensitive). + //! Returns zero if the strings are the same, + //! smaller than zero if this string is smaller than 'str', + //! greater than zero if this string is greater than 'str'. + int CompareIC( String const &str ) const + { + String str1(*this); + String str2(str); + str1.LowerCase(); + str2.LowerCase(); + return str1.Compare( str2 ); + } + + //! Compares this string to 'str' (case insensitive) limited to the first 'count' characters. + //! Returns zero if the strings are the same, + //! smaller than zero if this string is smaller than 'str', + //! greater than zero if this string is greater than 'str'. + int CompareIC( String const &str, int count ) const + { + String str1(*this); + String str2(str); + str1.LowerCase(); + str2.LowerCase(); + return str1.Compare( str2, count ); + } + + //! Returns if the char in the given position is a capital letter + int IsCapitalChar( int pos ) const + { + if ( string[pos] < 65 ) return false; + if ( string[pos] > 90 ) return false; + return true; + } + + //! Returns if the char in the given position is a lower case letter + int IsLowerCaseChar( int pos ) const + { + if ( string[pos] < 97 ) return false; + if ( string[pos] > 122 ) return false; + return true; + } + + //! Returns if the char in the given position is a numeric character + int IsNumericChar( int pos ) const + { + if ( string[pos] < 48 ) return false; + if ( string[pos] > 57 ) return false; + return true; + } + + //! Returns if the char in the given position is a lower case or capital letter + int IsAlphaChar( int pos ) const + { + if ( IsLowerCaseChar(pos) ) return true; + if ( IsCapitalChar(pos) ) return true; + return false; + } + + //! Returns if the char in the given position is a lower case or capital letter or a numeric character + int IsAlphaNumericChar( int pos ) const + { + if ( IsNumericChar(pos) ) return true; + if ( IsAlphaChar(pos) ) return true; + return false; + } + + //! Returns if the char in the given position is a lower case or capital letter, a numeric character or '_' + int IsNameChar( int pos ) const + { + if ( string[pos] == '-') return true; + else return IsAlphaNumericChar( pos ); + } + + //! Returns if the char in the given position is a space character + int IsSpaceChar( int pos ) const + { + switch ( string[pos] ) { + case ' ': + case '\t': + case '\n': + case '\r': + return true; + default: + return false; + } + } + + //! Returns if the char in the given position is a control char (including new line etc.) + int IsControlChar( int pos ) const + { + if ( string[pos] < 32 ) return true; + if ( string[pos] > 126 ) return true; + return false; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Append and substring + + //! Appends to the end of the string. + void Append( String const &str ) + { + int length2 = length + str.length; + char *string2 = NewString(length2); + strncpy(string2,string,length); + strncpy(string2+length,str.string,str.length); + ReplaceString( string2, length2 ); + } + + //! Appends to the end of the string and returns this string. + String& operator += ( String const &str ) { Append(str); return *this; } + + //! Appends two strings and returns the result + String operator + ( String const &right ) { + String r; + r.SetStrLen( length + right.length ); + strncpy( r.string, string, length ); + strncpy( r.string+length, right.string, right.length ); + return r; + } + + //! Converts the string to its sub-string starting from 'start' with length of 'count'. + //! If 'count' is too large, returns the sub-string till the end of the string. + void SubString( int start, int count ) + { + if ( start > length ) start = length; + int end = start + count; + if ( end > length ) { count -= end - length; end = length; } + length = count; + char *string2 = NewString(length); + strncpy( string2, string+start, length ); + ReplaceString( string2 ); + } + + //! Returns the sub-string from 'start' with the length of 'count'. + //! If 'count' is too big, returns the sub-string till the end of the string. + String GetSubString( int start, int count ) const + { + if ( start > length ) start = length; + int end = start + count; + if ( end > length ) { count -= end - length; end = length; } + String str(string+start,count); + return str; + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Conversion to numbers and number arrays + + //! Converts the string to int. + int ToInt() const { return atoi(string); } + + //! Converts the string to long. + long ToLong() const { return atol(string); } + + //! Converts the string to float. + float ToFloat() const { return (float) atof(string); } + + //! Converts the string to double. + double ToDouble() const { return atof(string); } + + //! Converts the string (ex: "23,43,14") to int array. + void ToIntArray(int n, int *v) const + { + int p1 = 0; + for ( int i=0; i 0 ) { + sub = GetSubString(p1,p2-p1); + p1 = p2+1; + } else { + sub = GetSubString(p1,length); + } + v[i] = sub.ToInt(); + } + } + + //! Converts the string to long. + void ToLongArray(int n, long *v) const + { + int p1 = 0; + for ( int i=0; i 0 ) { + sub = GetSubString(p1,p2-p1); + p1 = p2+1; + } else { + sub = GetSubString(p1,length); + } + v[i] = sub.ToLong(); + } + } + + //! Converts the string (ex: "23,43,14") to float array. + void ToFloatArray(int n, float *v) const + { + int p1 = 0; + for ( int i=0; i 0 ) { + sub = GetSubString(p1,p2-p1); + p1 = p2+1; + } else { + sub = GetSubString(p1,length); + } + v[i] = sub.ToFloat(); + } + } + + //! Converts the string (ex: "23,43,14") to double array. + void ToDoubleArray(int n, double *v) const + { + int p1 = 0; + for ( int i=0; i 0 ) { + sub = GetSubString(p1,p2-p1); + p1 = p2+1; + } else { + sub = GetSubString(p1,length); + } + v[i] = sub.ToDouble(); + } + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Trim and shrink + + //! Deletes empty characters from the beginning and end of the string. + void Trim() { TrimRight(); TrimLeft(); } + + //! Deletes empty characters from the beginning of the string. + void TrimLeft() + { + int i; + unsigned char *uchr = (unsigned char *) string; // unsigned to support extended ASCII characters + for ( i=0; i 32 && *uchr != 127 && *uchr != 255 ) break; + uchr++; + } + Delete(0,i); + } + + //! Deletes empty characters from the end of the string. + void TrimRight() + { + unsigned char *uchr = (unsigned char *) LastChar(); // unsigned to support extended ASCII characters + if ( uchr ) { + unsigned char *str = (unsigned char *) string; + for ( ; uchr >= str; uchr--) { + if ( *uchr > 32 && *uchr != 127 && *uchr != 255 ) break; + } + Delete( int(uchr-str)+1, length ); + } + } + + //! Deletes the rest of the string after the first null character. + void Shrink() + { + char *end = strchr(string,'\0'); + if ( end != nullptr ) { + int count = int(end - string); + if ( count < length ) SubString(0,count); + } + } + + ////////////////////////////////////////////////////////////////////////// + //!@name Case change + + //! Coverts the string to lower case. + void LowerCase() + { + for ( int i=0; i= 65 && string[i] <= 90 ) string[i] += 32; + } + + //! Coverts the string to upper case. + void UpperCase() + { + for ( int i=0; i= 97 && string[i] <= 122 ) string[i] -= 32; + } + + //! Coverts the string to swapped case. + void SwapCase() + { + for ( int i=0; i= 65 && string[i] <= 90 ) string[i] += 32; + else if ( string[i] >= 97 && string[i] <= 122 ) string[i] -= 32; + } + } + + //! Coverts the string to title case. + void TitleCase() + { + int wordstart = true; + for ( int i=0; i= 97 && string[i] <= 122 ) { + string[i] -= 32; + wordstart = false; + } + else if( string[i] >= 65 && string[i] <= 90 ) wordstart = false; + } else { + if ( string[i] >= 65 && string[i] <= 90 ) string[i] += 32; + else if( string[i] < 97 || string[i] > 122 ) wordstart = true; + } + } + } + + //! Returns the lower case version of the string. + String GetLowerCase() const { String str(*this); str.LowerCase(); return str; } + + //! Returns the upper case version of the string. + String GetUpperCase() const { String str(*this); str.UpperCase(); return str; } + + //! Returns the swapped case version of the string. + String GetSwapCase() const { String str(*this); str.SwapCase(); return str; } + + //! Returns the title case version of the string. + String GetTitleCase() const { String str(*this); str.TitleCase(); return str; } + + + ////////////////////////////////////////////////////////////////////////// + //!@name Load/save and file name methods + + //! Parses the string as file name string and returns path, filename. + void DecodeFileName( String &path, String &filename ) + { + int pos = ReverseSearchSet("\\/:"); + if ( pos >= 0 ) { + path = GetSubString(0,pos+1); + filename = GetSubString(pos+1,length); + } else { + path.EmptyString(); + filename.Set(*this); + } + } + + //! Parses the string as file name string and returns path, filename and extension. + void DecodeFileName( String &path, String &filename, String &extention ) + { + String fname; + DecodeFileName( path, fname ); + int pos = fname.GetLastPosition( '.' ); + if ( pos > 0 && pos < length - 1 ) { + filename = fname.GetSubString( 0, pos ); + extention = fname.GetSubString( pos+1, fname.length ); + } else { + filename.Set(fname); + extention.EmptyString(); + } + } + + //! Reads 'count' number of characters from the given file stream onto the string. + //! Returns final length of the string. + int LoadFromStream( FILE *stream, unsigned int count ) + { + SetStrLen(count); + if ( count ) { + count = (unsigned int) fread( string, 1, count, stream ); + string[count] = '\0'; + Shrink(); + } + return length; + } + + //! Loads the string from the file. Returns final length of the string. + int LoadFromFile( String const &filename ) + { + FILE *fp = fopen( filename.GetString(), "r" ); + if ( fp != nullptr ) { + int seek = fseek( fp, 0, SEEK_END ); + if ( seek == 0 ) { + int count = ftell(fp); + fseek( fp, 0, SEEK_SET ); + LoadFromStream( fp, count ); + fclose ( fp ); + return length; + } + } + EmptyString(); + return length; + } + + //! Writes string data to the given file stream. Returns the number of bytes written. + int SaveToStream( FILE *stream ) const + { + return (int) fwrite( string, 1, length, stream ); + } + + //! Saves the string to the text file. Returns the number of bytes written. + int SaveToFile( String const &filename ) const + { + FILE *fp = fopen( filename.GetString(), "w" ); + if ( fp != nullptr ) { + int count = SaveToStream( fp ); + fclose ( fp ); + return count; + } + return 0; + } + +private: + + //! \internal + ////////////////////////////////////////////////////////////////////////// + //!@name Internal methods + + char *string; // keeps the string data + int length; // keeps the length of the string (the actual length of the array is length +1) + + // Deletes string and allocates memory for new string with the given length. + // Returns the length of the string. + int SetStrLen( int newLength ) + { + if ( newLength < 0 || newLength == length ) return length; + ReplaceString( NewString(newLength), newLength ); + return length; + } + + // Deletes string data and sets as the given string. + void ReplaceString( char *str ) + { + DeleteString( string ); + string = str; + } + + // Deletes string data and sets as the given string and changes the length. + void ReplaceString( char *str, int len ) + { + DeleteString( string ); + string = str; + length = len; + } + + // Allocates memory for a string of given size and returns the new string. + // Sets the last character at [size] as null. + char* NewString( int size ) + { + char *str = new char[size+1]; + str[size] = '\0'; + return str; + } + + // Deletes allocated memory for a string. + void DeleteString( char *str ) + { + if ( str ) delete [] str; + } + + // Given a predicted size (should be greater than or equal to the final size) + // format and arguments list (args), formats the string. + void FormatString( int size, char const *format, va_list args ) + { + SetStrLen(size); + vsprintf( string, format, args ); + Shrink(); + } + +}; + +//------------------------------------------------------------------------------- +} // namespace cy +//------------------------------------------------------------------------------- + +typedef cy::String cyString; //!< String class for char arrays. + +//------------------------------------------------------------------------------- + +_CY_CRT_SECURE_RESUME_WARNINGS +#endif diff --git a/cyTimer.h b/include/cyTimer.h similarity index 97% rename from cyTimer.h rename to include/cyTimer.h index d429365..0acaf61 100644 --- a/cyTimer.h +++ b/include/cyTimer.h @@ -1,180 +1,180 @@ -// cyCodeBase by Cem Yuksel -// [www.cemyuksel.com] -//------------------------------------------------------------------------------- -//! \file cyTimer.h -//! \author Cem Yuksel -//! -//! \brief Timer classes to measure performance -//! -//! This file includes timer classes to measure performance in windows systems. -//! Timer class uses Windows specific calls to measure the time, -//! therefore this file can only be used in windows platforms. -//! -//------------------------------------------------------------------------------- -// -// Copyright (c) 2016, Cem Yuksel -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_TIMER_H_INCLUDED_ -#define _CY_TIMER_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include -#include - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -//! Simple stopwatch class. -//! -//! Use this class to measure the time between Start and Stop calls. - -class Timer -{ -public: - //! Starts the timer - void Start() { - startTime = clock(); - } - - //! Returns the time passed since Start call in seconds. - //! Note that this method does not actually stop the timer, - //! it only returns the time passed since Start call. - //! Therefore, you can call this method as many times as you like - //! once you call Start method once. - double Stop() const { - clock_t endTime = clock(); - return float(endTime-startTime)/CLOCKS_PER_SEC;; - } - -protected: - clock_t startTime; //!< Keeps the starting time -}; - -//------------------------------------------------------------------------------- - -//! Stopwatch class with statistics. -//! -//! Use this class to measure the time between Start and Stop calls. -//! Unlike Timer class, this class also provides statistical information. - -class TimerStats -{ -public: - TimerStats() { Clear(); } - - //!@name Timer Methods - - //! Starts the timer - void Start() { - timer.Start(); - } - - //! Stops the timer and records the current measurement. - //! Returns the time passed since Start call in seconds. - double Stop() { - double t = timer.Stop(); - unsigned char p = pos & 0x7F; - totalTime += t - times[ p ]; - times[ p ] = t; - if ( minTime > t ) minTime = t; - if ( maxTime < t ) maxTime = t; - // Increment pos such that the first bit shows if times array is full. - p++; - pos = ( p & 0x7F ) + ( ( pos | p ) & 0x80 ); - return t; - } - - - //!@name Statistics Methods - - //! Clears all the time records - void Clear() { - for ( int i=0; i<128; i++ ) times[i] = 0; - minTime = 1.0e30; - maxTime = 0; - totalTime = 0; - pos = 0; - } - - //! Returns the last measured time. - //! If no time is measured before, returns zero. - double GetLastTime() const { return times[ (pos-1) & 0x7F ]; } - - //! Returns the minimum measured time - double GetMin() const { return minTime; } - - //! Returns the maximum measured time - double GetMax() const { return maxTime; } - - //! Returns the average of all recorded times (max previous 128 records) - double GetAverage() const { return totalTime / (double) GetRecordCount(); } - - //! Returns the variance of the time records. - //! Note that this method goes over all time records, - //! so it may take a little time to compute the variance. - double GetVariance() const { - unsigned char count = GetRecordCount(); - double avrg = totalTime / (double) count; - double var = 0; - for ( int i=0; i +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_TIMER_H_INCLUDED_ +#define _CY_TIMER_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include +#include + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +//! Simple stopwatch class. +//! +//! Use this class to measure the time between Start and Stop calls. + +class Timer +{ +public: + //! Starts the timer + void Start() { + startTime = clock(); + } + + //! Returns the time passed since Start call in seconds. + //! Note that this method does not actually stop the timer, + //! it only returns the time passed since Start call. + //! Therefore, you can call this method as many times as you like + //! once you call Start method once. + double Stop() const { + clock_t endTime = clock(); + return float(endTime-startTime)/CLOCKS_PER_SEC;; + } + +protected: + clock_t startTime; //!< Keeps the starting time +}; + +//------------------------------------------------------------------------------- + +//! Stopwatch class with statistics. +//! +//! Use this class to measure the time between Start and Stop calls. +//! Unlike Timer class, this class also provides statistical information. + +class TimerStats +{ +public: + TimerStats() { Clear(); } + + //!@name Timer Methods + + //! Starts the timer + void Start() { + timer.Start(); + } + + //! Stops the timer and records the current measurement. + //! Returns the time passed since Start call in seconds. + double Stop() { + double t = timer.Stop(); + unsigned char p = pos & 0x7F; + totalTime += t - times[ p ]; + times[ p ] = t; + if ( minTime > t ) minTime = t; + if ( maxTime < t ) maxTime = t; + // Increment pos such that the first bit shows if times array is full. + p++; + pos = ( p & 0x7F ) + ( ( pos | p ) & 0x80 ); + return t; + } + + + //!@name Statistics Methods + + //! Clears all the time records + void Clear() { + for ( int i=0; i<128; i++ ) times[i] = 0; + minTime = 1.0e30; + maxTime = 0; + totalTime = 0; + pos = 0; + } + + //! Returns the last measured time. + //! If no time is measured before, returns zero. + double GetLastTime() const { return times[ (pos-1) & 0x7F ]; } + + //! Returns the minimum measured time + double GetMin() const { return minTime; } + + //! Returns the maximum measured time + double GetMax() const { return maxTime; } + + //! Returns the average of all recorded times (max previous 128 records) + double GetAverage() const { return totalTime / (double) GetRecordCount(); } + + //! Returns the variance of the time records. + //! Note that this method goes over all time records, + //! so it may take a little time to compute the variance. + double GetVariance() const { + unsigned char count = GetRecordCount(); + double avrg = totalTime / (double) count; + double var = 0; + for ( int i=0; i -// All rights reserved. -// -// 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. -// -//------------------------------------------------------------------------------- - -#ifndef _CY_TRIMESH_H_INCLUDED_ -#define _CY_TRIMESH_H_INCLUDED_ - -//------------------------------------------------------------------------------- - -#include "cyVector.h" -#include -#include - -//------------------------------------------------------------------------------- - -_CY_CRT_SECURE_NO_WARNINGS - -//------------------------------------------------------------------------------- -namespace cy { -//------------------------------------------------------------------------------- - -//! Triangular Mesh Class - -class TriMesh -{ -public: - //! Triangular Mesh Face - struct TriFace - { - unsigned int v[3]; //!< vertex indices - }; - - //! Simple character string - struct Str - { - char *data; //!< String data - Str() : data(nullptr) {} //!< Constructor - Str( Str const &s ) : data(nullptr) { *this = s; } //!< Copy constructor - ~Str() { if ( data ) delete [] data; } //!< Destructor - operator char const * () { return data; } //!< Implicit conversion to const char - void operator = ( Str const &s ) { *this = s.data; } //!< Assignment operator - void operator = ( char const *s ) { if (s) { size_t n=strlen(s); if (data) delete [] data; data=new char[n+1]; strncpy(data,s,n); data[n]='\0'; } else if (data) { delete [] data; data=nullptr; } } //!< Assignment operator - }; - - //! Material definition - struct Mtl - { - Str name; //!< Material name - float Ka[3]; //!< Ambient color - float Kd[3]; //!< Diffuse color - float Ks[3]; //!< Specular color - float Tf[3]; //!< Transmission color - float Ns; //!< Specular exponent - float Ni; //!< Index of refraction - int illum; //!< Illumination model - Str map_Ka; //!< Ambient color texture map - Str map_Kd; //!< Diffuse color texture map - Str map_Ks; //!< Specular color texture map - Str map_Ns; //!< Specular exponent texture map - Str map_d; //!< Alpha texture map - Str map_bump; //!< Bump texture map - Str map_disp; //!< Displacement texture map - - //! Constructor sets the default material values - Mtl() - { - Ka[0]=Ka[1]=Ka[2]=0; - Kd[0]=Kd[1]=Kd[2]=1; - Ks[0]=Ks[1]=Ks[2]=0; - Tf[0]=Tf[1]=Tf[2]=0; - Ns=0; - Ni=1; - illum=2; - } - }; - -protected: - Vec3f *v; //!< vertices - TriFace *f; //!< faces - Vec3f *vn; //!< vertex normal - TriFace *fn; //!< normal faces - Vec3f *vt; //!< texture vertices - TriFace *ft; //!< texture faces - Mtl *m; //!< materials - int *mcfc; //!< material cumulative face count - - unsigned int nv; //!< number of vertices - unsigned int nf; //!< number of faces - unsigned int nvn; //!< number of vertex normals - unsigned int nvt; //!< number of texture vertices - unsigned int nm; //!< number of materials - - Vec3f boundMin; //!< Bounding box minimum bound - Vec3f boundMax; //!< Bounding box maximum bound - -public: - - //!@name Constructors and Destructor - TriMesh() : v(nullptr), f(nullptr), vn(nullptr), fn(nullptr), vt(nullptr), ft(nullptr), m(nullptr), mcfc(nullptr) - , nv(0), nf(0), nvn(0), nvt(0), nm(0),boundMin(1,1,1), boundMax(0,0,0) {} - TriMesh( TriMesh const &t ) : v(nullptr), f(nullptr), vn(nullptr), fn(nullptr), vt(nullptr), ft(nullptr), m(nullptr), mcfc(nullptr) - , nv(0), nf(0), nvn(0), nvt(0), nm(0),boundMin(1,1,1), boundMax(0,0,0) { *this = t; } - virtual ~TriMesh() { Clear(); } - - //!@name Component Access Methods - Vec3f const & V (int i) const { return v[i]; } //!< returns the i^th vertex - Vec3f& V (int i) { return v[i]; } //!< returns the i^th vertex - TriFace const & F (int i) const { return f[i]; } //!< returns the i^th face - TriFace& F (int i) { return f[i]; } //!< returns the i^th face - Vec3f const & VN(int i) const { return vn[i]; } //!< returns the i^th vertex normal - Vec3f& VN(int i) { return vn[i]; } //!< returns the i^th vertex normal - TriFace const & FN(int i) const { return fn[i]; } //!< returns the i^th normal face - TriFace& FN(int i) { return fn[i]; } //!< returns the i^th normal face - Vec3f const & VT(int i) const { return vt[i]; } //!< returns the i^th vertex texture - Vec3f& VT(int i) { return vt[i]; } //!< returns the i^th vertex texture - TriFace const & FT(int i) const { return ft[i]; } //!< returns the i^th texture face - TriFace& FT(int i) { return ft[i]; } //!< returns the i^th texture face - Mtl const & M (int i) const { return m[i]; } //!< returns the i^th material - Mtl& M (int i) { return m[i]; } //!< returns the i^th material - - unsigned int NV () const { return nv; } //!< returns the number of vertices - unsigned int NF () const { return nf; } //!< returns the number of faces - unsigned int NVN() const { return nvn; } //!< returns the number of vertex normals - unsigned int NVT() const { return nvt; } //!< returns the number of texture vertices - unsigned int NM () const { return nm; } //!< returns the number of materials - - bool HasNormals() const { return NVN() > 0; } //!< returns true if the mesh has vertex normals - bool HasTextureVertices() const { return NVT() > 0; } //!< returns true if the mesh has texture vertices - - //!@name Set Component Count - void Clear() { SetNumVertex(0); SetNumFaces(0); SetNumNormals(0); SetNumTexVerts(0); SetNumMtls(0); boundMin.Set(1,1,1); boundMax.Zero(); } //!< Deletes all components of the mesh - void SetNumVertex ( unsigned int n ) { Allocate(n,v,nv); } //!< Sets the number of vertices and allocates memory for vertex positions - void SetNumFaces ( unsigned int n ) { Allocate(n,f,nf); if (fn||vn) Allocate(n,fn); if (ft||vt) Allocate(n,ft); } //!< Sets the number of faces and allocates memory for face data. Normal faces and texture faces are also allocated, if they are used. - void SetNumNormals ( unsigned int n ) { Allocate(n,vn,nvn); Allocate(n==0?0:nf,fn); } //!< Sets the number of normals and allocates memory for normals and normal faces. - void SetNumTexVerts( unsigned int n ) { Allocate(n,vt,nvt); Allocate(n==0?0:nf,ft); } //!< Sets the number of texture coordinates and allocates memory for texture coordinates and texture faces. - void SetNumMtls ( unsigned int n ) { Allocate(n,m,nm); Allocate(n,mcfc); } //!< Sets the number of materials and allocates memory for material data. - void operator = ( TriMesh const &t ); //!< Copies mesh data from the given mesh. - - //!@name Get Property Methods - bool IsBoundBoxReady() const { return boundMin.x<=boundMax.x && boundMin.y<=boundMax.y && boundMin.z<=boundMax.z; } //!< Returns true if the bounding box has been computed. - Vec3f GetBoundMin() const { return boundMin; } //!< Returns the minimum values of the bounding box - Vec3f GetBoundMax() const { return boundMax; } //!< Returns the maximum values of the bounding box - Vec3f GetVec (int faceID, Vec3f const &bc) const { return Interpolate(faceID,v,f,bc); } //!< Returns the point on the given face with the given barycentric coordinates (bc). - Vec3f GetNormal (int faceID, Vec3f const &bc) const { return Interpolate(faceID,vn,fn,bc); } //!< Returns the the surface normal on the given face at the given barycentric coordinates (bc). The returned vector is not normalized. - Vec3f GetTexCoord(int faceID, Vec3f const &bc) const { return Interpolate(faceID,vt,ft,bc); } //!< Returns the texture coordinate on the given face at the given barycentric coordinates (bc). - int GetMaterialIndex(int faceID) const; //!< Returns the material index of the face. This method goes through material counts of all materials to find the material index of the face. Returns a negative number if the face as no material - int GetMaterialFaceCount(int mtlID) const { return mtlID>0 ? mcfc[mtlID]-mcfc[mtlID-1] : mcfc[0]; } //!< Returns the number of faces associated with the given material ID. - int GetMaterialFirstFace(int mtlID) const { return mtlID>0 ? mcfc[mtlID-1] : 0; } //!< Returns the first face index associated with the given material ID. Other faces associated with the same material are placed are placed consecutively. - - //!@name Compute Methods - void ComputeBoundingBox(); //!< Computes the bounding box - void ComputeNormals(bool clockwise=false); //!< Computes and stores vertex normals - - //!@name Load and Save methods - bool LoadFromFileObj( char const *filename, bool loadMtl=true, std::ostream *outStream=&std::cout ); //!< Loads the mesh from an OBJ file. Automatically converts all faces to triangles. - bool SaveToFileObj( char const *filename, std::ostream *outStream ); //!< Saves the mesh to an OBJ file with the given name. - -private: - template void Allocate( unsigned int n, T* &t ) { if (t) delete [] t; if (n>0) t = new T[n]; else t=nullptr; } - template bool Allocate( unsigned int n, T* &t, unsigned int &nt ) { if (n==nt) return false; nt=n; Allocate(n,t); return true; } - template void Copy( T const *from, unsigned int n, T* &t, unsigned int &nt) { if (!from) n=0; Allocate(n,t,nt); if (t) memcpy(t,from,sizeof(T)*n); } - template void Copy( T const *from, unsigned int n, T* &t) { if (!from) n=0; Allocate(n,t); if (t) memcpy(t,from,sizeof(T)*n); } - static Vec3f Interpolate( int i, Vec3f const *v, TriFace const *f, Vec3f const &bc ) { return v[f[i].v[0]]*bc.x + v[f[i].v[1]]*bc.y + v[f[i].v[2]]*bc.z; } - - // Temporary structures +// cyCodeBase by Cem Yuksel +// [www.cemyuksel.com] +//------------------------------------------------------------------------------- +//! \file cyTriMesh.h +//! \author Cem Yuksel +//! +//! \brief Triangular Mesh class. +//! +//------------------------------------------------------------------------------- +// +// Copyright (c) 2016, Cem Yuksel +// All rights reserved. +// +// 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. +// +//------------------------------------------------------------------------------- + +#ifndef _CY_TRIMESH_H_INCLUDED_ +#define _CY_TRIMESH_H_INCLUDED_ + +//------------------------------------------------------------------------------- + +#include "cyVector.h" +#include +#include + +//------------------------------------------------------------------------------- + +_CY_CRT_SECURE_NO_WARNINGS + +//------------------------------------------------------------------------------- +namespace cy { +//------------------------------------------------------------------------------- + +//! Triangular Mesh Class + +class TriMesh +{ +public: + //! Triangular Mesh Face + struct TriFace + { + unsigned int v[3]; //!< vertex indices + }; + + //! Simple character string + struct Str + { + char *data; //!< String data + Str() : data(nullptr) {} //!< Constructor + Str( Str const &s ) : data(nullptr) { *this = s; } //!< Copy constructor + ~Str() { if ( data ) delete [] data; } //!< Destructor + operator char const * () { return data; } //!< Implicit conversion to const char + void operator = ( Str const &s ) { *this = s.data; } //!< Assignment operator + void operator = ( char const *s ) { if (s) { size_t n=strlen(s); if (data) delete [] data; data=new char[n+1]; strncpy(data,s,n); data[n]='\0'; } else if (data) { delete [] data; data=nullptr; } } //!< Assignment operator + }; + + //! Material definition + struct Mtl + { + Str name; //!< Material name + float Ka[3]; //!< Ambient color + float Kd[3]; //!< Diffuse color + float Ks[3]; //!< Specular color + float Tf[3]; //!< Transmission color + float Ns; //!< Specular exponent + float Ni; //!< Index of refraction + int illum; //!< Illumination model + Str map_Ka; //!< Ambient color texture map + Str map_Kd; //!< Diffuse color texture map + Str map_Ks; //!< Specular color texture map + Str map_Ns; //!< Specular exponent texture map + Str map_d; //!< Alpha texture map + Str map_bump; //!< Bump texture map + Str map_disp; //!< Displacement texture map + + //! Constructor sets the default material values + Mtl() + { + Ka[0]=Ka[1]=Ka[2]=0; + Kd[0]=Kd[1]=Kd[2]=1; + Ks[0]=Ks[1]=Ks[2]=0; + Tf[0]=Tf[1]=Tf[2]=0; + Ns=0; + Ni=1; + illum=2; + } + }; + +protected: + Vec3f *v; //!< vertices + TriFace *f; //!< faces + Vec3f *vn; //!< vertex normal + TriFace *fn; //!< normal faces + Vec3f *vt; //!< texture vertices + TriFace *ft; //!< texture faces + Mtl *m; //!< materials + int *mcfc; //!< material cumulative face count + + unsigned int nv; //!< number of vertices + unsigned int nf; //!< number of faces + unsigned int nvn; //!< number of vertex normals + unsigned int nvt; //!< number of texture vertices + unsigned int nm; //!< number of materials + + Vec3f boundMin; //!< Bounding box minimum bound + Vec3f boundMax; //!< Bounding box maximum bound + +public: + + //!@name Constructors and Destructor + TriMesh() : v(nullptr), f(nullptr), vn(nullptr), fn(nullptr), vt(nullptr), ft(nullptr), m(nullptr), mcfc(nullptr) + , nv(0), nf(0), nvn(0), nvt(0), nm(0),boundMin(1,1,1), boundMax(0,0,0) {} + TriMesh( TriMesh const &t ) : v(nullptr), f(nullptr), vn(nullptr), fn(nullptr), vt(nullptr), ft(nullptr), m(nullptr), mcfc(nullptr) + , nv(0), nf(0), nvn(0), nvt(0), nm(0),boundMin(1,1,1), boundMax(0,0,0) { *this = t; } + virtual ~TriMesh() { Clear(); } + + //!@name Component Access Methods + Vec3f const & V (int i) const { return v[i]; } //!< returns the i^th vertex + Vec3f& V (int i) { return v[i]; } //!< returns the i^th vertex + TriFace const & F (int i) const { return f[i]; } //!< returns the i^th face + TriFace& F (int i) { return f[i]; } //!< returns the i^th face + Vec3f const & VN(int i) const { return vn[i]; } //!< returns the i^th vertex normal + Vec3f& VN(int i) { return vn[i]; } //!< returns the i^th vertex normal + TriFace const & FN(int i) const { return fn[i]; } //!< returns the i^th normal face + TriFace& FN(int i) { return fn[i]; } //!< returns the i^th normal face + Vec3f const & VT(int i) const { return vt[i]; } //!< returns the i^th vertex texture + Vec3f& VT(int i) { return vt[i]; } //!< returns the i^th vertex texture + TriFace const & FT(int i) const { return ft[i]; } //!< returns the i^th texture face + TriFace& FT(int i) { return ft[i]; } //!< returns the i^th texture face + Mtl const & M (int i) const { return m[i]; } //!< returns the i^th material + Mtl& M (int i) { return m[i]; } //!< returns the i^th material + + unsigned int NV () const { return nv; } //!< returns the number of vertices + unsigned int NF () const { return nf; } //!< returns the number of faces + unsigned int NVN() const { return nvn; } //!< returns the number of vertex normals + unsigned int NVT() const { return nvt; } //!< returns the number of texture vertices + unsigned int NM () const { return nm; } //!< returns the number of materials + + bool HasNormals() const { return NVN() > 0; } //!< returns true if the mesh has vertex normals + bool HasTextureVertices() const { return NVT() > 0; } //!< returns true if the mesh has texture vertices + + //!@name Set Component Count + void Clear() { SetNumVertex(0); SetNumFaces(0); SetNumNormals(0); SetNumTexVerts(0); SetNumMtls(0); boundMin.Set(1,1,1); boundMax.Zero(); } //!< Deletes all components of the mesh + void SetNumVertex ( unsigned int n ) { Allocate(n,v,nv); } //!< Sets the number of vertices and allocates memory for vertex positions + void SetNumFaces ( unsigned int n ) { Allocate(n,f,nf); if (fn||vn) Allocate(n,fn); if (ft||vt) Allocate(n,ft); } //!< Sets the number of faces and allocates memory for face data. Normal faces and texture faces are also allocated, if they are used. + void SetNumNormals ( unsigned int n ) { Allocate(n,vn,nvn); Allocate(n==0?0:nf,fn); } //!< Sets the number of normals and allocates memory for normals and normal faces. + void SetNumTexVerts( unsigned int n ) { Allocate(n,vt,nvt); Allocate(n==0?0:nf,ft); } //!< Sets the number of texture coordinates and allocates memory for texture coordinates and texture faces. + void SetNumMtls ( unsigned int n ) { Allocate(n,m,nm); Allocate(n,mcfc); } //!< Sets the number of materials and allocates memory for material data. + void operator = ( TriMesh const &t ); //!< Copies mesh data from the given mesh. + + //!@name Get Property Methods + bool IsBoundBoxReady() const { return boundMin.x<=boundMax.x && boundMin.y<=boundMax.y && boundMin.z<=boundMax.z; } //!< Returns true if the bounding box has been computed. + Vec3f GetBoundMin() const { return boundMin; } //!< Returns the minimum values of the bounding box + Vec3f GetBoundMax() const { return boundMax; } //!< Returns the maximum values of the bounding box + Vec3f GetVec (int faceID, Vec3f const &bc) const { return Interpolate(faceID,v,f,bc); } //!< Returns the point on the given face with the given barycentric coordinates (bc). + Vec3f GetNormal (int faceID, Vec3f const &bc) const { return Interpolate(faceID,vn,fn,bc); } //!< Returns the the surface normal on the given face at the given barycentric coordinates (bc). The returned vector is not normalized. + Vec3f GetTexCoord(int faceID, Vec3f const &bc) const { return Interpolate(faceID,vt,ft,bc); } //!< Returns the texture coordinate on the given face at the given barycentric coordinates (bc). + int GetMaterialIndex(int faceID) const; //!< Returns the material index of the face. This method goes through material counts of all materials to find the material index of the face. Returns a negative number if the face as no material + int GetMaterialFaceCount(int mtlID) const { return mtlID>0 ? mcfc[mtlID]-mcfc[mtlID-1] : mcfc[0]; } //!< Returns the number of faces associated with the given material ID. + int GetMaterialFirstFace(int mtlID) const { return mtlID>0 ? mcfc[mtlID-1] : 0; } //!< Returns the first face index associated with the given material ID. Other faces associated with the same material are placed are placed consecutively. + + //!@name Compute Methods + void ComputeBoundingBox(); //!< Computes the bounding box + void ComputeNormals(bool clockwise=false); //!< Computes and stores vertex normals + + //!@name Load and Save methods + bool LoadFromFileObj( char const *filename, bool loadMtl=true, std::ostream *outStream=&std::cout ); //!< Loads the mesh from an OBJ file. Automatically converts all faces to triangles. + bool SaveToFileObj( char const *filename, std::ostream *outStream ); //!< Saves the mesh to an OBJ file with the given name. + +private: + template void Allocate( unsigned int n, T* &t ) { if (t) delete [] t; if (n>0) t = new T[n]; else t=nullptr; } + template bool Allocate( unsigned int n, T* &t, unsigned int &nt ) { if (n==nt) return false; nt=n; Allocate(n,t); return true; } + template void Copy( T const *from, unsigned int n, T* &t, unsigned int &nt) { if (!from) n=0; Allocate(n,t,nt); if (t) memcpy(t,from,sizeof(T)*n); } + template void Copy( T const *from, unsigned int n, T* &t) { if (!from) n=0; Allocate(n,t); if (t) memcpy(t,from,sizeof(T)*n); } + static Vec3f Interpolate( int i, Vec3f const *v, TriFace const *f, Vec3f const &bc ) { return v[f[i].v[0]]*bc.x + v[f[i].v[1]]*bc.y + v[f[i].v[2]]*bc.z; } + + // Temporary structures struct MtlData { std::string mtlName; @@ -200,75 +200,75 @@ class TriMesh MtlData() { faceCount=0; firstFace=0; } }; struct MtlLibName { std::string filename; }; -}; - -//------------------------------------------------------------------------------- - -inline void TriMesh::operator = ( TriMesh const &t ) -{ - Copy( t.v, t.nv, v, nv ); - Copy( t.f, t.nf, f, nf ); - Copy( t.vn, t.nvn, vn, nvn ); - Copy( t.fn, t.nf, fn ); - Copy( t.vt, t.nvt, vt, nvt ); - Copy( t.ft, t.nf, ft ); - Allocate(t.nm, m, nm); - for ( unsigned int i=0; i 0 ) { - boundMin=v[0]; - boundMax=v[0]; - for ( unsigned int i=1; i v[i].x ) boundMin.x = v[i].x; - if ( boundMin.y > v[i].y ) boundMin.y = v[i].y; - if ( boundMin.z > v[i].z ) boundMin.z = v[i].z; - if ( boundMax.x < v[i].x ) boundMax.x = v[i].x; - if ( boundMax.y < v[i].y ) boundMax.y = v[i].y; - if ( boundMax.z < v[i].z ) boundMax.z = v[i].z; - } - } else { - boundMin.Set(1,1,1); - boundMax.Set(0,0,0); - } -} - -inline void TriMesh::ComputeNormals(bool clockwise) -{ - SetNumNormals(nv); - for ( unsigned int i=0; i 0 ) { + boundMin=v[0]; + boundMax=v[0]; + for ( unsigned int i=1; i v[i].x ) boundMin.x = v[i].x; + if ( boundMin.y > v[i].y ) boundMin.y = v[i].y; + if ( boundMin.z > v[i].z ) boundMin.z = v[i].z; + if ( boundMax.x < v[i].x ) boundMax.x = v[i].x; + if ( boundMax.y < v[i].y ) boundMax.y = v[i].y; + if ( boundMax.z < v[i].z ) boundMax.z = v[i].z; + } + } else { + boundMin.Set(1,1,1); + boundMax.Set(0,0,0); + } +} + +inline void TriMesh::ComputeNormals(bool clockwise) +{ + SetNumNormals(nv); + for ( unsigned int i=0; i _v; // vertices - std::vector _f; // faces - std::vector _vn; // vertex normal - std::vector _fn; // normal faces - std::vector _vt; // texture vertices - std::vector _ft; // texture faces + + std::vector _v; // vertices + std::vector _f; // faces + std::vector _vn; // vertex normal + std::vector _fn; // normal faces + std::vector _vt; // texture vertices + std::vector _ft; // texture faces std::vector mtlFiles; std::vector faceMtlIndex; int currentMtlIndex = -1; bool hasTextures=false, hasNormals=false; - while ( int rb = buffer.ReadLine(fp) ) { - if ( buffer.IsCommand("v") ) { - Vec3f vertex; - buffer.ReadVertex(vertex); - _v.push_back(vertex); - } - else if ( buffer.IsCommand("vt") ) { - Vec3f texVert; - buffer.ReadVertex(texVert); - _vt.push_back(texVert); - hasTextures = true; - } - else if ( buffer.IsCommand("vn") ) { - Vec3f normal; - buffer.ReadVertex(normal); - _vn.push_back(normal); - hasNormals = true; - } - else if ( buffer.IsCommand("f") ) { + while ( int rb = buffer.ReadLine(fp) ) { + if ( buffer.IsCommand("v") ) { + Vec3f vertex; + buffer.ReadVertex(vertex); + _v.push_back(vertex); + } + else if ( buffer.IsCommand("vt") ) { + Vec3f texVert; + buffer.ReadVertex(texVert); + _vt.push_back(texVert); + hasTextures = true; + } + else if ( buffer.IsCommand("vn") ) { + Vec3f normal; + buffer.ReadVertex(normal); + _vn.push_back(normal); + hasNormals = true; + } + else if ( buffer.IsCommand("f") ) { int facevert = -1; bool inspace = true; bool negative = false; @@ -437,20 +437,20 @@ inline bool TriMesh::LoadFromFileObj( char const *filename, bool loadMtl, std::o faceMtlIndex.push_back(currentMtlIndex); if ( currentMtlIndex>=0 ) mtlList.mtlData[currentMtlIndex].faceCount += (unsigned int)_f.size() - nFacesBefore; } - else if ( loadMtl ) { - if ( buffer.IsCommand("usemtl") ) { - currentMtlIndex = mtlList.CreateMtl(buffer.Data(7), (unsigned int)_f.size()); - } - if ( buffer.IsCommand("mtllib") ) { - MtlLibName libName; - libName.filename = buffer.Data(7); - mtlFiles.push_back(libName); - } - } + else if ( loadMtl ) { + if ( buffer.IsCommand("usemtl") ) { + currentMtlIndex = mtlList.CreateMtl(buffer.Data(7), (unsigned int)_f.size()); + } + if ( buffer.IsCommand("mtllib") ) { + MtlLibName libName; + libName.filename = buffer.Data(7); + mtlFiles.push_back(libName); + } + } if ( feof(fp) ) break; } - fclose(fp); + fclose(fp); if ( _f.size() == 0 ) return true; // No faces found @@ -496,113 +496,113 @@ inline bool TriMesh::LoadFromFileObj( char const *filename, bool loadMtl, std::o } - // Load the .mtl files - if ( loadMtl ) { - // get the path from filename - char *mtlPathName = nullptr; - char const *pathEnd = strrchr(filename,'\\'); - if ( !pathEnd ) pathEnd = strrchr(filename,'/'); - if ( pathEnd ) { - int n = int(pathEnd-filename) + 1; - mtlPathName = new char[n+1]; - strncpy(mtlPathName,filename,n); - mtlPathName[n] = '\0'; - } - for ( unsigned int mi=0; mi= 0 ) buffer.Copy( m[mtlID].name, 7 ); - } else if ( mtlID >= 0 ) { - if ( buffer.IsCommand("Ka") ) buffer.ReadFloat3( m[mtlID].Ka ); - else if ( buffer.IsCommand("Kd") ) buffer.ReadFloat3( m[mtlID].Kd ); - else if ( buffer.IsCommand("Ks") ) buffer.ReadFloat3( m[mtlID].Ks ); - else if ( buffer.IsCommand("Tf") ) buffer.ReadFloat3( m[mtlID].Tf ); - else if ( buffer.IsCommand("Ns") ) buffer.ReadFloat( &m[mtlID].Ns ); - else if ( buffer.IsCommand("Ni") ) buffer.ReadFloat( &m[mtlID].Ni ); - else if ( buffer.IsCommand("illum") ) buffer.ReadInt( &m[mtlID].illum, 5 ); - else if ( buffer.IsCommand("map_Ka" ) ) buffer.Copy( m[mtlID].map_Ka, 7 ); - else if ( buffer.IsCommand("map_Kd" ) ) buffer.Copy( m[mtlID].map_Kd, 7 ); - else if ( buffer.IsCommand("map_Ks" ) ) buffer.Copy( m[mtlID].map_Ks, 7 ); - else if ( buffer.IsCommand("map_Ns" ) ) buffer.Copy( m[mtlID].map_Ns, 7 ); - else if ( buffer.IsCommand("map_d" ) ) buffer.Copy( m[mtlID].map_d, 6 ); - else if ( buffer.IsCommand("map_bump") ) buffer.Copy( m[mtlID].map_bump, 9 ); - else if ( buffer.IsCommand("bump" ) ) buffer.Copy( m[mtlID].map_bump, 5 ); - else if ( buffer.IsCommand("map_disp") ) buffer.Copy( m[mtlID].map_disp, 9 ); - else if ( buffer.IsCommand("disp" ) ) buffer.Copy( m[mtlID].map_disp, 5 ); - } - } - fclose(fp); - } - if ( mtlPathName ) delete [] mtlPathName; - } - - return true; -} - -//------------------------------------------------------------------------------- - -inline bool TriMesh::SaveToFileObj( char const *filename, std::ostream *outStream ) -{ - FILE *fp = fopen(filename,"w"); - if ( !fp ) { - if ( outStream ) *outStream << "ERROR: Cannot create file " << filename << std::endl; - return false; - } - - for ( unsigned int i=0; i0)<<1) | (nvt>0); - switch ( faceFormat ) { - case 0: - for ( unsigned int i=0; i= 0 ) buffer.Copy( m[mtlID].name, 7 ); + } else if ( mtlID >= 0 ) { + if ( buffer.IsCommand("Ka") ) buffer.ReadFloat3( m[mtlID].Ka ); + else if ( buffer.IsCommand("Kd") ) buffer.ReadFloat3( m[mtlID].Kd ); + else if ( buffer.IsCommand("Ks") ) buffer.ReadFloat3( m[mtlID].Ks ); + else if ( buffer.IsCommand("Tf") ) buffer.ReadFloat3( m[mtlID].Tf ); + else if ( buffer.IsCommand("Ns") ) buffer.ReadFloat( &m[mtlID].Ns ); + else if ( buffer.IsCommand("Ni") ) buffer.ReadFloat( &m[mtlID].Ni ); + else if ( buffer.IsCommand("illum") ) buffer.ReadInt( &m[mtlID].illum, 5 ); + else if ( buffer.IsCommand("map_Ka" ) ) buffer.Copy( m[mtlID].map_Ka, 7 ); + else if ( buffer.IsCommand("map_Kd" ) ) buffer.Copy( m[mtlID].map_Kd, 7 ); + else if ( buffer.IsCommand("map_Ks" ) ) buffer.Copy( m[mtlID].map_Ks, 7 ); + else if ( buffer.IsCommand("map_Ns" ) ) buffer.Copy( m[mtlID].map_Ns, 7 ); + else if ( buffer.IsCommand("map_d" ) ) buffer.Copy( m[mtlID].map_d, 6 ); + else if ( buffer.IsCommand("map_bump") ) buffer.Copy( m[mtlID].map_bump, 9 ); + else if ( buffer.IsCommand("bump" ) ) buffer.Copy( m[mtlID].map_bump, 5 ); + else if ( buffer.IsCommand("map_disp") ) buffer.Copy( m[mtlID].map_disp, 9 ); + else if ( buffer.IsCommand("disp" ) ) buffer.Copy( m[mtlID].map_disp, 5 ); + } + } + fclose(fp); + } + if ( mtlPathName ) delete [] mtlPathName; + } + + return true; +} + +//------------------------------------------------------------------------------- + +inline bool TriMesh::SaveToFileObj( char const *filename, std::ostream *outStream ) +{ + FILE *fp = fopen(filename,"w"); + if ( !fp ) { + if ( outStream ) *outStream << "ERROR: Cannot create file " << filename << std::endl; + return false; + } + + for ( unsigned int i=0; i0)<<1) | (nvt>0); + switch ( faceFormat ) { + case 0: + for ( unsigned int i=0; i