PlainMatrix.h 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2024 Alec Jacobson <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #ifndef IGL_PLAINMATRIX_H
  9. #define IGL_PLAINMATRIX_H
  10. #include <Eigen/Core>
  11. #include <type_traits>
  12. #include <Eigen/Dense>
  13. // Define void_t for compatibility if it's not in the standard library (C++11 and later)
  14. #if __cplusplus < 201703L
  15. namespace std {
  16. template <typename... Ts>
  17. using void_t = void;
  18. }
  19. #endif
  20. #ifndef IGL_DEFAULT_MAJORING
  21. #define IGL_DEFAULT_MAJORING Eigen::ColMajor
  22. #endif
  23. namespace igl
  24. {
  25. template <typename Derived, int Rows, int Cols, int Options>
  26. struct PlainMatrixHelper {
  27. using Type = Eigen::Matrix<typename Derived::Scalar,Rows,Cols,((Rows == 1 && Cols != 1) ? Eigen::RowMajor : ((Cols == 1 && Rows != 1) ? Eigen::ColMajor : Options))>;
  28. };
  29. template <typename Derived, typename = void>
  30. struct get_options {
  31. static constexpr int value = IGL_DEFAULT_MAJORING;
  32. };
  33. template <typename Derived>
  34. struct get_options<Derived, std::void_t<decltype(Derived::Options)>> {
  35. static constexpr int value = Derived::Options;
  36. };
  37. /// Some libigl implementations would (still do?) use a pattern like:
  38. ///
  39. /// template <typename DerivedA>
  40. /// void foo(const Eigen::MatrixBase<DerivedA>& A)
  41. /// {
  42. /// DerivedA B;
  43. /// igl::unique_rows(A,true,B);
  44. /// }
  45. ///
  46. /// If `DerivedA` is `Eigen::Matrix`, then this may compile, but `DerivedA` might be
  47. /// from a Eigen::Map or Eigen::Ref and fail to compile due to missing
  48. /// construtor.
  49. ///
  50. /// Even worse, the code above will work if `DerivedA` has dynamic rows, but will
  51. /// throw a runtime error if `DerivedA` has fixed number of rows.
  52. ///
  53. /// Instead it's better to declare `B` as a `Eigen::Matrix`
  54. ///
  55. /// Eigen::Matrix<typename DerivedA::Scalar,Eigen::Dynamic,DerivedA::ColsAtCompileTime,DerivedA::Options> B;
  56. ///
  57. /// Using `Eigen::Dynamic` for dimensions that may not be known at compile
  58. /// time (or may be different from A).
  59. ///
  60. /// `igl::PlainMatrix` is just a helper to make this easier. So in this case
  61. /// we could write:
  62. ///
  63. /// igl::PlainMatrix<DerivedA,Eigen::Dynamic> B;
  64. ///
  65. /// IIUC, if the code in question looks like:
  66. ///
  67. /// template <typename DerivedC>
  68. /// void foo(Eigen::PlainObjectBase<DerivedC>& C)
  69. /// {
  70. /// DerivedC B;
  71. /// …
  72. /// C.resize(not_known_at_compile_time,also_not_known_at_compile_time);
  73. /// }
  74. ///
  75. /// Then it's probably fine. If C can be resized to different sizes, then
  76. /// `DerivedC` should be `Eigen::Matrix`-like .
  77. // Helper to check if `Options` exists in Derived
  78. // Modify PlainMatrix to use get_options
  79. template <typename Derived,
  80. int Rows = Derived::RowsAtCompileTime,
  81. int Cols = Derived::ColsAtCompileTime,
  82. int Options = get_options<Derived>::value>
  83. using PlainMatrix = typename PlainMatrixHelper<Derived, Rows, Cols, Options>::Type;
  84. }
  85. #endif