123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- #include "AP_OADijkstra.h"
- #include <AC_Fence/AC_Fence.h>
- #include <AP_AHRS/AP_AHRS.h>
- #include <AP_Logger/AP_Logger.h>
- #define OA_DIJKSTRA_EXPANDING_ARRAY_ELEMENTS_PER_CHUNK 32
- #define OA_DIJKSTRA_POLYGON_SHORTPATH_NOTSET_IDX 255
- AP_OADijkstra::AP_OADijkstra() :
- _polyfence_pts(OA_DIJKSTRA_EXPANDING_ARRAY_ELEMENTS_PER_CHUNK),
- _short_path_data(OA_DIJKSTRA_EXPANDING_ARRAY_ELEMENTS_PER_CHUNK),
- _path(OA_DIJKSTRA_EXPANDING_ARRAY_ELEMENTS_PER_CHUNK)
- {
- }
- AP_OADijkstra::AP_OADijkstra_State AP_OADijkstra::update(const Location ¤t_loc, const Location &destination, Location& origin_new, Location& destination_new)
- {
-
- struct Location ekf_origin {};
- if (!AP::ahrs().get_origin(ekf_origin)) {
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_NOT_REQUIRED, 0, 0, destination, destination);
- return DIJKSTRA_STATE_NOT_REQUIRED;
- }
-
- if (!polygon_fence_enabled()) {
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_NOT_REQUIRED, 0, 0, destination, destination);
- return DIJKSTRA_STATE_NOT_REQUIRED;
- }
-
- if (current_loc.same_latlon_as(destination)) {
- return DIJKSTRA_STATE_NOT_REQUIRED;
- }
-
- if (check_polygon_fence_updated()) {
- _polyfence_with_margin_ok = false;
- _polyfence_visgraph_ok = false;
- _shortest_path_ok = false;
- }
-
- if (!_polyfence_with_margin_ok) {
- _polyfence_with_margin_ok = create_polygon_fence_with_margin(_polyfence_margin * 100.0f);
- if (!_polyfence_with_margin_ok) {
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_ERROR, 0, 0, destination, destination);
- return DIJKSTRA_STATE_ERROR;
- }
- }
-
- if (!_polyfence_visgraph_ok) {
- _polyfence_visgraph_ok = create_polygon_fence_visgraph();
- if (!_polyfence_visgraph_ok) {
- _shortest_path_ok = false;
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_ERROR, 0, 0, destination, destination);
- return DIJKSTRA_STATE_ERROR;
- }
- }
-
- if (!destination.same_latlon_as(_destination_prev)) {
- _destination_prev = destination;
- _shortest_path_ok = false;
- }
-
- if (!_shortest_path_ok) {
- _shortest_path_ok = calc_shortest_path(current_loc, destination);
- if (!_shortest_path_ok) {
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_ERROR, 0, 0, destination, destination);
- return DIJKSTRA_STATE_ERROR;
- }
-
- _path_idx_returned = 1;
- }
-
- Vector2f dest_pos;
- if (get_shortest_path_point(_path_idx_returned, dest_pos)) {
-
- Vector2f origin_pos;
- if ((_path_idx_returned > 0) && get_shortest_path_point(_path_idx_returned-1, origin_pos)) {
-
- Location temp_loc(Vector3f(origin_pos.x, origin_pos.y, 0.0f));
- origin_new = temp_loc;
- } else {
-
- origin_new = current_loc;
- }
-
- Location temp_loc(Vector3f(dest_pos.x, dest_pos.y, 0.0f));
- destination_new = destination;
- destination_new.lat = temp_loc.lat;
- destination_new.lng = temp_loc.lng;
-
- const bool near_oa_wp = current_loc.get_distance(destination_new) <= 2.0f;
- const bool past_oa_wp = current_loc.past_interval_finish_line(origin_new, destination_new);
- if (near_oa_wp || past_oa_wp) {
- _path_idx_returned++;
- }
-
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_SUCCESS, _path_idx_returned, _path_numpoints, destination, destination_new);
- return DIJKSTRA_STATE_SUCCESS;
- }
-
- AP::logger().Write_OADijkstra(DIJKSTRA_STATE_NOT_REQUIRED, 0, 0, destination, destination);
- return DIJKSTRA_STATE_NOT_REQUIRED;
- }
- bool AP_OADijkstra::polygon_fence_enabled() const
- {
- const AC_Fence *fence = AC_Fence::get_singleton();
- if (fence == nullptr) {
- return false;
- }
- if (!fence->is_polygon_valid()) {
- return false;
- }
- return ((fence->get_enabled_fences() & AC_FENCE_TYPE_POLYGON) > 0);
- }
- bool AP_OADijkstra::check_polygon_fence_updated() const
- {
-
- const AC_Fence *fence = AC_Fence::get_singleton();
- if (fence == nullptr) {
- return false;
- }
- return (_polyfence_update_ms != fence->get_boundary_update_ms());
- }
- bool AP_OADijkstra::create_polygon_fence_with_margin(float margin_cm)
- {
-
- const AC_Fence *fence = AC_Fence::get_singleton();
- if (fence == nullptr) {
- return false;
- }
-
- uint16_t num_points;
- const Vector2f* boundary = fence->get_boundary_points(num_points);
- if ((boundary == nullptr) || (num_points < 3)) {
- return false;
- }
-
- if (!_polyfence_pts.expand_to_hold(num_points)) {
- return false;
- }
-
-
- for (uint8_t i=0; i<num_points; i++) {
-
- const uint8_t before_idx = (i == 0) ? num_points-1 : i-1;
- const uint8_t after_idx = (i == num_points-1) ? 0 : i+1;
- Vector2f before_pt = boundary[before_idx] - boundary[i];
- Vector2f after_pt = boundary[after_idx] - boundary[i];
-
- if (before_pt.is_zero() || after_pt.is_zero() || (before_pt == after_pt)) {
- return false;
- }
-
- before_pt.normalize();
- after_pt.normalize();
-
- Vector2f intermediate_pt = (after_pt + before_pt) * 0.5f;
- float intermediate_len = intermediate_pt.length();
- intermediate_pt *= (margin_cm / intermediate_len);
-
- _polyfence_pts[i] = boundary[i] + intermediate_pt;
- if (Polygon_outside(_polyfence_pts[i], boundary, num_points)) {
- _polyfence_pts[i] = boundary[i] - intermediate_pt;
- if (Polygon_outside(_polyfence_pts[i], boundary, num_points)) {
-
-
- return false;
- }
- }
- }
-
- _polyfence_numpoints = num_points;
-
- _polyfence_update_ms = fence->get_boundary_update_ms();
- return true;
- }
- bool AP_OADijkstra::create_polygon_fence_visgraph()
- {
-
- if (_polyfence_numpoints == 0) {
- return false;
- }
-
- const AC_Fence *fence = AC_Fence::get_singleton();
- if (fence == nullptr) {
- return false;
- }
-
- uint16_t num_points;
- const Vector2f* boundary = fence->get_boundary_points(num_points);
- if ((boundary == nullptr) || (num_points < 3)) {
- return false;
- }
-
- if (num_points >= OA_DIJKSTRA_POLYGON_SHORTPATH_NOTSET_IDX) {
- return false;
- }
-
- _polyfence_visgraph.clear();
-
- for (uint8_t i=0; i<_polyfence_numpoints-1; i++) {
- const Vector2f &start1 = _polyfence_pts[i];
- for (uint8_t j=i+1; j<_polyfence_numpoints; j++) {
- const Vector2f &end1 = _polyfence_pts[j];
- Vector2f intersection;
-
-
- if (!Polygon_intersects(boundary, num_points, start1, end1, intersection)) {
-
- _polyfence_visgraph.add_item({AP_OAVisGraph::OATYPE_FENCE_POINT, i},
- {AP_OAVisGraph::OATYPE_FENCE_POINT, j},
- (_polyfence_pts[i] - _polyfence_pts[j]).length());
- }
- }
- }
- return true;
- }
- bool AP_OADijkstra::update_visgraph(AP_OAVisGraph& visgraph, const AP_OAVisGraph::OAItemID& oaid, const Vector2f &position, bool add_extra_position, Vector2f extra_position)
- {
-
- if (_polyfence_numpoints == 0) {
- return false;
- }
-
- const AC_Fence *fence = AC_Fence::get_singleton();
- if (fence == nullptr) {
- return false;
- }
-
- uint16_t num_points;
- const Vector2f* boundary = fence->get_boundary_points(num_points);
- if ((boundary == nullptr) || (num_points < 3)) {
- return false;
- }
-
- visgraph.clear();
-
- for (uint8_t i=0; i<_polyfence_numpoints; i++) {
- Vector2f intersection;
- if (!Polygon_intersects(boundary, num_points, position, _polyfence_pts[i], intersection)) {
-
- visgraph.add_item(oaid, {AP_OAVisGraph::OATYPE_FENCE_POINT, i}, (position - _polyfence_pts[i]).length());
- }
-
- }
-
- if (add_extra_position) {
- Vector2f intersection;
- if (!Polygon_intersects(boundary, num_points, position, extra_position, intersection)) {
- visgraph.add_item(oaid, {AP_OAVisGraph::OATYPE_DESTINATION, 0}, (position - extra_position).length());
- }
- }
- return true;
- }
- void AP_OADijkstra::update_visible_node_distances(node_index curr_node_idx)
- {
-
- if (curr_node_idx > _short_path_data_numpoints) {
- return;
- }
-
- const ShortPathNode &curr_node = _short_path_data[curr_node_idx];
-
- const AP_OAVisGraph* visgraphs[] = {&_polyfence_visgraph, &_destination_visgraph};
- for (uint8_t v=0; v<ARRAY_SIZE(visgraphs); v++) {
-
- const AP_OAVisGraph &curr_visgraph = *visgraphs[v];
- if (curr_visgraph.num_items() == 0) {
- continue;
- }
-
- for (uint8_t i=0; i<curr_visgraph.num_items(); i++) {
- const AP_OAVisGraph::VisGraphItem &item = curr_visgraph[i];
-
- if ((curr_node.id == item.id1) || (curr_node.id == item.id2)) {
- AP_OAVisGraph::OAItemID matching_id = (curr_node.id == item.id1) ? item.id2 : item.id1;
-
- node_index item_node_idx;
- if (find_node_from_id(matching_id, item_node_idx)) {
-
- const float dist_to_item_via_current_node = _short_path_data[curr_node_idx].distance_cm + item.distance_cm;
- if (dist_to_item_via_current_node < _short_path_data[item_node_idx].distance_cm) {
-
- _short_path_data[item_node_idx].distance_cm = dist_to_item_via_current_node;
- _short_path_data[item_node_idx].distance_from_idx = curr_node_idx;
- }
- }
- }
- }
- }
- }
- bool AP_OADijkstra::find_node_from_id(const AP_OAVisGraph::OAItemID &id, node_index &node_idx) const
- {
- switch (id.id_type) {
- case AP_OAVisGraph::OATYPE_SOURCE:
-
- if (_short_path_data_numpoints > 0) {
- node_idx = 0;
- return true;
- }
- break;
- case AP_OAVisGraph::OATYPE_DESTINATION:
-
- if (_short_path_data_numpoints > 1) {
- node_idx = 1;
- return true;
- }
- break;
- case AP_OAVisGraph::OATYPE_FENCE_POINT:
-
- if (_short_path_data_numpoints > id.id_num + 2) {
- node_idx = id.id_num + 2;
- return true;
- }
- break;
- }
-
- return false;
- }
- bool AP_OADijkstra::find_closest_node_idx(node_index &node_idx) const
- {
- node_index lowest_idx = 0;
- float lowest_dist = FLT_MAX;
-
- for (node_index i=0; i<_short_path_data_numpoints; i++) {
- const ShortPathNode &node = _short_path_data[i];
- if (!node.visited && (node.distance_cm < lowest_dist)) {
- lowest_idx = i;
- lowest_dist = node.distance_cm;
- }
- }
- if (lowest_dist < FLT_MAX) {
- node_idx = lowest_idx;
- return true;
- }
- return false;
- }
- bool AP_OADijkstra::calc_shortest_path(const Location &origin, const Location &destination)
- {
-
- Vector2f origin_NE, destination_NE;
- if (!origin.get_vector_xy_from_origin_NE(origin_NE) || !destination.get_vector_xy_from_origin_NE(destination_NE)) {
- return false;
- }
-
- update_visgraph(_source_visgraph, {AP_OAVisGraph::OATYPE_SOURCE, 0}, origin_NE, true, destination_NE);
- update_visgraph(_destination_visgraph, {AP_OAVisGraph::OATYPE_DESTINATION, 0}, destination_NE);
-
- if (!_short_path_data.expand_to_hold(2 + _polyfence_numpoints)) {
- return false;
- }
-
- _short_path_data[0] = {{AP_OAVisGraph::OATYPE_SOURCE, 0}, false, 0, 0};
- _short_path_data[1] = {{AP_OAVisGraph::OATYPE_DESTINATION, 0}, false, OA_DIJKSTRA_POLYGON_SHORTPATH_NOTSET_IDX, FLT_MAX};
- _short_path_data_numpoints = 2;
-
- for (uint8_t i=0; i<_polyfence_numpoints; i++) {
- _short_path_data[_short_path_data_numpoints++] = {{AP_OAVisGraph::OATYPE_FENCE_POINT, i}, false, OA_DIJKSTRA_POLYGON_SHORTPATH_NOTSET_IDX, FLT_MAX};
- }
-
- node_index current_node_idx = 0;
-
- for (uint8_t i=0; i<_source_visgraph.num_items(); i++) {
- node_index node_idx;
- if (find_node_from_id(_source_visgraph[i].id2, node_idx)) {
- _short_path_data[node_idx].distance_cm = _source_visgraph[i].distance_cm;
- _short_path_data[node_idx].distance_from_idx = current_node_idx;
- } else {
- return false;
- }
- }
-
- _short_path_data[current_node_idx].visited = true;
-
- while (find_closest_node_idx(current_node_idx)) {
-
- update_visible_node_distances(current_node_idx);
-
- _short_path_data[current_node_idx].visited = true;
- }
-
- bool success = false;
- node_index nidx;
- if (!find_node_from_id({AP_OAVisGraph::OATYPE_DESTINATION,0}, nidx)) {
- return false;
- }
- _path_numpoints = 0;
- while (true) {
-
- if (_path_numpoints >= _path.max_items()) {
- if (!_path.expand()) {
- break;
- }
- }
-
- if ((_short_path_data[nidx].distance_from_idx == OA_DIJKSTRA_POLYGON_SHORTPATH_NOTSET_IDX) ||
- (_short_path_data[nidx].distance_cm >= FLT_MAX)) {
- break;
- } else {
-
- _path[_path_numpoints] = _short_path_data[nidx].id;
- _path_numpoints++;
-
- if (_short_path_data[nidx].id.id_type == AP_OAVisGraph::OATYPE_SOURCE) {
- success = true;
- break;
- } else {
-
- nidx = _short_path_data[nidx].distance_from_idx;
- }
- }
- }
-
- if (success) {
- _path_source = origin_NE;
- _path_destination = destination_NE;
- }
- return success;
- }
- bool AP_OADijkstra::get_shortest_path_point(uint8_t point_num, Vector2f& pos)
- {
- if ((_path_numpoints == 0) || (point_num >= _path_numpoints)) {
- return false;
- }
-
- AP_OAVisGraph::OAItemID id = _path[_path_numpoints - point_num - 1];
-
- switch (id.id_type) {
- case AP_OAVisGraph::OATYPE_SOURCE:
- pos = _path_source;
- return true;
- case AP_OAVisGraph::OATYPE_DESTINATION:
- pos = _path_destination;
- return true;
- case AP_OAVisGraph::OATYPE_FENCE_POINT:
-
- if (id.id_num < _polyfence_numpoints) {
- pos = _polyfence_pts[id.id_num];
- return true;
- }
- return false;
- }
-
- return false;
- }
|