2015-08-10 02:25:15 -03:00
/*
* Location . cpp
*/
# include "Location.h"
2024-05-26 23:36:26 -03:00
# ifndef HAL_BOOTLOADER_BUILD
2015-08-10 02:25:15 -03:00
# include <AP_AHRS/AP_AHRS.h>
# include <AP_Terrain/AP_Terrain.h>
/// constructors
2019-01-01 22:53:47 -04:00
Location : : Location ( )
2015-08-10 02:25:15 -03:00
{
2016-07-10 19:41:20 -03:00
zero ( ) ;
2015-08-10 02:25:15 -03:00
}
2019-01-01 22:53:47 -04:00
const Location definitely_zero { } ;
bool Location : : is_zero ( void ) const
2019-01-01 19:57:48 -04:00
{
return ! memcmp ( this , & definitely_zero , sizeof ( * this ) ) ;
}
2019-01-01 22:53:47 -04:00
void Location : : zero ( void )
2019-01-01 19:57:48 -04:00
{
memset ( this , 0 , sizeof ( * this ) ) ;
}
2021-03-17 18:15:20 -03:00
// Construct location using position (NEU) from ekf_origin for the given altitude frame
2019-03-14 22:43:43 -03:00
Location : : Location ( int32_t latitude , int32_t longitude , int32_t alt_in_cm , AltFrame frame )
2015-08-10 02:25:15 -03:00
{
2023-12-13 19:20:16 -04:00
// make sure we know what size the Location object is:
ASSERT_STORAGE_SIZE ( Location , 16 ) ;
2019-01-01 19:57:48 -04:00
zero ( ) ;
2015-08-10 02:25:15 -03:00
lat = latitude ;
lng = longitude ;
2016-04-28 07:52:13 -03:00
set_alt_cm ( alt_in_cm , frame ) ;
2015-08-10 02:25:15 -03:00
}
2023-09-25 03:18:31 -03:00
# if AP_AHRS_ENABLED
2021-03-17 18:15:20 -03:00
Location : : Location ( const Vector3f & ekf_offset_neu , AltFrame frame )
2015-08-10 02:25:15 -03:00
{
2021-06-09 05:25:59 -03:00
zero ( ) ;
2015-08-10 02:25:15 -03:00
// store alt and alt frame
2021-03-17 18:15:20 -03:00
set_alt_cm ( ekf_offset_neu . z , frame ) ;
2015-08-10 02:25:15 -03:00
// calculate lat, lon
2018-05-29 22:28:53 -03:00
Location ekf_origin ;
if ( AP : : ahrs ( ) . get_origin ( ekf_origin ) ) {
lat = ekf_origin . lat ;
lng = ekf_origin . lng ;
2021-06-30 20:18:33 -03:00
offset ( ekf_offset_neu . x * 0.01 , ekf_offset_neu . y * 0.01 ) ;
}
}
2023-09-25 03:18:31 -03:00
# endif // AP_AHRS_ENABLED
2021-06-30 20:18:33 -03:00
2019-03-14 22:43:43 -03:00
void Location : : set_alt_cm ( int32_t alt_cm , AltFrame frame )
2015-08-10 02:25:15 -03:00
{
alt = alt_cm ;
2019-01-01 19:57:48 -04:00
relative_alt = false ;
terrain_alt = false ;
origin_alt = false ;
2015-08-10 02:25:15 -03:00
switch ( frame ) {
2019-03-14 22:43:43 -03:00
case AltFrame : : ABSOLUTE :
2015-08-10 02:25:15 -03:00
// do nothing
break ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_HOME :
2019-01-01 19:57:48 -04:00
relative_alt = true ;
2015-08-10 02:25:15 -03:00
break ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_ORIGIN :
2019-01-01 19:57:48 -04:00
origin_alt = true ;
2015-08-10 02:25:15 -03:00
break ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_TERRAIN :
2015-08-10 02:25:15 -03:00
// we mark it as a relative altitude, as it doesn't have
// home alt added
2019-01-01 19:57:48 -04:00
relative_alt = true ;
terrain_alt = true ;
2015-08-10 02:25:15 -03:00
break ;
}
}
// converts altitude to new frame
2019-03-14 22:43:43 -03:00
bool Location : : change_alt_frame ( AltFrame desired_frame )
2015-08-10 02:25:15 -03:00
{
int32_t new_alt_cm ;
if ( ! get_alt_cm ( desired_frame , new_alt_cm ) ) {
return false ;
}
2016-04-28 07:52:13 -03:00
set_alt_cm ( new_alt_cm , desired_frame ) ;
2015-08-10 02:25:15 -03:00
return true ;
}
// get altitude frame
2019-03-14 22:43:43 -03:00
Location : : AltFrame Location : : get_alt_frame ( ) const
2015-08-10 02:25:15 -03:00
{
2019-01-01 19:57:48 -04:00
if ( terrain_alt ) {
2019-03-14 22:43:43 -03:00
return AltFrame : : ABOVE_TERRAIN ;
2015-08-10 02:25:15 -03:00
}
2019-01-01 19:57:48 -04:00
if ( origin_alt ) {
2019-03-14 22:43:43 -03:00
return AltFrame : : ABOVE_ORIGIN ;
2015-08-10 02:25:15 -03:00
}
2019-01-01 19:57:48 -04:00
if ( relative_alt ) {
2019-03-14 22:43:43 -03:00
return AltFrame : : ABOVE_HOME ;
2015-08-10 02:25:15 -03:00
}
2019-03-14 22:43:43 -03:00
return AltFrame : : ABSOLUTE ;
2015-08-10 02:25:15 -03:00
}
/// get altitude in desired frame
2019-03-14 22:43:43 -03:00
bool Location : : get_alt_cm ( AltFrame desired_frame , int32_t & ret_alt_cm ) const
2015-08-10 02:25:15 -03:00
{
2018-07-25 22:40:05 -03:00
# if CONFIG_HAL_BOARD == HAL_BOARD_SITL
2019-06-15 04:59:32 -03:00
if ( ! initialised ( ) ) {
2021-05-28 04:44:46 -03:00
AP_HAL : : panic ( " Should not be called on invalid location: Location cannot be (0, 0, 0) " ) ;
2018-07-25 22:40:05 -03:00
}
# endif
2019-03-14 22:43:43 -03:00
Location : : AltFrame frame = get_alt_frame ( ) ;
2015-08-10 02:25:15 -03:00
// shortcut if desired and underlying frame are the same
if ( desired_frame = = frame ) {
ret_alt_cm = alt ;
return true ;
}
// check for terrain altitude
2016-05-20 16:28:46 -03:00
float alt_terr_cm = 0 ;
2019-03-14 22:43:43 -03:00
if ( frame = = AltFrame : : ABOVE_TERRAIN | | desired_frame = = AltFrame : : ABOVE_TERRAIN ) {
2016-05-20 16:28:46 -03:00
# if AP_TERRAIN_AVAILABLE
2021-02-12 23:46:34 -04:00
AP_Terrain * terrain = AP : : terrain ( ) ;
if ( terrain = = nullptr ) {
return false ;
}
2022-01-31 00:35:06 -04:00
if ( ! terrain - > height_amsl ( * this , alt_terr_cm ) ) {
2015-08-10 02:25:15 -03:00
return false ;
}
// convert terrain alt to cm
alt_terr_cm * = 100.0f ;
2016-05-20 16:28:46 -03:00
# else
return false ;
# endif
2015-08-10 02:25:15 -03:00
}
// convert alt to absolute
2018-07-25 22:40:05 -03:00
int32_t alt_abs = 0 ;
2015-08-10 02:25:15 -03:00
switch ( frame ) {
2019-03-14 22:43:43 -03:00
case AltFrame : : ABSOLUTE :
2015-08-10 02:25:15 -03:00
alt_abs = alt ;
break ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_HOME :
2023-09-25 03:18:31 -03:00
# if AP_AHRS_ENABLED
2018-05-29 22:28:53 -03:00
if ( ! AP : : ahrs ( ) . home_is_set ( ) ) {
2018-05-29 21:34:09 -03:00
return false ;
}
2018-05-29 22:28:53 -03:00
alt_abs = alt + AP : : ahrs ( ) . get_home ( ) . alt ;
2023-09-25 03:18:31 -03:00
# else
return false ;
# endif // AP_AHRS_ENABLED
2015-08-10 02:25:15 -03:00
break ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_ORIGIN :
2023-09-25 03:18:31 -03:00
# if AP_AHRS_ENABLED
2015-08-10 02:25:15 -03:00
{
// fail if we cannot get ekf origin
Location ekf_origin ;
2018-05-29 22:28:53 -03:00
if ( ! AP : : ahrs ( ) . get_origin ( ekf_origin ) ) {
2015-08-10 02:25:15 -03:00
return false ;
}
alt_abs = alt + ekf_origin . alt ;
}
break ;
2023-09-25 03:18:31 -03:00
# else
return false ;
# endif // AP_AHRS_ENABLED
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_TERRAIN :
2015-08-10 02:25:15 -03:00
alt_abs = alt + alt_terr_cm ;
break ;
}
// convert absolute to desired frame
switch ( desired_frame ) {
2019-03-14 22:43:43 -03:00
case AltFrame : : ABSOLUTE :
2015-08-10 02:25:15 -03:00
ret_alt_cm = alt_abs ;
return true ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_HOME :
2023-09-25 03:18:31 -03:00
# if AP_AHRS_ENABLED
2018-05-29 22:28:53 -03:00
if ( ! AP : : ahrs ( ) . home_is_set ( ) ) {
2018-05-29 21:34:09 -03:00
return false ;
}
2018-05-29 22:28:53 -03:00
ret_alt_cm = alt_abs - AP : : ahrs ( ) . get_home ( ) . alt ;
2023-09-25 03:18:31 -03:00
# else
return false ;
# endif // AP_AHRS_ENABLED
2015-08-10 02:25:15 -03:00
return true ;
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_ORIGIN :
2023-09-25 03:18:31 -03:00
# if AP_AHRS_ENABLED
2015-08-10 02:25:15 -03:00
{
// fail if we cannot get ekf origin
Location ekf_origin ;
2018-05-29 22:28:53 -03:00
if ( ! AP : : ahrs ( ) . get_origin ( ekf_origin ) ) {
2015-08-10 02:25:15 -03:00
return false ;
}
ret_alt_cm = alt_abs - ekf_origin . alt ;
return true ;
}
2023-09-25 03:18:31 -03:00
# else
return false ;
# endif // AP_AHRS_ENABLED
2019-03-14 22:43:43 -03:00
case AltFrame : : ABOVE_TERRAIN :
2015-08-10 02:25:15 -03:00
ret_alt_cm = alt_abs - alt_terr_cm ;
return true ;
}
2021-06-19 12:04:17 -03:00
return false ; // LCOV_EXCL_LINE - not reachable
2015-08-10 02:25:15 -03:00
}
2024-04-11 06:14:02 -03:00
bool Location : : get_alt_m ( AltFrame desired_frame , float & ret_alt ) const
{
int32_t ret_alt_cm ;
if ( ! get_alt_cm ( desired_frame , ret_alt_cm ) ) {
return false ;
}
ret_alt = ret_alt_cm * 0.01 ;
return true ;
}
2015-08-10 02:25:15 -03:00
2023-09-25 03:18:31 -03:00
# if AP_AHRS_ENABLED
2024-06-05 23:39:38 -03:00
// converts location to a vector from origin; if this method returns
// false then vec_ne is unmodified
2024-06-06 01:43:45 -03:00
template < typename T >
bool Location : : get_vector_xy_from_origin_NE ( T & vec_ne ) const
2015-08-10 02:25:15 -03:00
{
Location ekf_origin ;
2018-05-29 22:28:53 -03:00
if ( ! AP : : ahrs ( ) . get_origin ( ekf_origin ) ) {
2015-08-10 02:25:15 -03:00
return false ;
}
2017-12-13 22:09:59 -04:00
vec_ne . x = ( lat - ekf_origin . lat ) * LATLON_TO_CM ;
2021-06-30 20:18:33 -03:00
vec_ne . y = diff_longitude ( lng , ekf_origin . lng ) * LATLON_TO_CM * longitude_scale ( ( lat + ekf_origin . lat ) / 2 ) ;
2015-08-10 02:25:15 -03:00
return true ;
}
2024-06-06 01:43:45 -03:00
// define for float and position vectors
template bool Location : : get_vector_xy_from_origin_NE < Vector2f > ( Vector2f & vec_ne ) const ;
# if HAL_WITH_POSTYPE_DOUBLE
template bool Location : : get_vector_xy_from_origin_NE < Vector2p > ( Vector2p & vec_ne ) const ;
# endif
2024-06-05 23:39:38 -03:00
// converts location to a vector from origin; if this method returns
// false then vec_neu is unmodified
2024-06-06 01:43:45 -03:00
template < typename T >
bool Location : : get_vector_from_origin_NEU ( T & vec_neu ) const
2015-08-10 02:25:15 -03:00
{
// convert altitude
int32_t alt_above_origin_cm = 0 ;
2019-03-14 22:43:43 -03:00
if ( ! get_alt_cm ( AltFrame : : ABOVE_ORIGIN , alt_above_origin_cm ) ) {
2015-08-10 02:25:15 -03:00
return false ;
}
2024-06-05 23:39:38 -03:00
// convert lat, lon
if ( ! get_vector_xy_from_origin_NE ( vec_neu . xy ( ) ) ) {
return false ;
}
2015-08-10 02:25:15 -03:00
vec_neu . z = alt_above_origin_cm ;
return true ;
}
2024-06-06 01:43:45 -03:00
// define for float and position vectors
template bool Location : : get_vector_from_origin_NEU < Vector3f > ( Vector3f & vec_neu ) const ;
# if HAL_WITH_POSTYPE_DOUBLE
template bool Location : : get_vector_from_origin_NEU < Vector3p > ( Vector3p & vec_neu ) const ;
# endif
2023-09-25 03:18:31 -03:00
# endif // AP_AHRS_ENABLED
2015-08-10 02:25:15 -03:00
2022-04-23 03:04:19 -03:00
// return horizontal distance in meters between two locations
2023-02-02 18:58:38 -04:00
ftype Location : : get_distance ( const Location & loc2 ) const
2015-08-10 02:25:15 -03:00
{
2021-07-12 19:05:48 -03:00
ftype dlat = ( ftype ) ( loc2 . lat - lat ) ;
ftype dlng = ( ( ftype ) diff_longitude ( loc2 . lng , lng ) ) * longitude_scale ( ( lat + loc2 . lat ) / 2 ) ;
2016-04-16 06:58:46 -03:00
return norm ( dlat , dlng ) * LOCATION_SCALING_FACTOR ;
2015-08-10 02:25:15 -03:00
}
2021-09-18 20:13:07 -03:00
// return the altitude difference in meters taking into account alt frame.
2023-02-02 18:58:38 -04:00
bool Location : : get_alt_distance ( const Location & loc2 , ftype & distance ) const
2021-09-18 20:13:07 -03:00
{
int32_t alt1 , alt2 ;
if ( ! get_alt_cm ( AltFrame : : ABSOLUTE , alt1 ) | | ! loc2 . get_alt_cm ( AltFrame : : ABSOLUTE , alt2 ) ) {
return false ;
}
distance = ( alt1 - alt2 ) * 0.01 ;
return true ;
}
2019-04-08 09:22:38 -03:00
/*
return the distance in meters in North / East plane as a N / E vector
from loc1 to loc2
*/
Vector2f Location : : get_distance_NE ( const Location & loc2 ) const
{
return Vector2f ( ( loc2 . lat - lat ) * LOCATION_SCALING_FACTOR ,
2021-06-30 20:18:33 -03:00
diff_longitude ( loc2 . lng , lng ) * LOCATION_SCALING_FACTOR * longitude_scale ( ( loc2 . lat + lat ) / 2 ) ) ;
2019-04-08 09:22:38 -03:00
}
2021-09-18 20:13:07 -03:00
// return the distance in meters in North/East/Down plane as a N/E/D vector to loc2, NOT CONSIDERING ALT FRAME!
2019-04-08 10:27:31 -03:00
Vector3f Location : : get_distance_NED ( const Location & loc2 ) const
{
return Vector3f ( ( loc2 . lat - lat ) * LOCATION_SCALING_FACTOR ,
2021-06-30 20:18:33 -03:00
diff_longitude ( loc2 . lng , lng ) * LOCATION_SCALING_FACTOR * longitude_scale ( ( lat + loc2 . lat ) / 2 ) ,
2021-06-22 02:44:00 -03:00
( alt - loc2 . alt ) * 0.01 ) ;
}
// return the distance in meters in North/East/Down plane as a N/E/D vector to loc2
Vector3d Location : : get_distance_NED_double ( const Location & loc2 ) const
{
return Vector3d ( ( loc2 . lat - lat ) * double ( LOCATION_SCALING_FACTOR ) ,
2021-06-30 20:18:33 -03:00
diff_longitude ( loc2 . lng , lng ) * LOCATION_SCALING_FACTOR * longitude_scale ( ( lat + loc2 . lat ) / 2 ) ,
2021-06-22 02:44:00 -03:00
( alt - loc2 . alt ) * 0.01 ) ;
2019-04-08 10:27:31 -03:00
}
2024-03-02 21:01:25 -04:00
// return the distance in meters in North/East/Down plane as a N/E/D vector to loc2 considering alt frame, if altitude cannot be resolved down distance is 0
Vector3f Location : : get_distance_NED_alt_frame ( const Location & loc2 ) const
{
int32_t alt1 , alt2 = 0 ;
if ( ! get_alt_cm ( AltFrame : : ABSOLUTE , alt1 ) | | ! loc2 . get_alt_cm ( AltFrame : : ABSOLUTE , alt2 ) ) {
// one or both of the altitudes are invalid, don't do alt distance calc
alt1 = 0 , alt2 = 0 ;
}
return Vector3f ( ( loc2 . lat - lat ) * LOCATION_SCALING_FACTOR ,
diff_longitude ( loc2 . lng , lng ) * LOCATION_SCALING_FACTOR * longitude_scale ( ( loc2 . lat + lat ) / 2 ) ,
( alt1 - alt2 ) * 0.01 ) ;
}
2021-06-20 23:01:59 -03:00
Vector2d Location : : get_distance_NE_double ( const Location & loc2 ) const
{
return Vector2d ( ( loc2 . lat - lat ) * double ( LOCATION_SCALING_FACTOR ) ,
2021-06-30 20:18:33 -03:00
diff_longitude ( loc2 . lng , lng ) * double ( LOCATION_SCALING_FACTOR ) * longitude_scale ( ( lat + loc2 . lat ) / 2 ) ) ;
2021-06-20 23:01:59 -03:00
}
Vector2F Location : : get_distance_NE_ftype ( const Location & loc2 ) const
{
return Vector2F ( ( loc2 . lat - lat ) * ftype ( LOCATION_SCALING_FACTOR ) ,
2021-06-30 20:18:33 -03:00
diff_longitude ( loc2 . lng , lng ) * ftype ( LOCATION_SCALING_FACTOR ) * longitude_scale ( ( lat + loc2 . lat ) / 2 ) ) ;
2021-06-20 23:01:59 -03:00
}
2015-08-10 02:25:15 -03:00
// extrapolate latitude/longitude given distances (in meters) north and east
2021-07-09 01:58:09 -03:00
void Location : : offset_latlng ( int32_t & lat , int32_t & lng , ftype ofs_north , ftype ofs_east )
2015-08-10 02:25:15 -03:00
{
2019-11-05 20:56:23 -04:00
const int32_t dlat = ofs_north * LOCATION_SCALING_FACTOR_INV ;
2021-06-30 20:18:33 -03:00
const int64_t dlng = ( ofs_east * LOCATION_SCALING_FACTOR_INV ) / longitude_scale ( lat + dlat / 2 ) ;
2019-11-05 20:56:23 -04:00
lat + = dlat ;
2021-06-20 23:01:59 -03:00
lat = limit_lattitude ( lat ) ;
lng = wrap_longitude ( dlng + lng ) ;
2015-08-10 02:25:15 -03:00
}
2019-01-01 22:53:47 -04:00
2021-07-09 01:58:09 -03:00
// extrapolate latitude/longitude given distances (in meters) north and east
void Location : : offset ( ftype ofs_north , ftype ofs_east )
2021-06-22 02:44:00 -03:00
{
2021-07-09 01:58:09 -03:00
offset_latlng ( lat , lng , ofs_north , ofs_east ) ;
2021-06-22 02:44:00 -03:00
}
2023-09-06 01:03:29 -03:00
// extrapolate latitude/longitude given distances (in meters) north
// and east. Note that this is metres, *even for the altitude*.
void Location : : offset ( const Vector3p & ofs_ned )
{
offset_latlng ( lat , lng , ofs_ned . x , ofs_ned . y ) ;
alt + = - ofs_ned . z * 100 ; // m -> cm
}
2019-04-05 03:11:26 -03:00
/*
* extrapolate latitude / longitude given bearing and distance
* Note that this function is accurate to about 1 mm at a distance of
* 100 m . This function has the advantage that it works in relative
* positions , so it keeps the accuracy even when dealing with small
* distances and floating point numbers
*/
2021-07-12 19:05:48 -03:00
void Location : : offset_bearing ( ftype bearing_deg , ftype distance )
2019-04-05 03:11:26 -03:00
{
2021-07-12 19:05:48 -03:00
const ftype ofs_north = cosF ( radians ( bearing_deg ) ) * distance ;
const ftype ofs_east = sinF ( radians ( bearing_deg ) ) * distance ;
2019-04-05 03:11:26 -03:00
offset ( ofs_north , ofs_east ) ;
}
2020-07-01 03:10:55 -03:00
// extrapolate latitude/longitude given bearing, pitch and distance
2021-07-12 19:05:48 -03:00
void Location : : offset_bearing_and_pitch ( ftype bearing_deg , ftype pitch_deg , ftype distance )
2020-07-01 03:10:55 -03:00
{
2021-07-12 19:05:48 -03:00
const ftype ofs_north = cosF ( radians ( pitch_deg ) ) * cosF ( radians ( bearing_deg ) ) * distance ;
const ftype ofs_east = cosF ( radians ( pitch_deg ) ) * sinF ( radians ( bearing_deg ) ) * distance ;
2020-07-01 03:10:55 -03:00
offset ( ofs_north , ofs_east ) ;
2021-07-12 19:05:48 -03:00
const int32_t dalt = sinF ( radians ( pitch_deg ) ) * distance * 100.0f ;
2020-07-01 03:10:55 -03:00
alt + = dalt ;
}
2021-07-09 01:58:09 -03:00
ftype Location : : longitude_scale ( int32_t lat )
2019-03-06 03:27:27 -04:00
{
2021-07-09 01:58:09 -03:00
ftype scale = cosF ( lat * ( 1.0e-7 * DEG_TO_RAD ) ) ;
return MAX ( scale , 0.01 ) ;
2019-03-06 03:27:27 -04:00
}
2019-03-23 00:29:18 -03:00
/*
* convert invalid waypoint with useful data . return true if location changed
*/
bool Location : : sanitize ( const Location & defaultLoc )
{
bool has_changed = false ;
// convert lat/lng=0 to mean current point
if ( lat = = 0 & & lng = = 0 ) {
lat = defaultLoc . lat ;
lng = defaultLoc . lng ;
has_changed = true ;
}
// convert relative alt=0 to mean current alt
if ( alt = = 0 & & relative_alt ) {
2022-02-19 12:48:10 -04:00
int32_t defaultLoc_alt ;
if ( defaultLoc . get_alt_cm ( get_alt_frame ( ) , defaultLoc_alt ) ) {
alt = defaultLoc_alt ;
has_changed = true ;
}
2019-03-23 00:29:18 -03:00
}
// limit lat/lng to appropriate ranges
2019-04-08 10:51:23 -03:00
if ( ! check_latlng ( ) ) {
2019-03-23 00:29:18 -03:00
lat = defaultLoc . lat ;
lng = defaultLoc . lng ;
has_changed = true ;
}
return has_changed ;
}
2022-03-07 17:35:25 -04:00
// return bearing in radians from location to loc2, return is 0 to 2*Pi
2023-02-02 18:58:38 -04:00
ftype Location : : get_bearing ( const Location & loc2 ) const
2019-04-05 10:02:42 -03:00
{
2021-06-22 21:14:42 -03:00
const int32_t off_x = diff_longitude ( loc2 . lng , lng ) ;
2021-06-30 20:18:33 -03:00
const int32_t off_y = ( loc2 . lat - lat ) / loc2 . longitude_scale ( ( lat + loc2 . lat ) / 2 ) ;
2022-03-07 17:35:25 -04:00
ftype bearing = ( M_PI * 0.5 ) + atan2F ( - off_y , off_x ) ;
2019-04-05 10:02:42 -03:00
if ( bearing < 0 ) {
2022-03-07 17:35:25 -04:00
bearing + = 2 * M_PI ;
2019-04-05 10:02:42 -03:00
}
return bearing ;
}
2019-04-08 08:45:08 -03:00
/*
return true if lat and lng match . Ignores altitude and options
*/
bool Location : : same_latlon_as ( const Location & loc2 ) const
{
return ( lat = = loc2 . lat ) & & ( lng = = loc2 . lng ) ;
}
2019-04-08 10:51:23 -03:00
2023-02-15 00:49:40 -04:00
bool Location : : same_alt_as ( const Location & loc2 ) const
{
// fast path if the altitude frame is the same
if ( this - > get_alt_frame ( ) = = loc2 . get_alt_frame ( ) ) {
return this - > alt = = loc2 . alt ;
}
ftype alt_diff ;
bool have_diff = this - > get_alt_distance ( loc2 , alt_diff ) ;
const ftype tolerance = FLT_EPSILON ;
return have_diff & & ( fabsF ( alt_diff ) < tolerance ) ;
}
2019-04-08 10:51:23 -03:00
// return true when lat and lng are within range
bool Location : : check_latlng ( ) const
{
return check_lat ( lat ) & & check_lng ( lng ) ;
}
2019-04-09 05:24:22 -03:00
// see if location is past a line perpendicular to
// the line between point1 and point2 and passing through point2.
// If point1 is our previous waypoint and point2 is our target waypoint
// then this function returns true if we have flown past
// the target waypoint
bool Location : : past_interval_finish_line ( const Location & point1 , const Location & point2 ) const
{
return this - > line_path_proportion ( point1 , point2 ) > = 1.0f ;
}
2019-04-09 05:24:44 -03:00
/*
return the proportion we are along the path from point1 to
point2 , along a line parallel to point1 < - > point2 .
This will be more than 1 if we have passed point2
*/
float Location : : line_path_proportion ( const Location & point1 , const Location & point2 ) const
{
const Vector2f vec1 = point1 . get_distance_NE ( point2 ) ;
const Vector2f vec2 = point1 . get_distance_NE ( * this ) ;
2021-07-12 19:05:48 -03:00
const ftype dsquared = sq ( vec1 . x ) + sq ( vec1 . y ) ;
2019-04-09 05:24:44 -03:00
if ( dsquared < 0.001f ) {
// the two points are very close together
return 1.0f ;
}
return ( vec1 * vec2 ) / dsquared ;
}
2021-06-22 21:14:42 -03:00
/*
wrap longitude for - 180e7 to 180e7
*/
2021-06-20 23:01:59 -03:00
int32_t Location : : wrap_longitude ( int64_t lon )
2021-06-22 21:14:42 -03:00
{
if ( lon > 1800000000L ) {
2021-06-20 23:01:59 -03:00
lon = int32_t ( lon - 3600000000LL ) ;
2021-06-22 21:14:42 -03:00
} else if ( lon < - 1800000000L ) {
2021-06-20 23:01:59 -03:00
lon = int32_t ( lon + 3600000000LL ) ;
2021-06-22 21:14:42 -03:00
}
2021-06-20 23:01:59 -03:00
return int32_t ( lon ) ;
2021-06-22 21:14:42 -03:00
}
/*
get lon1 - lon2 , wrapping at - 180e7 to 180e7
*/
int32_t Location : : diff_longitude ( int32_t lon1 , int32_t lon2 )
{
if ( ( lon1 & 0x80000000 ) = = ( lon2 & 0x80000000 ) ) {
// common case of same sign
return lon1 - lon2 ;
}
int64_t dlon = int64_t ( lon1 ) - int64_t ( lon2 ) ;
if ( dlon > 1800000000LL ) {
dlon - = 3600000000LL ;
} else if ( dlon < - 1800000000LL ) {
dlon + = 3600000000LL ;
}
return int32_t ( dlon ) ;
}
2021-06-20 23:01:59 -03:00
/*
2023-10-11 04:41:51 -03:00
limit latitude to - 90e7 to 90e7
2021-06-20 23:01:59 -03:00
*/
int32_t Location : : limit_lattitude ( int32_t lat )
{
if ( lat > 900000000L ) {
lat = 1800000000LL - lat ;
} else if ( lat < - 900000000L ) {
lat = - ( 1800000000LL + lat ) ;
}
return lat ;
}
2021-03-19 04:57:36 -03:00
// update altitude and alt-frame base on this location's horizontal position between point1 and point2
// this location's lat,lon is used to calculate the alt of the closest point on the line between point1 and point2
// origin and destination's altitude frames must be the same
// this alt-frame will be updated to match the destination alt frame
void Location : : linearly_interpolate_alt ( const Location & point1 , const Location & point2 )
{
// new target's distance along the original track and then linear interpolate between the original origin and destination altitudes
set_alt_cm ( point1 . alt + ( point2 . alt - point1 . alt ) * constrain_float ( line_path_proportion ( point1 , point2 ) , 0.0f , 1.0f ) , point2 . get_alt_frame ( ) ) ;
}
2024-05-26 23:36:26 -03:00
# endif // HAL_BOOTLOADER_BUILD