Skip to content

perf: cull polylines via cached projected bounding boxes & chore: prepare for v8.3.1 release#2212

Merged
JaffaKetchup merged 4 commits into
fleaflet:masterfrom
ben-milanko:perf/polyline-culling-bbox
Jun 30, 2026
Merged

perf: cull polylines via cached projected bounding boxes & chore: prepare for v8.3.1 release#2212
JaffaKetchup merged 4 commits into
fleaflet:masterfrom
ben-milanko:perf/polyline-culling-bbox

Conversation

@ben-milanko

Copy link
Copy Markdown
Contributor

While profiling flutter_map in a production app on low-powered hardware, I found two per-frame O(points) scans in PolylineLayer's aggressive culling:

  • stretchesBeyondTheLimits() iterates every point of every polyline that overlaps the viewport latitudes, every frame
  • fully-visible polylines still go through the per-segment aabbContainsLine scan (and sublist allocations), even though nothing needs to be culled

This PR caches the projected-space bounding box on _ProjectedPolyline (computed lazily — culled fragments never compute one; cached instances are created once per zoom level alongside simplification). The world-stretch check becomes an O(1) bbox comparison, and polylines whose bbox is contained in the viewport bounds are yielded whole, skipping the segment scan entirely.

Results

Measured with flutter test benchmark/feature_layer_benchmark_test.dart (JIT, best-of-reps):

before after
600 polylines × 60 pts, all visible, panning 2,631 µs/frame 2,484 µs/frame (~6%)
Mostly-culled scenario unchanged unchanged

Modest in this paint-dominated scenario, but the cull step itself no longer scales with point count, which matters as polyline density grows.

All existing tests pass. The benchmark harness commit is shared with #2211 (identical file content — it collapses out of this diff once either merges).

Cache the projected-space bounding box on each projected polyline
(lazily, so culled fragments never compute one). This replaces two
per-frame O(points) scans in aggressive culling:

- world-stretch detection now compares the bbox against the world east
  and west edges, instead of iterating every point of every polyline
  that overlaps the viewport latitudes
- fully-visible polylines (bbox contained in the viewport bounds) skip
  the per-segment aabbContainsLine scan and its sublist allocations

Benchmark (benchmark/feature_layer_benchmark_test.dart, JIT):
600 polylines x 60 pts, all visible, panning:
2631 -> 2484 us/frame. Mostly-culled scenario unchanged.
Widget- and kernel-level CPU benchmarks for the polyline, polygon, and
marker layers, plus a direct getOffsetsXY benchmark. Lives in
benchmark/ (not test/) so it is opt-in and does not extend CI runtime:

    flutter test benchmark/feature_layer_benchmark_test.dart

Numbers are JIT and only meaningful relative to each other (before vs
after a change on the same machine).

(cherry picked from commit ed76dc6)
@JaffaKetchup

Copy link
Copy Markdown
Member

Hey, thanks for these performance improvements! (Slightly annoyed that I left gaps in when putting all the caching stuff together lol 😂).

I'm still travelling right now, but I'll try to give these a review when I'm back in a couple weeks :)

@ben-milanko

Copy link
Copy Markdown
Contributor Author

Thanks @JaffaKetchup . Full disclosure these came up when I was doing some AI debugging and optimisations.

To provide some verification of the claims, I put together a repo with samples

There's pretty minimal improvements on this optimisation, as seen below.

polylines_before_after.mp4

Full repo is https://github.com/ben-milanko/flutter_map_perf_demo

Change demo app user agent to fix tile loading
Add simple AI guidelines to CONTRIBUTING.md
@JaffaKetchup JaffaKetchup self-requested a review June 30, 2026 22:58
@JaffaKetchup JaffaKetchup changed the title perf: cull polylines via cached projected bounding boxes perf: cull polylines via cached projected bounding boxes & chore: prepare for v8.3.1 release Jun 30, 2026
@JaffaKetchup JaffaKetchup enabled auto-merge (squash) June 30, 2026 22:59

@JaffaKetchup JaffaKetchup left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM I think, thanks again!

(I'm not super happy with the _ProjectedPolyline no longer having a const constructor and departing from symmetry with the _ProjectedPolygon, but it's still immutable which is the important thing.)

I've also hijacked this PR to prepare for a patch release (v8.3.1).

@JaffaKetchup JaffaKetchup merged commit 0a4b176 into fleaflet:master Jun 30, 2026
10 of 11 checks passed
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