Now update the BacktrackState and ring building to use sub_ways instead of outer_ways.


Edit

    std::vector<bool> used(outer_ways.size(), false);
    std::vector<std::vector<std::pair<double,double>>> rings;

    // Backtracking ring closure using coordinate matching
    struct BacktrackState {
        const std::vector<WayRef>& ways;
        const std::unordered_map<int64_t, std::vector<std::pair<size_t, bool>>>& adj;
        std::vector<bool>& used;
        decltype(coord_key)& key_fn;

        bool try_close(int64_t first_key, int64_t last_key,
                       std::vector<std::pair<size_t, bool>>& path, int depth) {
            if (depth > 5000) return false;
            if (!path.empty() && first_key == last_key) return true;

            auto it = adj.find(last_key);
            if (it == adj.end()) return false;

            for (const auto& [wi, is_last] : it->second) {
                if (used[wi]) continue;
                const auto* g = ways[wi].geom;
                bool reversed = is_last;
                auto& endpoint = reversed ? g->coords.front() : g->coords.back();
                int64_t new_key = key_fn(endpoint.first, endpoint.second);

                used[wi] = true;
                path.push_back({wi, reversed});

                if (try_close(first_key, new_key, path, depth + 1)) return true;

                path.pop_back();
                used[wi] = false;
            }
            return false;
        }
    };

    BacktrackState state{outer_ways, coord_adj, used, coord_key};

    for (size_t start_idx = 0; start_idx < outer_ways.size(); start_idx++) {
        if (used[start_idx]) continue;

        const auto* sg = outer_ways[start_idx].geom;
        int64_t first_key = coord_key(sg->coords.front().first, sg->coords.front().second);
        int64_t last_key = coord_key(sg->coords.back().first, sg->coords.back().second);

        // Single way already closed
        if (sg->coords.size() >= 4 && first_key == last_key) {
            used[start_idx] = true;
            rings.push_back(sg->coords);
            continue;
        }

        // Try to build a closed ring
        used[start_idx] = true;
        std::vector<std::pair<size_t, bool>> path;
        if (state.try_close(first_key, last_key, path, 0)) {
            std::vector<std::pair<double,double>> ring = sg->coords;
            for (const auto& [wi, reversed] : path) {
                const auto& coords = outer_ways[wi].geom->coords;
                if (!reversed) {
                    ring.insert(ring.end(), coords.begin() + 1, coords.end());
                } else {
                    for (auto rit = coords.rbegin() + 1; rit != coords.rend(); ++rit) {
                        ring.push_back(*rit);
                    }
                }
            }
            if (ring.size() >= 4) {
                rings.push_back(std::move(ring));
            }
        } else {
            used[start_idx] = false;
        }
    }

    return rings;

    std::vector<bool> used(sub_ways.size(), false);
    std::vector<std::vector<std::pair<double,double>>> rings;

    // Backtracking ring closure on sub-ways
    struct BacktrackState {
        const std::vector<SubWay>& sways;
        const std::unordered_map<int64_t, std::vector<std::pair<size_t, bool>>>& adj;
        std::vector<bool>& used;
        decltype(coord_key)& key_fn;

        bool try_close(int64_t first_key, int64_t last_key,
                       std::vector<std::pair<size_t, bool>>& path, int depth) {
            if (depth > 10000) return false;
            if (!path.empty() && first_key == last_key) return true;

            auto it = adj.find(last_key);
            if (it == adj.end()) return false;

            for (const auto& [wi, is_last] : it->second) {
                if (used[wi]) continue;
                const auto& sw = sways[wi];
                bool reversed = is_last;
                auto& endpoint = reversed ? sw.coords.front() : sw.coords.back();
                int64_t new_key = key_fn(endpoint.first, endpoint.second);

                used[wi] = true;
                path.push_back({wi, reversed});

                if (try_close(first_key, new_key, path, depth + 1)) return true;

                path.pop_back();
                used[wi] = false;
            }
            return false;
        }
    };

    BacktrackState state{sub_ways, coord_adj, used, coord_key};

    for (size_t start_idx = 0; start_idx < sub_ways.size(); start_idx++) {
        if (used[start_idx]) continue;

        const auto& sg = sub_ways[start_idx];
        int64_t first_key = coord_key(sg.coords.front().first, sg.coords.front().second);
        int64_t last_key = coord_key(sg.coords.back().first, sg.coords.back().second);

        // Single sub-way already closed
        if (sg.coords.size() >= 4 && first_key == last_key) {
            used[start_idx] = true;
            rings.push_back(sg.coords);
            continue;
        }

        // Try to build a closed ring from sub-ways
        used[start_idx] = true;
        std::vector<std::pair<size_t, bool>> path;
        if (state.try_close(first_key, last_key, path, 0)) {
            std::vector<std::pair<double,double>> ring = sg.coords;
            for (const auto& [wi, reversed] : path) {
                const auto& coords = sub_ways[wi].coords;
                if (!reversed) {
                    ring.insert(ring.end(), coords.begin() + 1, coords.end());
                } else {
                    for (auto rit = coords.rbegin() + 1; rit != coords.rend(); ++rit) {
                        ring.push_back(*rit);
                    }
                }
            }
            if (ring.size() >= 4) {
                rings.push_back(std::move(ring));
            }
        } else {
            used[start_idx] = false;
        }
    }

    return rings;