23 const auto future = QtConcurrent::run([self, lat, lon, kRingRadius] {
26 spdlog::warn(
"H3MazeAdapter was deleted before maze generation completed");
31 self->generateMaze(lat, lon, kRingRadius);
32 }
catch (
const std::exception &e) {
33 spdlog::critical(
"Maze generation failed: {}", e.what());
42 std::ranges::remove_if(
pendingFutures_, [](
const QFuture<void> &f) {
return f.isFinished(); }).begin(),
47 std::unordered_set<H3Index> walls;
49 const LatLng ll{.lat = lat, .lng = lon};
51 H3Index centerCell = H3_NULL;
52 H3Error err = E_SUCCESS;
53 err = latLngToCell(&ll, 3, ¢erCell);
54 if (err != E_SUCCESS) {
55 spdlog::warn(
"{} {}",
"Failed to convert center coordinates to H3", describeH3Error(err));
57 int radius = kRingRadius;
58 spdlog::info(
"Generating maze at center cell with radius {}", radius);
63 }
catch (
const std::exception &e) {
64 spdlog::error(
"{}", e.what());
67 spdlog::info(
"Cell maze generated: {} wall cells", walls.size());
72 err = maxGridDiskSize(radius, &ringSize);
73 if (err != E_SUCCESS) {
74 spdlog::error(
"maxGridDiskSize failed: {}", describeH3Error(err));
78 std::vector<H3Index> ring1st(ringSize);
79 err = gridRing(centerCell, radius, ring1st.data());
80 if (err != E_SUCCESS) {
81 spdlog::error(
"gridRing failed: {}", describeH3Error(err));
86 std::erase_if(ring1st, [](
const H3Index cell) {
return cell == H3_NULL || !isValidCell(cell); });
88 if (ring1st.empty()) {
89 spdlog::error(
"No valid cells in ring after filtering");
93 const H3Index zeroCell = ring1st.front();
96 if (middleCell == H3_NULL) {
97 spdlog::error(
"Failed to find middle cell in ring");
104 for (
auto const &cellId : ring1st | std::views::drop(1)) {
105 if (cellId == middleCell) {
108 if (!isValidCell(cellId)) {
111 if (walls.contains(cellId)) {
114 walls.insert(cellId);
119 cellToLatLng(centerCell, ¢erLatLng);
120 double maxDistance = 0.0;
122 for (
const auto &wallCell : walls) {
123 if (!isValidCell(wallCell)) {
127 if (
const auto err2 = cellToLatLng(wallCell, &wallLatLng); err2 != E_SUCCESS) {
130 if (
const double distance = greatCircleDistanceM(¢erLatLng, &wallLatLng); distance > maxDistance) {
131 maxDistance = distance;
136 const double radiusWithBuffer = maxDistance + 150000;
137 const QGeoCoordinate center(lat, lon);
139 spdlog::info(
"Maze radius calculated: max distance = {} m, with buffer = {} m", maxDistance, radiusWithBuffer);
142 QMetaObject::invokeMethod(
144 [
this, walls, center, radiusWithBuffer] {
147 emit mazePolygonsComputed(mergedPolygons);
148 spdlog::info(
"Maze polygons computed and emitted");
157 spdlog::info(
"Maze generation complete: {} wall cells", walls.size());
159 Qt::QueuedConnection);
168 std::vector<H3Index> cellsVec;
169 cellsVec.reserve(cells.size());
172 for (
const auto &cell : cells) {
173 if (cell == H3_NULL || !isValidCell(cell)) {
176 if (isPentagon(cell)) {
180 const int res = getResolution(cell);
181 if (targetRes == -1) {
183 }
else if (res != targetRes) {
187 cellsVec.emplace_back(cell);
190 if (cellsVec.empty()) {
191 spdlog::warn(
"No valid cells to convert to polygons");
195 spdlog::info(
"Converting {} valid cells (res={}) to polygons", cellsVec.size(), targetRes);
197 LinkedGeoPolygon polygon{};
200 auto cleanup = qScopeGuard([&polygon] { destroyLinkedMultiPolygon(&polygon); });
202 if (
const H3Error err = cellsToLinkedMultiPolygon(cellsVec.data(),
static_cast<int>(cellsVec.size()), &polygon);
204 spdlog::warn(
"cellsToLinkedMultiPolygon failed: {} (cells count: {})", describeH3Error(err), cellsVec.size());
209 std::vector<QVariantList> result;
210 const LinkedGeoPolygon *currentPoly = &polygon;
211 while (currentPoly !=
nullptr) {
213 if (currentPoly->first !=
nullptr) {
214 QVariantList polyPath;
216 const LinkedLatLng *currentVertex = currentPoly->first->first;
217 double prevLng = 0.0;
220 while (currentVertex !=
nullptr) {
221 const double lat = radsToDegs(currentVertex->vertex.lat);
222 double lng = radsToDegs(currentVertex->vertex.lng);
226 if (
const double delta = lng - prevLng; delta > 180.0) {
228 }
else if (delta < -180.0) {
233 polyPath.emplace_back(QVariant::fromValue(QGeoCoordinate{lat, lng, 0}));
236 currentVertex = currentVertex->next;
240 if (!polyPath.isEmpty() && currentPoly->first->first !=
nullptr) {
241 const double lat = radsToDegs(currentPoly->first->first->vertex.lat);
242 double lng = radsToDegs(currentPoly->first->first->vertex.lng);
245 if (
const double delta = lng - prevLng; delta > 180.0) {
247 }
else if (delta < -180.0) {
251 polyPath.emplace_back(QVariant::fromValue(QGeoCoordinate{lat, lng, 0}));
254 if (!polyPath.isEmpty()) {
255 result.emplace_back(std::move(polyPath));
259 currentPoly = currentPoly->next;
265 spdlog::info(
"Converted {} cells to {} polygons", cells.size(), result.size());
271 constexpr int kRingSize = 3;
272 H3Error err = maxGridDiskSize(kRingSize, &maxSize);
273 if (err != E_SUCCESS) {
274 spdlog::warn(describeH3Error(err));
277 std::vector<H3Index> disk(maxSize);
278 err = gridDisk(start, kRingSize, disk.data());
279 if (err != E_SUCCESS) {
280 spdlog::warn(describeH3Error(err));
282 for (
auto d : disk) {
283 if (walls.contains(d)) {
289 std::vector<H3Index> disk2(maxSize);
290 err = gridDisk(end, kRingSize, disk2.data());
291 if (err != E_SUCCESS) {
292 spdlog::warn(describeH3Error(err));
294 for (
auto d : disk2) {
295 if (walls.contains(d)) {
302 cellToLatLng(zeroCell, &zeroLatLng);
305 H3Index middleCell = H3_NULL;
306 H3Error err = E_SUCCESS;
307 for (
auto const &cellId : distances | std::views::drop(1)) {
308 if (!isValidCell(cellId)) {
311 err = cellToLatLng(cellId, &ll);
312 if (err != E_SUCCESS) {
313 spdlog::warn(describeH3Error(err));
315 if (
const auto distTemp = greatCircleDistanceM(&zeroLatLng, &ll); distTemp > dist) {