Skip to content

Trees off roads: whole trunk checked, headroom over streets, slimmer models where one does not fit - #1517

Merged
louis-e merged 2 commits into
mainfrom
trees-off-roads
Nov 14, 2026
Merged

louis-e merged 2 commits into
mainfrom
trees-off-roads

Conversation

@louis-e

@louis-e louis-e commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

Trees no longer stand in the road or hang low over it. Mapped street trees that land in a road drawn wider than the real one move to the kerb, and a tree whose model does not fit beside a road is replaced by one that does instead of being left out.

Problem

  • Trees only checked the one column under the model's anchor against the roads. The anchor is the middle of the model's box, so wide trunks, off-centre trunks, root flares and low branches ended up on roads and paths, and low leaves hung at head height over them.
  • Mapped trees (natural=tree, natural=tree_row) skipped the check so they can stand on sidewalks. Where the road is drawn wider than the real one, that put them in the road.

Changes

  • Whole trunk checked: each model keeps its wood columns (the lowest log in each). No wood may stand in the headroom over a road: off any paving for scattered trees, off the carriageway for mapped ones. A trunk column rooted in the ground counts down to its own ground.
  • Headroom: leaves keep 4 m clear over carriageways and 2.5 m over footways, paths and other paving, so crowns still reach over the street. It stops growing past 1:1, since players and vehicles keep their size. Procedural trees drop a branch that would reach low over a road; micro trees are left alone.
  • Replaced, not dropped: the picker takes an optional fit check. The picked model is tried in its other turns, then the species' other models (nearest height, slimmest trunk first), then the community's other species. Without a fit check every pick is the same as before.
  • Mapped trees stay where they are mapped if any model of their own fits there: the one picked, then a slimmer one of its species, then the rest of its genus or leaf type. Otherwise they move to the nearest spot off the road that fits one, up to 8 m. Only where none of their own fits does a tree of their community stand in. Their middle stays off the carriageway too, and open ground wins over a sidewalk at the same distance.
  • Carriageway mask: collected in the same pass as the road mask, shared with the tile editors and released with the sealed-surface mask. Signs read it from the editor instead of building their own.

Results

Munich, 1.3 × 1.6 km (48.134,11.560,48.146,11.582), default trees:

main this PR
Mapped trees with the trunk in the road 96 0
Road columns with tree wood or leaves at head height 610 0
Footway and path columns blocked at head height 1,082 284
Generated trees 2,687 2,698
Mapped trees placed 1,115 1,100
  • What is left over footways is mostly mapped trees standing on sidewalks, which they may. 1,019 mapped trees stand exactly where they are mapped; the rest moved 1 to 8 blocks, most of them 1 to 3.
  • The 15 mapped trees left out stand in a tram median the carriageways and four tram rails with their tree-free band fill completely: nothing within 8 m is neither road nor track.
  • Slimmer trees beside roads leave some neighbouring slots free, hence a few more generated trees than on main.

Performance

CI benchmark area, main against this PR, runs interleaved: wall time, CPU and peak memory the same within noise. The fit check walks a model's wood columns, usually a handful, works out the base row only when wood reaches over a road, and searches further only when the picked model does not fit. Slots already taken are skipped before picking. The carriageway mask is one bit per column, replaces the one signs built for themselves, and is dropped before saving.

Testing

  • cargo test: 2,673 passed. Clippy and fmt clean.
  • New tests: trees beside a road and a footway leave the headroom clear; a slot whose model would reach into the road still gets a tree; a mapped tree in the road moves out of it; a one-block trunk moves to the nearest column off the road; a wide trunk is checked on every column; the picker turns a model, finds a stand-in, or gives up only when nothing fits, and a check that takes everything changes no pick; a mapped lime only moves as a lime before its community stands in; headroom stops at its 1:1 height; micro trees keep their leaves and step off the road. Each fails with its part of the change switched off.

Known limits

  • Clearance is measured from the ground, so on a bridge it counts from the terrain below the deck.
  • A moved mapped tree keeps its mapped position for the canopy map's crown check (5 m around it); moves are mostly 1 to 3 blocks.
  • A mapped tree does not move across a tile seam, so near one it may move further along the road.

…models where one does not fit

- Every wood column of a tree model is checked against the roads, not only the
  model's middle: off any paving for scattered trees, off the carriageway for
  mapped ones.
- Leaves keep 4 m clear over carriageways and 2.5 m over footways and paving.
- A model that does not fit turns, then gives way to a slimmer or smaller one of
  its species, then to another species of its community.
- Mapped trees in the road move out of it: as picked up to 4 m, as any model
  that fits up to 8 m, onto open ground before a sidewalk.
- Carriageway mask collected in the same pass as the road mask.
@github-actions

github-actions Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

⏱️ Benchmark run finished in 0m 44s
🏗️ Generation time: 30s (excl. data fetching)
🧠 Peak memory usage: 1278 MB

📈 Compared against baseline: 48s time, 1250 MB memory
🧮 Delta: -18s time, 28 MB memory
🔢 Commit: 1e27887

✅ This PR improves generation time.
🟢 Peak memory is unchanged.

📅 Last benchmark: 2026-11-14 12:50:53 UTC

You can retrigger the benchmark by commenting retrigger-benchmark.

…re moving, review fixes

- A mapped tree tries its own pool first (its genus, its leaf type or its
  community) at the nearest spot off the road, so a slimmer model of its species
  stands where it is mapped before it moves, and a lime stays a lime up to 8 m
  away before a tree of its community stands in. Its middle stays off the
  carriageway too, so a model without logs cannot hang over it.
- Headroom stops growing past 1:1, micro trees keep their leaves, and mapped
  trees can always step off a road drawn at its narrowest.
- Signs read the editor's carriageway mask instead of building their own.
- The base row is only worked out when wood reaches over a road, taken slots
  are skipped before picking, and the spot checks are shared.
@louis-e
louis-e merged commit 963ff11 into main Nov 14, 2026
3 checks passed
@louis-e
louis-e deleted the trees-off-roads branch November 14, 2026 13:18
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.

1 participant