refactor river fendering

This commit is contained in:
Azgaar 2021-07-20 00:20:04 +03:00
parent 6405b442a5
commit 0adc0e883a
6 changed files with 187 additions and 149 deletions

View file

@ -530,92 +530,111 @@ function toggleAddRiver() {
}
function addRiverOnClick() {
const cells = pack.cells;
const {cells, rivers} = pack;
const point = d3.mouse(this);
let i = findCell(point[0], point[1]);
if (cells.r[i] || cells.h[i] < 20 || cells.b[i]) return;
const dataRiver = []; // to store river points
let river = +getNextId("river").slice(5); // river id
cells.fl[i] = grid.cells.prec[cells.g[i]]; // initial flux
if (cells.r[i]) return tip("There already a river here", false, "error");
if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error");
if (cells.b[i]) return;
const riverPoints = [];
let riverId = +getNextId("river").slice(5);
const initialFlux = grid.cells.prec[cells.g[i]];
cells.fl[i] = initialFlux;
const h = Rivers.alterHeights();
Lakes.prepareLakeData(h);
Rivers.resolveDepressions(h);
while (i) {
cells.r[i] = river;
cells.r[i] = riverId;
const [x, y] = cells.p[i];
dataRiver.push({x, y, cell: i});
riverPoints.push({x, y, cell: 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");
const [tx, ty] = cells.p[min];
// pour to water body
if (h[min] < 20) {
// pour to water body
dataRiver.push({x: tx, y: ty, cell: i});
riverPoints.push({x: tx, y: ty, cell: i});
const feature = pack.features[cells.f[min]];
if (feature.type === "lake") {
riverPoints[0].parent = feature.outlet || 0;
feature.inlets ? feature.inlets.push(riverId) : (feature.inlets = [riverId]);
}
break;
}
// continue propagation if min cell has no river
if (!cells.r[min]) {
// continue if next cell has not river
cells.fl[min] += cells.fl[i];
i = min;
continue;
}
// 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 oldRiverId = cells.r[min];
const riverCells = cells.i.filter(i => cells.r[i] === oldRiverId);
const riverCellsUpper = riverCells.filter(i => h[i] > h[min]);
// finish new river if old river is longer
if (dataRiver.length <= riverCellsUpper.length) {
// create new river as a tributary
if (riverPoints.length <= riverCellsUpper.length) {
cells.conf[min] += cells.fl[i];
dataRiver.push({x: tx, y: ty, cell: min});
dataRiver[0].parent = r; // new river is tributary
riverPoints.push({x: tx, y: ty, cell: min});
riverPoints[0].parent = oldRiverId;
break;
}
// extend old river
rivers.select("#river" + r).remove();
cells.i.filter(i => cells.r[i] === river).forEach(i => (cells.r[i] = r));
riverCells.forEach(i => (cells.r[i] = 0));
river = r;
cells.fl[min] = cells.fl[i] + grid.cells.prec[cells.g[min]];
i = min;
// 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];
});
riverId = oldRiverId;
break;
}
const points = Rivers.addMeandering(dataRiver, 1, 0.5);
const widthFactor = rn(0.8 + Math.random() * 0.4, 1); // river width modifier [.8, 1.2]
const river = rivers.find(r => r.i === riverId);
const sourceWidth = 0.1;
const [path, length, offset] = Rivers.getPath(points, widthFactor, sourceWidth);
rivers
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
.select("#rivers")
.append("path")
.attr("d", path)
.attr("id", "river" + river);
.attr("id", "river" + riverId);
// add new river to data or change extended river attributes
const r = pack.rivers.find(r => r.i === river);
const mouth = last(dataRiver).cell;
const source = riverPoints[0].cell;
const mouth = last(riverPoints).cell;
const discharge = cells.fl[mouth]; // in m3/s
const width = rn(offset ** 2, 2); // mounth width in km
if (r) {
r.source = dataRiver[0].cell;
r.length = length;
r.discharge = discharge;
if (river) {
river.source = source;
river.length = length;
river.discharge = discharge;
river.width = width;
river.points = points;
} else {
const parent = dataRiver[0].parent || 0;
const basin = Rivers.getBasin(river);
const source = dataRiver[0].cell;
const width = rn(offset ** 2, 2); // mounth width in km
const parent = riverPoints[0].parent || 0;
const basin = Rivers.getBasin(parent);
const name = Rivers.getName(mouth);
const smallLength = pack.rivers.map(r => r.length || 0).sort((a, b) => a - b)[Math.ceil(pack.rivers.length * 0.15)];
const smallLength = rivers.map(r => r.length || 0).sort((a, b) => a - b)[Math.ceil(pack.rivers.length * 0.15)];
const type = length < smallLength ? rw({Creek: 9, River: 3, Brook: 3, Stream: 1}) : "River";
pack.rivers.push({i: river, source, mouth, discharge, length, width, widthFactor, sourceWidth, parent, basin, name, type});
rivers.push({i: riverId, source, mouth, discharge, length, width, widthFactor, sourceWidth, parent, cells: riverCells, basin, name, type});
}
if (d3.event.shiftKey === false) {