78 std::priority_queue<Node, std::vector<Node>, std::greater<>> forwardOpen;
79 std::unordered_map<H3Index, double, H3IndexHash> forwardG;
80 std::unordered_map<H3Index, H3Index, H3IndexHash> forwardPrev;
81 std::unordered_set<H3Index, H3IndexHash> forwardClosed;
84 std::priority_queue<Node, std::vector<Node>, std::greater<>> backwardOpen;
85 std::unordered_map<H3Index, double, H3IndexHash> backwardG;
86 std::unordered_map<H3Index, H3Index, H3IndexHash> backwardPrev;
87 std::unordered_set<H3Index, H3IndexHash> backwardClosed;
90 int64_t estimatedDistance = 0;
91 if (gridDistance(start, end, &estimatedDistance) == E_SUCCESS && estimatedDistance > 0) {
94 const size_t reserveSize = std::max(
size_t(estimatedDistance * 1.5),
size_t(150));
95 forwardG.reserve(reserveSize);
96 forwardPrev.reserve(reserveSize);
97 forwardClosed.reserve(reserveSize);
98 backwardG.reserve(reserveSize);
99 backwardPrev.reserve(reserveSize);
100 backwardClosed.reserve(reserveSize);
103 constexpr size_t defaultReserve = 150;
104 forwardG.reserve(defaultReserve);
105 forwardPrev.reserve(defaultReserve);
106 forwardClosed.reserve(defaultReserve);
107 backwardG.reserve(defaultReserve);
108 backwardPrev.reserve(defaultReserve);
109 backwardClosed.reserve(defaultReserve);
114 if (cellToLatLng(start, &startCoord) != E_SUCCESS) {
118 forwardG[start] = 0.0;
119 forwardOpen.emplace(
Node{start, 0.0,
heuristic(start, endCoord)});
121 backwardG[end] = 0.0;
122 backwardOpen.emplace(
Node{end, 0.0,
heuristic(end, startCoord)});
125 H3Index meetingPoint = H3_NULL;
126 double bestPathCost = std::numeric_limits<double>::infinity();
127 int nodesExplored = 0;
130 while (!forwardOpen.empty() && !backwardOpen.empty()) {
132 const double forwardMin = forwardOpen.top().fScore;
133 const double backwardMin = backwardOpen.top().fScore;
135 if (forwardMin + backwardMin >= bestPathCost) {
140 if (!forwardOpen.empty()) {
141 Node current = forwardOpen.top();
145 if (!forwardClosed.contains(current.
cell)) {
146 forwardClosed.insert(current.
cell);
147 emit newCell(current.
cell);
150 if (backwardClosed.contains(current.
cell)) {
151 double pathCost = forwardG[current.
cell] + backwardG[current.
cell];
152 if (pathCost < bestPathCost) {
153 bestPathCost = pathCost;
154 meetingPoint = current.
cell;
159 for (
const auto neighbors =
getNeighbors(current.
cell);
const H3Index &neighbor : neighbors) {
160 if (neighbor == H3_NULL || forwardClosed.contains(neighbor) ||
blockedCells.contains(neighbor)) {
165 double tentativeG = forwardG[current.
cell] + edgeDistance;
167 if (!forwardG.contains(neighbor) || tentativeG < forwardG[neighbor]) {
168 forwardPrev[neighbor] = current.
cell;
169 forwardG[neighbor] = tentativeG;
170 double h =
heuristic(neighbor, endCoord);
171 forwardOpen.emplace(
Node{neighbor, tentativeG, tentativeG + h});
178 if (!backwardOpen.empty()) {
179 Node current = backwardOpen.top();
183 if (!backwardClosed.contains(current.
cell)) {
184 backwardClosed.insert(current.
cell);
185 emit newCell(current.
cell);
188 if (forwardClosed.contains(current.
cell)) {
189 double pathCost = forwardG[current.
cell] + backwardG[current.
cell];
190 if (pathCost < bestPathCost) {
191 bestPathCost = pathCost;
192 meetingPoint = current.
cell;
197 for (
const auto neighbors =
getNeighbors(current.
cell);
const H3Index &neighbor : neighbors) {
198 if (neighbor == H3_NULL || backwardClosed.contains(neighbor) ||
blockedCells.contains(neighbor)) {
203 double tentativeG = backwardG[current.
cell] + edgeDistance;
205 if (!backwardG.contains(neighbor) || tentativeG < backwardG[neighbor]) {
206 backwardPrev[neighbor] = current.
cell;
207 backwardG[neighbor] = tentativeG;
208 double h =
heuristic(neighbor, startCoord);
209 backwardOpen.emplace(
Node{neighbor, tentativeG, tentativeG + h});
217 if (meetingPoint != H3_NULL) {
219 std::vector<H3Index> forwardPath;
220 H3Index current = meetingPoint;
221 while (current != start) {
222 forwardPath.emplace_back(current);
223 auto it = forwardPrev.find(current);
224 if (it == forwardPrev.end()) {
227 current = it->second;
229 forwardPath.emplace_back(start);
230 std::ranges::reverse(forwardPath);
233 std::vector<H3Index> backwardPath;
234 current = meetingPoint;
235 while (current != end) {
236 auto it = backwardPrev.find(current);
237 if (it == backwardPrev.end()) {
240 current = it->second;
241 backwardPath.emplace_back(current);
243 backwardPath.emplace_back(end);
246 forwardPath.insert(forwardPath.end(), backwardPath.begin(), backwardPath.end());
248 spdlog::info(
"Bidirectional A* found path, explored {} nodes (meeting at 0x{:x})", nodesExplored, meetingPoint);
252 spdlog::warn(
"No path found, explored {} nodes", nodesExplored);
265 if (cellToLatLng(end, &endCoord) != E_SUCCESS) {
269 std::priority_queue<Node, std::vector<Node>, std::greater<>> openSet;
270 std::unordered_map<H3Index, double, H3IndexHash> gScores;
271 std::unordered_map<H3Index, H3Index, H3IndexHash> previous;
272 std::unordered_set<H3Index, H3IndexHash> closedSet;
274 gScores[start] = 0.0;
275 openSet.push({start, 0.0,
heuristic(start, endCoord)});
280 while (!openSet.empty() && iterations++ < maxIterations) {
281 Node current = openSet.top();
284 if (current.
cell == end) {
288 if (closedSet.contains(current.
cell))
290 closedSet.insert(current.
cell);
292 for (
const auto neighbors =
getNeighbors(current.
cell);
const H3Index &neighbor : neighbors) {
293 if (neighbor == H3_NULL)
296 if (closedSet.contains(neighbor) ||
blockedCells.contains(neighbor)) {
300 int parentRes = getResolution(limitParent);
301 H3Index neighborParent = H3_NULL;
302 cellToParent(neighbor, parentRes, &neighborParent);
303 if (neighborParent != limitParent) {
308 const double tentativeGScore = gScores[current.
cell] + edgeDistance;
310 if (!gScores.contains(neighbor) || tentativeGScore < gScores[neighbor]) {
311 previous[neighbor] = current.
cell;
312 gScores[neighbor] = tentativeGScore;
313 double h =
heuristic(neighbor, endCoord);
314 openSet.push({neighbor, tentativeGScore, tentativeGScore + h});
323 const H3Index originalEnd,
const int endRes) {
324 std::vector<H3Index> segment;
329 H3Index currentCell = parentEnd;
331 for (
int res = 4; res <= endRes; ++res) {
334 if (children.empty()) {
339 H3Index targetAtRes = H3_NULL;
341 targetAtRes = originalEnd;
344 for (
const H3Index &child : children) {
345 H3Index childParent = H3_NULL;
346 cellToParent(originalEnd, res, &childParent);
347 if (child == childParent) {
354 if (targetAtRes == H3_NULL) {
360 entryCell != H3_NULL) {
362 std::vector<H3Index> subPath;
363 subPath.reserve(children.size());
366 segment.insert(segment.end(), subPath.begin(), subPath.end());
367 currentCell = targetAtRes;
374 const int startRes)
const {
375 std::vector<H3Index> segment;
376 segment.emplace_back(originalStart);
379 H3Index currentCell = originalStart;
381 for (
int res = startRes - 1; res >= 3; --res) {
383 H3Index parent = H3_NULL;
384 if (cellToParent(currentCell, res, &parent) != E_SUCCESS) {
394 boundaryCell != H3_NULL && boundaryCell != currentCell) {
399 subPath.size() > 1) {
400 segment.insert(segment.end(), subPath.begin() + 1, subPath.end());
402 currentCell = boundaryCell;
407 currentCell = parent;
408 segment.emplace_back(currentCell);
413std::vector<H3Index>
H3AStar::refinePath(
const std::vector<H3Index> &pathRes3,
const H3Index originalStart,
414 const H3Index originalEnd,
const int startRes,
const int endRes) {
415 if (pathRes3.size() < 2) {
419 std::vector<H3Index> refinedPath;
420 refinedPath.reserve(pathRes3.size() - 1);
425 refinedPath.insert(refinedPath.end(), startSegment.begin(), startSegment.end());
427 refinedPath.emplace_back(pathRes3.front());
431 for (
size_t i = 1; i < pathRes3.size() - 1; ++i) {
432 refinedPath.emplace_back(pathRes3[i]);
436 if (endRes > 3 && pathRes3.size() >= 2) {
437 std::vector<H3Index> endSegment;
438 endSegment.reserve(pathRes3.size() - 1);
441 refinedPath.insert(refinedPath.end(), endSegment.begin(), endSegment.end());
443 refinedPath.emplace_back(pathRes3.back());
449 const H3Index direction) {
454 LatLng fromCoord, directionCoord;
455 if (cellToLatLng(from, &fromCoord) != E_SUCCESS || cellToLatLng(direction, &directionCoord) != E_SUCCESS) {
456 return cells.front();
460 const double dirLat = directionCoord.lat - fromCoord.lat;
461 const double dirLon = directionCoord.lng - fromCoord.lng;
463 H3Index bestCell = H3_NULL;
464 double maxProjection = -std::numeric_limits<double>::max();
466 for (
const H3Index &cell : cells) {
468 if (cellToLatLng(cell, &cellCoord) != E_SUCCESS) {
473 const double toLat = cellCoord.lat - fromCoord.lat;
474 const double toLon = cellCoord.lng - fromCoord.lng;
477 if (
const double projection = toLat * dirLat + toLon * dirLon; projection > maxProjection) {
478 maxProjection = projection;
483 return bestCell != H3_NULL ? bestCell : cells.front();