ROI and brushing
Drawing an ROI
Section titled “Drawing an ROI”- Press
D, or use Draw ROI in the global bar or the palette. The Moon enters drawing mode. - Click to add vertices. Coordinates are geographic lon/lat in degrees on a sphere of radius
1737.4 km (
+proj=longlat +R=1737400). - Double-click, or press Enter, to close the ring. Backspace removes the last vertex; Escape cancels the draft.
- The ring is sent to Python for evaluation (
POST /roi/evaluate). The returned evaluation is the state that the Rows, Cells, Evidence and Figure instruments display.
On a phone or small tablet, tap to add vertices and use the Close ROI, Undo vertex and Cancel drawing buttons under the Moon instead of the keys (see Phones and small tablets).
Constraints enforced by the sidecar:
| Constraint | Value | Failure |
|---|---|---|
| Vertices | 3 to 512 (closure is implicit) | 422 |
| Vertex | two finite numbers; latitude in [−90, 90] | 422 |
| Geometry | a valid polygon, or one repaired by make_valid that is still a polygon | 422 “ring self-intersects” or “zero area” |
| Mask | at least one grid cell centre inside the polygon | 422 “contains no grid cell centre” |
A ring is evaluated as a user polygon. The mask rule is cell-centre-inside
(MASK_RULE in roi.py), which differs from the v1 lattice closed rule used for the source
ROIs. A user ROI is therefore METHOD_EXECUTED over a user mask and is never reported as
NUMERIC_REPRODUCED or admitted.
Identity
Section titled “Identity”The ring’s identity is the SHA-256 of its vertices formatted at 1e-9 degree. The first 12
hexadecimal characters label user ROIs (user:<12 hex>). If the ring digest matches a served
source ring exactly, the ROI is labelled source:<index> and its kind is source-ring.
Otherwise its kind is user-drawn.
Source ROIs
Section titled “Source ROIs”The Moon’s Source ROIs control lists the reference rings served by GET /site. Each has an
index roi and a closed ring of lon/lat pairs. Selecting one submits its served ring as a
normal ROI, so it resolves to the source:<index> identity above.
τ selection
Section titled “τ selection”τ is the slope-RMS cutoff. It is a data-quality threshold on the slope RMS grid, not an uncertainty, error bar or confidence bound.
For each τ, a cell is jointly valid when both of these hold:
- the slope is finite and within [0, 90] degrees;
- the slope RMS is finite and strictly positive.
A jointly valid cell is included when its slope RMS is less than or equal to τ (inclusive):
The inclusion fraction is included_cells / joint_cells. When joint_cells is zero the
fraction is undefined (null), not zero. The default τ values are 0.5, 2.0 and 25.0.
Selecting a row in the Rows table selects that τ in the research context.
Cell brushing
Section titled “Cell brushing”Brushing links a single grid cell between the Moon and the Cells grid. It runs in both
directions as a ResearchCommand.
Moon to Cells
Section titled “Moon to Cells”- With an evaluated ROI selected and not in drawing mode, click the Moon.
- The browser sends the lon/lat pick, the ROI ring and the current τ values to
GET /cell. - Python projects the pick, checks that it lies inside the ROI, finds the containing pixel and returns that cell’s values and per-τ inclusion.
- The linked cell centre is marked on the Moon, and the Cells grid scrolls to and highlights the matching sampled row. If the cell is not in the stride sample, the panel shows its Python values with the note “not in the sample”.
Cells to Moon
Section titled “Cells to Moon”Clicking a sampled cell links its Python coordinates (row, col, and the cell-centre
lon_deg and lat_deg from the sample) to the Moon marker, through the cell.link command.
Pixel footprint
Section titled “Pixel footprint”Python inverts the grid affine transform to find the containing pixel:
- The pick is projected from lon/lat into the grid CRS.
- The pixel coordinates
(column, row)are the inverse affine transform of the projected point. - A pixel’s footprint is half-open in grid coordinates: the top and left edges are included,
and the bottom and right edges are excluded. Concretely, the cell is
row = floor(pixel_row),col = floor(pixel_col), and the cell centre is the affine transform of(col + 0.5, row + 0.5). - Grid bounds are
0 ≤ pixel_row < rowsand0 ≤ pixel_col < cols.
ROI membership is tested at the picked point, not at the cell centre. A pick can therefore be inside the ROI while its containing cell centre lies outside the sampling mask. The response is then a valid “not in sample” result, not an error.
Values
Section titled “Values”- Non-finite slope or slope RMS serialises as
null, never as zero. includedis a map keyed by Python’s τ labels ("0.5","2","25", formatted as%g).- Each cell request is decoded with Effect Schema before it reaches research state.
Outcomes
Section titled “Outcomes”| Condition | HTTP status | Body |
|---|---|---|
Pick is inside the Site grid and, when ring is supplied, inside that ring | 200 | Cell result |
| Pick is outside the Site grid | 404 | {"error": "location is outside the Site grid"} |
| Pick is outside the supplied ROI | 404 | {"error": "location is outside the selected ROI"} |
| Longitude or latitude is missing, non-numeric, non-finite, or latitude is outside [−90, 90] | 422 | {"error": "..."} |
ring is not a JSON list, or fails the ring checks | 422 | {"error": "..."} |
tau values are not finite and non-negative | 422 | {"error": "..."} |
The grid check precedes the ROI check, so a point outside both returns the grid message.
Request cancellation
Section titled “Request cancellation”ROI changes, τ changes and newer sample clicks abort any pending cell request. A late response therefore cannot replace the current linked cell.
Verification boundary
Section titled “Verification boundary”The workbench and cell tests, the native localhost sidecar with the Effect decoder, the commands, and a research-state smoke test have been run without a Vite server. Cesium marker rendering and the live Perspective highlight have not yet been observed in a browser capture. See Residuals.