# define _USE_MATH_DEFINES 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <iostream> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <cmath> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <eigen3/Eigen/Dense> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "common/transformations/orientation.hpp" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "common/transformations/coordinates.hpp" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Quaterniond  ensure_unique ( Eigen : : Quaterniond  quat ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( quat . w ( )  >  0 ) { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  quat ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  else  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  Eigen : : Quaterniond ( - quat . w ( ) ,  - quat . x ( ) ,  - quat . y ( ) ,  - quat . z ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Quaterniond  euler2quat ( Eigen : : Vector3d  euler ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Quaterniond  q ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  q  =  Eigen : : AngleAxisd ( euler ( 2 ) ,  Eigen : : Vector3d : : UnitZ ( ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    *  Eigen : : AngleAxisd ( euler ( 1 ) ,  Eigen : : Vector3d : : UnitY ( ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    *  Eigen : : AngleAxisd ( euler ( 0 ) ,  Eigen : : Vector3d : : UnitX ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  ensure_unique ( q ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Vector3d  quat2euler ( Eigen : : Quaterniond  quat ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // TODO: switch to eigen implementation if the range of the Euler angles doesn't matter anymore
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // Eigen::Vector3d euler = quat.toRotationMatrix().eulerAngles(2, 1, 0);
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // return {euler(2), euler(1), euler(0)};
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  gamma  =  atan2 ( 2  *  ( quat . w ( )  *  quat . x ( )  +  quat . y ( )  *  quat . z ( ) ) ,  1  -  2  *  ( quat . x ( ) * quat . x ( )  +  quat . y ( ) * quat . y ( ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  double  asin_arg_clipped  =  std : : clamp ( 2  *  ( quat . w ( )  *  quat . y ( )  -  quat . z ( )  *  quat . x ( ) ) ,  - 1.0 ,  1.0 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  theta  =  asin ( asin_arg_clipped ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  psi  =  atan2 ( 2  *  ( quat . w ( )  *  quat . z ( )  +  quat . x ( )  *  quat . y ( ) ) ,  1  -  2  *  ( quat . y ( ) * quat . y ( )  +  quat . z ( ) * quat . z ( ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  { gamma ,  theta ,  psi } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Matrix3d  quat2rot ( Eigen : : Quaterniond  quat ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  quat . toRotationMatrix ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								Eigen : : Quaterniond  rot2quat ( const  Eigen : : Matrix3d  & rot ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  ensure_unique ( Eigen : : Quaterniond ( rot ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Matrix3d  euler2rot ( Eigen : : Vector3d  euler ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  quat2rot ( euler2quat ( euler ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								Eigen : : Vector3d  rot2euler ( const  Eigen : : Matrix3d  & rot ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  quat2euler ( rot2quat ( rot ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Matrix3d  rot_matrix ( double  roll ,  double  pitch ,  double  yaw ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  euler2rot ( { roll ,  pitch ,  yaw } ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Matrix3d  rot ( Eigen : : Vector3d  axis ,  double  angle ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Quaterniond  q ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  q  =  Eigen : : AngleAxisd ( angle ,  axis ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  q . toRotationMatrix ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Vector3d  ecef_euler_from_ned ( ECEF  ecef_init ,  Eigen : : Vector3d  ned_pose )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /*
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    Using  Rotations  to  Build  Aerospace  Coordinate  Systems 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    Don  Koks 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    https : //apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  */ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LocalCoord  converter  =  LocalCoord ( ecef_init ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  zero  =  ecef_init . to_vector ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x0  =  converter . ned2ecef ( { 1 ,  0 ,  0 } ) . to_vector ( )  -  zero ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y0  =  converter . ned2ecef ( { 0 ,  1 ,  0 } ) . to_vector ( )  -  zero ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  z0  =  converter . ned2ecef ( { 0 ,  0 ,  1 } ) . to_vector ( )  -  zero ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x1  =  rot ( z0 ,  ned_pose ( 2 ) )  *  x0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y1  =  rot ( z0 ,  ned_pose ( 2 ) )  *  y0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  z1  =  rot ( z0 ,  ned_pose ( 2 ) )  *  z0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x2  =  rot ( y1 ,  ned_pose ( 1 ) )  *  x1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y2  =  rot ( y1 ,  ned_pose ( 1 ) )  *  y1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  z2  =  rot ( y1 ,  ned_pose ( 1 ) )  *  z1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x3  =  rot ( x2 ,  ned_pose ( 0 ) )  *  x2 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y3  =  rot ( x2 ,  ned_pose ( 0 ) )  *  y2 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  x0  =  Eigen : : Vector3d ( 1 ,  0 ,  0 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  y0  =  Eigen : : Vector3d ( 0 ,  1 ,  0 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  z0  =  Eigen : : Vector3d ( 0 ,  0 ,  1 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  psi  =  atan2 ( x3 . dot ( y0 ) ,  x3 . dot ( x0 ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  theta  =  atan2 ( - x3 . dot ( z0 ) ,  sqrt ( pow ( x3 . dot ( x0 ) ,  2 )  +  pow ( x3 . dot ( y0 ) ,  2 ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  y2  =  rot ( z0 ,  psi )  *  y0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  z2  =  rot ( y2 ,  theta )  *  z0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  phi  =  atan2 ( y3 . dot ( z2 ) ,  y3 . dot ( y2 ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  { phi ,  theta ,  psi } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Eigen : : Vector3d  ned_euler_from_ecef ( ECEF  ecef_init ,  Eigen : : Vector3d  ecef_pose ) { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /*
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    Using  Rotations  to  Build  Aerospace  Coordinate  Systems 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    Don  Koks 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    https : //apps.dtic.mil/dtic/tr/fulltext/u2/a484864.pdf
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  */ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LocalCoord  converter  =  LocalCoord ( ecef_init ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x0  =  Eigen : : Vector3d ( 1 ,  0 ,  0 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y0  =  Eigen : : Vector3d ( 0 ,  1 ,  0 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  z0  =  Eigen : : Vector3d ( 0 ,  0 ,  1 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x1  =  rot ( z0 ,  ecef_pose ( 2 ) )  *  x0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y1  =  rot ( z0 ,  ecef_pose ( 2 ) )  *  y0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  z1  =  rot ( z0 ,  ecef_pose ( 2 ) )  *  z0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x2  =  rot ( y1 ,  ecef_pose ( 1 ) )  *  x1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y2  =  rot ( y1 ,  ecef_pose ( 1 ) )  *  y1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  z2  =  rot ( y1 ,  ecef_pose ( 1 ) )  *  z1 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  x3  =  rot ( x2 ,  ecef_pose ( 0 ) )  *  x2 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  y3  =  rot ( x2 ,  ecef_pose ( 0 ) )  *  y2 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  Eigen : : Vector3d  zero  =  ecef_init . to_vector ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  x0  =  converter . ned2ecef ( { 1 ,  0 ,  0 } ) . to_vector ( )  -  zero ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  y0  =  converter . ned2ecef ( { 0 ,  1 ,  0 } ) . to_vector ( )  -  zero ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  z0  =  converter . ned2ecef ( { 0 ,  0 ,  1 } ) . to_vector ( )  -  zero ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  psi  =  atan2 ( x3 . dot ( y0 ) ,  x3 . dot ( x0 ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  theta  =  atan2 ( - x3 . dot ( z0 ) ,  sqrt ( pow ( x3 . dot ( x0 ) ,  2 )  +  pow ( x3 . dot ( y0 ) ,  2 ) ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  y2  =  rot ( z0 ,  psi )  *  y0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  z2  =  rot ( y2 ,  theta )  *  z0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  phi  =  atan2 ( y3 . dot ( z2 ) ,  y3 . dot ( y2 ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  { phi ,  theta ,  psi } ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}