Location.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * Location.cpp
  3. */
  4. #include "Location.h"
  5. #include <AP_AHRS/AP_AHRS.h>
  6. #include <AP_Terrain/AP_Terrain.h>
  7. AP_Terrain *Location::_terrain = nullptr;
  8. /// constructors
  9. Location::Location()
  10. {
  11. zero();
  12. }
  13. const Location definitely_zero{};
  14. bool Location::is_zero(void) const
  15. {
  16. return !memcmp(this, &definitely_zero, sizeof(*this));
  17. }
  18. void Location::zero(void)
  19. {
  20. memset(this, 0, sizeof(*this));
  21. }
  22. Location::Location(int32_t latitude, int32_t longitude, int32_t alt_in_cm, AltFrame frame)
  23. {
  24. zero();
  25. lat = latitude;
  26. lng = longitude;
  27. set_alt_cm(alt_in_cm, frame);
  28. }
  29. Location::Location(const Vector3f &ekf_offset_neu)
  30. {
  31. // store alt and alt frame
  32. set_alt_cm(ekf_offset_neu.z, AltFrame::ABOVE_ORIGIN);
  33. // calculate lat, lon
  34. Location ekf_origin;
  35. if (AP::ahrs().get_origin(ekf_origin)) {
  36. lat = ekf_origin.lat;
  37. lng = ekf_origin.lng;
  38. offset(ekf_offset_neu.x / 100.0f, ekf_offset_neu.y / 100.0f);
  39. }
  40. }
  41. void Location::set_alt_cm(int32_t alt_cm, AltFrame frame)
  42. {
  43. alt = alt_cm;
  44. relative_alt = false;
  45. terrain_alt = false;
  46. origin_alt = false;
  47. switch (frame) {
  48. case AltFrame::ABSOLUTE:
  49. // do nothing
  50. break;
  51. case AltFrame::ABOVE_HOME:
  52. relative_alt = true;
  53. break;
  54. case AltFrame::ABOVE_ORIGIN:
  55. origin_alt = true;
  56. break;
  57. case AltFrame::ABOVE_TERRAIN:
  58. // we mark it as a relative altitude, as it doesn't have
  59. // home alt added
  60. relative_alt = true;
  61. terrain_alt = true;
  62. break;
  63. }
  64. }
  65. // converts altitude to new frame
  66. bool Location::change_alt_frame(AltFrame desired_frame)
  67. {
  68. int32_t new_alt_cm;
  69. if (!get_alt_cm(desired_frame, new_alt_cm)) {
  70. return false;
  71. }
  72. set_alt_cm(new_alt_cm, desired_frame);
  73. return true;
  74. }
  75. // get altitude frame
  76. Location::AltFrame Location::get_alt_frame() const
  77. {
  78. if (terrain_alt) {
  79. return AltFrame::ABOVE_TERRAIN;
  80. }
  81. if (origin_alt) {
  82. return AltFrame::ABOVE_ORIGIN;
  83. }
  84. if (relative_alt) {
  85. return AltFrame::ABOVE_HOME;
  86. }
  87. return AltFrame::ABSOLUTE;
  88. }
  89. /// get altitude in desired frame
  90. bool Location::get_alt_cm(AltFrame desired_frame, int32_t &ret_alt_cm) const
  91. {
  92. #if CONFIG_HAL_BOARD == HAL_BOARD_SITL
  93. if (!initialised()) {
  94. AP_HAL::panic("Should not be called on invalid location");
  95. }
  96. #endif
  97. Location::AltFrame frame = get_alt_frame();
  98. // shortcut if desired and underlying frame are the same
  99. if (desired_frame == frame) {
  100. ret_alt_cm = alt;
  101. return true;
  102. }
  103. // check for terrain altitude
  104. float alt_terr_cm = 0;
  105. if (frame == AltFrame::ABOVE_TERRAIN || desired_frame == AltFrame::ABOVE_TERRAIN) {
  106. #if AP_TERRAIN_AVAILABLE
  107. if (_terrain == nullptr || !_terrain->height_amsl(*(Location *)this, alt_terr_cm, true)) {
  108. return false;
  109. }
  110. // convert terrain alt to cm
  111. alt_terr_cm *= 100.0f;
  112. #else
  113. return false;
  114. #endif
  115. }
  116. // convert alt to absolute
  117. int32_t alt_abs = 0;
  118. switch (frame) {
  119. case AltFrame::ABSOLUTE:
  120. alt_abs = alt;
  121. break;
  122. case AltFrame::ABOVE_HOME:
  123. if (!AP::ahrs().home_is_set()) {
  124. return false;
  125. }
  126. alt_abs = alt + AP::ahrs().get_home().alt;
  127. break;
  128. case AltFrame::ABOVE_ORIGIN:
  129. {
  130. // fail if we cannot get ekf origin
  131. Location ekf_origin;
  132. if (!AP::ahrs().get_origin(ekf_origin)) {
  133. return false;
  134. }
  135. alt_abs = alt + ekf_origin.alt;
  136. }
  137. break;
  138. case AltFrame::ABOVE_TERRAIN:
  139. alt_abs = alt + alt_terr_cm;
  140. break;
  141. }
  142. // convert absolute to desired frame
  143. switch (desired_frame) {
  144. case AltFrame::ABSOLUTE:
  145. ret_alt_cm = alt_abs;
  146. return true;
  147. case AltFrame::ABOVE_HOME:
  148. if (!AP::ahrs().home_is_set()) {
  149. return false;
  150. }
  151. ret_alt_cm = alt_abs - AP::ahrs().get_home().alt;
  152. return true;
  153. case AltFrame::ABOVE_ORIGIN:
  154. {
  155. // fail if we cannot get ekf origin
  156. Location ekf_origin;
  157. if (!AP::ahrs().get_origin(ekf_origin)) {
  158. return false;
  159. }
  160. ret_alt_cm = alt_abs - ekf_origin.alt;
  161. return true;
  162. }
  163. case AltFrame::ABOVE_TERRAIN:
  164. ret_alt_cm = alt_abs - alt_terr_cm;
  165. return true;
  166. }
  167. return false;
  168. }
  169. bool Location::get_vector_xy_from_origin_NE(Vector2f &vec_ne) const
  170. {
  171. Location ekf_origin;
  172. if (!AP::ahrs().get_origin(ekf_origin)) {
  173. return false;
  174. }
  175. vec_ne.x = (lat-ekf_origin.lat) * LATLON_TO_CM;
  176. vec_ne.y = (lng-ekf_origin.lng) * LATLON_TO_CM * ekf_origin.longitude_scale();
  177. return true;
  178. }
  179. bool Location::get_vector_from_origin_NEU(Vector3f &vec_neu) const
  180. {
  181. // convert lat, lon
  182. Vector2f vec_ne;
  183. if (!get_vector_xy_from_origin_NE(vec_ne)) {
  184. return false;
  185. }
  186. vec_neu.x = vec_ne.x;
  187. vec_neu.y = vec_ne.y;
  188. // convert altitude
  189. int32_t alt_above_origin_cm = 0;
  190. if (!get_alt_cm(AltFrame::ABOVE_ORIGIN, alt_above_origin_cm)) {
  191. return false;
  192. }
  193. vec_neu.z = alt_above_origin_cm;
  194. return true;
  195. }
  196. // return distance in meters between two locations
  197. float Location::get_distance(const struct Location &loc2) const
  198. {
  199. float dlat = (float)(loc2.lat - lat);
  200. float dlng = ((float)(loc2.lng - lng)) * loc2.longitude_scale();
  201. return norm(dlat, dlng) * LOCATION_SCALING_FACTOR;
  202. }
  203. /*
  204. return the distance in meters in North/East plane as a N/E vector
  205. from loc1 to loc2
  206. */
  207. Vector2f Location::get_distance_NE(const Location &loc2) const
  208. {
  209. return Vector2f((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
  210. (loc2.lng - lng) * LOCATION_SCALING_FACTOR * longitude_scale());
  211. }
  212. // return the distance in meters in North/East/Down plane as a N/E/D vector to loc2
  213. Vector3f Location::get_distance_NED(const Location &loc2) const
  214. {
  215. return Vector3f((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
  216. (loc2.lng - lng) * LOCATION_SCALING_FACTOR * longitude_scale(),
  217. (alt - loc2.alt) * 0.01f);
  218. }
  219. // extrapolate latitude/longitude given distances (in meters) north and east
  220. void Location::offset(float ofs_north, float ofs_east)
  221. {
  222. // use is_equal() because is_zero() is a local class conflict and is_zero() in AP_Math does not belong to a class
  223. if (!is_equal(ofs_north, 0.0f) || !is_equal(ofs_east, 0.0f)) {
  224. int32_t dlat = ofs_north * LOCATION_SCALING_FACTOR_INV;
  225. int32_t dlng = (ofs_east * LOCATION_SCALING_FACTOR_INV) / longitude_scale();
  226. lat += dlat;
  227. lng += dlng;
  228. }
  229. }
  230. /*
  231. * extrapolate latitude/longitude given bearing and distance
  232. * Note that this function is accurate to about 1mm at a distance of
  233. * 100m. This function has the advantage that it works in relative
  234. * positions, so it keeps the accuracy even when dealing with small
  235. * distances and floating point numbers
  236. */
  237. void Location::offset_bearing(float bearing, float distance)
  238. {
  239. const float ofs_north = cosf(radians(bearing)) * distance;
  240. const float ofs_east = sinf(radians(bearing)) * distance;
  241. offset(ofs_north, ofs_east);
  242. }
  243. float Location::longitude_scale() const
  244. {
  245. float scale = cosf(lat * (1.0e-7f * DEG_TO_RAD));
  246. return MAX(scale, 0.01f);
  247. }
  248. /*
  249. * convert invalid waypoint with useful data. return true if location changed
  250. */
  251. bool Location::sanitize(const Location &defaultLoc)
  252. {
  253. bool has_changed = false;
  254. // convert lat/lng=0 to mean current point
  255. if (lat == 0 && lng == 0) {
  256. lat = defaultLoc.lat;
  257. lng = defaultLoc.lng;
  258. has_changed = true;
  259. }
  260. // convert relative alt=0 to mean current alt
  261. if (alt == 0 && relative_alt) {
  262. relative_alt = false;
  263. alt = defaultLoc.alt;
  264. has_changed = true;
  265. }
  266. // limit lat/lng to appropriate ranges
  267. if (!check_latlng()) {
  268. lat = defaultLoc.lat;
  269. lng = defaultLoc.lng;
  270. has_changed = true;
  271. }
  272. return has_changed;
  273. }
  274. // make sure we know what size the Location object is:
  275. assert_storage_size<Location, 16> _assert_storage_size_Location;
  276. // return bearing in centi-degrees from location to loc2
  277. int32_t Location::get_bearing_to(const struct Location &loc2) const
  278. {
  279. const int32_t off_x = loc2.lng - lng;
  280. const int32_t off_y = (loc2.lat - lat) / loc2.longitude_scale();
  281. int32_t bearing = 9000 + atan2f(-off_y, off_x) * DEGX100;
  282. if (bearing < 0) {
  283. bearing += 36000;
  284. }
  285. return bearing;
  286. }
  287. /*
  288. return true if lat and lng match. Ignores altitude and options
  289. */
  290. bool Location::same_latlon_as(const Location &loc2) const
  291. {
  292. return (lat == loc2.lat) && (lng == loc2.lng);
  293. }
  294. // return true when lat and lng are within range
  295. bool Location::check_latlng() const
  296. {
  297. return check_lat(lat) && check_lng(lng);
  298. }
  299. // see if location is past a line perpendicular to
  300. // the line between point1 and point2 and passing through point2.
  301. // If point1 is our previous waypoint and point2 is our target waypoint
  302. // then this function returns true if we have flown past
  303. // the target waypoint
  304. bool Location::past_interval_finish_line(const Location &point1, const Location &point2) const
  305. {
  306. return this->line_path_proportion(point1, point2) >= 1.0f;
  307. }
  308. /*
  309. return the proportion we are along the path from point1 to
  310. point2, along a line parallel to point1<->point2.
  311. This will be more than 1 if we have passed point2
  312. */
  313. float Location::line_path_proportion(const Location &point1, const Location &point2) const
  314. {
  315. const Vector2f vec1 = point1.get_distance_NE(point2);
  316. const Vector2f vec2 = point1.get_distance_NE(*this);
  317. const float dsquared = sq(vec1.x) + sq(vec1.y);
  318. if (dsquared < 0.001f) {
  319. // the two points are very close together
  320. return 1.0f;
  321. }
  322. return (vec1 * vec2) / dsquared;
  323. }