LCOV - code coverage report
Current view: top level - AP_Common - Location.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 287 311 92.3 %
Date: 2026-09-09 11:02:08 Functions: 46 52 88.5 %

          Line data    Source code
       1             : /*
       2             :  * Location.cpp
       3             :  */
       4             : 
       5             : #include "Location.h"
       6             : 
       7             : #ifndef HAL_BOOTLOADER_BUILD
       8             : 
       9             : #include <AP_AHRS/AP_AHRS.h>
      10             : #include <AP_Terrain/AP_Terrain.h>
      11             : 
      12             : const Location definitely_zero{};
      13    83981569 : bool Location::is_zero(void) const
      14             : {
      15    83981569 :     return !memcmp(this, &definitely_zero, sizeof(*this));
      16             : }
      17             : 
      18  2250112989 : void Location::zero(void)
      19             : {
      20  2250112989 :     memset(this, 0, sizeof(*this));
      21  2250112989 : }
      22             : 
      23             : // Construct location using position (NEU) from ekf_origin for the given altitude frame
      24   126010199 : Location::Location(int32_t latitude, int32_t longitude, int32_t alt_in_cm, AltFrame frame)
      25             : {
      26             :     // make sure we know what size the Location object is:
      27             :     ASSERT_STORAGE_SIZE(Location, 16);
      28             : 
      29   126010199 :     zero();
      30   126010199 :     lat = latitude;
      31   126010199 :     lng = longitude;
      32   126010199 :     set_alt_cm(alt_in_cm, frame);
      33   126010199 : }
      34             : 
      35             : #if AP_AHRS_ENABLED
      36        3781 : Location::Location(const Vector3f &ekf_offset_neu_cm, AltFrame frame)
      37             : {
      38        3781 :     zero();
      39             : 
      40             :     // store alt and alt frame
      41        3781 :     set_alt_cm(ekf_offset_neu_cm.z, frame);
      42             : 
      43             :     // calculate lat, lon
      44        3781 :     Location ekf_origin;
      45        3781 :     if (AP::ahrs().get_origin(ekf_origin)) {
      46        3777 :         lat = ekf_origin.lat;
      47        3777 :         lng = ekf_origin.lng;
      48        3777 :         offset(ekf_offset_neu_cm.x * 0.01, ekf_offset_neu_cm.y * 0.01);
      49             :     }
      50        3781 : }
      51             : 
      52    10408135 : Location::Location(const Vector3d &ekf_offset_neu_cm, AltFrame frame)
      53             : {
      54    10408135 :     zero();
      55             : 
      56             :     // store alt and alt frame
      57    10408135 :     set_alt_cm(ekf_offset_neu_cm.z, frame);
      58             : 
      59             :     // calculate lat, lon
      60    10408135 :     Location ekf_origin;
      61    10408135 :     if (AP::ahrs().get_origin(ekf_origin)) {
      62    10408135 :         lat = ekf_origin.lat;
      63    10408135 :         lng = ekf_origin.lng;
      64    10408135 :         offset(ekf_offset_neu_cm.x * 0.01, ekf_offset_neu_cm.y * 0.01);
      65             :     }
      66    10408135 : }
      67             : 
      68             : // named constructors
      69           0 : Location Location::from_ekf_offset_NED_m(const Vector3f& ekf_offset_ned_m, AltFrame frame)
      70             : {
      71           0 :     const Vector3f ekf_offset_neu_cm(ekf_offset_ned_m.x * 100.0, ekf_offset_ned_m.y * 100.0, -ekf_offset_ned_m.z * 100.0);
      72           0 :     return Location(ekf_offset_neu_cm, frame);
      73             : }
      74             : 
      75    10408135 : Location Location::from_ekf_offset_NED_m(const Vector3d& ekf_offset_ned_m, AltFrame frame)
      76             : {
      77    10408135 :     const Vector3d ekf_offset_neu_cm(ekf_offset_ned_m.x * 100.0, ekf_offset_ned_m.y * 100.0, -ekf_offset_ned_m.z * 100.0);
      78    10408135 :     return Location(ekf_offset_neu_cm, frame);
      79             : }
      80             : 
      81             : #endif  // AP_AHRS_ENABLED
      82             : 
      83   266589086 : void Location::set_alt_cm(int32_t alt_cm, AltFrame frame)
      84             : {
      85   266589086 :     alt = alt_cm;
      86   266589086 :     relative_alt = false;
      87   266589086 :     terrain_alt = false;
      88   266589086 :     origin_alt = false;
      89   266589086 :     switch (frame) {
      90   196983084 :         case AltFrame::ABSOLUTE:
      91             :             // do nothing
      92   196983084 :             break;
      93    28737970 :         case AltFrame::ABOVE_HOME:
      94    28737970 :             relative_alt = true;
      95    28737970 :             break;
      96    40804065 :         case AltFrame::ABOVE_ORIGIN:
      97    40804065 :             origin_alt = true;
      98    40804065 :             break;
      99       63960 :         case AltFrame::ABOVE_TERRAIN:
     100             :             // we mark it as a relative altitude, as it doesn't have
     101             :             // home alt added
     102       63960 :             relative_alt = true;
     103       63960 :             terrain_alt = true;
     104       63960 :             break;
     105             :     }
     106   266589086 : }
     107             : 
     108             : // converts altitude to new frame
     109    27631744 : bool Location::change_alt_frame(AltFrame desired_frame)
     110             : {
     111             :     int32_t new_alt_cm;
     112    27631744 :     if (!get_alt_cm(desired_frame, new_alt_cm)) {
     113      185871 :         return false;
     114             :     }
     115    27445873 :     set_alt_cm(new_alt_cm, desired_frame);
     116    27445873 :     return true;
     117             : }
     118             : 
     119      186798 : void Location::copy_alt_from(const Location &other)
     120             : {
     121      186798 :     alt = other.alt;
     122      186798 :     relative_alt = other.relative_alt;
     123      186798 :     terrain_alt = other.terrain_alt;
     124      186798 :     origin_alt = other.origin_alt;
     125      186798 : }
     126             : 
     127             : // get altitude frame
     128    49251038 : Location::AltFrame Location::get_alt_frame() const
     129             : {
     130    49251038 :     if (terrain_alt) {
     131             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
     132      421942 :         if (!relative_alt) {
     133           0 :             AP_HAL::panic("terrain loc must be relative_alt1");
     134             :         }
     135             : #endif
     136      421955 :         return AltFrame::ABOVE_TERRAIN;
     137             :     }
     138    48829083 :     if (origin_alt) {
     139    27558144 :         return AltFrame::ABOVE_ORIGIN;
     140             :     }
     141    21270939 :     if (relative_alt) {
     142     8800376 :         return AltFrame::ABOVE_HOME;
     143             :     }
     144    12470563 :     return AltFrame::ABSOLUTE;
     145             : }
     146             : 
     147             : /// get altitude in desired frame.  Must not change ret_alt_cm unless true is returned!
     148    47652619 : bool Location::get_alt_cm(AltFrame desired_frame, int32_t &ret_alt_cm) const
     149             : {
     150             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
     151    47652565 :     if (!initialised()) {
     152           0 :         AP_HAL::panic("Should not be called on invalid location: Location cannot be (0, 0, 0)");
     153             :     }
     154    47652565 :     if (terrain_alt && !relative_alt) {
     155           0 :         AP_HAL::panic("terrain loc must be relative_alt2");
     156             :     }
     157             : #endif
     158    47652619 :     Location::AltFrame frame = get_alt_frame();
     159             : 
     160             :     // shortcut if desired and underlying frame are the same
     161    47652616 :     if (desired_frame == frame) {
     162    11077831 :         ret_alt_cm = alt;
     163    11077831 :         return true;
     164             :     }
     165             : 
     166             :     // check for terrain altitude
     167    36574785 :     float alt_terr_cm = 0;
     168    36574785 :     if (frame == AltFrame::ABOVE_TERRAIN || desired_frame == AltFrame::ABOVE_TERRAIN) {
     169             : #if AP_TERRAIN_AVAILABLE
     170     8718139 :         AP_Terrain *terrain = AP::terrain();
     171     8718143 :         if (terrain == nullptr) {
     172           0 :             return false;
     173             :         }
     174     8718143 :         if (!terrain->height_amsl(*this, alt_terr_cm)) {
     175      684795 :             return false;
     176             :         }
     177             :         // convert terrain alt to cm
     178     8033348 :         alt_terr_cm *= 100.0f;
     179             : #else
     180             :         return false;
     181             : #endif
     182             :     }
     183             : 
     184             :     // convert alt to absolute
     185    35889994 :     int32_t alt_abs = 0;
     186    35889994 :     switch (frame) {
     187      311742 :         case AltFrame::ABSOLUTE:
     188      311742 :             alt_abs = alt;
     189      311742 :             break;
     190     7708228 :         case AltFrame::ABOVE_HOME:
     191             : #if AP_AHRS_ENABLED
     192     7708228 :             if (!AP::ahrs().home_is_set()) {
     193         418 :                 return false;
     194             :             }
     195     7707810 :             alt_abs = alt + AP::ahrs().get_home().alt;
     196             : #else
     197             :             return false;
     198             : #endif  // AP_AHRS_ENABLED
     199     7707810 :             break;
     200    27558132 :         case AltFrame::ABOVE_ORIGIN:
     201             : #if AP_AHRS_ENABLED
     202             :             {
     203             :                 // fail if we cannot get ekf origin
     204    27558132 :                 Location ekf_origin;
     205    27558132 :                 if (!AP::ahrs().get_origin(ekf_origin)) {
     206      185819 :                     return false;
     207             :                 }
     208    27372313 :                 alt_abs = alt + ekf_origin.alt;
     209             :             }
     210    27372313 :             break;
     211             : #else
     212             :             return false;
     213             : #endif  // AP_AHRS_ENABLED
     214      311892 :         case AltFrame::ABOVE_TERRAIN:
     215      311892 :             alt_abs = alt + alt_terr_cm;
     216      311892 :             break;
     217             :     }
     218             : 
     219             :     // convert absolute to desired frame
     220    35703757 :     switch (desired_frame) {
     221      913922 :         case AltFrame::ABSOLUTE:
     222      913922 :             ret_alt_cm = alt_abs;
     223      913922 :             return true;
     224    26583423 :         case AltFrame::ABOVE_HOME:
     225             : #if AP_AHRS_ENABLED
     226    26583423 :             if (!AP::ahrs().home_is_set()) {
     227         257 :                 return false;
     228             :             }
     229    26583166 :             ret_alt_cm = alt_abs - AP::ahrs().get_home().alt;
     230             : #else
     231             :             return false;
     232             : #endif  // AP_AHRS_ENABLED
     233    26583165 :             return true;
     234      485080 :         case AltFrame::ABOVE_ORIGIN:
     235             : #if AP_AHRS_ENABLED
     236             :             {
     237             :                 // fail if we cannot get ekf origin
     238      485080 :                 Location ekf_origin;
     239      485080 :                 if (!AP::ahrs().get_origin(ekf_origin)) {
     240        3602 :                     return false;
     241             :                 }
     242      481478 :                 ret_alt_cm = alt_abs - ekf_origin.alt;
     243      481478 :                 return true;
     244             :             }
     245             : #else
     246             :             return false;
     247             : #endif  // AP_AHRS_ENABLED
     248     7721332 :         case AltFrame::ABOVE_TERRAIN:
     249     7721332 :             ret_alt_cm = alt_abs - alt_terr_cm;
     250     7721332 :             return true;
     251             :     }
     252             :     return false;  // LCOV_EXCL_LINE  - not reachable
     253             : }
     254             : //  Must not change ret_alt_cm unless true is returned!
     255    13586334 : bool Location::get_alt_m(AltFrame desired_frame, float &ret_alt) const
     256             : {
     257             :     int32_t ret_alt_cm;
     258    13586334 :     if (!get_alt_cm(desired_frame, ret_alt_cm)) {
     259      685155 :         return false;
     260             :     }
     261    12901179 :     ret_alt = ret_alt_cm * 0.01;
     262    12901179 :     return true;
     263             : }
     264             : 
     265             : #if AP_AHRS_ENABLED
     266             : // converts location to a vector from origin; if this method returns
     267             : // false then vec_ne is unmodified
     268             : template<typename T>
     269   271054938 : bool Location::get_vector_xy_from_origin_NE_cm(T &vec_ne) const
     270             : {
     271   271054938 :     Location ekf_origin;
     272   271054937 :     if (!AP::ahrs().get_origin(ekf_origin)) {
     273      447959 :         return false;
     274             :     }
     275   270606978 :     vec_ne.x = (lat-ekf_origin.lat) * LATLON_TO_CM;
     276   270606978 :     vec_ne.y = diff_longitude(lng,ekf_origin.lng) * LATLON_TO_CM * longitude_scale((lat+ekf_origin.lat)/2);
     277   270606975 :     return true;
     278             : }
     279             : 
     280             : // define for float and position vectors
     281             : template bool Location::get_vector_xy_from_origin_NE_cm<Vector2f>(Vector2f &vec_ne) const;
     282             : #if HAL_WITH_POSTYPE_DOUBLE
     283             : template bool Location::get_vector_xy_from_origin_NE_cm<Vector2p>(Vector2p &vec_ne) const;
     284             : #endif
     285             : 
     286             : // converts location to a vector from origin; if this method returns
     287             : // false then vec_neu is unmodified
     288             : template<typename T>
     289       25949 : bool Location::get_vector_from_origin_NEU_cm(T &vec_neu) const
     290             : {
     291             :     // convert altitude
     292       25949 :     int32_t alt_above_origin_cm = 0;
     293       25949 :     if (!get_alt_cm(AltFrame::ABOVE_ORIGIN, alt_above_origin_cm)) {
     294         823 :         return false;
     295             :     }
     296             : 
     297             :     // convert lat, lon
     298       25126 :     if (!get_vector_xy_from_origin_NE_cm(vec_neu.xy())) {
     299           0 :         return false;
     300             :     }
     301             : 
     302       25126 :     vec_neu.z = alt_above_origin_cm;
     303             : 
     304       25126 :     return true;
     305             : }
     306             : template<typename T>
     307           0 : bool Location::get_vector_from_origin_NEU(T &vec_neu) const
     308             : {
     309           0 :     return get_vector_from_origin_NEU_cm(vec_neu);
     310             : }
     311             : 
     312             : // define for float and position vectors
     313             : template bool Location::get_vector_from_origin_NEU_cm<Vector3f>(Vector3f &vec_neu) const;
     314             : template bool Location::get_vector_from_origin_NEU<Vector3f>(Vector3f &vec_neu) const;
     315             : #if HAL_WITH_POSTYPE_DOUBLE
     316             : template bool Location::get_vector_from_origin_NEU_cm<Vector3p>(Vector3p &vec_neu) const;
     317             : template bool Location::get_vector_from_origin_NEU<Vector3p>(Vector3p &vec_neu) const;
     318             : #endif
     319             : 
     320             : template<typename T>
     321        1793 : bool Location::get_vector_xy_from_origin_NE_m(T &vec_ne) const
     322             : {
     323        1793 :     if (!get_vector_xy_from_origin_NE_cm(vec_ne)) {
     324           8 :         return false;
     325             :     }
     326        1785 :     vec_ne *= 0.01;
     327        1785 :     return true;
     328             : }
     329             : template bool Location::get_vector_xy_from_origin_NE_m<Vector2f>(Vector2f &vec_ne) const;
     330             : #if HAL_WITH_POSTYPE_DOUBLE
     331             : template bool Location::get_vector_xy_from_origin_NE_m<Vector2p>(Vector2p &vec_ne) const;
     332             : #endif
     333             : 
     334             : template<typename T>
     335          21 : bool Location::get_vector_from_origin_NED_m(T &vec_ned) const
     336             : {
     337          21 :     if (!get_vector_from_origin_NEU_cm(vec_ned)) {
     338           0 :         return false;
     339             :     }
     340          21 :     vec_ned *= 0.01;
     341          21 :     vec_ned.z *= -1.0;
     342          21 :     return true;
     343             : }
     344             : // define for float and position vectors
     345             : template bool Location::get_vector_from_origin_NED_m<Vector3f>(Vector3f &vec_ned) const;
     346             : #if HAL_WITH_POSTYPE_DOUBLE
     347             : template bool Location::get_vector_from_origin_NED_m<Vector3p>(Vector3p &vec_ned) const;
     348             : #endif
     349             : 
     350             : template<typename T>
     351         919 : bool Location::get_vector_from_origin_NEU_m(T &vec_neu) const
     352             : {
     353         919 :     if (!get_vector_from_origin_NEU_cm(vec_neu)) {
     354         107 :         return false;
     355             :     }
     356         812 :     vec_neu *= 0.01;
     357         812 :     return true;
     358             : }
     359             : // define for float and position vectors
     360             : template bool Location::get_vector_from_origin_NEU_m<Vector3f>(Vector3f &vec_neu) const;
     361             : #if HAL_WITH_POSTYPE_DOUBLE
     362             : template bool Location::get_vector_from_origin_NEU_m<Vector3p>(Vector3p &vec_neu) const;
     363             : #endif
     364             : 
     365             : 
     366             : #endif  // AP_AHRS_ENABLED
     367             : 
     368             : // return horizontal distance in meters between two locations
     369     3708376 : ftype Location::get_distance(const Location &loc2) const
     370             : {
     371     3708376 :     ftype dlat = (ftype)(loc2.lat - lat);
     372     3708376 :     ftype dlng = ((ftype)diff_longitude(loc2.lng,lng)) * longitude_scale((lat+loc2.lat)/2);
     373     3708375 :     return norm(dlat, dlng) * LOCATION_SCALING_FACTOR;
     374             : }
     375             : 
     376             : /**
     377             :  * return the altitude difference in meters taking into account alt
     378             :  * frame.  if loc2 is below this location then "distance" will be
     379             :  * positive.  ie. this method returns how far above loc2 this location
     380             :  * is.
     381             :  *
     382             :  * @param loc2 [in] location to compare against
     383             :  * @param distance [out] the distance in meters between this location and loc2
     384             :  * 
     385             :  * @return true if the distance was calculated successfully, 
     386             :  *         false if the altitude could not be resolved
     387             :  * 
     388             :  */
     389      138098 : bool Location::get_height_above(const Location &loc2, ftype &distance) const
     390             : {
     391      138098 :     if (get_alt_frame() == loc2.get_alt_frame()) {
     392      137512 :         switch (get_alt_frame()) {
     393      137438 :         case AltFrame::ABSOLUTE:
     394             :         case AltFrame::ABOVE_HOME:
     395             :         case AltFrame::ABOVE_ORIGIN:
     396             :             // all of these use the same reference
     397      137438 :             distance = (alt - loc2.alt) * 0.01;
     398      137438 :             return true;
     399          74 :         case AltFrame::ABOVE_TERRAIN:
     400             :             // 1m above terrain here is not the same as 1m above
     401             :             // terrain at loc2, so convert both to absolute and then
     402             :             // subtract.
     403          74 :             break;
     404             :         }
     405             :     }
     406             : 
     407             :     int32_t alt1, alt2;
     408         660 :     if (!get_alt_cm(AltFrame::ABSOLUTE, alt1) || !loc2.get_alt_cm(AltFrame::ABSOLUTE, alt2)) {
     409          19 :         return false;
     410             :     }
     411         641 :     distance = (alt1 - alt2) * 0.01;
     412         641 :     return true;
     413             : }
     414             : 
     415             : /*
     416             :   return the distance in meters in North/East plane as a N/E vector
     417             :   from loc1 to loc2
     418             :  */
     419  1018334479 : Vector2f Location::get_distance_NE(const Location &loc2) const
     420             : {
     421  2036668850 :     return Vector2f((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
     422  1018334479 :                     diff_longitude(loc2.lng,lng) * LOCATION_SCALING_FACTOR * longitude_scale((loc2.lat+lat)/2));
     423             : }
     424             : 
     425             : // return the distance in meters in North/East/Down plane as a N/E/D vector to loc2, NOT CONSIDERING ALT FRAME!
     426      246454 : Vector3f Location::get_distance_NED(const Location &loc2) const
     427             : {
     428      739362 :     return Vector3f((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
     429      246454 :                     diff_longitude(loc2.lng,lng) * LOCATION_SCALING_FACTOR * longitude_scale((lat+loc2.lat)/2),
     430      492908 :                     (alt - loc2.alt) * 0.01);
     431             : }
     432             : 
     433    36707525 : Vector3p Location::get_distance_NED_postype(const Location &loc2) const
     434             : {
     435    36707525 :     return Vector3p((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
     436    36707525 :                     diff_longitude(loc2.lng,lng) * LOCATION_SCALING_FACTOR * longitude_scale((lat+loc2.lat)/2),
     437    73415050 :                     (alt - loc2.alt) * 0.01);
     438             : }
     439             : 
     440             : // return the distance in meters in North/East/Down plane as a N/E/D vector to loc2
     441   167668581 : Vector3d Location::get_distance_NED_double(const Location &loc2) const
     442             : {
     443   167668581 :     return Vector3d((loc2.lat - lat) * double(LOCATION_SCALING_FACTOR),
     444   167668581 :                     diff_longitude(loc2.lng,lng) * LOCATION_SCALING_FACTOR * longitude_scale((lat+loc2.lat)/2),
     445   335337162 :                     (alt - loc2.alt) * 0.01);
     446             : }
     447             : 
     448             : // 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
     449          56 : Vector3f Location::get_distance_NED_alt_frame(const Location &loc2) const
     450             : {
     451          56 :     int32_t alt1, alt2 = 0;
     452          56 :     if (!get_alt_cm(AltFrame::ABSOLUTE, alt1) || !loc2.get_alt_cm(AltFrame::ABSOLUTE, alt2)) {
     453             :         // one or both of the altitudes are invalid, don't do alt distance calc
     454           0 :         alt1 = 0, alt2 = 0;
     455             :     }
     456         168 :     return Vector3f((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
     457          56 :                     diff_longitude(loc2.lng,lng) * LOCATION_SCALING_FACTOR * longitude_scale((loc2.lat+lat)/2),
     458         112 :                     (alt1 - alt2) * 0.01);
     459             : }
     460             : 
     461   399082419 : Vector2d Location::get_distance_NE_double(const Location &loc2) const
     462             : {
     463   399082419 :     return Vector2d((loc2.lat - lat) * double(LOCATION_SCALING_FACTOR),
     464   798164838 :                     diff_longitude(loc2.lng,lng) * double(LOCATION_SCALING_FACTOR) * longitude_scale((lat+loc2.lat)/2));
     465             : }
     466             : 
     467    82249557 : Vector2p Location::get_distance_NE_postype(const Location &loc2) const
     468             : {
     469    82249557 :     return Vector2p((loc2.lat - lat) * double(LOCATION_SCALING_FACTOR),
     470   164499114 :                     diff_longitude(loc2.lng,lng) * double(LOCATION_SCALING_FACTOR) * longitude_scale((lat+loc2.lat)/2));
     471             : }
     472             : 
     473     1641296 : Vector2F Location::get_distance_NE_ftype(const Location &loc2) const
     474             : {
     475     1641296 :     return Vector2F((loc2.lat - lat) * ftype(LOCATION_SCALING_FACTOR),
     476     3282592 :                     diff_longitude(loc2.lng,lng) * ftype(LOCATION_SCALING_FACTOR) * longitude_scale((lat+loc2.lat)/2));
     477             : }
     478             : 
     479             : // extrapolate latitude/longitude given distances (in meters) north and east
     480  1761066090 : void Location::offset_latlng(int32_t &lat, int32_t &lng, ftype ofs_north, ftype ofs_east)
     481             : {
     482  1761066090 :     const int32_t dlat = ofs_north * LOCATION_SCALING_FACTOR_INV;
     483  1761066090 :     const int64_t dlng = (ofs_east * LOCATION_SCALING_FACTOR_INV) / longitude_scale(lat+dlat/2);
     484  1761064822 :     lat += dlat;
     485  1761064822 :     lat = limit_lattitude(lat);
     486  1761064399 :     lng = wrap_longitude(dlng+lng);
     487  1761064211 : }
     488             : 
     489             : // extrapolate latitude/longitude given distances (in meters) north and east
     490  1760996336 : void Location::offset(ftype ofs_north, ftype ofs_east)
     491             : {
     492  1760996336 :     offset_latlng(lat, lng, ofs_north, ofs_east);
     493  1760994816 : }
     494             : 
     495             : // extrapolate latitude/longitude given distances (in meters) north
     496             : // and east. Note that this is metres, *even for the altitude*.
     497       64227 : void Location::offset(const Vector3p &ofs_ned)
     498             : {
     499       64227 :     offset_latlng(lat, lng, ofs_ned.x, ofs_ned.y);
     500       64227 :     alt += -ofs_ned.z * 100;  // m -> cm
     501       64227 : }
     502             : 
     503             : /*
     504             :  *  extrapolate latitude/longitude given bearing and distance
     505             :  * Note that this function is accurate to about 1mm at a distance of
     506             :  * 100m. This function has the advantage that it works in relative
     507             :  * positions, so it keeps the accuracy even when dealing with small
     508             :  * distances and floating point numbers
     509             :  */
     510     5416995 : void Location::offset_bearing(ftype bearing_deg, ftype distance)
     511             : {
     512     5416995 :     const ftype ofs_north = cosF(radians(bearing_deg)) * distance;
     513     5416993 :     const ftype ofs_east  = sinF(radians(bearing_deg)) * distance;
     514     5416993 :     offset(ofs_north, ofs_east);
     515     5416984 : }
     516             : 
     517             : // extrapolate latitude/longitude given bearing, pitch and distance
     518         662 : void Location::offset_bearing_and_pitch(ftype bearing_deg, ftype pitch_deg, ftype distance)
     519             : {
     520         662 :     const ftype ofs_north =  cosF(radians(pitch_deg)) * cosF(radians(bearing_deg)) * distance;
     521         662 :     const ftype ofs_east  =  cosF(radians(pitch_deg)) * sinF(radians(bearing_deg)) * distance;
     522         662 :     offset(ofs_north, ofs_east);
     523         662 :     const int32_t dalt =  sinF(radians(pitch_deg)) * distance *100.0f;
     524         662 :     alt += dalt; 
     525         662 : }
     526             : 
     527             : 
     528  3743240217 : ftype Location::longitude_scale(int32_t lat)
     529             : {
     530  3743240217 :     ftype scale = cosF(lat * (1.0e-7 * DEG_TO_RAD));
     531  3743238845 :     return MAX(scale, 0.01);
     532             : }
     533             : 
     534             : /*
     535             :  * convert invalid waypoint with useful data. return true if location changed
     536             :  */
     537         343 : bool Location::sanitize(const Location &defaultLoc)
     538             : {
     539         343 :     bool has_changed = false;
     540             :     // convert lat/lng=0 to mean current point
     541         343 :     if (lat == 0 && lng == 0) {
     542          35 :         lat = defaultLoc.lat;
     543          35 :         lng = defaultLoc.lng;
     544          35 :         has_changed = true;
     545             :     }
     546             : 
     547             :     // convert relative alt=0 to mean current alt
     548         343 :     if (alt == 0 && relative_alt) {
     549             :         int32_t defaultLoc_alt;
     550          58 :         if (defaultLoc.get_alt_cm(get_alt_frame(), defaultLoc_alt)) {
     551          58 :             alt = defaultLoc_alt;
     552          58 :             has_changed = true;
     553             :         }
     554             :     }
     555             : 
     556             :     // limit lat/lng to appropriate ranges
     557         343 :     if (!check_latlng()) {
     558           4 :         lat = defaultLoc.lat;
     559           4 :         lng = defaultLoc.lng;
     560           4 :         has_changed = true;
     561             :     }
     562             : 
     563         343 :     return has_changed;
     564             : }
     565             : 
     566             : // return bearing in radians from location to loc2, return is 0 to 2*Pi
     567     1930326 : ftype Location::get_bearing(const Location &loc2) const
     568             : {
     569     1930326 :     const int32_t off_x = diff_longitude(loc2.lng,lng);
     570     1930326 :     const int32_t off_y = (loc2.lat - lat) / loc2.longitude_scale((lat+loc2.lat)/2);
     571     1930325 :     ftype bearing = (M_PI*0.5) + atan2F(-off_y, off_x);
     572     1930326 :     if (bearing < 0) {
     573      730039 :         bearing += 2*M_PI;
     574             :     }
     575     1930326 :     return bearing;
     576             : }
     577             : 
     578             : /*
     579             :   return true if lat and lng match. Ignores altitude and options
     580             :  */
     581      112801 : bool Location::same_latlon_as(const Location &loc2) const
     582             : {
     583      112801 :     return (lat == loc2.lat) && (lng == loc2.lng);
     584             : }
     585             : 
     586       33420 : bool Location::same_alt_as(const Location &loc2) const
     587             : {
     588             :     // fast path if the altitude frame is the same
     589       33420 :     if (this->get_alt_frame() == loc2.get_alt_frame()) {
     590       33420 :         return this->alt == loc2.alt;
     591             :     }
     592             : 
     593             :     ftype alt_diff;
     594           0 :     bool have_diff = this->get_height_above(loc2, alt_diff);
     595             : 
     596           0 :     const ftype tolerance = FLT_EPSILON;
     597           0 :     return have_diff && (fabsF(alt_diff) < tolerance);
     598             : }
     599             : 
     600             : // return true when lat and lng are within range
     601        7163 : bool Location::check_latlng() const
     602             : {
     603        7163 :     return check_lat(lat) && check_lng(lng);
     604             : }
     605             : 
     606             : // see if location is past a line perpendicular to
     607             : // the line between point1 and point2 and passing through point2.
     608             : // If point1 is our previous waypoint and point2 is our target waypoint
     609             : // then this function returns true if we have flown past
     610             : // the target waypoint
     611      262933 : bool Location::past_interval_finish_line(const Location &point1, const Location &point2) const
     612             : {
     613      262933 :     return this->line_path_proportion(point1, point2) >= 1.0f;
     614             : }
     615             : 
     616             : /*
     617             :   return the proportion we are along the path from point1 to
     618             :   point2, along a line parallel to point1<->point2.
     619             : 
     620             :   This will be more than 1 if we have passed point2
     621             :  */
     622      900352 : float Location::line_path_proportion(const Location &point1, const Location &point2) const
     623             : {
     624      900352 :     const Vector2f vec1 = point1.get_distance_NE(point2);
     625      900352 :     const Vector2f vec2 = point1.get_distance_NE(*this);
     626      900352 :     const ftype dsquared = sq(vec1.x) + sq(vec1.y);
     627      900352 :     if (dsquared < 0.001f) {
     628             :         // the two points are very close together
     629      162316 :         return 1.0f;
     630             :     }
     631      738036 :     return (vec1 * vec2) / dsquared;
     632             : }
     633             : 
     634             : /*
     635             :   wrap longitude for -180e7 to 180e7
     636             :  */
     637  1761064031 : int32_t Location::wrap_longitude(int64_t lon)
     638             : {
     639  1761064031 :     if (lon > 1800000000L) {
     640           6 :         lon = int32_t(lon-3600000000LL);
     641  1761064025 :     } else if (lon < -1800000000L) {
     642           2 :         lon = int32_t(lon+3600000000LL);
     643             :     }
     644  1761064031 :     return int32_t(lon);
     645             : }
     646             : 
     647             : /*
     648             :   get lon1-lon2, wrapping at -180e7 to 180e7
     649             :  */
     650  1982192898 : int32_t Location::diff_longitude(int32_t lon1, int32_t lon2)
     651             : {
     652  1982192898 :     if ((lon1 & 0x80000000) == (lon2 & 0x80000000)) {
     653             :         // common case of same sign
     654  1982189935 :         return lon1 - lon2;
     655             :     }
     656        2963 :     int64_t dlon = int64_t(lon1)-int64_t(lon2);
     657        2963 :     if (dlon > 1800000000LL) {
     658        2408 :         dlon -= 3600000000LL;
     659         555 :     } else if (dlon < -1800000000LL) {
     660           0 :         dlon += 3600000000LL;
     661             :     }
     662        2963 :     return int32_t(dlon);
     663             : }
     664             : 
     665             : /*
     666             :   limit latitude to -90e7 to 90e7
     667             :  */
     668  1761064398 : int32_t Location::limit_lattitude(int32_t lat)
     669             : {
     670  1761064398 :     if (lat > 900000000L) {
     671           0 :         lat = 1800000000LL - lat;
     672  1761064398 :     } else if (lat < -900000000L) {
     673           0 :         lat = -(1800000000LL + lat);
     674             :     }
     675  1761064398 :     return lat;
     676             : }
     677             : 
     678             : // update altitude and alt-frame base on this location's horizontal position between point1 and point2
     679             : // this location's lat,lon is used to calculate the alt of the closest point on the line between point1 and point2
     680             : // origin and destination's altitude frames must be the same
     681             : // this alt-frame will be updated to match the destination alt frame
     682           0 : void Location::linearly_interpolate_alt(const Location &point1, const Location &point2)
     683             : {
     684             : #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
     685             :     // alt frames must match; mixing frames produces meaningless interpolated altitudes
     686           0 :     if (point1.get_alt_frame() != point2.get_alt_frame()) {
     687           0 :         AP_HAL::panic("linearly_interpolate_alt: alt frames differ (point1=%u point2=%u)",
     688           0 :                       (unsigned)point1.get_alt_frame(), (unsigned)point2.get_alt_frame());
     689             :     }
     690             : #endif
     691             :     // new target's distance along the original track and then linear interpolate between the original origin and destination altitudes
     692           0 :     set_alt_cm(point1.alt + (point2.alt - point1.alt) * constrain_float(line_path_proportion(point1, point2), 0.0f, 1.0f), point2.get_alt_frame());
     693           0 : }
     694             : 
     695             : #endif // HAL_BOOTLOADER_BUILD

Generated by: LCOV version 1.14