| 522 | template <typename Vertex, typename Edge, typename Weight> |
| 523 | template <class P, class Emitter> |
| 524 | typename AStarAlgorithm<Vertex, Edge, Weight>::Result AStarAlgorithm<Vertex, Edge, Weight>::FindPathBidirectionalEx( |
| 525 | P & params, Emitter && emitter) const |
| 526 | { |
| 527 | auto const epsilon = params.m_weightEpsilon; |
| 528 | auto & graph = params.m_graph; |
| 529 | auto const & finalVertex = params.m_finalVertex; |
| 530 | auto const & startVertex = params.m_startVertex; |
| 531 | |
| 532 | BidirectionalStepContext forward(true /* forward */, startVertex, finalVertex, graph); |
| 533 | BidirectionalStepContext backward(false /* forward */, startVertex, finalVertex, graph); |
| 534 | |
| 535 | auto & forwardParents = forward.GetParents(); |
| 536 | auto & backwardParents = backward.GetParents(); |
| 537 | |
| 538 | bool foundAnyPath = false; |
| 539 | Weight bestPathReducedLength = kZeroDistance; |
| 540 | Weight bestPathRealLength = kZeroDistance; |
| 541 | |
| 542 | forward.UpdateDistance(State(startVertex, kZeroDistance)); |
| 543 | forward.queue.push(State(startVertex, kZeroDistance, forward.ConsistentHeuristic(startVertex))); |
| 544 | |
| 545 | backward.UpdateDistance(State(finalVertex, kZeroDistance)); |
| 546 | backward.queue.push(State(finalVertex, kZeroDistance, backward.ConsistentHeuristic(finalVertex))); |
| 547 | |
| 548 | // To use the search code both for backward and forward directions |
| 549 | // we keep the pointers to everything related to the search in the |
| 550 | // 'current' and 'next' directions. Swapping these pointers indicates |
| 551 | // changing the end we are searching from. |
| 552 | BidirectionalStepContext * cur = &forward; |
| 553 | BidirectionalStepContext * nxt = &backward; |
| 554 | |
| 555 | auto const EmitResult = [cur, nxt, &bestPathRealLength, &emitter]() |
| 556 | { |
| 557 | // No problem if length check fails, but we still emit the result. |
| 558 | // Happens with "transit" route because of length, haven't seen with regular car route. |
| 559 | // ASSERT(params.m_checkLengthCallback(bestPathRealLength), ()); |
| 560 | |
| 561 | RoutingResult<Vertex, Weight> result; |
| 562 | ReconstructPathBidirectional(cur->bestVertex, nxt->bestVertex, cur->parent, nxt->parent, result.m_path); |
| 563 | result.m_distance = bestPathRealLength; |
| 564 | if (!cur->forward) |
| 565 | reverse(result.m_path.begin(), result.m_path.end()); |
| 566 | |
| 567 | return emitter(std::move(result)); |
| 568 | }; |
| 569 | |
| 570 | typename Graph::EdgeListT adj; |
| 571 | |
| 572 | // It is not necessary to check emptiness for both queues here |
| 573 | // because if we have not found a path by the time one of the |
| 574 | // queues is exhausted, we never will. |
| 575 | uint32_t steps = 0; |
| 576 | PeriodicPollCancellable periodicCancellable(params.m_cancellable); |
| 577 | |
| 578 | while (!cur->queue.empty() && !nxt->queue.empty()) |
| 579 | { |
| 580 | ++steps; |
| 581 |
no test coverage detected