mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-18 10:01:23 +01:00
refactor: submap - restore rivers
This commit is contained in:
parent
1d9ba6f17c
commit
499762f1bb
6 changed files with 100 additions and 81 deletions
4
main.js
4
main.js
|
|
@ -1177,8 +1177,8 @@ function rankCells() {
|
||||||
cells.s = new Int16Array(cells.i.length); // cell suitability array
|
cells.s = new Int16Array(cells.i.length); // cell suitability array
|
||||||
cells.pop = new Float32Array(cells.i.length); // cell population array
|
cells.pop = new Float32Array(cells.i.length); // cell population array
|
||||||
|
|
||||||
const flMean = d3.median(cells.fl.filter(f => f)) || 0,
|
const flMean = d3.median(cells.fl.filter(f => f)) || 0;
|
||||||
flMax = d3.max(cells.fl) + d3.max(cells.conf); // to normalize flux
|
const flMax = d3.max(cells.fl) + d3.max(cells.conf); // to normalize flux
|
||||||
const areaMean = d3.mean(cells.area); // to adjust population by cell area
|
const areaMean = d3.mean(cells.area); // to adjust population by cell area
|
||||||
|
|
||||||
for (const i of cells.i) {
|
for (const i of cells.i) {
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,13 @@ window.Resample = (function () {
|
||||||
OceanLayers();
|
OceanLayers();
|
||||||
calculateMapCoordinates();
|
calculateMapCoordinates();
|
||||||
calculateTemperatures();
|
calculateTemperatures();
|
||||||
generatePrecipitation();
|
|
||||||
|
|
||||||
reGraph();
|
reGraph();
|
||||||
Features.markupPack();
|
Features.markupPack();
|
||||||
createDefaultRuler();
|
createDefaultRuler();
|
||||||
|
|
||||||
restoreCellData(parentMap, inverse);
|
restoreCellData(parentMap, inverse, scale);
|
||||||
restoreRivers(parentMap, projection);
|
restoreRivers(parentMap, projection, scale);
|
||||||
rankCells();
|
|
||||||
|
|
||||||
restoreCultures(parentMap, projection);
|
restoreCultures(parentMap, projection);
|
||||||
restoreBurgs(parentMap, projection, scale);
|
restoreBurgs(parentMap, projection, scale);
|
||||||
restoreStates(parentMap, projection);
|
restoreStates(parentMap, projection);
|
||||||
|
|
@ -71,9 +68,11 @@ window.Resample = (function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreCellData(parentMap, inverse) {
|
function restoreCellData(parentMap, inverse, scale) {
|
||||||
pack.cells.biome = new Uint8Array(pack.cells.i.length);
|
pack.cells.biome = new Uint8Array(pack.cells.i.length);
|
||||||
pack.cells.fl = new Uint16Array(pack.cells.i.length);
|
pack.cells.fl = new Uint16Array(pack.cells.i.length);
|
||||||
|
pack.cells.s = new Int16Array(pack.cells.i.length);
|
||||||
|
pack.cells.pop = new Float32Array(pack.cells.i.length);
|
||||||
pack.cells.culture = new Uint16Array(pack.cells.i.length);
|
pack.cells.culture = new Uint16Array(pack.cells.i.length);
|
||||||
pack.cells.state = new Uint16Array(pack.cells.i.length);
|
pack.cells.state = new Uint16Array(pack.cells.i.length);
|
||||||
pack.cells.burg = new Uint16Array(pack.cells.i.length);
|
pack.cells.burg = new Uint16Array(pack.cells.i.length);
|
||||||
|
|
@ -88,8 +87,14 @@ window.Resample = (function () {
|
||||||
if (isWater(pack, newPackCell)) continue;
|
if (isWater(pack, newPackCell)) continue;
|
||||||
|
|
||||||
const parentPackCell = parentPackLandCellsQuadtree.find(x, y, Infinity)[2];
|
const parentPackCell = parentPackLandCellsQuadtree.find(x, y, Infinity)[2];
|
||||||
|
const parentCellArea = parentMap.pack.cells.area[parentPackCell];
|
||||||
|
const areaRatio = pack.cells.area[newPackCell] / parentCellArea;
|
||||||
|
const scaleRatio = areaRatio / scale;
|
||||||
|
|
||||||
pack.cells.biome[newPackCell] = parentMap.pack.cells.biome[parentPackCell];
|
pack.cells.biome[newPackCell] = parentMap.pack.cells.biome[parentPackCell];
|
||||||
pack.cells.fl[newPackCell] = parentMap.pack.cells.fl[parentPackCell];
|
pack.cells.fl[newPackCell] = parentMap.pack.cells.fl[parentPackCell];
|
||||||
|
pack.cells.s[newPackCell] = parentMap.pack.cells.s[parentPackCell] * scaleRatio;
|
||||||
|
pack.cells.pop[newPackCell] = parentMap.pack.cells.pop[parentPackCell] * scaleRatio;
|
||||||
pack.cells.culture[newPackCell] = parentMap.pack.cells.culture[parentPackCell];
|
pack.cells.culture[newPackCell] = parentMap.pack.cells.culture[parentPackCell];
|
||||||
pack.cells.state[newPackCell] = parentMap.pack.cells.state[parentPackCell];
|
pack.cells.state[newPackCell] = parentMap.pack.cells.state[parentPackCell];
|
||||||
pack.cells.religion[newPackCell] = parentMap.pack.cells.religion[parentPackCell];
|
pack.cells.religion[newPackCell] = parentMap.pack.cells.religion[parentPackCell];
|
||||||
|
|
@ -97,9 +102,10 @@ window.Resample = (function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreRivers(parentMap, projection) {
|
function restoreRivers(parentMap, projection, scale) {
|
||||||
pack.cells.r = new Uint16Array(pack.cells.i.length);
|
pack.cells.r = new Uint16Array(pack.cells.i.length);
|
||||||
pack.cells.conf = new Uint8Array(pack.cells.i.length);
|
pack.cells.conf = new Uint8Array(pack.cells.i.length);
|
||||||
|
const offset = grid.spacing * 2;
|
||||||
|
|
||||||
pack.rivers = parentMap.pack.rivers
|
pack.rivers = parentMap.pack.rivers
|
||||||
.map(river => {
|
.map(river => {
|
||||||
|
|
@ -107,7 +113,7 @@ window.Resample = (function () {
|
||||||
const points = parentPoints
|
const points = parentPoints
|
||||||
.map(([parentX, parentY]) => {
|
.map(([parentX, parentY]) => {
|
||||||
const [x, y] = projection(parentX, parentY);
|
const [x, y] = projection(parentX, parentY);
|
||||||
return isInMap(x, y) ? [rn(x, 2), rn(y, 2)] : null;
|
return isInMap(x, y, offset) ? [rn(x, 2), rn(y, 2)] : null;
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
if (points.length < 2) return null;
|
if (points.length < 2) return null;
|
||||||
|
|
@ -118,7 +124,8 @@ window.Resample = (function () {
|
||||||
pack.cells.r[cellId] = river.i;
|
pack.cells.r[cellId] = river.i;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {...river, cells, points, source: cells.at(0), mouth: cells.at(-2)};
|
const widthFactor = river.widthFactor * scale;
|
||||||
|
return {...river, cells, points, source: cells.at(0), mouth: cells.at(-2), widthFactor};
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
||||||
|
|
@ -203,12 +210,14 @@ window.Resample = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreRoutes(parentMap, projection) {
|
function restoreRoutes(parentMap, projection) {
|
||||||
|
const offset = grid.spacing * 2;
|
||||||
|
|
||||||
pack.routes = parentMap.pack.routes
|
pack.routes = parentMap.pack.routes
|
||||||
.map(route => {
|
.map(route => {
|
||||||
const points = route.points
|
const points = route.points
|
||||||
.map(([parentX, parentY]) => {
|
.map(([parentX, parentY]) => {
|
||||||
const [x, y] = projection(parentX, parentY);
|
const [x, y] = projection(parentX, parentY);
|
||||||
if (!isInMap(x, y)) return null;
|
if (!isInMap(x, y, offset)) return null;
|
||||||
|
|
||||||
const cell = findCell(x, y);
|
const cell = findCell(x, y);
|
||||||
return [rn(x, 2), rn(y, 2), cell];
|
return [rn(x, 2), rn(y, 2), cell];
|
||||||
|
|
@ -320,8 +329,8 @@ window.Resample = (function () {
|
||||||
return graph.cells.h[cellId] < 20;
|
return graph.cells.h[cellId] < 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInMap(x, y) {
|
function isInMap(x, y, offset = 0) {
|
||||||
return x >= 0 && x <= graphWidth && y >= 0 && y <= graphHeight;
|
return x + offset >= 0 && x - offset <= graphWidth && y + offset >= 0 && y - offset <= graphHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {process};
|
return {process};
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,15 @@ window.Rivers = (function () {
|
||||||
const meanderedPoints = addMeandering(riverCells);
|
const meanderedPoints = addMeandering(riverCells);
|
||||||
const discharge = cells.fl[mouth]; // m3 in second
|
const discharge = cells.fl[mouth]; // m3 in second
|
||||||
const length = getApproximateLength(meanderedPoints);
|
const length = getApproximateLength(meanderedPoints);
|
||||||
const width = getWidth(getOffset(discharge, meanderedPoints.length, widthFactor, 0));
|
const sourceWidth = getSourceWidth(cells.fl[source]);
|
||||||
|
const width = getWidth(
|
||||||
|
getOffset({
|
||||||
|
flux: discharge,
|
||||||
|
pointIndex: meanderedPoints.length,
|
||||||
|
widthFactor,
|
||||||
|
sourceWidth
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
pack.rivers.push({
|
pack.rivers.push({
|
||||||
i: riverId,
|
i: riverId,
|
||||||
|
|
@ -200,7 +208,7 @@ window.Rivers = (function () {
|
||||||
length,
|
length,
|
||||||
width,
|
width,
|
||||||
widthFactor,
|
widthFactor,
|
||||||
sourceWidth: 0,
|
sourceWidth,
|
||||||
parent,
|
parent,
|
||||||
cells: riverCells
|
cells: riverCells
|
||||||
});
|
});
|
||||||
|
|
@ -306,59 +314,49 @@ window.Rivers = (function () {
|
||||||
|
|
||||||
// add points at 1/3 and 2/3 of a line between adjacents river cells
|
// add points at 1/3 and 2/3 of a line between adjacents river cells
|
||||||
const addMeandering = function (riverCells, riverPoints = null, meandering = 0.5) {
|
const addMeandering = function (riverCells, riverPoints = null, meandering = 0.5) {
|
||||||
const {fl, conf, h} = pack.cells;
|
const {fl, h} = pack.cells;
|
||||||
const meandered = [];
|
const meandered = [];
|
||||||
const lastStep = riverCells.length - 1;
|
const lastStep = riverCells.length - 1;
|
||||||
const points = getRiverPoints(riverCells, riverPoints);
|
const points = getRiverPoints(riverCells, riverPoints);
|
||||||
let step = h[riverCells[0]] < 20 ? 1 : 10;
|
let step = h[riverCells[0]] < 20 ? 1 : 10;
|
||||||
|
|
||||||
let fluxPrev = 0;
|
|
||||||
const getFlux = (step, flux) => (step === lastStep ? fluxPrev : flux);
|
|
||||||
|
|
||||||
for (let i = 0; i <= lastStep; i++, step++) {
|
for (let i = 0; i <= lastStep; i++, step++) {
|
||||||
const cell = riverCells[i];
|
const cell = riverCells[i];
|
||||||
const isLastCell = i === lastStep;
|
const isLastCell = i === lastStep;
|
||||||
|
|
||||||
const [x1, y1] = points[i];
|
const [x1, y1] = points[i];
|
||||||
const flux1 = getFlux(i, fl[cell]);
|
|
||||||
fluxPrev = flux1;
|
|
||||||
|
|
||||||
meandered.push([x1, y1, flux1]);
|
meandered.push([x1, y1, fl[cell]]);
|
||||||
if (isLastCell) break;
|
if (isLastCell) break;
|
||||||
|
|
||||||
const nextCell = riverCells[i + 1];
|
const nextCell = riverCells[i + 1];
|
||||||
const [x2, y2] = points[i + 1];
|
const [x2, y2] = points[i + 1];
|
||||||
|
|
||||||
if (nextCell === -1) {
|
if (nextCell === -1) {
|
||||||
meandered.push([x2, y2, fluxPrev]);
|
meandered.push([x2, y2, fl[cell]]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dist2 = (x2 - x1) ** 2 + (y2 - y1) ** 2; // square distance between cells
|
const dist2 = (x2 - x1) ** 2 + (y2 - y1) ** 2; // square distance between cells
|
||||||
if (dist2 <= 25 && riverCells.length >= 6) continue;
|
if (dist2 <= 25 && riverCells.length >= 6) continue;
|
||||||
|
|
||||||
const flux2 = getFlux(i + 1, fl[nextCell]);
|
|
||||||
const keepInitialFlux = conf[nextCell] || flux1 === flux2;
|
|
||||||
|
|
||||||
const meander = meandering + 1 / step + Math.max(meandering - step / 100, 0);
|
const meander = meandering + 1 / step + Math.max(meandering - step / 100, 0);
|
||||||
const angle = Math.atan2(y2 - y1, x2 - x1);
|
const angle = Math.atan2(y2 - y1, x2 - x1);
|
||||||
const sinMeander = Math.sin(angle) * meander;
|
const sinMeander = Math.sin(angle) * meander;
|
||||||
const cosMeander = Math.cos(angle) * meander;
|
const cosMeander = Math.cos(angle) * meander;
|
||||||
|
|
||||||
if (step < 10 && (dist2 > 64 || (dist2 > 36 && riverCells.length < 5))) {
|
if (step < 20 && (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
|
// 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 + -sinMeander;
|
const p1x = (x1 * 2 + x2) / 3 + -sinMeander;
|
||||||
const p1y = (y1 * 2 + y2) / 3 + cosMeander;
|
const p1y = (y1 * 2 + y2) / 3 + cosMeander;
|
||||||
const p2x = (x1 + x2 * 2) / 3 + sinMeander / 2;
|
const p2x = (x1 + x2 * 2) / 3 + sinMeander / 2;
|
||||||
const p2y = (y1 + y2 * 2) / 3 - cosMeander / 2;
|
const p2y = (y1 + y2 * 2) / 3 - cosMeander / 2;
|
||||||
const [p1fl, p2fl] = keepInitialFlux ? [flux1, flux1] : [(flux1 * 2 + flux2) / 3, (flux1 + flux2 * 2) / 3];
|
meandered.push([p1x, p1y, 0], [p2x, p2y, 0]);
|
||||||
meandered.push([p1x, p1y, p1fl], [p2x, p2y, p2fl]);
|
|
||||||
} else if (dist2 > 25 || riverCells.length < 6) {
|
} else if (dist2 > 25 || riverCells.length < 6) {
|
||||||
// if dist is medium or river is small add 1 extra middlepoint
|
// if dist is medium or river is small add 1 extra middlepoint
|
||||||
const p1x = (x1 + x2) / 2 + -sinMeander;
|
const p1x = (x1 + x2) / 2 + -sinMeander;
|
||||||
const p1y = (y1 + y2) / 2 + cosMeander;
|
const p1y = (y1 + y2) / 2 + cosMeander;
|
||||||
const p1fl = keepInitialFlux ? flux1 : (flux1 + flux2) / 2;
|
meandered.push([p1x, p1y, 0]);
|
||||||
meandered.push([p1x, p1y, p1fl]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -385,29 +383,35 @@ window.Rivers = (function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
const FLUX_FACTOR = 500;
|
const FLUX_FACTOR = 500;
|
||||||
const MAX_FLUX_WIDTH = 2;
|
const MAX_FLUX_WIDTH = 1;
|
||||||
const LENGTH_FACTOR = 200;
|
const LENGTH_FACTOR = 200;
|
||||||
const STEP_WIDTH = 1 / LENGTH_FACTOR;
|
const LENGTH_STEP_WIDTH = 1 / LENGTH_FACTOR;
|
||||||
const LENGTH_PROGRESSION = [1, 1, 2, 3, 5, 8, 13, 21, 34].map(n => n / LENGTH_FACTOR);
|
const LENGTH_PROGRESSION = [1, 1, 2, 3, 5, 8, 13, 21, 34].map(n => n / LENGTH_FACTOR);
|
||||||
const MAX_PROGRESSION = last(LENGTH_PROGRESSION);
|
const MAX_PROGRESSION = last(LENGTH_PROGRESSION);
|
||||||
|
|
||||||
const getOffset = (flux, pointNumber, widthFactor, startingWidth = 0) => {
|
const getOffset = ({flux, pointIndex, widthFactor, startingWidth}) => {
|
||||||
const fluxWidth = Math.min(flux ** 0.9 / FLUX_FACTOR, MAX_FLUX_WIDTH);
|
if (pointIndex === 0) return startingWidth;
|
||||||
const lengthWidth = pointNumber * STEP_WIDTH + (LENGTH_PROGRESSION[pointNumber] || MAX_PROGRESSION);
|
|
||||||
|
const fluxWidth = Math.min(flux ** 0.7 / FLUX_FACTOR, MAX_FLUX_WIDTH);
|
||||||
|
const lengthWidth = pointIndex * LENGTH_STEP_WIDTH + (LENGTH_PROGRESSION[pointIndex] || MAX_PROGRESSION);
|
||||||
return widthFactor * (lengthWidth + fluxWidth) + startingWidth;
|
return widthFactor * (lengthWidth + fluxWidth) + startingWidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getSourceWidth = flux => rn(Math.min(flux ** 0.9 / FLUX_FACTOR, MAX_FLUX_WIDTH), 2);
|
||||||
|
|
||||||
// build polygon from a list of points and calculated offset (width)
|
// build polygon from a list of points and calculated offset (width)
|
||||||
const getRiverPath = function (points, widthFactor, startingWidth = 0) {
|
const getRiverPath = (points, widthFactor, startingWidth) => {
|
||||||
const riverPointsLeft = [];
|
const riverPointsLeft = [];
|
||||||
const riverPointsRight = [];
|
const riverPointsRight = [];
|
||||||
|
let flux = 0;
|
||||||
|
|
||||||
for (let p = 0; p < points.length; p++) {
|
for (let pointIndex = 0; pointIndex < points.length; pointIndex++) {
|
||||||
const [x0, y0] = points[p - 1] || points[p];
|
const [x0, y0] = points[pointIndex - 1] || points[pointIndex];
|
||||||
const [x1, y1, flux] = points[p];
|
const [x1, y1, pointFlux] = points[pointIndex];
|
||||||
const [x2, y2] = points[p + 1] || points[p];
|
const [x2, y2] = points[pointIndex + 1] || points[pointIndex];
|
||||||
|
if (pointFlux > flux) flux = pointFlux;
|
||||||
|
|
||||||
const offset = getOffset(flux, p, widthFactor, startingWidth);
|
const offset = getOffset({flux, pointIndex, widthFactor, startingWidth});
|
||||||
const angle = Math.atan2(y0 - y2, x0 - x2);
|
const angle = Math.atan2(y0 - y2, x0 - x2);
|
||||||
const sinOffset = Math.sin(angle) * offset;
|
const sinOffset = Math.sin(angle) * offset;
|
||||||
const cosOffset = Math.cos(angle) * offset;
|
const cosOffset = Math.cos(angle) * offset;
|
||||||
|
|
@ -507,6 +511,7 @@ window.Rivers = (function () {
|
||||||
getBasin,
|
getBasin,
|
||||||
getWidth,
|
getWidth,
|
||||||
getOffset,
|
getOffset,
|
||||||
|
getSourceWidth,
|
||||||
getApproximateLength,
|
getApproximateLength,
|
||||||
getRiverPoints,
|
getRiverPoints,
|
||||||
remove,
|
remove,
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,10 @@ function createRiver() {
|
||||||
|
|
||||||
function addRiver() {
|
function addRiver() {
|
||||||
const {rivers, cells} = pack;
|
const {rivers, cells} = pack;
|
||||||
const {addMeandering, getApproximateLength, getWidth, getOffset, getName, getRiverPath, getBasin, getNextId} =
|
|
||||||
Rivers;
|
|
||||||
|
|
||||||
const riverCells = createRiver.cells;
|
const riverCells = createRiver.cells;
|
||||||
if (riverCells.length < 2) return tip("Add at least 2 cells", false, "error");
|
if (riverCells.length < 2) return tip("Add at least 2 cells", false, "error");
|
||||||
|
|
||||||
const riverId = getNextId(rivers);
|
const riverId = Rivers.getNextId(rivers);
|
||||||
const parent = cells.r[last(riverCells)] || riverId;
|
const parent = cells.r[last(riverCells)] || riverId;
|
||||||
|
|
||||||
riverCells.forEach(cell => {
|
riverCells.forEach(cell => {
|
||||||
|
|
@ -89,17 +86,24 @@ function createRiver() {
|
||||||
|
|
||||||
const source = riverCells[0];
|
const source = riverCells[0];
|
||||||
const mouth = parent === riverId ? last(riverCells) : riverCells[riverCells.length - 2];
|
const mouth = parent === riverId ? last(riverCells) : riverCells[riverCells.length - 2];
|
||||||
const sourceWidth = 0.05;
|
const sourceWidth = Rivers.getSourceWidth(cells.fl[source]);
|
||||||
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
|
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
|
||||||
const widthFactor = 1.2 * defaultWidthFactor;
|
const widthFactor = 1.2 * defaultWidthFactor;
|
||||||
|
|
||||||
const meanderedPoints = addMeandering(riverCells);
|
const meanderedPoints = Rivers.addMeandering(riverCells);
|
||||||
|
|
||||||
const discharge = cells.fl[mouth]; // m3 in second
|
const discharge = cells.fl[mouth]; // m3 in second
|
||||||
const length = getApproximateLength(meanderedPoints);
|
const length = Rivers.getApproximateLength(meanderedPoints);
|
||||||
const width = getWidth(getOffset(discharge, meanderedPoints.length, widthFactor, sourceWidth));
|
const width = Rivers.getWidth(
|
||||||
const name = getName(mouth);
|
Rivers.getOffset({
|
||||||
const basin = getBasin(parent);
|
flux: discharge,
|
||||||
|
pointIndex: meanderedPoints.length,
|
||||||
|
widthFactor,
|
||||||
|
startingWidth: sourceWidth
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const name = Rivers.getName(mouth);
|
||||||
|
const basin = Rivers.getBasin(parent);
|
||||||
|
|
||||||
rivers.push({
|
rivers.push({
|
||||||
i: riverId,
|
i: riverId,
|
||||||
|
|
@ -124,7 +128,7 @@ function createRiver() {
|
||||||
.select("#rivers")
|
.select("#rivers")
|
||||||
.append("path")
|
.append("path")
|
||||||
.attr("id", id)
|
.attr("id", id)
|
||||||
.attr("d", getRiverPath(meanderedPoints, widthFactor, sourceWidth));
|
.attr("d", Rivers.getRiverPath(meanderedPoints, widthFactor, sourceWidth));
|
||||||
|
|
||||||
editRiver(id);
|
editRiver(id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,10 +86,16 @@ function editRiver(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateRiverWidth(river) {
|
function updateRiverWidth(river) {
|
||||||
const {addMeandering, getWidth, getOffset} = Rivers;
|
|
||||||
const {cells, discharge, widthFactor, sourceWidth} = river;
|
const {cells, discharge, widthFactor, sourceWidth} = river;
|
||||||
const meanderedPoints = addMeandering(cells);
|
const meanderedPoints = Rivers.addMeandering(cells);
|
||||||
river.width = getWidth(getOffset(discharge, meanderedPoints.length, widthFactor, sourceWidth));
|
river.width = Rivers.getWidth(
|
||||||
|
Rivers.getOffset({
|
||||||
|
flux: discharge,
|
||||||
|
pointIndex: meanderedPoints.length,
|
||||||
|
widthFactor,
|
||||||
|
startingWidth: sourceWidth
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const width = `${rn(river.width * distanceScale, 3)} ${distanceUnitInput.value}`;
|
const width = `${rn(river.width * distanceScale, 3)} ${distanceUnitInput.value}`;
|
||||||
byId("riverWidth").value = width;
|
byId("riverWidth").value = width;
|
||||||
|
|
|
||||||
|
|
@ -668,28 +668,15 @@ function addRiverOnClick() {
|
||||||
if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error");
|
if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error");
|
||||||
if (cells.b[i]) return;
|
if (cells.b[i]) return;
|
||||||
|
|
||||||
const {
|
|
||||||
alterHeights,
|
|
||||||
resolveDepressions,
|
|
||||||
addMeandering,
|
|
||||||
getRiverPath,
|
|
||||||
getBasin,
|
|
||||||
getName,
|
|
||||||
getType,
|
|
||||||
getWidth,
|
|
||||||
getOffset,
|
|
||||||
getApproximateLength,
|
|
||||||
getNextId
|
|
||||||
} = Rivers;
|
|
||||||
const riverCells = [];
|
const riverCells = [];
|
||||||
let riverId = getNextId(rivers);
|
let riverId = Rivers.getNextId(rivers);
|
||||||
let parent = riverId;
|
let parent = riverId;
|
||||||
|
|
||||||
const initialFlux = grid.cells.prec[cells.g[i]];
|
const initialFlux = grid.cells.prec[cells.g[i]];
|
||||||
cells.fl[i] = initialFlux;
|
cells.fl[i] = initialFlux;
|
||||||
|
|
||||||
const h = alterHeights();
|
const h = Rivers.alterHeights();
|
||||||
resolveDepressions(h);
|
Rivers.resolveDepressions(h);
|
||||||
|
|
||||||
while (i) {
|
while (i) {
|
||||||
cells.r[i] = riverId;
|
cells.r[i] = riverId;
|
||||||
|
|
@ -763,11 +750,19 @@ function addRiverOnClick() {
|
||||||
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
|
const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2);
|
||||||
const widthFactor =
|
const widthFactor =
|
||||||
river?.widthFactor || (!parent || parent === riverId ? defaultWidthFactor * 1.2 : defaultWidthFactor);
|
river?.widthFactor || (!parent || parent === riverId ? defaultWidthFactor * 1.2 : defaultWidthFactor);
|
||||||
const meanderedPoints = addMeandering(riverCells);
|
const sourceWidth = river?.sourceWidth || Rivers.getSourceWidth(cells.fl[source]);
|
||||||
|
const meanderedPoints = Rivers.addMeandering(riverCells);
|
||||||
|
|
||||||
const discharge = cells.fl[mouth]; // m3 in second
|
const discharge = cells.fl[mouth]; // m3 in second
|
||||||
const length = getApproximateLength(meanderedPoints);
|
const length = Rivers.getApproximateLength(meanderedPoints);
|
||||||
const width = getWidth(getOffset(discharge, meanderedPoints.length, widthFactor));
|
const width = Rivers.getWidth(
|
||||||
|
Rivers.getOffset({
|
||||||
|
flux: discharge,
|
||||||
|
pointIndex: meanderedPoints.length,
|
||||||
|
widthFactor,
|
||||||
|
startingWidth: sourceWidth
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
if (river) {
|
if (river) {
|
||||||
river.source = source;
|
river.source = source;
|
||||||
|
|
@ -776,9 +771,9 @@ function addRiverOnClick() {
|
||||||
river.width = width;
|
river.width = width;
|
||||||
river.cells = riverCells;
|
river.cells = riverCells;
|
||||||
} else {
|
} else {
|
||||||
const basin = getBasin(parent);
|
const basin = Rivers.getBasin(parent);
|
||||||
const name = getName(mouth);
|
const name = Rivers.getName(mouth);
|
||||||
const type = getType({i: riverId, length, parent});
|
const type = Rivers.getType({i: riverId, length, parent});
|
||||||
|
|
||||||
rivers.push({
|
rivers.push({
|
||||||
i: riverId,
|
i: riverId,
|
||||||
|
|
@ -788,7 +783,7 @@ function addRiverOnClick() {
|
||||||
length,
|
length,
|
||||||
width,
|
width,
|
||||||
widthFactor,
|
widthFactor,
|
||||||
sourceWidth: 0,
|
sourceWidth,
|
||||||
parent,
|
parent,
|
||||||
cells: riverCells,
|
cells: riverCells,
|
||||||
basin,
|
basin,
|
||||||
|
|
@ -799,7 +794,7 @@ function addRiverOnClick() {
|
||||||
|
|
||||||
// render river
|
// render river
|
||||||
lineGen.curve(d3.curveCatmullRom.alpha(0.1));
|
lineGen.curve(d3.curveCatmullRom.alpha(0.1));
|
||||||
const path = getRiverPath(meanderedPoints, widthFactor);
|
const path = Rivers.getRiverPath(meanderedPoints, widthFactor, sourceWidth);
|
||||||
const id = "river" + riverId;
|
const id = "river" + riverId;
|
||||||
const riversG = viewbox.select("#rivers");
|
const riversG = viewbox.select("#rivers");
|
||||||
riversG.append("path").attr("id", id).attr("d", path);
|
riversG.append("path").attr("id", id).attr("d", path);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue