@mytec: iter2.5 vectorization start
This commit is contained in:
@@ -8,38 +8,35 @@ interface ElevationLayerProps {
|
||||
opacity: number;
|
||||
}
|
||||
|
||||
// Terrain color gradient: low = green, mid = yellow/tan, high = brown/white
|
||||
const COLOR_STOPS = [
|
||||
{ elev: 0, r: 20, g: 100, b: 40 }, // dark green
|
||||
{ elev: 100, r: 50, g: 160, b: 60 }, // green
|
||||
{ elev: 200, r: 130, g: 200, b: 80 }, // yellow-green
|
||||
{ elev: 350, r: 210, g: 190, b: 100 }, // tan
|
||||
{ elev: 500, r: 180, g: 140, b: 80 }, // brown
|
||||
{ elev: 800, r: 160, g: 120, b: 90 }, // dark brown
|
||||
{ elev: 1200, r: 200, g: 190, b: 180 }, // light grey
|
||||
{ elev: 2000, r: 240, g: 240, b: 240 }, // near white
|
||||
// Color gradient for normalized elevation (0 = lowest local, 1 = highest local)
|
||||
// Blue (valleys) → Green → Yellow → Orange → Brown (peaks)
|
||||
const GRADIENT_STOPS: [number, number, number][] = [
|
||||
[33, 102, 172], // 0.0 — deep blue (lowest)
|
||||
[103, 169, 207], // 0.2 — light blue
|
||||
[145, 207, 96], // 0.4 — green
|
||||
[254, 224, 139], // 0.6 — yellow
|
||||
[252, 141, 89], // 0.8 — orange
|
||||
[215, 48, 39], // 1.0 — brown/red (highest)
|
||||
];
|
||||
|
||||
function getColorForElevation(elev: number): [number, number, number] {
|
||||
if (elev <= COLOR_STOPS[0].elev) {
|
||||
return [COLOR_STOPS[0].r, COLOR_STOPS[0].g, COLOR_STOPS[0].b];
|
||||
function getColorForNormalizedElevation(normalized: number): [number, number, number] {
|
||||
const n = Math.max(0, Math.min(1, normalized));
|
||||
// Map 0-1 to gradient index (0-5)
|
||||
const scaled = n * (GRADIENT_STOPS.length - 1);
|
||||
const idx = Math.floor(scaled);
|
||||
const t = scaled - idx;
|
||||
|
||||
if (idx >= GRADIENT_STOPS.length - 1) {
|
||||
return GRADIENT_STOPS[GRADIENT_STOPS.length - 1];
|
||||
}
|
||||
|
||||
for (let i = 1; i < COLOR_STOPS.length; i++) {
|
||||
if (elev <= COLOR_STOPS[i].elev) {
|
||||
const low = COLOR_STOPS[i - 1];
|
||||
const high = COLOR_STOPS[i];
|
||||
const t = (elev - low.elev) / (high.elev - low.elev);
|
||||
return [
|
||||
Math.round(low.r + t * (high.r - low.r)),
|
||||
Math.round(low.g + t * (high.g - low.g)),
|
||||
Math.round(low.b + t * (high.b - low.b)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
const last = COLOR_STOPS[COLOR_STOPS.length - 1];
|
||||
return [last.r, last.g, last.b];
|
||||
const low = GRADIENT_STOPS[idx];
|
||||
const high = GRADIENT_STOPS[idx + 1];
|
||||
return [
|
||||
Math.round(low[0] + t * (high[0] - low[0])),
|
||||
Math.round(low[1] + t * (high[1] - low[1])),
|
||||
Math.round(low[2] + t * (high[2] - low[2])),
|
||||
];
|
||||
}
|
||||
|
||||
export default function ElevationLayer({ visible, opacity }: ElevationLayerProps) {
|
||||
@@ -100,10 +97,16 @@ export default function ElevationLayer({ visible, opacity }: ElevationLayerProps
|
||||
const imageData = ctx.createImageData(data.cols, data.rows);
|
||||
const pixels = imageData.data;
|
||||
|
||||
// Use LOCAL min/max for color normalization (not absolute thresholds)
|
||||
const minElev = data.min_elevation;
|
||||
const maxElev = data.max_elevation;
|
||||
const elevRange = maxElev - minElev || 1; // avoid division by zero
|
||||
|
||||
for (let row = 0; row < data.rows; row++) {
|
||||
for (let col = 0; col < data.cols; col++) {
|
||||
const elev = data.grid[row][col];
|
||||
const [r, g, b] = getColorForElevation(elev);
|
||||
const normalized = (elev - minElev) / elevRange;
|
||||
const [r, g, b] = getColorForNormalizedElevation(normalized);
|
||||
const idx = (row * data.cols + col) * 4;
|
||||
pixels[idx] = r;
|
||||
pixels[idx + 1] = g;
|
||||
|
||||
Reference in New Issue
Block a user