Repository navigation
Conversation
mayIntersect() resolves the z15 tiles of a query box that the rough bounding-box bitmap flags, one exact intersects() with the candidate geometries per tile, until one intersects. A large query box that lies within a huge geometry's bounding box without touching it, such as an offshore marine reserve inside a country's bounding box, checks every one of thousands of tiles against that geometry and finds nothing. When more than 16 tiles would need that check, intersect the query box with the candidates once instead: if nothing intersects it, nothing intersects any tile in it. Otherwise return true and leave it to the caller's exact check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01736kJW6d4B5wvq7B5vaKD9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Gain:
Intersects()/FindIntersecting()calls that took minutes now take milliseconds, when the feature's bounding box falls inside a huge shapefile/GeoJSON polygon's bounding box but doesn't touch the polygon.The stock OMT profile doesn't call
IntersectsorFindIntersecting, so numbers in this PR refer to a custom profile of mine that ran into the issue.Problem
Before running the exact
intersects(), tilemaker checks a z15 bitmap. A tile's bit is set if it falls inside the bounding box of any indexed polygon. The first time a query hits a set bit, tilemaker intersects that tile with the polygon to confirm it and caches the answer. It goes tile by tile until one confirms.When a feature lies inside a polygon's bounding box but outside the polygon, no tile ever confirms. So tilemaker intersects every z15 tile under the feature with the polygon. For a marine reserve a couple of degrees across, that's tens of thousands of intersections, each against the whole polygon.
Two marine reserves off British Columbia (13 nodes each), master, 1 thread:
FindIntersecting('states')FindIntersecting('countries')Fix
If more than 16 of the feature's z15 tiles would need confirming, intersect the feature's bounding box with the candidate polygons once instead. If none intersect it, none can intersect a tile inside it, so the answer is
false. Otherwise the exact check decides, as before. Features covering 16 tiles or fewer keep the per-tile check and its cache.This is only a pre-filter before the exact
intersects()inintersectsQuery(), so results can't change.Results (British Columbia, 16 threads)
FindIntersectingon states, countries and parks for 17,600 featuresIntersects()on parks for every wayFor the search-index profile, every feature got the same full, sorted list of matches with and without this PR.
The two marine reserves above now take about 0 s per lookup.
A new
test/shp_mem_tiles.test.cpp(inmake test) covers small and large boxes, both touching the polygon and inside its empty bounding box, before and after caching.The investigation, patch, test and benchmarks were done with Claude Code. I reviewed the results.
🤖 Generated with Claude Code