/*========================================================================= Program: Visualization Toolkit Module: vtkMathPrivate.hxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkMathPrivate * @brief Internal toolkit used in some vtkMath methods. * * vtkMatrixUtilities provides matrix indexing / wrapping tools. One can use * this utility to wrap a 1D array into a matrix shape, index it at compile * time. * @sa * vtkMath * vtkMathPrivate */ #ifndef vtkMatrixUtilities_h #define vtkMatrixUtilities_h #include // for type traits namespace vtkMatrixUtilities { //============================================================================= /** * This struct determines a prior transform to input matrices, changing the * way they are indexed */ struct Layout { /** * Input matrix is unchanged, i.e. sorted row-wise ordered */ struct Identity; /* * Input matrix is transposed, i.e. sorted in column-wise ordered. */ struct Transpose; /** * Input matrix is considered diagonal, and value at index idx points * to component of coordinates (idx, idx) in the diagonal matrix. */ struct Diag; }; namespace detail { // Extracting for STL-like containers template struct ScalarTypeExtractor { typedef typename ContainerT::value_type value_type; static_assert(std::is_integral::value || std::is_floating_point::value, "value_type is not a numeric type"); }; // Extracting for C++ arrays template struct ScalarTypeExtractor<1, ContainerT> { typedef typename std::remove_pointer< typename std::remove_all_extents::type>::type>::type value_type; static_assert(std::is_integral::value || std::is_floating_point::value, "value_type is not a numeric type"); }; } // namespace detail //============================================================================= /** * This class extract the underlying value type of containers. It works on * multi-dimensional C++ arrays as well as with STL container like that * have a value_type typedef. * * One can access the value type by fetching * ScalarTypeExtractor::value_type. */ template struct ScalarTypeExtractor { private: typedef typename std::remove_reference::type DerefContainer; public: typedef typename detail::ScalarTypeExtractor< // This parameter equals 0 or 1 std::is_array::value || std::is_pointer::value, ContainerT>::value_type value_type; static_assert(std::is_integral::value || std::is_floating_point::value, "value_type is not a numeric type"); }; //----------------------------------------------------------------------------- /** * At compile time, returns `true` if the templated parameter is a 2D array * (`double[3][3]` for instance), false otherwise. */ template static constexpr bool MatrixIs2DArray() { typedef typename std::remove_extent::type Row; typedef typename std::remove_extent::type Value; return std::is_array::value && std::is_array::value && !std::is_array::value; } //----------------------------------------------------------------------------- /** * At compile time, returns `true` if the templated parameter is a pointer to * pointer (`double**` for instance), false otherwise. */ template static constexpr bool MatrixIsPointerToPointer() { typedef typename std::remove_pointer::type Row; typedef typename std::remove_pointer::type Value; return std::is_pointer::value && std::is_pointer::value && !std::is_pointer::value; } //----------------------------------------------------------------------------- /** * At compile time, returns `true` if the templated parameter layout is 2D, * i.e. elements can be accessed using the operator `[][]`. It returns false otherwise. */ template static constexpr bool MatrixLayoutIs2D() { typedef typename std::remove_pointer::type RowPointer; typedef typename std::remove_extent::type RowArray; typedef typename std::remove_pointer::type ValuePointerPointer; typedef typename std::remove_extent::type ValuePointerArray; typedef typename std::remove_pointer::type ValueArrayPointer; typedef typename std::remove_extent::type ValueArrayArray; return ((std::is_array::value && !std::is_same::value) || std::is_pointer::value || std::is_array::value || (std::is_pointer::value && !std::is_same::value)) && (!std::is_array::value || !std::is_pointer::value) && (!std::is_array::value || !std::is_pointer::value) && (!std::is_array::value || !std::is_pointer::value) && (!std::is_array::value || !std::is_pointer::value); } namespace detail { // Class actually implementing matrix mapping. template struct Mapper; // Specialization of the matrix mapper for when the layout is the identity template struct Mapper { template static constexpr int GetIndex() { static_assert(RowT >= 0 && RowT < RowsT, "RowT out of bounds"); static_assert(ColT >= 0 && ColT < ColsT, "ColT out of bounds"); return ColsT * RowT + ColT; } }; template struct Mapper { template static constexpr int GetIndex() { static_assert(RowT >= 0 && RowT < RowsT, "RowT out of bounds"); static_assert(ColT >= 0 && ColT < ColsT, "ColT out of bounds"); return RowsT * ColT + RowT; } }; } // namespace detail //============================================================================= /** * This class is a helper class to compute at compile time the index of a matrix * stored as a 1D array from its 2D coordinates. This class maps matrices of * dimension RowsT x ColsT. The LayoutT template parameter permits to switch to * the indexing of the transpose of the matrix. LayoutT can be set to * Layout::Identity for a row-wise ordering, or to Layout::Transpose for a * column-wise ordering * * @warning This mapper does not work with matrices stored as 2D arrays, or with * diagonal matrices. */ template struct Mapper { template static constexpr int GetIndex() { return detail::Mapper::template GetIndex(); } }; namespace detail { // Class implementing matrix wrapping. template class Wrapper; // Specializaion of matrix wrapping for matrices stored as 1D arrays // in row-wise order template class Wrapper { private: using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; public: template static const Scalar& Get(const MatrixT& M) { return M[Mapper::template GetIndex()]; } template static Scalar& Get(MatrixT& M) { return M[Mapper::template GetIndex()]; } }; // Specialization for matrices stored as 2D arrays with an unchanged layout template class Wrapper { private: using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; public: template static const Scalar& Get(const MatrixT& M) { return M[RowT][ColT]; } template static Scalar& Get(MatrixT& M) { return M[RowT][ColT]; } }; // Specialization for matrices stored as 2D arrays read as its transposed self. template class Wrapper { private: using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; public: template static const Scalar& Get(const MatrixT& M) { return M[ColT][RowT]; } template static Scalar& Get(MatrixT& M) { return M[ColT][RowT]; } }; // Specialization for diagonal matrices. // Note: a diagonal matrix has to be stored in a 1D array. template class Wrapper { private: using Scalar = typename vtkMatrixUtilities::ScalarTypeExtractor::value_type; template struct Helper { static constexpr Scalar ZERO = Scalar(0); static Scalar& Get(const MatrixT&) { return ZERO; } }; template struct Helper { static Scalar& Get(MatrixT& M) { return M[RowT]; } static const Scalar& Get(const MatrixT& M) { return M[RowT]; } }; public: template const Scalar& Get(const MatrixT& M) { return Helper::Get(M); } template Scalar& Get(MatrixT& M) { return Helper::Get(M); } }; } // namespace detail //============================================================================= /** * Matrix wrapping class. This class implements a getter templated on the * coordinates of the wanted element. A matrix can be a 2D C++ array, a 1D C++ * array row-wise ordered, or any STL-like container implementing operator[] and * having a value_type typedef. * * This class wraps a RowsT x ColsT matrix stored in the container MatrixT. The * LayoutT template parameter permits to reindex at compile-time the matrix. If * it is set to Layout::Identity, the matrix is assumed to be row-wised ordered. * If it is set to Layout::Transpose, the matrix is assumed to be column-wise ordered. * One can also convert a 1D input array into a diagonal matrix by setting * LayoutT to Layout::Diag. In ths particular case, method Get will return a * read-only zero on elements outside of the diagonal. */ template class Wrapper { private: using Scalar = typename ScalarTypeExtractor::value_type; static_assert(!MatrixLayoutIs2D() || !std::is_same::value, "A diagonal matrix cannot be a 2D array"); public: template static const Scalar& Get(const MatrixT& M) { return detail::Wrapper()>::template Get(M); } template static Scalar& Get(MatrixT& M) { return detail::Wrapper()>::template Get(M); } }; } // namespace vtkMatrixUtilities #endif // VTK-HeaderTest-Exclude: vtkMatrixUtilities.h