1 /*********************************************************************
2 Copyright 2013 Karl Jones
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 For Further Information Please Contact me at
27 http://p.sf.net/kdis/UserGuide
28 *********************************************************************/
30 /********************************************************************
35 purpose: Holds all common conversions, Datum conversion,
37 *********************************************************************/
41 #include "./../KDefines.h"
45 #define KDIS_PI 3.14159265358979323846
51 /************************************************************************/
52 /* Conversions to and from radians / degrees */
53 /************************************************************************/
56 inline Type
RadToDeg( Type Rad
)
58 return static_cast<Type
>(Rad
* ( 180.0 / KDIS_PI
));
62 inline Type
DegToRad( Type Deg
)
64 return static_cast<Type
>(Deg
* ( KDIS_PI
/ 180.0 ));
67 /************************************************************************/
68 /* Conversions to and from feet / meters */
69 /************************************************************************/
72 inline Type
FeetToMeters( Type Feet
)
74 return static_cast<Type
>(Feet
/ 3.2808);
77 //////////////////////////////////////////////////////////////////////////
80 inline Type
MetersToFeet( Type Meters
)
82 return static_cast<Type
>(Meters
* 3.2808);
85 /************************************************************************/
86 /* Conversions to and from Geocentric / Geodetic - ECEF / LLA */
87 /************************************************************************/
89 // Reference Ellipsoids, data taken from Wikipedia and DoD, WGS84, DMA TR 8350.2-B,1 Sept. 1991
100 Everest_Sabah_Sarawak
,
106 Fischer_1960_Modified
,
122 //////////////////////////////////////////////////////////////////////////
125 inline void GetEllipsoidAxis( RefEllipsoid R
, Type
& MajorAxis
, Type
& MinorAxis
)
130 MajorAxis
= static_cast<Type
>(6377563.396);
131 MinorAxis
= static_cast<Type
>(6356256.909);
136 MajorAxis
= static_cast<Type
>(6377340.189);
137 MinorAxis
= static_cast<Type
>(6356034.448);
141 case Australian_National
:
142 MajorAxis
= static_cast<Type
>(6378160.000);
143 MinorAxis
= static_cast<Type
>(6356774.719);
148 MajorAxis
= static_cast<Type
>(6377397.155);
149 MinorAxis
= static_cast<Type
>(6356078.963);
153 case Bessel_1841_Namibia
:
154 MajorAxis
= static_cast<Type
>(6377483.865);
155 MinorAxis
= static_cast<Type
>(6356078.963);
160 MajorAxis
= static_cast<Type
>(6378206.400);
161 MinorAxis
= static_cast<Type
>(6356583.800);
166 MajorAxis
= static_cast<Type
>(6378249.145);
167 MinorAxis
= static_cast<Type
>(6356514.870);
171 case Everest_Sabah_Sarawak
:
172 MajorAxis
= static_cast<Type
>(6377298.556);
173 MinorAxis
= static_cast<Type
>(6356097.550);
178 MajorAxis
= static_cast<Type
>(6377276.345);
179 MinorAxis
= static_cast<Type
>(6356075.413);
184 MajorAxis
= static_cast<Type
>(6377304.063);
185 MinorAxis
= static_cast<Type
>(6356103.039);
190 MajorAxis
= static_cast<Type
>(6377301.243);
191 MinorAxis
= static_cast<Type
>(6356100.228);
196 MajorAxis
= static_cast<Type
>(6377295.664);
197 MinorAxis
= static_cast<Type
>(6356094.668);
202 MajorAxis
= static_cast<Type
>(6378166.000);
203 MinorAxis
= static_cast<Type
>(6356784.284);
207 case Fischer_1960_Modified
:
208 MajorAxis
= static_cast<Type
>(6378155.000);
209 MinorAxis
= static_cast<Type
>(6356773.320);
214 MajorAxis
= static_cast<Type
>(6378150.000);
215 MinorAxis
= static_cast<Type
>(6356768.337);
220 MajorAxis
= static_cast<Type
>(6378137.000);
221 MinorAxis
= static_cast<Type
>(6356752.314);
226 MajorAxis
= static_cast<Type
>(6378200.000);
227 MinorAxis
= static_cast<Type
>(6356818.170);
232 MajorAxis
= static_cast<Type
>(6378270.000);
233 MinorAxis
= static_cast<Type
>(6356794.343);
237 case International_1924
:
238 MajorAxis
= static_cast<Type
>(6378388.000);
239 MinorAxis
= static_cast<Type
>(6356911.946);
244 MajorAxis
= static_cast<Type
>(6378245.000);
245 MinorAxis
= static_cast<Type
>(6356863.019);
250 MajorAxis
= static_cast<Type
>(6378136.000);
251 MinorAxis
= static_cast<Type
>(6356751.302);
255 case South_American_1969
:
256 MajorAxis
= static_cast<Type
>(6378160.000);
257 MinorAxis
= static_cast<Type
>(6356774.719);
262 MajorAxis
= static_cast<Type
>(6371000);
263 MinorAxis
= static_cast<Type
>(6371000);
267 MajorAxis
= static_cast<Type
>(6378165.000);
268 MinorAxis
= static_cast<Type
>(6356783.287);
273 MajorAxis
= static_cast<Type
>(6378145.000);
274 MinorAxis
= static_cast<Type
>(6356759.769);
279 MajorAxis
= static_cast<Type
>(6378135.000);
280 MinorAxis
= static_cast<Type
>(6356750.520);
285 MajorAxis
= static_cast<Type
>(6378137.000);
286 MinorAxis
= static_cast<Type
>(6356752.314245);
292 //////////////////////////////////////////////////////////////////////////
295 inline void DecimalToDMS( Type Decimal
, Type
& DegOUT
, Type
& MinOUT
, Type
& SecOUT
)
297 Decimal
= std::abs( Decimal
); // Make sure the value is not negative
298 DegOUT
= static_cast<Type
>(( KUINT32
)Decimal
);
299 Decimal
-= DegOUT
; // Degrees
301 MinOUT
= static_cast<Type
>(Decimal
* 60.0);
303 Decimal
= MinOUT
- static_cast<Type
>(( KUINT32
)MinOUT
);
305 MinOUT
= static_cast<Type
>(( KUINT32
)MinOUT
); // Minutes
306 SecOUT
= static_cast<Type
>(Decimal
* 60.0); // Seconds
309 //////////////////////////////////////////////////////////////////////////
312 inline Type
DMSToDecimal( Type Deg
, Type Min
, Type Sec
)
314 return static_cast<Type
>(Deg
+ ( Min
/ 60.0 ) + ( Sec
/ 3600.0 ));
317 //////////////////////////////////////////////////////////////////////////
319 //************************************
320 // FullName: KDIS::UTILS<Type>::GeodeticToGeocentric
321 // Description: Converts Geodetic coords to Geocentric Cartesian.
322 // Parameter: Type GeodeticLat - in degrees
323 // Parameter: Type GeodeticLon - in degrees
324 // Parameter: Type GeodeticHeight - in meters
325 // Parameter: Type & GeocentricX
326 // Parameter: Type & GeocentricY
327 // Parameter: Type & GeocentricZ
328 // Parameter: RefEllipsoid R
329 //************************************
332 inline void GeodeticToGeocentric( Type GeodeticLat
, Type GeodeticLon
, Type GeodeticHeight
,
333 Type
& GeocentricX
, Type
& GeocentricY
, Type
& GeocentricZ
,
336 GeodeticLat
= DegToRad( GeodeticLat
);
337 GeodeticLon
= DegToRad( GeodeticLon
);
339 Type MajorAxis
, MinorAxis
;
340 GetEllipsoidAxis( R
, MajorAxis
, MinorAxis
);
342 Type Esq
= ( pow( MajorAxis
, 2 ) - pow( MinorAxis
, 2 ) ) / pow( MajorAxis
, 2 );
343 Type V
= MajorAxis
/ sqrt( 1 - ( Esq
* pow( sin( GeodeticLat
), 2 ) ) );
345 GeocentricX
= ( V
+ GeodeticHeight
) * cos( GeodeticLat
) * cos( GeodeticLon
);
346 GeocentricY
= ( V
+ GeodeticHeight
) * cos( GeodeticLat
) * sin( GeodeticLon
);
347 GeocentricZ
= ( ( 1 - Esq
) * V
+ GeodeticHeight
) * sin( GeodeticLat
);
350 //////////////////////////////////////////////////////////////////////////
352 //************************************
353 // FullName: KDIS::UTILS<Type>::GeocentricToGeodetic
354 // Description: Converts Geocentric Cartesian coords to Geodetic.
355 // Parameter: Type x - in radians
356 // Parameter: Type y - in radians
357 // Parameter: Type z - in radians
358 // Parameter: Type & lat
359 // Parameter: Type & lon
360 // Parameter: Type & alt
361 // Parameter: RefEllipsoid R
362 //************************************
365 inline void GeocentricToGeodetic( Type x
, Type y
, Type z
,Type
& lat
, Type
& lon
, Type
& alt
, RefEllipsoid R
)
367 // This is the 'closed form solution'
368 // equations described by https://microem.ru/files/2012/08/GPS.G1-X-00006.pdf
369 // and many other places on the web. start at wikipedia, "ECEF"
371 Type a
; // semi-major axis
372 Type b
; // semi-minor axis
373 GetEllipsoidAxis( R
, a
, b
);
375 Type
const e2
= (a
*a
-b
*b
) / (a
*a
); // eccentricity (first)
376 Type
const e_prime2
= (a
*a
-b
*b
) / (b
*b
); // eccentricity (second)
377 Type
const f
= 1 - b
/a
; // flattening
379 // 'auxiliary values'
380 Type
const p
= sqrt(x
*x
+ y
*y
);
381 Type
const theta
= static_cast<Type
>(atan2 ( (z
*a
) , (p
*b
)));
384 lat
= static_cast<Type
>(atan2 ( ( z
+ (e_prime2
) * b
* pow (sin(theta
),3) ),
385 ( p
- (e2
*a
*pow(cos(theta
),3)))));
387 // Radius of curvature
388 Type
const N
= a
/ sqrt ( 1 - e2
*sin(lat
)*sin(lat
));
391 Type cosLat
= cos(lat
);
392 Type
const COS_THRESHOLD
= 0.0000001;
393 if( (cosLat
> -COS_THRESHOLD
) && (cosLat
< COS_THRESHOLD
) ) // Very near the poles
394 alt
= std::abs( z
) - b
;
396 alt
= p
/ cosLat
- N
;
399 lon
= static_cast<Type
>(atan2(y
,x
));
401 lon
= RadToDeg( lon
);
402 lat
= RadToDeg( lat
);
405 //////////////////////////////////////////////////////////////////////////
408 inline void RotateAboutAxis( Type d
[3] ,Type
const s
[3] ,Type
const n
[3] ,Type t
)
410 double st
= sin( t
);
411 double ct
= cos( t
);
413 d
[0] = static_cast<Type
>((1.0-ct
)*(n
[0]*n
[0]*s
[0] + n
[0]*n
[1]*s
[1] + n
[0]*n
[2]*s
[2]) + ct
*s
[0] + st
*(n
[1]*s
[2]-n
[2]*s
[1]));
414 d
[1] = static_cast<Type
>((1.0-ct
)*(n
[0]*n
[1]*s
[0] + n
[1]*n
[1]*s
[1] + n
[1]*n
[2]*s
[2]) + ct
*s
[1] + st
*(n
[2]*s
[0]-n
[0]*s
[2]));
415 d
[2] = static_cast<Type
>((1.0-ct
)*(n
[0]*n
[2]*s
[0] + n
[1]*n
[2]*s
[1] + n
[2]*n
[2]*s
[2]) + ct
*s
[2] + st
*(n
[0]*s
[1]-n
[1]*s
[0]));
419 inline void Cross( Type d
[3] ,Type
const a
[3] ,Type
const b
[3] )
421 d
[0] = a
[1] * b
[2] - b
[1] * a
[2] ;
422 d
[1] = b
[0] * a
[2] - a
[0] * b
[2] ;
423 d
[2] = a
[0] * b
[1] - b
[0] * a
[1] ;
427 inline Type
Dot( Type
const a
[3] ,Type
const b
[3] )
429 return a
[0]*b
[0] + a
[1]*b
[1] + a
[2]*b
[2];
432 //************************************
433 // FullName: KDIS::UTILS<Type>::HeadingPitchRollToEuler
434 // Description: Converts Heading, Pitch and Roll to Euler for DIS.
435 // Parameter: Type H - Heading in radians
436 // Parameter: Type P - Pitch in radians
437 // Parameter: Type R - Roll in radians
438 // Parameter: Type Lat - Geodetic Latitude in radians
439 // Parameter: Type Lon - Geodetic Longitude in radians
440 // Parameter: Type & Psi - Euler angle out
441 // Parameter: Type & Theta - Euler angle out
442 // Parameter: Type & Phi - Euler angle out
443 //************************************
446 inline void HeadingPitchRollToEuler( Type H
, Type P
, Type R
, Type Lat
, Type Lon
, Type
& Psi
, Type
& Theta
,
450 //Type const D0[3] = { 1.0 , 0.0 , 0.0 };
451 Type
const E0
[3] = { 0.0 , 1.0 , 0.0 };
452 Type
const N0
[3] = { 0.0 , 0.0 , 1.0 };
458 RotateAboutAxis( E
, E0
, N0
, Lon
);
463 RotateAboutAxis( N
, N0
, me
, Lat
);
469 // rotate about D by heading
470 Type N1
[3] , E1
[3] , D1
[3] ;
471 RotateAboutAxis( N1
, N
, D
, H
);
472 RotateAboutAxis( E1
, E
, D
, H
);
473 memcpy( D1
, D
, sizeof( Type
[3] ) );
474 // rotate about E1 vector by pitch
475 Type N2
[3] , E2
[3] , D2
[3] ;
476 RotateAboutAxis( N2
, N1
, E1
, P
);
477 memcpy( E2
, E1
, sizeof( Type
[3] ) );
478 RotateAboutAxis( D2
, D1
, E1
, P
);
479 // rotate about N2 by roll
480 Type N3
[3] , E3
[3] , D3
[3] ;
481 memcpy( N3
, N2
, sizeof( Type
[3] ) );
482 RotateAboutAxis( E3
, E2
, N2
, R
);
483 RotateAboutAxis( D3
, D2
, N2
, R
);
485 // calculate angles from vectors
486 Type x0
[3] = { 1.0 , 0.0 , 0.0 }; // == D0
487 Type y0
[3] = { 0.0 , 1.0 , 0.0 }; // == E0
488 Type z0
[3] = { 0.0 , 0.0 , 1.0 }; // == Z0
491 Psi
= static_cast<Type
>(atan2( Dot( N3
, y0
) , Dot( N3
, x0
) ));
492 Theta
= static_cast<Type
>(atan2( -Dot( N3
, z0
) , sqrt( pow(Dot( N3
, x0
), 2) + pow(Dot( N3
, y0
), 2) ) ));
493 RotateAboutAxis( y2
, y0
, z0
, Psi
);
494 RotateAboutAxis( z2
, z0
, y2
, Theta
);
495 Phi
= static_cast<Type
>(atan2( Dot( E3
, z2
) , Dot( E3
, y2
) ));
498 //////////////////////////////////////////////////////////////////////////
500 //************************************
501 // FullName: KDIS::UTILS<Type>::EulerToHeadingPitchRoll
502 // Description: Converts Euler to Heading, Pitch and Roll.
503 // Parameter: Type Lat - Geodetic Latitude in radians
504 // Parameter: Type Lon - Geodetic Longitude in radians
505 // Parameter: Type Psi - Euler angle
506 // Parameter: Type Theta - Euler angle
507 // Parameter: Type Phi - Euler angle
508 // Parameter: Type & H - Heading in radians out
509 // Parameter: Type & P - Pitch in radians out
510 // Parameter: Type & R - Roll in radians out
511 //************************************
514 void EulerToHeadingPitchRoll( Type Lat
, Type Lon
, Type Psi
, Type Theta
, Type Phi
, Type
& H
, Type
& P
, Type
& R
)
516 // local NED vectors in ECEF coordinate frame
521 // Calculate NED from lat and lon
523 //Type const D0[3] = { 1. , 0. , 0. };
524 Type
const E0
[3] = { 0. , 1. , 0. };
525 Type
const N0
[3] = { 0. , 0. , 1. };
528 RotateAboutAxis( E
, E0
, N0
, Lon
);
533 RotateAboutAxis( N
, N0
, me
, Lat
);
538 * input : (x0,y0,z0)=(N,E,D) and (Psi,Theta,Phi Euler angles)
539 * output: (x3,y3,z3)=body vectors in local frame
541 // rotate about Z by Psi
542 Type X
[]= {1.,0.,0.};
543 Type Y
[]= {0.,1.,0.};
544 Type Z
[]= {0.,0.,1.};
545 Type X1
[3] , Y1
[3] , Z1
[3] ;
546 RotateAboutAxis( X1
, X
, Z
, Psi
);
547 RotateAboutAxis( Y1
, Y
, Z
, Psi
);
548 memcpy( Z1
, Z
, sizeof( Type
[3] ) );
549 // rotate about Y1 vector by Theta
550 Type X2
[3] , Y2
[3] , Z2
[3] ;
551 RotateAboutAxis( X2
, X1
, Y1
, Theta
);
552 memcpy( Y2
, Y1
, sizeof( Type
[3] ) );
553 RotateAboutAxis( Z2
, Z1
, Y1
, Theta
);
554 // rotate about X2 by Phi
555 Type X3
[3] , Y3
[3] , Z3
[3] ;
556 memcpy( X3
, X2
, sizeof( Type
[3] ) );
557 RotateAboutAxis( Y3
, Y2
, X2
, Phi
);
558 RotateAboutAxis( Z3
, Z2
, X2
, Phi
);
559 // calculate angles from vectors
561 memcpy( x0
, N
, sizeof( Type
[3] ) );
563 memcpy( y0
, E
, sizeof( Type
[3] ) );
565 memcpy( z0
, D
, sizeof( Type
[3] ) );
568 H
= static_cast<Type
>(atan2( Dot( X3
, y0
) , Dot( X3
, x0
) ));
569 P
= static_cast<Type
>(atan2( -Dot( X3
, z0
) , sqrt( pow(Dot( X3
, x0
), 2) + pow(Dot( X3
, y0
), 2) ) ));
570 RotateAboutAxis( y2
, y0
, z0
, H
);
571 RotateAboutAxis( z2
, z0
, y2
, P
);
572 R
= static_cast<Type
>(atan2( Dot( Y3
, z2
) , Dot( Y3
, y2
) ));
575 } // END namespace UTILS
576 } // END namespace KDIS