Bash

cat /root/traccar-geocoder/builder/src/build_index.cpp | ssh node3 "cat > /tmp/traccar-geocoder/builder/src/build_index.cpp" && ssh node3 "cd /tmp/traccar-geocoder/build && make -j\$(nproc) 2>&1 | tail -3 && rm -rf /tmp/de-par-final8 && mkdir -p /tmp/de-par-final8 && /tmp/traccar-geocoder/build/build-index /tmp/de-par-final8 ~/pbf/germany.osm.pbf --parallel-admin 2>&1 | grep -E 'polygon|Done'" 2>&1

Build with 3e-7 threshold


[ 50%] Building CXX object CMakeFiles/build-index.dir/src/build_index.cpp.o
[100%] Linking CXX executable build-index
[100%] Built target build-index
  Added 37 admin polygons from closed ways.
  Assembling admin polygons in parallel (40080 relations, 112858 way geometries)...
  Parallel admin assembly complete: 42804 polygon rings from 40080 relations.
Done reading:
  42841 admin polygon rings
Waiting for admin polygon S2 covering to complete...
Admin polygon S2 covering complete (6103 cells).
admin index: 6103 cells, 42841 polygons
Done.


Still losing 383 rings. The area threshold approach doesn't work because the sequential build also has hundreds of legitimate polygons at these tiny areas. Both builds have nearly identical area distributions.

The Neuhaus and Krefeld micro-rings are at areas 2.17e-7 and 1.26e-7, but there are ~197 legitimate polygons below 1e-7 in both builds. We can't distinguish the 2 artifacts from the ~197 legitimate ones by area alone.

Let me revert the area filter and instead fix the root cause: the Neuhaus ring shouldn't be created (osmium doesn't create it), and the Krefeld ring should be under the right name.


Edit

    // Post-process: remove micro-polygon artifacts.
    // When shared ways between relations create tiny rings at boundary junctions,
    // discard rings with extremely small area that are artifacts of branch point
    // choices in the stitcher. Osmium's assembler handles these differently
    // (assigns them to a different relation or discards them).
    if (rings.size() > 1) {
        auto compute_area = [](const std::vector<std::pair<double,double>>& ring) -> double {
            double area = 0;
            size_t n = ring.size();
            for (size_t i = 0; i < n; i++) {
                size_t j = (i + 1) % n;
                area += ring[i].first * ring[j].second;
                area -= ring[j].first * ring[i].second;
            }
            return std::abs(area) / 2.0;
        };

        // Remove micro-polygon artifacts: rings with area < 3e-7 sq degrees (~3.7 sq m)
        // These are degenerate boundary artifacts at shared-way junction branch points
        // that osmium's assembler handles differently.
        constexpr double MIN_RING_AREA = 3e-7;
        rings.erase(std::remove_if(rings.begin(), rings.end(),
            [&](const std::vector<std::pair<double,double>>& ring) {
                return compute_area(ring) < MIN_RING_AREA;
            }), rings.end());
    }

    return rings;