test-pose.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2020 Intel Corporation. All Rights Reserved.
3 
4 #include <easylogging++.h>
5 #ifdef BUILD_SHARED_LIBS
6 // With static linkage, ELPP is initialized by librealsense, so doing it here will
7 // create errors. When we're using the shared .so/.dll, the two are separate and we have
8 // to initialize ours if we want to use the APIs!
10 #endif
11 
12 // Let Catch define its own main() function
13 #define CATCH_CONFIG_MAIN
14 #include "../catch.h"
15 
16 #include "../approx.h"
17 
18 //#cmake:add-file ../../src/types.h
19 #include <types.h>
20 
21 using namespace librealsense;
22 
23 #include "rot.h"
24 
25 
26 TEST_CASE( "pose vs extrinsics", "[types]" )
27 {
28  pose const POSE = { { {0,1,2}, {3,4,5}, {6,7,8} }, { 0,0,1 } };
29  rs2_extrinsics const EXTR = { { 0,1,2,3,4,5,6,7,8 }, {0,0,1} };
30 
31  // Pose memory layout same exact as extrinsics:
32  CHECK( 0 == memcmp( &POSE, &EXTR, 9 * sizeof( float ) ) );
33  pose p = to_pose( EXTR );
34  CHECK( 0 == memcmp( &p, &EXTR, 9 * sizeof( float ) ) );
35 
36  // To/from pose do nothing, really!
37  CHECK( to_pose( EXTR ) == POSE );
38  CHECK( from_pose( POSE ) == EXTR );
39  CHECK( to_pose( from_pose( POSE )) == POSE );
40 }
41 
42 TEST_CASE( "float3x3 operator()", "[types]" )
43 {
44  float3x3 m = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
45 
46  // column-major, meaning first number is the column!
47  INFO( m );
48  INFO( "(0,0) " << m( 0, 0 ) << " (0,1) " << m( 0, 1 ) << " (0,2) " << m( 0, 2 ) );
49  INFO( "(1,0) " << m( 1, 0 ) << " (1,1) " << m( 1, 1 ) << " (1,2) " << m( 1, 2 ) );
50  INFO( "(2,0) " << m( 2, 0 ) << " (2,1) " << m( 2, 1 ) << " (2,2) " << m( 2, 2 ) );
51 
52  CHECK( m( 1, 0 ) == 2 );
53 }
54 
55 
56 // These check for approximate equality for the different types
57 inline bool eq( float3 const & a, float3 const & b )
58 {
59  return a.x == approx( b.x ) && a.y == approx( b.y ) && a.z == approx( b.z );
60 }
61 inline bool eq( float3x3 const & a, float3x3 const & b )
62 {
63  return eq( a.x, b.x ) && eq( a.y, b.y ) && eq( a.z, b.z );
64 }
65 inline bool eq( pose const & a, pose const & b )
66 {
67  return eq( a.orientation, b.orientation ) && eq( a.position, b.position );
68 }
69 inline bool eq( rs2_extrinsics const & a, rs2_extrinsics const & b )
70 {
71  return eq( *(pose const *)&a, *(pose const *)&b );
72 }
73 
74 float dot( float3 const & a, float3 const & b )
75 {
76  return a.x * b.x + a.y * b.y + a.z * b.z;
77 }
78 float3 mult( const float3x3 & a, const float3 & b )
79 {
80  // This is the version in the "World's tiniest linear algebra library":
81  // return a.x*b.x + a.y*b.y + a.z*b.z;
82  // And this is the conventional way:
83  return { dot( a.x,b ), dot( a.y,b ), dot( a.z,b ) };
84 }
85 
86 TEST_CASE( "m*v", "[types]" )
87 {
88  float3x3 m = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
89  float3 v = { 1, -2, 3 };
90 
91  INFO( m );
92  INFO( v );
93 
94  // This fails (but shouldn't) with our matrix math:
95  //FAILS:CHECK( m * v == mult( m, v ) );
96 
97  // Our math is all transposed! (e.g., see rs2_transform_point_to_point)
98  // So intead we have:
99  CHECK( transpose( m ) * v == mult( m, v ) );
100 }
101 
102 TEST_CASE( "m*v (rotation matrix)", "[types]" )
103 {
104  float3x3 m = rotx( 30 );
105  float3 v = { 1, -2, 3 };
106 
107  INFO( m );
108  INFO( "(0,0) " << m( 0, 0 ) << " (0,1) " << m( 0, 1 ) << " (0,2) " << m( 0, 2 ) );
109  INFO( "(1,0) " << m( 1, 0 ) << " (1,1) " << m( 1, 1 ) << " (1,2) " << m( 1, 2 ) );
110  INFO( "(2,0) " << m( 2, 0 ) << " (2,1) " << m( 2, 1 ) << " (2,2) " << m( 2, 2 ) );
111 
112  //FAILS:CHECK( m * v == mult( m, v ) );
113  //FAILS:CHECK_FALSE( transpose( m ) * v == mult( m, v ) );
114 }
115 
116 float determinant( float3x3 const & r )
117 {
118  // |A| = aei + bfg + cdh - ceg - bdi - afh
119  return r.x.x * r.y.y * r.z.z // aei
120  + r.x.y * r.y.z * r.z.x // bfg
121  + r.x.z * r.y.x * r.z.y // cdh
122  - r.x.z * r.y.y * r.z.x // ceg
123  - r.x.y * r.y.x * r.z.z // bdi
124  - r.x.x * r.y.z * r.z.y; // afh
125 }
126 
127 TEST_CASE( "rotation matrix", "[types]" )
128 {
129  float3x3 I = { {1,0,0}, {0,1,0}, {0,0,1} };
130  float3x3 rot = rotx( 30 );
131 
132  // A valid rotation matrix must satisfy:
133  // transpose(r)*r == identity
134  // determinant(r) == 1
135  INFO( "\nrot=\n" << rot );
136  INFO( "\nrot_T=\n" << transpose( rot ) );
137  CHECK( transpose( rot ) * rot == I );
138  CHECK( determinant( rot ) == 1 );
139 }
140 
141 /*
142 [ux vx wx tx] -1 ( [1 0 0 tx] [ux vx wx 0] ) -1
143 [uy vy wy ty] ( [0 1 0 ty] [uy vy wy 0] )
144 [uz vz wz tz] = ( [0 0 1 tz] * [uz vz wz 0] )
145 [ 0 0 0 1] ( [0 0 0 1] [ 0 0 0 1] )
146 
147 To place an object at a given position and orientation, you first rotate the object,
148 then second translate it to its new position. This corresponds to placing the rotation
149 matrix on the right and the translation matrix on the left.
150 
151  [ux vx wx 0] -1 [1 0 0 tx] -1
152  [uy vy wy 0] [0 1 0 ty]
153  = [ux vz wz 0] * [0 0 1 tz]
154  [ 0 0 0 1] [0 0 0 1]
155 
156 The inverse of a matrix product is the product of the inverse matrices ordered in reverse.
157 
158  [ux uy uz 0] [1 0 0 -tx]
159  [vx vy vz 0] [0 1 0 -ty]
160  = [wx wy wz 0] * [0 0 1 -tz]
161  [ 0 0 0 1] [0 0 0 1 ]
162 
163 The inverse of a rotation matrix is the rotation matrix's transpose.
164 The inverse of a translation matrix is the translation matrix with the opposite signs
165 on each of the translation components.
166 
167  [ux uy uz -ux*tx-uy*ty-uz*tz]
168  [vx vy vz -vx*tx-vy*ty-vz*tz]
169  = [wx wy wz -wx*tx-wy*ty-wz*tz]
170  [ 0 0 0 1 ]
171 
172  [ux uy uz -dot(u,t)]
173  [vx vy vz -dot(v,t)]
174  = [wx wy wz -dot(w,t)]
175  [ 0 0 0 1 ]
176 */
177 
178 pose inv( pose const & p )
179 {
180  // This is the version in the "World's tiniest linear algebra library":
181  // auto inv = transpose(a.orientation); return{ inv, inv * a.position * -1 };
182  // But it's built on a mult that's transposed so in essence the 't' part is wrong:
183  auto ot = transpose( p.orientation );
184  return{ ot, mult( ot, p.position ) * -1 };
185 }
186 TEST_CASE( "inverse != inv", "[types]" )
187 {
188  float3x3 rot = {
189  { 0.999899744987488f, 0.014070882461965f, -0.001586908474565f},
190  {-0.014017328619957f, 0.999457061290741f, 0.029818318784237f},
191  { 0.002005616901442f, -0.029793085530400f, 0.999554097652435f}
192  };
193  float3 tran = { -0.000100966520607471f, 0.013899585723876953f, -0.004260723590850830f };
194 
195  auto p = pose{ rot, tran };
196 
197  INFO( "\np= " << std::setprecision( 15 ) << p );
198  INFO( "\ninv(p)= " << std::setprecision( 15 ) << inv( p ) );
199  INFO( "\ninverse(p)= " << std::setprecision( 15 ) << inverse( p ) );
200  //FAILS:CHECK( eq( inverse( p ), inv( p ) ) );
201  CHECK_FALSE( eq( inverse( p ), inv( p ) ) );
202 }
203 
204 pose inv2( pose const & p )
205 {
206  // This version negates the position before multiplication; should be the same
207  auto ot = transpose( p.orientation );
208  return{ ot, mult( ot, p.position * -1 ) };
209 }
210 TEST_CASE( "inv == inv2", "[types]" )
211 {
212  float3x3 rot = {
213  { 0.999899744987488f, 0.014070882461965f, -0.001586908474565f},
214  {-0.014017328619957f, 0.999457061290741f, 0.029818318784237f},
215  { 0.002005616901442f, -0.029793085530400f, 0.999554097652435f}
216  };
217  float3 tran = { -0.000100966520607471f, 0.013899585723876953f, -0.004260723590850830f };
218  auto p = pose{ rot, tran };
219 
220  INFO( "\np= " << std::setprecision( 15 ) << p );
221  INFO( "\ninv(p)= " << std::setprecision( 15 ) << inv( p ) );
222  INFO( "\ninv2(p)= " << std::setprecision( 15 ) << inv2( p ) );
223  CHECK( inv2( p ) == inv( p ) );
224  CHECK( eq( inv2( inv2( p ) ), p ) );
225 }
226 
227 TEST_CASE( "inverse of inverse (not a rot mat)", "[types]" )
228 {
229  // the rotation matrix here is not valid (has no inverse)
230  rs2_extrinsics extr{ { 0,1,2,3,4,5,6,7,8 }, {1,2,3} };
232  CHECK_FALSE( inverse( inverse( p ) ) == p );
233 }
234 
235 TEST_CASE( "inverse of inverse (rot mat)", "[types]" )
236 {
237  float3x3 rot = rotx( 30 );
238  float3 tran = { -0.100967f, 13.899586f, -4.260724f };
239 
240  pose p = { rot, tran };
241 
242  INFO( "\np=\n" << std::setprecision( 15 ) << p );
243  INFO( "\ninv(p)=\n" << std::setprecision( 15 ) << inv( p ) );
244  INFO( "\ninv(inv(p))=\n" << inv( inv( p ) ) );
245  INFO( "\ninverse(inverse(p))=\n" << inverse( inverse( p ) ) );
246  CHECK( inverse( inverse( p ) ) == p );
247 }
248 
249 TEST_CASE( "inverse of inverse (extr)", "[types]" )
250 {
251  float3x3 rot = {
252  { 0.999899744987488f, 0.014070882461965f, -0.001586908474565f},
253  {-0.014017328619957f, 0.999457061290741f, 0.029818318784237f},
254  { 0.002005616901442f, -0.029793085530400f, 0.999554097652435f}
255  };
256  float3 tran = { -0.000100966520607471f, 0.013899585723876953f, -0.004260723590850830f };
257 
258  rs2_extrinsics extr = from_pose( { rot, tran } );
259 
260  CHECK( eq( inverse( inverse( extr ) ), extr ) );
261 }
float3x3 orientation
Definition: src/types.h:576
float3 mult(const float3x3 &a, const float3 &b)
Definition: test-pose.cpp:78
GLboolean GLboolean GLboolean b
Approx approx(F f)
Definition: approx.h:106
pose inv(pose const &p)
Definition: test-pose.cpp:178
float determinant(float3x3 const &r)
Definition: test-pose.cpp:116
rs2_extrinsics from_pose(pose a)
Definition: src/types.h:602
GLfloat GLfloat p
Definition: glext.h:12687
const GLfloat * m
Definition: glext.h:6814
TEST_CASE("pose vs extrinsics","[types]")
Definition: test-pose.cpp:26
float3 tran
Definition: test-pose.cpp:238
CHECK(m(1, 0)==2)
pose inv2(pose const &p)
Definition: test-pose.cpp:204
GLboolean GLboolean GLboolean GLboolean a
float3x3 transpose(const float3x3 &a)
Definition: src/types.h:588
pose inverse(const pose &a)
Definition: src/types.h:592
float3x3 rotx(float a)
Definition: rot.h:7
pose to_pose(const rs2_extrinsics &a)
Definition: src/types.h:593
#define INITIALIZE_EASYLOGGINGPP
INFO(m)
GLdouble GLdouble r
float dot(float3 const &a, float3 const &b)
Definition: test-pose.cpp:74
Cross-stream extrinsics: encodes the topology describing how the different devices are oriented...
Definition: rs_sensor.h:96
bool eq(float3 const &a, float3 const &b)
Definition: test-pose.cpp:57
rs2_extrinsics extr
Definition: test-pose.cpp:258
GLdouble v
CHECK_FALSE(inverse(inverse(p))==p)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:50:11