From 76c787b6e9607ee81b3d26fc1a37dbc870a2c850 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Tue, 20 Jul 2021 01:31:48 +0300 Subject: [PATCH] allow to add river - fix --- modules/river-generator.js | 14 +++++------ modules/ui/tools.js | 51 ++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/modules/river-generator.js b/modules/river-generator.js index 9d0c0376..948afd07 100644 --- a/modules/river-generator.js +++ b/modules/river-generator.js @@ -245,19 +245,19 @@ }; // add points at 1/3 and 2/3 of a line between adjacents river cells - const addMeandering = function (cells, width = 1, meandering = 0.5) { + const addMeandering = function (riverCells, width = 1, meandering = 0.5) { const meandered = []; - const {p, conf, h} = pack.cells; - const lastCell = cells.length - 1; + const {p, conf} = pack.cells; + const lastCell = riverCells.length - 1; for (let i = 0; i <= lastCell; i++, width++) { - const cell = cells[i]; + const cell = riverCells[i]; const [x1, y1] = p[cell]; meandered.push([x1, y1, conf[cell]]); if (i === lastCell) break; - const nextCell = cells[i + 1]; + const nextCell = riverCells[i + 1]; if (nextCell === -1) { meandered.push(getBorderPoint(cell)); break; @@ -271,14 +271,14 @@ const meander = meandering + 1 / width + Math.random() * Math.max(meandering - width / 100, 0); const dist2 = (x2 - x1) ** 2 + (y2 - y1) ** 2; // square distance between cells - if (width < 10 && (dist2 > 64 || (dist2 > 36 && cells.length < 5))) { + if (width < 10 && (dist2 > 64 || (dist2 > 36 && riverCells.length < 5))) { // if dist2 is big or river is small add extra points at 1/3 and 2/3 of segment const p1x = (x1 * 2 + x2) / 3 + -sin * meander; const p1y = (y1 * 2 + y2) / 3 + cos * meander; const p2x = (x1 + x2 * 2) / 3 + sin * meander; const p2y = (y1 + y2 * 2) / 3 + cos * meander; meandered.push([p1x, p1y], [p2x, p2y]); - } else if (dist2 > 25 || cells.length < 6) { + } else if (dist2 > 25 || riverCells.length < 6) { // if dist is medium or river is small add 1 extra middlepoint const p1x = (x1 + x2) / 2 + -sin * meander; const p1y = (y1 + y2) / 2 + cos * meander; diff --git a/modules/ui/tools.js b/modules/ui/tools.js index 72ce5fb9..7501e17d 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -538,8 +538,9 @@ function addRiverOnClick() { if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error"); if (cells.b[i]) return; - const riverPoints = []; + const riverCells = []; let riverId = +getNextId("river").slice(5); + let parent = 0; const initialFlux = grid.cells.prec[cells.g[i]]; cells.fl[i] = initialFlux; @@ -549,8 +550,7 @@ function addRiverOnClick() { while (i) { cells.r[i] = riverId; - const [x, y] = cells.p[i]; - riverPoints.push({x, y, cell: i}); + riverCells.push(i); 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"); @@ -559,16 +559,23 @@ function addRiverOnClick() { // pour to water body if (h[min] < 20) { - riverPoints.push({x: tx, y: ty, cell: i}); + riverCells.push(min); const feature = pack.features[cells.f[min]]; if (feature.type === "lake") { - riverPoints[0].parent = feature.outlet || 0; + parent = feature.outlet || 0; feature.inlets ? feature.inlets.push(riverId) : (feature.inlets = [riverId]); } break; } + // pour outside of map from border cell + if (cells.b[min]) { + cells.fl[min] += cells.fl[i]; + riverCells.push(-1); + break; + } + // continue propagation if min cell has no river if (!cells.r[min]) { cells.fl[min] += cells.fl[i]; @@ -578,24 +585,28 @@ function addRiverOnClick() { // handle case when lowest cell already has a river const oldRiverId = cells.r[min]; - const riverCells = cells.i.filter(i => cells.r[i] === oldRiverId); - const riverCellsUpper = riverCells.filter(i => h[i] > h[min]); + const oldRiver = rivers.find(river => river.i === oldRiverId); + const oldRiverCells = oldRiver?.cells || cells.i.filter(i => cells.r[i] === oldRiverId); + const oldRiverCellsUpper = oldRiverCells.filter(i => h[i] > h[min]); // create new river as a tributary - if (riverPoints.length <= riverCellsUpper.length) { + if (riverCells.length <= oldRiverCellsUpper.length) { cells.conf[min] += cells.fl[i]; - riverPoints.push({x: tx, y: ty, cell: min}); - riverPoints[0].parent = oldRiverId; + riverCells.push(min); + parent = oldRiverId; break; } // continue old river document.getElementById("river" + oldRiverId)?.remove(); - cells.i.filter(i => cells.r[i] === riverId).forEach(i => (cells.r[i] = oldRiverId)); - const oldRiver = rivers.find(river => river.i === oldRiverId); - oldRiver?.points.forEach(([x, y, cell]) => { - riverPoints.push({x, y, cell}); - cells.fl[cell] += cells.fl[i]; + riverCells.forEach(i => (cells.r[i] = oldRiverId)); + oldRiverCells.forEach(cell => { + if (h[cell] > h[min]) { + cells.r[cell] = 0; + } else { + riverCells.push(cell); + cells.fl[cell] += cells.fl[i]; + } }); riverId = oldRiverId; @@ -604,9 +615,8 @@ function addRiverOnClick() { const river = rivers.find(r => r.i === riverId); const sourceWidth = 0.1; - const widthFactor = river.widthFactor || rn(0.8 + Math.random() * 0.4, 1); + const widthFactor = river?.widthFactor || rn(0.8 + Math.random() * 0.4, 1); - const riverCells = riverPoints.map(point => point.cell); const riverMeandered = Rivers.addMeandering(riverCells, sourceWidth * 10, 0.5); const [path, length, offset] = Rivers.getPath(riverMeandered, widthFactor, sourceWidth); viewbox @@ -616,8 +626,8 @@ function addRiverOnClick() { .attr("id", "river" + riverId); // add new river to data or change extended river attributes - const source = riverPoints[0].cell; - const mouth = last(riverPoints).cell; + const source = riverCells[0]; + const mouth = last(riverCells); const discharge = cells.fl[mouth]; // in m3/s const width = rn(offset ** 2, 2); // mounth width in km @@ -626,9 +636,8 @@ function addRiverOnClick() { river.length = length; river.discharge = discharge; river.width = width; - river.points = points; + river.cells = riverCells; } else { - const parent = riverPoints[0].parent || 0; const basin = Rivers.getBasin(parent); const name = Rivers.getName(mouth); const smallLength = rivers.map(r => r.length || 0).sort((a, b) => a - b)[Math.ceil(pack.rivers.length * 0.15)];