mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
fix(fires): paint aggregated heat cells warm by density, not by strongest FRP
Coloring each far-zoom cell with the ramp stop of its strongest detection turned a burning region into a blue / teal / lime mosaic: neighbouring cells flipped hue on one outlier and the cold stops did not read as fire. Cells say where it burns, so they go back to the heat-normalized score (density, night share, max FRP) on the warm end of the ramp — lime, amber, red — with the cell card accent matching. Single detections keep the full six-stop FRP ramp. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
1dad6b658a
commit
887b261195
4 files changed
+39
-15
No files matched your search
@@ -2,7 +2,8 @@
|
||||
cold → hot ramp (blue · teal · lime · amber · orange · red at 0 · 5 · 20 ·
|
||||
50 · 100 · 300 MW), and add a log-scale minimum-FRP slider whose track is the
|
||||
ramp, an All / Nominal+ / High confidence switch and an "N of M shown"
|
||||
counter to the layer row. The filter applies once before rendering, so
|
||||
counter to the layer row. Far-zoom heat cells keep a warm density fill
|
||||
(lime · amber · red). The filter applies once before rendering, so
|
||||
markers, cards, heat cells, context and the top-fires query agree; share
|
||||
links keep it (`w` token: `f`, `c`), and `get_active_fires` takes matching
|
||||
`min_frp_mw` and `confidence` arguments. Default 0 MW / All (gekh, #1426).
|
||||
@@ -2058,9 +2058,12 @@ accessible name remains "Don't show this again". Control behavior is unchanged.
|
||||
|
||||
Every FIRMS detection is colored by fire radiative power on a six-stop cold →
|
||||
hot ramp: blue from 0 MW, teal from 5, lime from 20, amber from 50, orange from
|
||||
100 and red from 300 MW (`FRP_RAMP` in `src/data/firmsIntensity.js`). Heat
|
||||
cells, glow sprites and card accents read the same ramp; confidence and
|
||||
brightness do not affect the color.
|
||||
100 and red from 300 MW (`FRP_RAMP` in `src/data/firmsIntensity.js`). Glow
|
||||
sprites and fire-card accents read that ramp; confidence and brightness do
|
||||
not affect the color. Aggregated heat cells (far zoom) instead take the warm
|
||||
end of the ramp — lime, amber or red — from their heat-normalized score
|
||||
(density, night share and strongest FRP), so a region reads as one field
|
||||
rather than a per-cell mosaic; the cell card's accent matches its fill.
|
||||
|
||||
The Active Fires row carries a "Fire intensity (FRP)" slider on a log scale
|
||||
whose track is painted with the ramp and ticked at the same six values (its
|
||||
|
||||
@@ -137,15 +137,33 @@ export function createModel({
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill color for an aggregated heat cell: the ramp color of its strongest
|
||||
* detection, so cells, markers and the slider legend read on one scale.
|
||||
* @param {number} maxFrp - Strongest FRP in the cell, megawatts.
|
||||
* Severity stop for an aggregated heat cell from its heat-normalized score
|
||||
* (density, night share and strongest FRP together). Cells say *where* it
|
||||
* burns, so they stay on the warm end of the ramp — lime, amber, red — and
|
||||
* read as one field instead of a per-cell mosaic; the cold stops belong to
|
||||
* single detections, which say *how hard* each one burns.
|
||||
* @param {number} normalized - 0..1 heat score (sqrt-normalized to the view).
|
||||
* @returns {{name: string, minFrp: number, color: Cesium.Color}}
|
||||
*/
|
||||
|
||||
function cellColorStop(normalized) {
|
||||
const name =
|
||||
normalized > 0.72 ? 'red' : normalized > 0.42 ? 'amber' : 'lime';
|
||||
return (
|
||||
DETECTION_COLOR_STOPS.find((stop) => stop.name === name) ||
|
||||
DETECTION_COLOR_STOPS[0]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill color for an aggregated heat cell.
|
||||
* @param {number} normalized - 0..1 heat score (see {@link cellColorStop}).
|
||||
* @param {number} alpha - Fill alpha (heat-normalized by the caller).
|
||||
* @returns {Cesium.Color}
|
||||
*/
|
||||
|
||||
function heatColor(maxFrp, alpha) {
|
||||
return frpColorStop(maxFrp).color.withAlpha(alpha);
|
||||
function heatColor(normalized, alpha) {
|
||||
return cellColorStop(normalized).color.withAlpha(alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -476,14 +494,14 @@ export function createModel({
|
||||
}
|
||||
|
||||
/**
|
||||
* Cell card accent: the ramp stop of the cell's strongest detection,
|
||||
* Cell card accent: the warm severity stop of the cell's heat score,
|
||||
* mirroring heatColor.
|
||||
* @param {number} maxFrp - Strongest FRP in the cell, megawatts.
|
||||
* @param {number} normalized - 0..1 heat score.
|
||||
* @returns {string} "r, g, b" accent string.
|
||||
*/
|
||||
|
||||
function cellAccent(maxFrp) {
|
||||
return accentForSeverity(frpColorStop(maxFrp).name);
|
||||
function cellAccent(normalized) {
|
||||
return accentForSeverity(cellColorStop(normalized).name);
|
||||
}
|
||||
|
||||
/** Coordinate line like "30.512°N 75.831°E". */
|
||||
@@ -590,6 +608,7 @@ export function createModel({
|
||||
cellIntersectsBounds,
|
||||
heatScore,
|
||||
heatColor,
|
||||
cellColorStop,
|
||||
frpColorStop,
|
||||
detectionColorStop,
|
||||
frpPixelSize,
|
||||
|
||||
@@ -144,7 +144,7 @@ export function createRendering({
|
||||
const score = components.model.heatScore(cell);
|
||||
const normalized = Math.min(1, Math.sqrt(score / maxScore));
|
||||
const alpha = 0.16 + normalized * 0.5;
|
||||
const color = components.model.heatColor(cell.maxFrp, alpha);
|
||||
const color = components.model.heatColor(normalized, alpha);
|
||||
const centerLon = cell.lonCell + lod.gridDegrees / 2;
|
||||
const centerLat = cell.latCell + lod.gridDegrees / 2;
|
||||
const position = Cesium.Cartesian3.fromDegrees(centerLon, centerLat, 0);
|
||||
@@ -170,12 +170,13 @@ export function createRendering({
|
||||
});
|
||||
|
||||
// Cells arrive heat-sorted, so candidate order doubles as label priority.
|
||||
// Accent is resolved here because `normalized` only exists in this walk.
|
||||
layerState._labelCandidates.push({
|
||||
position,
|
||||
cullPosition: components.model.cellCullPosition(centerLon, centerLat),
|
||||
fire: null,
|
||||
cell,
|
||||
accent: components.model.cellAccent(cell.maxFrp),
|
||||
accent: components.model.cellAccent(normalized),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user