/* This file is part of the Pangolin Project. * http://github.com/stevenlovegrove/Pangolin * * Copyright (c) 2011 Steven Lovegrove * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #include #include #include #include #include namespace pangolin { static const double Identity3d[] = {1,0,0, 0,1,0, 0,0,1}; static const double Zero3d[] = {0,0,0, 0,0,0, 0,0,0}; static const double Identity4d[] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; static const double Zero4d[] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; static const float Identity3f[] = {1,0,0, 0,1,0, 0,0,1}; static const float Zero3f[] = {0,0,0, 0,0,0, 0,0,0}; static const float Identity4f[] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; static const float Zero4f[] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; template void MatPrint(const P m[R*C]) { for( int r=0; r < R; ++r) { for( int c=0; c < C; ++c ) std::cout << m[R*c+r] << " "; std::cout << std::endl; } std::cout << std::endl; } template void MatPrint(const P m[R*C], std::string name) { std::cout << name << " = [" << std::endl; for( int r=0; r < R; ++r) { for( int c=0; c < C; ++c ) std::cout << m[R*c+r] << " "; std::cout << std::endl; } std::cout << std::endl << "]" << std::endl; } // Set array using varadic arguments template void MatSet(P m[R*C], ...) { va_list ap; va_start(ap,m); for( int i=0; i< R*C; ++i ) { *m = (P)va_arg(ap,double); ++m; } } // m = zeroes(N) template void SetZero(P m[R*C] ) { std::fill_n(m,R*C,0); } // m = identity(N) template void SetIdentity(P m[N*N] ) { std::fill_n(m,N*N,0); for( int i=0; i< N; ++i ) m[N*i+i] = 1; } // mo = m1 * m2 template void MatMul(P mo[R*C], const P m1[R*M], const P m2[M*C] ) { for( int r=0; r < R; ++r) for( int c=0; c < C; ++c ) { mo[R*c+r] = 0; for( int m=0; m < M; ++ m) mo[R*c+r] += m1[R*m+r] * m2[M*c+m]; } } // mo = m1 * m2 * s template void MatMul(P mo[R*C], const P m1[R*M], const P m2[M*C], P s ) { for( int r=0; r < R; ++r) for( int c=0; c < C; ++c ) { mo[R*c+r] = 0; for( int m=0; m < M; ++ m) mo[R*c+r] += m1[R*m+r] * m2[M*c+m] * s; } } // mo = m1 * transpose(m2) template void MatMulTranspose(P mo[R*C], const P m1[R*M], const P m2[C*M] ) { for( int r=0; r < R; ++r) for( int c=0; c < C; ++c ) { mo[R*c+r] = 0; for( int m=0; m < M; ++ m) mo[R*c+r] += m1[R*m+r] * m2[C*m+c]; } } // m = m1 + m2 template void MatAdd(P m[R*C], const P m1[R*C], const P m2[R*C]) { for( int i=0; i< R*C; ++i ) m[i] = m1[i] + m2[i]; } // m = m1 - m2 template void MatSub(P m[R*C], const P m1[R*C], const P m2[R*C]) { for( int i=0; i< R*C; ++i ) m[i] = m1[i] - m2[i]; } // m = m1 * scalar template void MatMul(P m[R*C], const P m1[R*C], P scalar) { for( int i=0; i< R*C; ++i ) m[i] = m1[i] * scalar; } // m = m1 + m2 template void MatMul(P m[R*C], P scalar) { for( int i=0; i< R*C; ++i ) m[i] *= scalar; } template void MatTranspose(P out[N*N], const P in[N*N] ) { for( int c=0; c void MatTranspose(P m[N*N] ) { for( int c=0; c(m[N*c+r],m[N*r+c]); } // m = a x b template void VecCross3(P m[3], const P a[3], const P b[3]) { m[0] = a[1]*b[2] - a[2]*b[1]; m[1] = a[2]*b[0] - a[0]*b[2]; m[2] = a[0]*b[1] - a[1]*b[0]; } // s = skewSymetrixMatrix(v) template void MatSkew(P s[3*3], const P v[3] ) { s[0] = 0; s[1] = v[2]; s[2] = -v[1]; s[3] = -v[2]; s[4] = 0; s[5] = v[0]; s[6] = v[1]; s[7] = -v[0]; s[8] = 0; } template void MatOrtho( P m[N*N] ) { // http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/index.htm P Itimes3[N*N]; SetIdentity(Itimes3); MatMul(Itimes3,(P)3.0); P mmT[N*N]; MatMulTranspose(mmT,m,m); P _c[N*N]; MatSub(_c,Itimes3,mmT); P _m[N*N]; MatMul(_m,m,_c,(P)0.5); std::copy(_m,_m+(N*N),m); } template void Rotation(P R[3*3], P x, P y, P z) { P sx = sin(x); P sy = sin(y); P sz = sin(z); P cx = cos(x); P cy = cos(y); P cz = cos(z); // P cx = sqrt( (P)1.0 - sx * sx); // P cy = sqrt( (P)1.0 - sy * sy); // P cz = sqrt( (P)1.0 - sz * sz); R[0] = cy * cz; R[1] = sx * sy * cz + cx * sz; R[2] = -cx * sy * cz + sx * sz; R[3] = -cy * sz; R[4] = -sx * sy * sz + cx * cz; R[5] = cx * sy * sz + sx * cz; R[6] = sy; R[7] = -sx * cy; R[8] = cx * cy; } template void LieSetIdentity(P T_ba[3*4] ) { SetIdentity<3>(T_ba); std::fill_n(T_ba+(3*3),3,0); } template void LieSetRotation(P T_ba[3*4], const P R_ba[3*3] ) { std::copy(R_ba,R_ba+(3*3),T_ba); } template void LieSetTranslation(P T_ba[3*4], const P a_b[3] ) { std::copy(a_b, a_b+3, T_ba+(3*3)); } template void LieSetSE3(P T_ba[3*4], const P R_ba[3*3], const P a_b[3] ) { LieSetRotation

(T_ba,R_ba); LieSetTranslation

(T_ba,a_b); } template void LieGetRotation(P R_ba[3*3], const P T_ba[3*4] ) { std::copy(T_ba,T_ba+(3*3),R_ba); } template void LieApplySO3( P out[3], const P R_ba[3*3], const P in[3] ) { MatMul<3,3,1,P>(out,R_ba,in); } template void LieApplySE3vec( P x_b[3], const P T_ba[3*4], const P x_a[3] ) { P rot[3]; MatMul<3,3,1,P>(rot,T_ba,x_a); MatAdd<3,1,P>(x_b,rot,T_ba+(3*3)); } template void LieApplySE34x4vec3( P x_b[3], const P T_ba[4*4], const P x_a[3] ) { x_b[0] = T_ba[0]*x_a[0] + T_ba[4]*x_a[1] + T_ba[8]*x_a[2] + T_ba[12]; x_b[1] = T_ba[1]*x_a[0] + T_ba[5]*x_a[1] + T_ba[9]*x_a[2] + T_ba[13]; x_b[2] = T_ba[2]*x_a[0] + T_ba[6]*x_a[1] + T_ba[10]*x_a[2] + T_ba[14]; } template void LieMulSO3( P R_ca[3*3], const P R_cb[3*3], const P R_ba[3*3] ) { MatMul<3,3,3>(R_ca,R_cb,R_ba); } template void LieMulSE3( P T_ca[3*4], const P T_cb[3*4], const P T_ba[3*4] ) { LieMulSO3<>(T_ca,T_cb,T_ba); P R_cb_times_a_b[3]; LieApplySO3<>(R_cb_times_a_b,T_cb,T_ba+(3*3)); MatAdd<3,1>(T_ca+(3*3),R_cb_times_a_b,T_cb+(3*3)); } template void LiePutSE3in4x4(P out[4*4], const P in[3*4] ) { SetIdentity<4>(out); std::copy(in,in+3, out); std::copy(in+3,in+6, out+4); std::copy(in+6,in+9, out+8); std::copy(in+9,in+12, out+12); } template void LieSE3from4x4(P out[3*4], const P in[4*4] ) { std::copy(in,in+3, out); std::copy(in+4,in+7, out+3); std::copy(in+8,in+11, out+6); std::copy(in+12,in+15, out+9); } template void LieMul4x4bySE3( P T_ca[4*4], const P T_cb[3*4], const P T_ba[4*4] ) { // TODO: fast P T_cb4[4*4]; LiePutSE3in4x4<>(T_cb4,T_cb); P res[4*4]; MatMul<4,4,4>(res,T_cb4,T_ba); std::copy(res,res+(4*4),T_ca); } template void LieTransposeSO3( P R_ab[3*3], const P R_ba[3*3] ) { MatTranspose<3,P>(R_ab,R_ba); } template void LieInverseSE3( P T_ab[3*4], const P T_ba[3*4] ) { LieTransposeSO3

(T_ab,T_ba); P minus_b_a[3]; LieApplySO3(minus_b_a, T_ab, T_ba+(3*3)); MatMul<3,1,P>(T_ab+(3*3),minus_b_a, -1); } // c = a x b template void CrossProduct( P c[3], const P a[3], const P b[3] ) { c[0] = a[1] * b[2] - a[2] * b[1]; c[1] = a[2] * b[0] - a[0] * b[2]; c[2] = a[0] * b[1] - a[1] * b[0]; } template P Length( P v[R] ) { P sum_sq = 0; for(size_t r = 0; r < R; ++r ) { sum_sq += v[r] * v[r]; } return sqrt(sum_sq); } template void Normalise( P v[R] ) { const P length = Length(v); for(size_t r = 0; r < R; ++r ) { v[r] /= length; } } template void EnforceUpT_wc(P T_wc[3*4], const P up_w[3]) { // Copy R_wc P R_wc[3*3]; std::copy(T_wc,T_wc+3*3,R_wc); // New R_wc should go into T_wc P* NR_wc = T_wc; // // cx_w,cy_w,cz_w are camera axis in world coordinates // // Calculate new camera coordinates (ncx_w,ncy_w,ncz_w) // ncx_w = up_w x cz_w CrossProduct(NR_wc + 0*3, up_w, R_wc + 2*3); // ncy_w = cz_w x ncx_w CrossProduct(NR_wc + 1*3, R_wc + 2*3, NR_wc + 0*3); // ncz_w = cz_w std::copy(R_wc + 2*3, R_wc + 3*3, NR_wc + 2*3); Normalise<3,P>(NR_wc + 0*3); Normalise<3,P>(NR_wc + 1*3); Normalise<3,P>(NR_wc + 2*3); } template void EnforceUpT_cw(P T_cw_4x4[4*4], const P up_w[3]) { // 3x4 from 4x4 P T_cw[3*4]; LieSE3from4x4

(T_cw,T_cw_4x4); // Invert T_cw P T_wc[3*4]; LieInverseSE3

(T_wc, T_cw); // Enforce up for T_wc EnforceUpT_wc

(T_wc, up_w); // Invert LieInverseSE3

(T_cw, T_wc); // 4x4 from 3x4 LiePutSE3in4x4

(T_cw_4x4,T_cw); } }