From 2162c043c934719e01536fe450d34bda8ce5f6bb Mon Sep 17 00:00:00 2001 From: Azgaar Date: Thu, 10 Jun 2021 20:23:45 +0300 Subject: [PATCH] fix add river on click --- modules/lakes.js | 51 +++++++++++++++++++++++++++++++++- modules/river-generator.js | 56 +++----------------------------------- modules/ui/tools.js | 23 ++++++---------- 3 files changed, 63 insertions(+), 67 deletions(-) diff --git a/modules/lakes.js b/modules/lakes.js index cf73b5dc..9cae7196 100644 --- a/modules/lakes.js +++ b/modules/lakes.js @@ -37,6 +37,55 @@ lake.shoreline = [...uniqueCells]; }; + const prepareLakeData = h => { + const cells = pack.cells; + const ELEVATION_LIMIT = 10; + + pack.features.forEach(f => { + if (f.type !== "lake") return; + delete f.flux; + delete f.inlets; + delete f.outlet; + delete f.height; + delete f.closed; + !f.shoreline && Lakes.getShoreline(f); + + // lake surface height is as lowest land cells around + const min = f.shoreline.sort((a, b) => h[a] - h[b])[0]; + f.height = h[min] - 0.1; + + // check if lake can be open (not in deep depression) + let deep = true; + const treshold = f.height + ELEVATION_LIMIT; + const queue = [min]; + const checked = []; + checked[min] = true; + + // check if elevated lake can potentially pour to another water body + while (deep && queue.length) { + const q = queue.pop(); + + for (const n of cells.c[q]) { + if (checked[n]) continue; + if (h[n] >= treshold) continue; + + if (h[n] < 20) { + const nFeature = pack.features[cells.f[n]]; + if (nFeature.type === "ocean" || f.height > nFeature.height) { + deep = false; + break; + } + } + + checked[n] = true; + queue.push(n); + } + } + + f.closed = deep; + }); + }; + const cleanupLakeData = function () { for (const feature of pack.features) { if (feature.type !== "lake") continue; @@ -95,5 +144,5 @@ return "freshwater"; } - return {setClimateData, cleanupLakeData, defineGroup, generateName, getName, getShoreline}; + return {setClimateData, cleanupLakeData, prepareLakeData, defineGroup, generateName, getName, getShoreline}; }); diff --git a/modules/river-generator.js b/modules/river-generator.js index b6152544..81f3457f 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -16,7 +16,7 @@ let riverNext = 1; // first river id is 1 const h = alterHeights(); - prepareLakeData(); + Lakes.prepareLakeData(h); resolveDepressions(h, 200); drainWater(); defineRivers(); @@ -26,54 +26,6 @@ TIME && console.timeEnd("generateRivers"); - function prepareLakeData() { - const ELEVATION_LIMIT = 10; - - features.forEach(f => { - if (f.type !== "lake") return; - delete f.flux; - delete f.inlets; - delete f.outlet; - delete f.height; - delete f.closed; - !f.shoreline && Lakes.getShoreline(f); - - // lake surface height is as lowest land cells around - const min = f.shoreline.sort((a, b) => h[a] - h[b])[0]; - f.height = h[min] - 0.1; - - // check if lake can be open (not in deep depression) - let deep = true; - const treshold = f.height + ELEVATION_LIMIT; - const queue = [min]; - const checked = []; - checked[min] = true; - - // check if elevated lake can potentially pour to another water body - while (deep && queue.length) { - const q = queue.pop(); - - for (const n of cells.c[q]) { - if (checked[n]) continue; - if (h[n] >= treshold) continue; - - if (h[n] < 20) { - const nFeature = features[cells.f[n]]; - if (nFeature.type === "ocean" || f.height > nFeature.height) { - deep = false; - break; - } - } - - checked[n] = true; - queue.push(n); - } - } - - f.closed = deep; - }); - } - function drainWater() { const MIN_FLUX_TO_FORM_RIVER = 30; const land = cells.i.filter(i => h[i] >= 20).sort((a, b) => h[b] - h[a]); @@ -223,13 +175,13 @@ }; // add distance to water value to land cells to make map less depressed - function alterHeights() { + const alterHeights = () => { const cells = pack.cells; return Array.from(cells.h).map((h, i) => { if (h < 20 || cells.t[i] < 1) return h; return h + cells.t[i] / 100 + d3.mean(cells.c[i].map(c => cells.t[c])) / 10000; }); - } + }; // depression filling algorithm (for a correct water flux modeling) const resolveDepressions = function (h, maxIterations) { @@ -426,5 +378,5 @@ return getBasin(parent); }; - return {generate, resolveDepressions, addMeandering, getPath, specify, getName, getBasin, remove}; + return {generate, alterHeights, resolveDepressions, addMeandering, getPath, specify, getName, getBasin, remove}; }); diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 16b8fa87..1a5dd1a1 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -539,25 +539,19 @@ function addRiverOnClick() { let river = +getNextId("river").slice(5); // river id cells.fl[i] = grid.cells.prec[cells.g[i]]; // initial flux - // height with added t value to make map less depressed - const h = Array.from(cells.h) - .map((h, i) => (h < 20 || cells.t[i] < 1 ? h : h + cells.t[i] / 100)) - .map((h, i) => (h < 20 || cells.t[i] < 1 ? h : h + d3.mean(cells.c[i].map(c => cells.t[c])) / 10000)); + const h = Rivers.alterHeights(); + Lakes.prepareLakeData(h); Rivers.resolveDepressions(h, 200); while (i) { cells.r[i] = river; - const x = cells.p[i][0], - y = cells.p[i][1]; + const [x, y] = cells.p[i]; dataRiver.push({x, y, cell: i}); - const min = cells.c[i][d3.scan(cells.c[i], (a, b) => h[a] - h[b])]; // downhill cell - if (h[i] <= h[min]) { - tip(`Cell ${i} is depressed, river cannot flow further`, false, "error"); - return; - } - const tx = cells.p[min][0], - ty = cells.p[min][1]; + const min = cells.c[i].sort((a, b) => h[a] - h[b])[0]; // downhill cell + if (h[i] <= h[min]) return tip(`Cell ${i} is depressed, river cannot flow further`, false, "error"); + + const [tx, ty] = cells.p[min]; if (h[min] < 20) { // pour to water body @@ -572,7 +566,7 @@ function addRiverOnClick() { continue; } - // hadnle case when lowest cell already has a river + // handle case when lowest cell already has a river const r = cells.r[min]; const riverCells = cells.i.filter(i => cells.r[i] === r); const riverCellsUpper = riverCells.filter(i => h[i] > h[min]); @@ -625,6 +619,7 @@ function addRiverOnClick() { } if (d3.event.shiftKey === false) { + Lakes.cleanupLakeData(); unpressClickToAddButton(); document.getElementById("addNewRiver").classList.remove("pressed"); if (addNewRiver.offsetParent) riversOverviewRefresh.click();