NDEVR
API Documentation
MatrixFunctions.h
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: MatrixFunctions
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include "DLLInfo.h"
34#include "Matrix.hpp"
35#include <NDEVR/Vertex.h>
36#include <NDEVR/LineSegment.h>
37#include <NDEVR/Bounds.h>
38#include <NDEVR/Triangle.h>
39#include <NDEVR/Polyline.h>
40namespace NDEVR
41{
48 template<class t_type, class t_vector, uint01 t_dims, uint01 t_row_dims, uint01 t_col_dims>
50 {
51 return matrix * vertex;
52 }
53
60 template<class t_type, class t_vector, uint01 t_row_dims, uint01 t_col_dims>
62 {
64 trans = matrix * trans;
65 return Vertex<1, t_type, t_vector>(trans.template as<1, t_type>() / trans[1]);
66 }
67
74 template<class t_type, class t_vector, uint01 t_row_dims, uint01 t_col_dims>
76 {
77 t_type bottom = right[0] * matrix[0][3] + right[1] * matrix[1][3] + matrix[2][3] + matrix[3][3];
79 (right[0] * matrix[0][0] + right[1] * matrix[1][0] + matrix[2][0] + matrix[3][0]) / bottom
80 , (right[0] * matrix[0][1] + right[1] * matrix[1][1] + matrix[2][1] + matrix[3][1]) / bottom);
81 }
82
89 template<class t_type, class t_vector>
91 {
92 const t_type x = v[0], y = v[1], z = v[2];
93
94 const t_type bottom =
95 x * m.inlineGet(3) +
96 y * m.inlineGet(7) +
97 z * m.inlineGet(11) +
98 m.inlineGet(15);
99
100 const t_type inv_bottom = t_type(1) / bottom;
101
103 (x * m.inlineGet(0) + y * m.inlineGet(4) + z * m.inlineGet(8) + m.inlineGet(12)) * inv_bottom,
104 (x * m.inlineGet(1) + y * m.inlineGet(5) + z * m.inlineGet(9) + m.inlineGet(13)) * inv_bottom,
105 (x * m.inlineGet(2) + y * m.inlineGet(6) + z * m.inlineGet(10) + m.inlineGet(14)) * inv_bottom
106 );
107 }
108
115 template<class t_type, class t_vector>
117 {
119 (right[0] * matrix[0][0] + right[1] * matrix[1][0] + right[2] * matrix[2][0])
120 , (right[0] * matrix[0][1] + right[1] * matrix[1][1] + right[2] * matrix[2][1])
121 , (right[0] * matrix[0][2] + right[1] * matrix[1][2] + right[2] * matrix[2][2]));
122 }
123
130 template<class t_type, class t_vector>
132 {
133 const t_type x = v[0], y = v[1], z = v[2], w = v[3];
135 x * m.inlineGet(0) + y * m.inlineGet(4) + z * m.inlineGet(8) + w * m.inlineGet(12),
136 x * m.inlineGet(1) + y * m.inlineGet(5) + z * m.inlineGet(9) + w * m.inlineGet(13),
137 x * m.inlineGet(2) + y * m.inlineGet(6) + z * m.inlineGet(10) + w * m.inlineGet(14),
138 x * m.inlineGet(3) + y * m.inlineGet(7) + z * m.inlineGet(11) + w * m.inlineGet(15)
139 );
140 }
141
148 template<class t_type, class t_vector, uint01 t_dims, uint01 t_row_dims, uint01 t_col_dims>
149 inline Ray<t_dims, t_type> operator*(const Vertex<t_dims, t_type, t_vector>& vertex, const Matrix<t_type, t_row_dims, t_col_dims>& matrix)
150 {
151 return matrix * vertex;
152 }
153
160 template<class t_type, class t_vector, uint01 t_row_dims, uint01 t_col_dims>
161 inline Ray<1, t_type, t_vector> operator*(const Matrix<t_type, t_row_dims, t_col_dims>& matrix, const Ray<1, t_type, t_vector>& right)
162 {
163 return Ray<1, t_type, t_vector>(right[0] * matrix[0][0]);
164 }
165
172 template<class t_type, class t_vector, uint01 t_row_dims, uint01 t_col_dims>
173 inline Ray<2, t_type, t_vector> operator*(const Matrix<t_type, t_row_dims, t_col_dims>& matrix, const Ray<2, t_type, t_vector>& right)
174 {
175 return Ray<2, t_type, t_vector>(
176 (right[0] * matrix[0][0] + right[1] * matrix[1][0] + matrix[2][0])
177 , (right[0] * matrix[0][1] + right[1] * matrix[1][1] + matrix[2][1]));
178 }
179
186 template<class t_type, class t_vector>
187 inline Ray<3, t_type> operator*(const Matrix<t_type, 4, 4>& matrix, const Ray<3, t_type, t_vector>& right)
188 {
189 return Ray<3, t_type, t_vector>(
190 (right[0] * matrix[0][0] + right[1] * matrix[1][0] + right[2] * matrix[2][0])
191 , (right[0] * matrix[0][1] + right[1] * matrix[1][1] + right[2] * matrix[2][1])
192 , (right[0] * matrix[0][2] + right[1] * matrix[1][2] + right[2] * matrix[2][2]));
193 }
194
201 template<class t_type, class t_vector>
202 inline Ray<3, t_type> operator*(const Matrix<t_type, 3, 3>& matrix, const Ray<3, t_type, t_vector>& right)
203 {
204 return Ray<3, t_type, t_vector>(
205 (right[0] * matrix[0][0] + right[1] * matrix[1][0] + right[2] * matrix[2][0])
206 , (right[0] * matrix[0][1] + right[1] * matrix[1][1] + right[2] * matrix[2][1])
207 , (right[0] * matrix[0][2] + right[1] * matrix[1][2] + right[2] * matrix[2][2]));
208 }
209
216 template<class t_type, class t_vector>
217 inline Ray<4, t_type> operator*(const Matrix<t_type, 4, 4>& matrix, const Ray<4, t_type, t_vector>& right)
218 {
219 return Ray<4, t_type, t_vector>(
220 right[0] * matrix[0][0] + right[1] * matrix[1][0] + right[2] * matrix[2][0] + right[3] * matrix[3][0]
221 , right[0] * matrix[0][1] + right[1] * matrix[1][1] + right[2] * matrix[2][1] + right[3] * matrix[3][1]
222 , right[0] * matrix[0][2] + right[1] * matrix[1][2] + right[2] * matrix[2][2] + right[3] * matrix[3][2]
223 , right[0] * matrix[0][3] + right[1] * matrix[1][3] + right[2] * matrix[2][3] + right[3] * matrix[3][3]);
224 }
225
232 template<class t_type, uint01 t_dims, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
234 {
235 return LineSegment<t_dims, t_type>(matrix * line.vertex(A), matrix * line.vertex(B));
236 }
237
244 template<class t_type, uint01 t_dims, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
246 {
247 return Triangle<t_dims, t_type, t_vertex>(matrix * tri.vertex(A), matrix * tri.vertex(B), matrix * tri.vertex(C));
248 }
249
256 template<class t_type, class t_vertex, uint01 t_dims, uint01 t_row_dims, uint01 t_col_dims>
258 {
260 for (uint04 i = 0; i < poly.vertexCount(); i++)
261 {
262 polyline.add(matrix * poly.vertex(i));
263 }
264 return polyline;
265 }
266
273 template<class t_type, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
275 {
277 t_vertex upper_1;
278 for (uint01 max_min = 0; max_min < 2; max_min++)
279 {
280 for (uint01 n = 0; n < 3; n++)
281 upper_1[n] = matrix[0][n] * bounds[max_min][X] + matrix[3][n];
282 t_type lower_1 = matrix[0][3] * bounds[max_min][X] + matrix[3][3];
283 bounds_2.addToBounds(upper_1 / lower_1);
284 }
285 return bounds_2;
286 }
287
294 template<class t_type, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
296 {
298 t_vertex upper_1;
299 for (uint01 i = MIN; i <= MAX; i++)
300 {
301 for (uint01 n = 0; n < 3; n++)
302 upper_1[n] = matrix[0][n] * bounds[i][X] + matrix[3][n];
303 t_type lower_1 = matrix[0][3] * bounds[i][X] + matrix[3][3];
304 t_vertex upper_2;
305 for (uint01 j = MIN; j <= MAX; j++)
306 {
307 for (uint01 n = 0; n < 3; n++)
308 upper_2[n] = upper_1[n] + matrix[1][n] * bounds[j][Y];
309 t_type lower_2 = lower_1 + matrix[1][3] * bounds[j][Y];
310 trans_bounds.addToBounds(upper_2 / lower_2);
311 }
312 }
313 return trans_bounds;
314 }
315
322 template<class t_type, class t_vertex, uint01 t_row_dims, uint01 t_col_dims>
324 {
325 if (IsInvalid(bounds))
326 return bounds;
327 else if (bounds == Constant<Bounds<3, t_type, t_vertex>>::Max)
328 return bounds;
329 else if (bounds == Constant<Bounds<3, t_type, t_vertex>>::Min)
330 return bounds;
332 t_vertex upper_1;
333 for (uint01 max_min = MIN; max_min <= MAX; max_min++)
334 {
335 for (uint01 n = 0; n < 3; n++)
336 upper_1[n] = matrix[0][n] * bounds[max_min][X] + matrix[3][n];
337 t_type lower_1 = matrix[0][3] * bounds[max_min][X] + matrix[3][3];
338 t_vertex upper_2;
339 for (uint01 max_min_2 = MIN; max_min_2 <= MAX; max_min_2++)
340 {
341 for (uint01 n = 0; n < 3; n++)
342 upper_2[n] = upper_1[n] + matrix[1][n] * bounds[max_min_2][Y];
343 t_type lower_2 = lower_1 + matrix[1][3] * bounds[max_min_2][Y];
344 t_vertex upper_3;
345 for (uint01 max_min_3 = MIN; max_min_3 <= MAX; max_min_3++)
346 {
347 for (uint01 n = 0; n < 3; n++)
348 upper_3[n] = upper_2[n] + matrix[2][n] * bounds[max_min_3][Z];
349 t_type lower_3 = lower_2 + matrix[2][3] * bounds[max_min_3][Z];
350 trans_bounds.addToBounds(upper_3 / lower_3);
351 }
352 }
353 }
354 /*Bounds<3, t_type, t_vertex> trans_bounds(Constant<Bounds<3, t_type, t_vertex>>::Min);
355 trans_bounds.addToBounds(matrix * t_vertex(bounds[MIN][X], bounds[MIN][Y], bounds[MIN][Z]));
356 trans_bounds.addToBounds(matrix * t_vertex(bounds[MIN][X], bounds[MIN][Y], bounds[MAX][Z]));
357 trans_bounds.addToBounds(matrix * t_vertex(bounds[MIN][X], bounds[MAX][Y], bounds[MIN][Z]));
358 trans_bounds.addToBounds(matrix * t_vertex(bounds[MIN][X], bounds[MAX][Y], bounds[MAX][Z]));
359 trans_bounds.addToBounds(matrix * t_vertex(bounds[MAX][X], bounds[MIN][Y], bounds[MIN][Z]));
360 trans_bounds.addToBounds(matrix * t_vertex(bounds[MAX][X], bounds[MIN][Y], bounds[MAX][Z]));
361 trans_bounds.addToBounds(matrix * t_vertex(bounds[MAX][X], bounds[MAX][Y], bounds[MIN][Z]));
362 trans_bounds.addToBounds(matrix * t_vertex(bounds[MAX][X], bounds[MAX][Y], bounds[MAX][Z]));*/
363 return trans_bounds;
364 }
365
375 template<class t_type, class t_vertex>
377 {
379 const t_type x[2] = { bounds[MIN][X], bounds[MAX][X] };
380 const t_type y[2] = { bounds[MIN][Y], bounds[MAX][Y] };
381 const t_type z[2] = { bounds[MIN][Z], bounds[MAX][Z] };
382
383 const auto& m = matrix;
384 const t_type m00 = m[0][0], m01 = m[0][1], m02 = m[0][2], m03 = m[0][3];
385 const t_type m10 = m[1][0], m11 = m[1][1], m12 = m[1][2], m13 = m[1][3];
386 const t_type m20 = m[2][0], m21 = m[2][1], m22 = m[2][2], m23 = m[2][3];
387 const t_type m30 = m[3][0], m31 = m[3][1], m32 = m[3][2], m33 = m[3][3];
388
389 for (uint08 i = 0; i < 8; ++i)
390 {
391 t_type xi = x[(i >> 0) & 1];
392 t_type yi = y[(i >> 1) & 1];
393 t_type zi = z[(i >> 2) & 1];
394 t_type w = xi * m03 + yi * m13 + zi * m23 + m33;
395 t_type rx = (xi * m00 + yi * m10 + zi * m20 + m30) / w;
396 t_type ry = (xi * m01 + yi * m11 + zi * m21 + m31) / w;
397 t_type rz = (xi * m02 + yi * m12 + zi * m22 + m32) / w;
398 trans_bounds.addToBounds(t_vertex(rx, ry, rz));
399 }
400 return trans_bounds;
401 }
402
413 template<class t_type, class t_vertex>
415 {
416 const Vertex<3, t_type> box_corners[8] = {
417 { bounds[MIN][X], bounds[MIN][Y], bounds[MIN][Z] },
418 { bounds[MIN][X], bounds[MIN][Y], bounds[MAX][Z] },
419 { bounds[MIN][X], bounds[MAX][Y], bounds[MIN][Z] },
420 { bounds[MIN][X], bounds[MAX][Y], bounds[MAX][Z] },
421 { bounds[MAX][X], bounds[MIN][Y], bounds[MIN][Z] },
422 { bounds[MAX][X], bounds[MIN][Y], bounds[MAX][Z] },
423 { bounds[MAX][X], bounds[MAX][Y], bounds[MIN][Z] },
424 { bounds[MAX][X], bounds[MAX][Y], bounds[MAX][Z] }
425 };
426 // Precompute all transformed corners
427 Vertex<4, t_type> transformed[8];
428 for (uint08 i = 0; i < 8; ++i)
429 transformed[i] = m * Vertex<4, t_type>(box_corners[i], t_type(1));
430 // 12 edges (precomputed corner indices)
431 const uint01 edge_pairs[12][2] = {
432 {0, 1}, {0, 2}, {0, 4},
433 {1, 3}, {1, 5},
434 {2, 3}, {2, 6},
435 {3, 7},
436 {4, 5}, {4, 6},
437 {5, 7},
438 {6, 7}
439 };
440
442 bool added[8] = {false, false, false, false, false, false, false, false};
443
444 for (uint08 e = 0; e < 12; ++e)
445 {
446 const uint01 i0 = edge_pairs[e][0];
447 const uint01 i1 = edge_pairs[e][1];
448 const Vertex<4, t_type>& a = transformed[i0];
449 const Vertex<4, t_type>& b = transformed[i1];
450 const t_type wa = a[W], wb = b[W];
451
452 const bool a_in = wa > t_type(0);
453 const bool b_in = wb > t_type(0);
454
455 if (a_in && b_in)
456 {
457 if (!added[i0]) {
458 result.addToBounds(a.template as<3, t_type>() / wa);
459 added[i0] = true;
460 }
461 if (!added[i1]) {
462 result.addToBounds(b.template as<3, t_type>() / wb);
463 added[i1] = true;
464 }
465 }
466 else if (a_in || b_in)
467 {
468 const t_type t = (t_type(1e-5) - wa) / (wb - wa);
469 const Vertex<4, t_type> clip = a + t * (b - a);
470 const Vertex<3, t_type> clipped = clip.template as<3, t_type>() / clip[W];
471 if (a_in && !added[i0]) {
472 result.addToBounds(a.template as<3, t_type>() / wa);
473 added[i0] = true;
474 }
475 else if (b_in && !added[i1]) {
476 result.addToBounds(b.template as<3, t_type>() / wb);
477 added[i1] = true;
478 }
479 result.addToBounds(clipped);
480 }
481 }
482 return result;
483 }
484
492 template<class t_type, uint01 t_row_dims, uint01 t_col_dims>
494 {
495 for (uint01 i = 0; i < t_row_dims; i++)
496 if (!equals(a[i], b[i], epsilon))
497 return false;
498 return true;
499 }
500
507 template<class t_type, uint01 t_row_dims, uint01 t_col_dims>
509 {
511 for (uint01 i = 0; i < t_row_dims; i++)
512 multiplied_matrix[i] = mult * matrix[i];
513 return multiplied_matrix;
514 }
515
519 class NDEVR_BASE_API MatrixFunctions
520 {
521 public:
526 {
529 bool solve_offset_xy = true;;
530 bool solve_offset_z = true;
531 bool solve_heading = true;
532 bool solve_rotation = false;
533 bool solve_scale = false;
534 };
535
542
550
558 };
559
560}
561
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:54
constexpr void addToBounds(const t_vertex &vector)
Definition Bounds.hpp:415
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
Class: LineSegment.
Definition Line.hpp:52
constexpr const t_vertex & vertex(uint01 index) const
Definition Line.hpp:155
Provides static utility functions for solving best-fit and affine matrix transformations.
static Matrix< fltp08 > SolveBestFitTransform(const TransformSolveOptions &options)
Computes the best-fit rigid or similarity transform between two point sets.
static Matrix< fltp08 > SolveLeastSquaredAffine(const Buffer< Vertex< 3, fltp08 > > &a, const Buffer< Vertex< 3, fltp08 > > &b)
Solves for the least-squared affine transformation between two 3D point sets.
static Matrix< fltp08 > Solve2DAffine(const Buffer< Vertex< 2, fltp08 > > &a, const Buffer< Vertex< 2, fltp08 > > &b)
Solves for a 2D affine transformation between two sets of 2D points.
Templated logic for doing matrix multiplication.
Definition Matrix.hpp:182
A sequence of connected line segments defined by ordered vertices along a path.
Definition PolyLine.hpp:55
uint04 vertexCount() const
Definition PolyLine.hpp:194
const t_vertex & vertex(uint04 index) const
Definition PolyLine.hpp:146
void add(const t_vertex &vertex)
Definition PolyLine.hpp:244
A three-vertex polygon representing a triangle in N-dimensional space.
Definition Triangle.hpp:142
constexpr t_vertex & vertex(TriangleLocation triangle_node)
Vertices the given triangle node.
Definition Triangle.hpp:172
A point in N-dimensional space, used primarily for spatial location information.
Definition Vertex.hpp:44
The primary namespace for the NDEVR SDK.
Bounds< 3, t_type > TransformBoundsAndClipNearPlane(const Bounds< 3, t_type, t_vertex > &bounds, const Matrix< t_type, 4, 4 > &m)
Transforms 3D bounds by a 4x4 matrix and clips edges against the near plane (w=0).
uint64_t uint08
-Defines an alias representing an 8 byte, unsigned integer
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
static constexpr Angle< t_type > operator*(const Angle< t_type > &angle_a, const Angle< t_type > &angle_b)
Multiplication operator.
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
Definition Angle.h:388
constexpr bool equals(const LineSegment< t_dims, t_type, t_vertex > &left, const LineSegment< t_dims, t_type, t_vertex > &right, const t_type &epsilon=cast< t_type >(0))
Tests if objects are considered equal.
Definition Line.hpp:791
constexpr t_type clip(const t_type &value, const t_type &lower_bound, const t_type &upper_bound)
Clips the value given so that that the returned value falls between upper and lower bound.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...
Options controlling which degrees of freedom are solved when computing a best-fit transform.
Buffer< Vertex< 3, fltp08 > > a
Source point set for the transformation solve.
bool solve_heading
Whether to solve for heading (yaw) rotation.
Buffer< Vertex< 3, fltp08 > > b
Target point set for the transformation solve.
bool solve_offset_z
Whether to solve for XY translation offset.
bool solve_rotation
Whether to solve for full 3D rotation.
bool solve_scale
Whether to solve for uniform scale.