Skip to content

fix(convert_osm): replace clip_map with overlap-based boundary clipping - #1178

Open
AlyZaki wants to merge 1 commit into
a-b-street:mainfrom
AlyZaki:fix/clip-map-boundary-overlap
Open

fix(convert_osm): replace clip_map with overlap-based boundary clipping#1178
AlyZaki wants to merge 1 commit into
a-b-street:mainfrom
AlyZaki:fix/clip-map-boundary-overlap

Conversation

@AlyZaki

@AlyZaki AlyZaki commented May 16, 2026

Copy link
Copy Markdown

The current clip_map drops any building where a single vertex falls outside the GPS boundary
polygon. At city edges this quietly removes buildings that are 95% inside the map — one corner
clips a boundary way and the whole building disappears. You only notice the effect when zoomed in
on the border and see a sudden gap in the building layer.

Fix

New clip_resilient.rs with clip_map_resilient() that keeps buildings with ≥5% area overlap
instead of requiring all vertices to be inside.

To avoid making it slow on large maps, there are two cheap rejection steps before the expensive
polygon intersection call:

  1. Fast path — if all vertices are inside, return immediately (handles most buildings)
  2. Bounding box rejection — if the building's bbox doesn't intersect the boundary's bbox, skip
    the intersection call entirely (handles buildings clearly outside)

Polygon intersection is only computed for buildings near the boundary — which is where you actually
want the precision.

Additional guards that prevent panics further downstream:

  • Degenerate polygons (<4 ring points) are logged and dropped
  • NaN coordinates are caught before they reach Ring arithmetic

No new dependencies. Tested against Cairo urban core (~750K buildings).


Developed while importing Cairo urban core OSM data for a city simulation research project at Egypt University of Informatics.

The current clip_map silently drops any building where a single vertex lies
outside the GPS boundary polygon. At city edges this removes buildings that
are 95% inside the map — one corner clips a boundary way and the whole
building disappears.

Replace with clip_map_resilient() which retains buildings with >=5% area
overlap. The overlap is computed via polygon intersection, only called for
buildings not fully inside (fast path) and whose bounding boxes overlap the
boundary bbox (cheap early rejection before the expensive intersection test).

Additional guards: degenerate polygons (<4 ring points) and NaN coordinates
are logged and dropped rather than causing arithmetic panics downstream.

Tested against Cairo urban core (~750K buildings, complex boundary polygon).
// Pre-compute boundary bounding box for cheap early rejection.
// Buildings whose bbox doesn't overlap the boundary bbox can't overlap the boundary.
let boundary_pts: Vec<_> = boundary_polygon.get_outer_ring().points().clone();
let (bnd_min_x, bnd_max_x, bnd_min_y, bnd_max_y) = boundary_pts.iter().fold(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

geom::Bounds::from_polygons can do this

}

// Guard: NaN coordinates
if outer_pts.iter().any(|pt| !pt.x().is_finite() || !pt.y().is_finite()) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like my comment in the other PR -- this should either be prevented outright in the input, or at worst, filtered out upfront when parsing from OSM (streets_reader/src/osm_reader/reader.rs in the osm2streets repo)

Comment thread convert_osm/src/lib.rs

clip_map(&mut map, timer);
crate::clip_resilient::clip_map_resilient(&mut map, timer);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of dead code hanging around, so if we go with the new approach, please delete the old method. And then calling it "resilient" is kind of redundant; it's just the only way to clip the map, and it handles more cases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants