gap: the grass keep-out asks the register's category, so orchards and cover crops lose their grass too #225

Closed
opened 2026-08-30 08:37:36 +00:00 by viberfox-agent · 0 comments
Collaborator

Found while QA-ing what #203 shipped (#217).

What I did

Served the crop tree from a stand-in extractor (see #217) and stood on the ground
at 52.499607, 5.658834 — the seam between a registered pear orchard (gewascode
1098, category Bouwland) and the natural grassland beside it (1926,
Grasland) — with and without the register served, everything else identical:

cargo run -p cartopolis -- --shot /tmp/ground.png \
    --at 52.499607,5.658834,25 --look=-35,0 --time 12 --clouds 0 --rain 0 --hide-ui

What happened

The keep-out works, and it takes the orchard's grass with it. Without the
register the orchard floor is carpeted in near-field blades; with it the trees
stand on bare ground, with a straight edge where the grassland parcel starts.

grows_grass() asks the category and nothing else:

// crates/geo/src/crops.rs
pub fn grows_grass(self) -> bool { !matches!(self, Self::Arable) }

Everything the register files as Bouwland is therefore treated as ploughed
earth — including the parcels this same file styles as something else entirely:

  • 1096 / 1097 / 1098 — apples and pears. The tone table gives them their own
    orchard green ("standing trees, the deepest green here after maize") and OSM
    independently tags the same ground landuse=orchard, which is what puts the
    tree rows on it. An orchard alley in the Netherlands is mown grass.
  • 6751 / 6755 / 6762 / 6783 / 6785 / 7126 — groenbemesting, vanggewas:
    ryegrass and red fescue sown to be ploughed in. The table gives them a cover-crop
    green and calls them "the second most numerous thing on arable land after the
    crop itself"; five of the 72 arable parcels in the sampled Flevoland cell are
    these. They are literally fields of grass with the blades switched off.
  • 1067–1093 — nursery stock, "rows of young trees on open ground".

What a user would expect

Grass under the fruit trees. The register's category answers "is this land
worked?", which is not the same question as "does grass grow here?" — and the
distinction matters most for the two families the tone table already treats as
green.

Where the seam is

crates/geo/src/crops.rs — CropCategory::grows_grass, and crops::rgb a few
lines below it, which already knows the finer answer per code. The keep-out
consumer is crates/geo/src/turf.rs (ArableMask::build →
crops::arable_triangles), so a per-code rule costs nothing there: the same
filter, asked of the code instead of the category. Suggested shape —
grows_grass(code) returning true for the orchard, cover-crop and nursery
families and falling back to the category otherwise, with the existing
blades grew on an arable parcel test extended by one case per family.

Note the fix is a strict improvement in area terms either way: without it the
correct behaviour on true arable land (the thing #203 set out to fix, and it does
fix) costs the orchards and cover crops their grass.

Found while QA-ing what #203 shipped (#217). ## What I did Served the crop tree from a stand-in extractor (see #217) and stood on the ground at 52.499607, 5.658834 — the seam between a registered pear orchard (`gewascode` 1098, category `Bouwland`) and the natural grassland beside it (1926, `Grasland`) — with and without the register served, everything else identical: ``` cargo run -p cartopolis -- --shot /tmp/ground.png \ --at 52.499607,5.658834,25 --look=-35,0 --time 12 --clouds 0 --rain 0 --hide-ui ``` ## What happened The keep-out works, and it takes the orchard's grass with it. Without the register the orchard floor is carpeted in near-field blades; with it the trees stand on bare ground, with a straight edge where the grassland parcel starts. `grows_grass()` asks the **category** and nothing else: ```rust // crates/geo/src/crops.rs pub fn grows_grass(self) -> bool { !matches!(self, Self::Arable) } ``` Everything the register files as `Bouwland` is therefore treated as ploughed earth — including the parcels this same file styles as something else entirely: * **1096 / 1097 / 1098** — apples and pears. The tone table gives them their own orchard green ("standing trees, the deepest green here after maize") and OSM independently tags the same ground `landuse=orchard`, which is what puts the tree rows on it. An orchard alley in the Netherlands is mown grass. * **6751 / 6755 / 6762 / 6783 / 6785 / 7126** — `groenbemesting, vanggewas`: ryegrass and red fescue sown to be ploughed in. The table gives them a cover-crop green and calls them "the second most numerous thing on arable land after the crop itself"; five of the 72 arable parcels in the sampled Flevoland cell are these. They are literally fields of grass with the blades switched off. * **1067–1093** — nursery stock, "rows of young trees on open ground". ## What a user would expect Grass under the fruit trees. The register's category answers "is this land worked?", which is not the same question as "does grass grow here?" — and the distinction matters most for the two families the tone table already treats as green. ## Where the seam is `crates/geo/src/crops.rs` — `CropCategory::grows_grass`, and `crops::rgb` a few lines below it, which already knows the finer answer per code. The keep-out consumer is `crates/geo/src/turf.rs` (`ArableMask::build` → `crops::arable_triangles`), so a per-code rule costs nothing there: the same filter, asked of the code instead of the category. Suggested shape — `grows_grass(code)` returning true for the orchard, cover-crop and nursery families and falling back to the category otherwise, with the existing `blades grew on an arable parcel` test extended by one case per family. Note the fix is a strict improvement in area terms either way: without it the correct behaviour on true arable land (the thing #203 set out to fix, and it does fix) costs the orchards and cover crops their grass.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jeroen/cartopolis#225
No description provided.