#pragma once12#include <AP_Math/AP_Math.h>34#define LOCATION_ALT_MAX_M 83000 // maximum altitude (in meters) that can be fit into Location structure's alt field56class Location7{8public:910uint8_t relative_alt : 1; // 1 if altitude is relative to home11uint8_t loiter_ccw : 1; // 0 if clockwise, 1 if counter clockwise12uint8_t terrain_alt : 1; // this altitude is above terrain13uint8_t origin_alt : 1; // this altitude is above ekf origin14uint8_t loiter_xtrack : 1; // 0 to crosstrack from center of waypoint, 1 to crosstrack from tangent exit location1516// note that mission storage only stores 24 bits of altitude (~ +/- 83km)17int32_t alt; // in cm18int32_t lat; // in 1E7 degrees19int32_t lng; // in 1E7 degrees2021/// enumeration of possible altitude types22enum class AltFrame {23ABSOLUTE = 0,24ABOVE_HOME = 1,25ABOVE_ORIGIN = 2,26ABOVE_TERRAIN = 327};2829/// constructors30Location() { zero(); }31Location(int32_t latitude, int32_t longitude, int32_t alt_in_cm, AltFrame frame);32Location(const Vector3f &ekf_offset_neu_cm, AltFrame frame);33Location(const Vector3d &ekf_offset_neu_cm, AltFrame frame);3435// named constructors36static Location from_ekf_offset_NED_m(const Vector3f& ekf_offset_ned_m, AltFrame frame);37static Location from_ekf_offset_NED_m(const Vector3d& ekf_offset_ned_m, AltFrame frame);3839// set altitude40void set_alt_cm(int32_t alt_cm, AltFrame frame);41// set_alt_m - set altitude in metres42void set_alt_m(float alt_m, AltFrame frame) {43set_alt_cm(alt_m*100, frame);44}4546// get altitude (in cm) in the desired frame47// does not modify ret_alt_cm unless true is returned48// returns false on failure to get altitude in the desired frame which can only happen if the original frame or desired frame is:49// - above-terrain and the terrain database can't supply terrain height amsl50// - above-home and home is not set51// - above-origin and origin is not set52bool get_alt_cm(AltFrame desired_frame, int32_t &ret_alt_cm) const WARN_IF_UNUSED;53// same as get_alt_cm but in metres:54bool get_alt_m(AltFrame desired_frame, float &ret_alt) const WARN_IF_UNUSED;5556// get altitude frame57AltFrame get_alt_frame() const;5859// converts altitude to new frame60// returns false on failure to convert which can only happen if the original frame or desired frame is:61// - above-terrain and the terrain database can't supply terrain height amsl62// - above-home and home is not set63// - above-origin and origin is not set64bool change_alt_frame(AltFrame desired_frame);6566// copy altitude and its frame of other Location object:67void copy_alt_from(const Location &other);6869// get position as a vector (in cm) from origin (x,y only or70// x,y,z) return false on failure to get the vector which can only71// happen if the EKF origin has not been set yet x, y and z are in72// centimetres. If this method returns false then vec_ne is73// unmodified.74template<typename T>75bool get_vector_xy_from_origin_NE_cm(T &vec_ne) const WARN_IF_UNUSED;76// converts location to a vector from origin; if this method returns77// false then vec_neu is unmodified78template<typename T>79bool get_vector_from_origin_NEU_cm(T &vec_neu) const WARN_IF_UNUSED;80// same as get_vector_from_origin_NEU_cm, but only here so we can81// continue to use it in LUA scripts:82template<typename T>83bool get_vector_from_origin_NEU(T &vec_neu) const WARN_IF_UNUSED;8485// get position as a vector (in metres) from origin (x,y only or86// x,y,z) return false on failure to get the vector which can only87// happen if the EKF origin has not been set yet x, y and z are in88// metres. If this method returns false then vec_ne is89// unmodified.90template<typename T>91bool get_vector_xy_from_origin_NE_m(T &vec_ne) const;92template<typename T>93bool get_vector_from_origin_NEU_m(T &vec_neu) const;94template<typename T>95bool get_vector_from_origin_NED_m(T &vec_ned) const;9697// return horizontal distance in meters between two locations98ftype get_distance(const Location &loc2) const;99100// return the altitude difference in meters taking into account101// alt frame. if loc2 is below this location then "distance" will102// be positive. ie. this method returns how far above loc2 this103// location is.104bool get_height_above(const Location &loc2, ftype &distance) const WARN_IF_UNUSED;105106// return the distance in meters in North/East/Down plane as a N/E/D vector to loc2107// NOT CONSIDERING ALT FRAME!108Vector3f get_distance_NED(const Location &loc2) const;109Vector3p get_distance_NED_postype(const Location &loc2) const;110Vector3d get_distance_NED_double(const Location &loc2) const;111112// 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 0113Vector3f get_distance_NED_alt_frame(const Location &loc2) const;114115// return the distance in meters in North/East plane as a N/E vector to loc2116Vector2f get_distance_NE(const Location &loc2) const;117Vector2p get_distance_NE_postype(const Location &loc2) const;118Vector2d get_distance_NE_double(const Location &loc2) const;119Vector2F get_distance_NE_ftype(const Location &loc2) const;120121// extrapolate latitude/longitude given distances (in meters) north and east122static void offset_latlng(int32_t &lat, int32_t &lng, ftype ofs_north, ftype ofs_east);123void offset(ftype ofs_north, ftype ofs_east);124// extrapolate latitude/longitude given distances (in meters) north125// and east. Note that this is metres, *even for the altitude*.126void offset(const Vector3p &ofs_ned);127void offset_up_cm(int32_t alt_offset_cm) {128alt += alt_offset_cm;129}130void offset_up_m(float alt_offset_m) {131alt += alt_offset_m * 100;132}133134// extrapolate latitude/longitude given bearing and distance135void offset_bearing(ftype bearing_deg, ftype distance);136137// extrapolate latitude/longitude given bearing, pitch and distance138void offset_bearing_and_pitch(ftype bearing_deg, ftype pitch_deg, ftype distance);139140// longitude_scale - returns the scaler to compensate for141// shrinking longitude as you move north or south from the equator142// Note: this does not include the scaling to convert143// longitude/latitude points to meters or centimeters144static ftype longitude_scale(int32_t lat);145146bool is_zero(void) const WARN_IF_UNUSED;147148void zero(void);149150// return the bearing in radians, from 0 to 2*Pi151ftype get_bearing(const Location &loc2) const;152153// return bearing in centi-degrees from location to loc2, return is 0 to 35999154int32_t get_bearing_to(const Location &loc2) const {155return int32_t(rad_to_cd(get_bearing(loc2)) + 0.5);156}157158// check if lat and lng match. Ignore altitude and options159bool same_latlon_as(const Location &loc2) const;160161// check if altitude matches.162bool same_alt_as(const Location &loc2) const;163164// check if lat, lng, and alt match.165bool same_loc_as(const Location &loc2) const {166return same_latlon_as(loc2) && same_alt_as(loc2);167}168169/*170* convert invalid waypoint with useful data. return true if location changed171*/172bool sanitize(const Location &defaultLoc);173174// return true when lat and lng are within range175bool check_latlng() const;176177// see if location is past a line perpendicular to178// the line between point1 and point2 and passing through point2.179// If point1 is our previous waypoint and point2 is our target waypoint180// then this function returns true if we have flown past181// the target waypoint182bool past_interval_finish_line(const Location &point1, const Location &point2) const;183184/*185return the proportion we are along the path from point1 to186point2, along a line parallel to point1<->point2.187This will be more than 1 if we have passed point2188*/189float line_path_proportion(const Location &point1, const Location &point2) const;190191// update altitude and alt-frame base on this location's horizontal position between point1 and point2192// this location's lat,lon is used to calculate the alt of the closest point on the line between point1 and point2193// origin and destination's altitude frames must be the same194// this alt-frame will be updated to match the destination alt frame195void linearly_interpolate_alt(const Location &point1, const Location &point2);196197bool initialised() const { return (lat !=0 || lng != 0 || alt != 0); }198// return true if alt is *exactly* zero. This is not intended to199// be used for anything except magically changing a 0-altitude200// passed via mavlink into the current vehicle's altitude201bool alt_is_zero() const { return alt == 0; }202203// wrap longitude at -180e7 to 180e7204static int32_t wrap_longitude(int64_t lon);205206// limit latitude to -90e7 to 90e7207static int32_t limit_lattitude(int32_t lat);208209// get lon1-lon2, wrapping at -180e7 to 180e7210static int32_t diff_longitude(int32_t lon1, int32_t lon2);211212private:213214// scaling factor from 1e-7 degrees to meters at equator215// == 1.0e-7 * DEG_TO_RAD * RADIUS_OF_EARTH216static constexpr float LOCATION_SCALING_FACTOR = LATLON_TO_M;217// inverse of LOCATION_SCALING_FACTOR218static constexpr float LOCATION_SCALING_FACTOR_INV = LATLON_TO_M_INV;219};220221222