Repository navigation
feat(spatial): "cover" polygon cell selection for thin/concave areas - #20
Merged
Merged
Conversation
The polygon reader keeps a cell only when its center falls inside the ring (`pointInPolygon`). A thin or concave polygon narrower than the grid step then selects very few — or zero — cells, forcing the caller into a degenerate single-cell fallback (which, for a concave ring, can resolve to a point outside the drawn shape). Add an opt-in `selection: "cover"` to PolygonReadOptions. Alongside the center test, it keeps any cell whose FOOTPRINT overlaps the polygon (conservative rasterization: corner-in-ring, ring-vertex-in-cell, or edge-crossing). This tracks the cells a shape visibly covers and guarantees a non-empty selection whenever the polygon overlaps any cell — the right membership for an area "distribution over the zone" reduction. - `selection` defaults to "center"; existing behaviour is unchanged. - Footprints come from neighbour midpoints; a `coverBBox` scan box keys off footprints (superset of the center-bbox) so a sub-cell polygon that contains no center still resolves. - Implemented for the 1d-rectilinear and 2d-curvilinear layouts; npoints degrades to "center".
There was a problem hiding this comment.
Pull request overview
Adds an opt-in polygon cell selection mode (selection: "cover") to make resolvePolygonCells / readPolygon robust for thin and concave polygons that often select too few (or zero) cells under the existing center-only rule.
Changes:
- Extend
PolygonReadOptionswithselection?: "center" | "cover"(defaulting to"center"for back-compat). - Implement conservative “cover” membership via per-cell footprint bounds + polygon/rect overlap predicate for 1d-rectilinear and 2d-curvilinear layouts (npoints falls back to center).
- Add a dedicated unit test suite covering hard cases for both 1d and 2d layouts.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/unit/polygon-reader.cover.test.ts | Adds unit tests validating "cover" behavior (cover ⊇ center; non-empty selections on coarse grids; 1d + 2d cases). |
| src/spatial/polygon-reader.ts | Introduces the "cover" selection path (cell footprint computation + overlap test) and wires it into selection resolution. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+160
to
+170
| const d1 = cross(b1, b2, a1); | ||
| const d2 = cross(b1, b2, a2); | ||
| const d3 = cross(a1, a2, b1); | ||
| const d4 = cross(a1, a2, b2); | ||
| if (d1 > 0 !== d2 > 0 && d3 > 0 !== d4 > 0) return true; | ||
| // Colinear / touching cases. | ||
| if (d1 === 0 && onSeg(b1, a1, b2)) return true; | ||
| if (d2 === 0 && onSeg(b1, a2, b2)) return true; | ||
| if (d3 === 0 && onSeg(a1, b1, a2)) return true; | ||
| if (d4 === 0 && onSeg(a1, b2, a2)) return true; | ||
| return false; |
npillar
added a commit
that referenced
this pull request
Jul 17, 2026
Minor release adding the "cover" polygon cell selection from PR #20: PolygonReadOptions.selection: "center" | "cover" (default "center", back-compat). "cover" keeps any cell whose footprint overlaps the ring (conservative rasterization), guaranteeing a non-empty selection for thin or concave areas where center-in-ring picks too few — or zero — cells and the centroid fallback can resolve outside the shape. Implemented for the 1d-rectilinear and 2d-curvilinear layouts; npoints degrades to "center".
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.
What
Adds an opt-in
selection: "cover"toPolygonReadOptions(resolvePolygonCells/readPolygon).Today the reader keeps a cell only when its center falls inside the ring. For a thin or concave polygon narrower than the grid step this selects very few — or zero — cells, so the consumer (area meteogram, spec 058) drops to a degenerate single-cell fallback. For a concave ring that fallback cell can even resolve outside the drawn shape.
"cover"adds conservative rasterization: alongside the center test, it also keeps any cell whose footprint overlaps the polygon (corner-in-ring ∪ ring-vertex-in-cell ∪ edge-crossing). The selection then tracks the cells the shape visibly covers, and is non-empty whenever the polygon overlaps any cell.Why
Consumers need a meaningful "distribution over the zone" band for any area shape, including thin/route-like corridors. Center-only membership makes those areas fragile (few cells) or wrong (empty → fallback outside the ring).
Details
selectiondefaults to"center"— existing behaviour is unchanged (verified by a back-compat test).coverBBoxscan box keys off footprints (a superset of the center-bbox), so a sub-cell polygon that contains no center still resolves.npointsdegrades to"center".Validation
New
tests/unit/polygon-reader.cover.test.ts(7 cases, 1d + 2d incl. a skewed curvilinear grid): cover ⊇ center; coarse grid where center collapses to empty but cover stays populated; sub-cell polygon between four centers. Fullpolygon-readersuite (48) still green.Driven against a real thin/concave area on the production
wrf3km(2d-curvilinear) grid: center 12 cells → cover 41, producing a fuller min/median/max band.Follow-up (separate PR, consumer side)
Wire
selection: "cover"into the nautilusarea-meteogramread path (readAreaVariable:resolvePolygonCells+readPolygon, speed + direction) and bump the@i4sea/zarr-nodedependency once this is published.