VTK  9.3.0
vtkMatrixUtilities.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
15#ifndef vtkMatrixUtilities_h
16#define vtkMatrixUtilities_h
17
18#include "vtkABINamespace.h"
19
20#include <type_traits> // for type traits
21
23{
24VTK_ABI_NAMESPACE_BEGIN
25//=============================================================================
30struct Layout
31{
35 struct Identity;
36 /*
37 * Input matrix is transposed, i.e. sorted in column-wise ordered.
38 */
39 struct Transpose;
40
45 struct Diag;
46};
47
48namespace detail
49{
50// Extracting for STL-like containers
51template <int ContainerTypeT, class ContainerT>
53{
54 typedef typename ContainerT::value_type value_type;
55 static_assert(std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
56 "value_type is not a numeric type");
57};
58
59// Extracting for C++ arrays
60template <class ContainerT>
61struct ScalarTypeExtractor<1, ContainerT>
62{
63 typedef typename std::remove_pointer<
64 typename std::remove_all_extents<typename std::remove_pointer<ContainerT>::type>::type>::type
66 static_assert(std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
67 "value_type is not a numeric type");
68};
69} // namespace detail
70
71//=============================================================================
80template <class ContainerT>
82{
83private:
84 typedef typename std::remove_reference<ContainerT>::type DerefContainer;
85
86public:
87 typedef typename detail::ScalarTypeExtractor<
88 // This parameter equals 0 or 1
89 std::is_array<DerefContainer>::value || std::is_pointer<DerefContainer>::value,
91 static_assert(std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
92 "value_type is not a numeric type");
93};
94
95//-----------------------------------------------------------------------------
100template <class MatrixT>
101static constexpr bool MatrixIs2DArray()
102{
103 typedef typename std::remove_extent<MatrixT>::type Row;
104 typedef typename std::remove_extent<Row>::type Value;
105 return std::is_array<MatrixT>::value && std::is_array<Row>::value && !std::is_array<Value>::value;
106}
107
108//-----------------------------------------------------------------------------
113template <class MatrixT>
114static constexpr bool MatrixIsPointerToPointer()
115{
116 typedef typename std::remove_pointer<MatrixT>::type Row;
117 typedef typename std::remove_pointer<Row>::type Value;
118 return std::is_pointer<MatrixT>::value && std::is_pointer<Row>::value &&
119 !std::is_pointer<Value>::value;
120}
121
122//-----------------------------------------------------------------------------
127template <class MatrixT>
128static constexpr bool MatrixLayoutIs2D()
129{
130 typedef typename std::remove_pointer<MatrixT>::type RowPointer;
131 typedef typename std::remove_extent<MatrixT>::type RowArray;
132 typedef typename std::remove_pointer<MatrixT>::type ValuePointerPointer;
133 typedef typename std::remove_extent<MatrixT>::type ValuePointerArray;
134 typedef typename std::remove_pointer<MatrixT>::type ValueArrayPointer;
135 typedef typename std::remove_extent<MatrixT>::type ValueArrayArray;
136 return ((std::is_array<RowPointer>::value && !std::is_same<RowPointer, MatrixT>::value) ||
137 std::is_pointer<RowPointer>::value || std::is_array<RowArray>::value ||
138 (std::is_pointer<RowArray>::value && !std::is_same<RowArray, MatrixT>::value)) &&
139 (!std::is_array<ValuePointerPointer>::value || !std::is_pointer<ValuePointerPointer>::value) &&
140 (!std::is_array<ValueArrayPointer>::value || !std::is_pointer<ValueArrayPointer>::value) &&
141 (!std::is_array<ValuePointerArray>::value || !std::is_pointer<ValuePointerArray>::value) &&
142 (!std::is_array<ValueArrayArray>::value || !std::is_pointer<ValueArrayArray>::value);
143}
144
145namespace detail
146{
147// Class actually implementing matrix mapping.
148template <int RowsT, int ColsT, class LayoutT>
149struct Mapper;
150
151// Specialization of the matrix mapper for when the layout is the identity
152template <int RowsT, int ColsT>
153struct Mapper<RowsT, ColsT, Layout::Identity>
154{
155 template <int RowT, int ColT>
156 static constexpr int GetIndex()
157 {
158 static_assert(RowT >= 0 && RowT < RowsT, "RowT out of bounds");
159 static_assert(ColT >= 0 && ColT < ColsT, "ColT out of bounds");
160 return ColsT * RowT + ColT;
161 }
162};
163
164template <int RowsT, int ColsT>
165struct Mapper<RowsT, ColsT, Layout::Transpose>
166{
167 template <int RowT, int ColT>
168 static constexpr int GetIndex()
169 {
170 static_assert(RowT >= 0 && RowT < RowsT, "RowT out of bounds");
171 static_assert(ColT >= 0 && ColT < ColsT, "ColT out of bounds");
172 return RowsT * ColT + RowT;
173 }
174};
175} // namespace detail
176
177//=============================================================================
189template <int RowsT, int ColsT, class LayoutT = Layout::Identity>
190struct Mapper
191{
192 template <int RowT, int ColT>
193 static constexpr int GetIndex()
194 {
195 return detail::Mapper<RowsT, ColsT, LayoutT>::template GetIndex<RowT, ColT>();
196 }
197};
198
199namespace detail
200{
201// Class implementing matrix wrapping.
202template <int RowsT, int ColsT, class MatrixT, class LayoutT, bool MatrixLayoutIs2DT>
204
205// Specializaion of matrix wrapping for matrices stored as 1D arrays
206// in row-wise order
207template <int RowsT, int ColsT, class MatrixT, class LayoutT>
208class Wrapper<RowsT, ColsT, MatrixT, LayoutT, false>
209{
210private:
212
213public:
214 template <int RowT, int ColT>
215 static const Scalar& Get(const MatrixT& M)
216 {
217 return M[Mapper<RowsT, ColsT, LayoutT>::template GetIndex<RowT, ColT>()];
218 }
219
220 template <int RowT, int ColT>
221 static Scalar& Get(MatrixT& M)
222 {
223 return M[Mapper<RowsT, ColsT, LayoutT>::template GetIndex<RowT, ColT>()];
224 }
225};
226
227// Specialization for matrices stored as 2D arrays with an unchanged layout
228template <int RowsT, int ColsT, class MatrixT>
229class Wrapper<RowsT, ColsT, MatrixT, Layout::Identity, true>
230{
231private:
233
234public:
235 template <int RowT, int ColT>
236 static const Scalar& Get(const MatrixT& M)
237 {
238 return M[RowT][ColT];
239 }
240
241 template <int RowT, int ColT>
242 static Scalar& Get(MatrixT& M)
243 {
244 return M[RowT][ColT];
245 }
246};
247
248// Specialization for matrices stored as 2D arrays read as its transposed self.
249template <int RowsT, int ColsT, class MatrixT>
250class Wrapper<RowsT, ColsT, MatrixT, Layout::Transpose, true>
251{
252private:
254
255public:
256 template <int RowT, int ColT>
257 static const Scalar& Get(const MatrixT& M)
258 {
259 return M[ColT][RowT];
260 }
261
262 template <int RowT, int ColT>
263 static Scalar& Get(MatrixT& M)
264 {
265 return M[ColT][RowT];
266 }
267};
268
269// Specialization for diagonal matrices.
270// Note: a diagonal matrix has to be stored in a 1D array.
271template <int RowsT, int ColsT, class MatrixT>
272class Wrapper<RowsT, ColsT, MatrixT, Layout::Diag, false>
273{
274private:
276
277 template <int RowT, int ColT>
278 struct Helper
279 {
280 static constexpr Scalar ZERO = Scalar(0);
281
282 static Scalar& Get(const MatrixT&) { return ZERO; }
283 };
284
285 template <int RowT>
286 struct Helper<RowT, RowT>
287 {
288 static Scalar& Get(MatrixT& M) { return M[RowT]; }
289
290 static const Scalar& Get(const MatrixT& M) { return M[RowT]; }
291 };
292
293public:
294 template <int RowT, int ColT>
295 const Scalar& Get(const MatrixT& M)
296 {
297 return Helper<RowT, ColT>::Get(M);
298 }
299
300 template <int RowT, int ColT>
301 Scalar& Get(MatrixT& M)
302 {
303 return Helper<RowT, ColT>::Get(M);
304 }
305};
306} // namespace detail
307
308//=============================================================================
323template <int RowsT, int ColsT, class MatrixT, class LayoutT = Layout::Identity>
325{
326private:
327 using Scalar = typename ScalarTypeExtractor<MatrixT>::value_type;
328
329 static_assert(!MatrixLayoutIs2D<MatrixT>() || !std::is_same<LayoutT, Layout::Diag>::value,
330 "A diagonal matrix cannot be a 2D array");
331
332public:
333 template <int RowT, int ColT>
334 static const Scalar& Get(const MatrixT& M)
335 {
336 return detail::Wrapper<RowsT, ColsT, MatrixT, LayoutT,
337 MatrixLayoutIs2D<MatrixT>()>::template Get<RowT, ColT>(M);
338 }
339
340 template <int RowT, int ColT>
341 static Scalar& Get(MatrixT& M)
342 {
343 return detail::Wrapper<RowsT, ColsT, MatrixT, LayoutT,
344 MatrixLayoutIs2D<MatrixT>()>::template Get<RowT, ColT>(M);
345 }
346};
347VTK_ABI_NAMESPACE_END
348} // namespace vtkMatrixUtilities
349#endif
350
351// VTK-HeaderTest-Exclude: vtkMatrixUtilities.h
static const Scalar & Get(const MatrixT &M)
static Scalar & Get(MatrixT &M)
static constexpr bool MatrixIsPointerToPointer()
At compile time, returns true if the templated parameter is a pointer to pointer (double** for instan...
static constexpr bool MatrixIs2DArray()
At compile time, returns true if the templated parameter is a 2D array (double[3][3] for instance),...
static constexpr bool MatrixLayoutIs2D()
At compile time, returns true if the templated parameter layout is 2D, i.e.
This struct determines a prior transform to input matrices, changing the way they are indexed.
This class is a helper class to compute at compile time the index of a matrix stored as a 1D array fr...
static constexpr int GetIndex()
This class extract the underlying value type of containers.
detail::ScalarTypeExtractor< std::is_array< DerefContainer >::value||std::is_pointer< DerefContainer >::value, ContainerT >::value_type value_type
std::remove_pointer< typenamestd::remove_all_extents< typenamestd::remove_pointer< ContainerT >::type >::type >::type value_type