mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-18 18:11:24 +01:00
refactor: addLakesInDeepDepressions
This commit is contained in:
parent
b2f16c4b8f
commit
3c6da6585e
16 changed files with 250 additions and 266 deletions
|
|
@ -1,167 +0,0 @@
|
|||
import * as d3 from "d3";
|
||||
|
||||
import {TIME} from "config/logging";
|
||||
import {minmax} from "utils/numberUtils";
|
||||
import {rand} from "utils/probabilityUtils";
|
||||
|
||||
// simplest precipitation model
|
||||
export function generatePrecipitation(grid) {
|
||||
TIME && console.time("generatePrecipitation");
|
||||
prec.selectAll("*").remove();
|
||||
|
||||
const {cells, cellsX, cellsY} = grid;
|
||||
const precipitation = new Uint8Array(cells.i.length); // precipitation array
|
||||
|
||||
const cellsNumberModifier = (pointsInput.dataset.cells / 10000) ** 0.25;
|
||||
const precInputModifier = precInput.value / 100;
|
||||
const modifier = cellsNumberModifier * precInputModifier;
|
||||
|
||||
const westerly = [];
|
||||
const easterly = [];
|
||||
let southerly = 0;
|
||||
let northerly = 0;
|
||||
|
||||
// precipitation modifier per latitude band
|
||||
// x4 = 0-5 latitude: wet through the year (rising zone)
|
||||
// x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone)
|
||||
// x1 = 20-30 latitude: dry all year (sinking zone)
|
||||
// x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone)
|
||||
// x3 = 50-60 latitude: wet all year (rising zone)
|
||||
// x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone)
|
||||
// x1 = 70-85 latitude: dry all year (sinking zone)
|
||||
// x0.5 = 85-90 latitude: dry all year (sinking zone)
|
||||
const latitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5];
|
||||
const MAX_PASSABLE_ELEVATION = 85;
|
||||
|
||||
// define wind directions based on cells latitude and prevailing winds there
|
||||
d3.range(0, cells.i.length, cellsX).forEach(function (c, i) {
|
||||
const lat = mapCoordinates.latN - (i / cellsY) * mapCoordinates.latT;
|
||||
const latBand = ((Math.abs(lat) - 1) / 5) | 0;
|
||||
const latMod = latitudeModifier[latBand];
|
||||
const windTier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S
|
||||
const {isWest, isEast, isNorth, isSouth} = getWindDirections(windTier);
|
||||
|
||||
if (isWest) westerly.push([c, latMod, windTier]);
|
||||
if (isEast) easterly.push([c + cellsX - 1, latMod, windTier]);
|
||||
if (isNorth) northerly++;
|
||||
if (isSouth) southerly++;
|
||||
});
|
||||
|
||||
// distribute winds by direction
|
||||
if (westerly.length) passWind(westerly, 120 * modifier, 1, cellsX);
|
||||
if (easterly.length) passWind(easterly, 120 * modifier, -1, cellsX);
|
||||
|
||||
const vertT = southerly + northerly;
|
||||
if (northerly) {
|
||||
const bandN = ((Math.abs(mapCoordinates.latN) - 1) / 5) | 0;
|
||||
const latModN = mapCoordinates.latT > 60 ? d3.mean(latitudeModifier) : latitudeModifier[bandN];
|
||||
const maxPrecN = (northerly / vertT) * 60 * modifier * latModN;
|
||||
passWind(d3.range(0, cellsX, 1), maxPrecN, cellsX, cellsY);
|
||||
}
|
||||
|
||||
if (southerly) {
|
||||
const bandS = ((Math.abs(mapCoordinates.latS) - 1) / 5) | 0;
|
||||
const latModS = mapCoordinates.latT > 60 ? d3.mean(latitudeModifier) : latitudeModifier[bandS];
|
||||
const maxPrecS = (southerly / vertT) * 60 * modifier * latModS;
|
||||
passWind(d3.range(cells.i.length - cellsX, cells.i.length, 1), maxPrecS, -cellsX, cellsY);
|
||||
}
|
||||
|
||||
function getWindDirections(tier) {
|
||||
const angle = options.winds[tier];
|
||||
|
||||
const isWest = angle > 40 && angle < 140;
|
||||
const isEast = angle > 220 && angle < 320;
|
||||
const isNorth = angle > 100 && angle < 260;
|
||||
const isSouth = angle > 280 || angle < 80;
|
||||
|
||||
return {isWest, isEast, isNorth, isSouth};
|
||||
}
|
||||
|
||||
function passWind(source, maxPrec, next, steps) {
|
||||
const maxPrecInit = maxPrec;
|
||||
|
||||
for (let first of source) {
|
||||
if (first[0]) {
|
||||
maxPrec = Math.min(maxPrecInit * first[1], 255);
|
||||
first = first[0];
|
||||
}
|
||||
|
||||
let humidity = maxPrec - cells.h[first]; // initial water amount
|
||||
if (humidity <= 0) continue; // if first cell in row is too elevated consider wind dry
|
||||
|
||||
for (let s = 0, current = first; s < steps; s++, current += next) {
|
||||
if (cells.temp[current] < -5) continue; // no flux in permafrost
|
||||
|
||||
if (cells.h[current] < 20) {
|
||||
// water cell
|
||||
if (cells.h[current + next] >= 20) {
|
||||
precipitation[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation
|
||||
} else {
|
||||
humidity = Math.min(humidity + 5 * modifier, maxPrec); // wind gets more humidity passing water cell
|
||||
precipitation[current] += 5 * modifier; // water cells precipitation (need to correctly pour water through lakes)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// land cell
|
||||
const isPassable = cells.h[current + next] <= MAX_PASSABLE_ELEVATION;
|
||||
const cellPrec = isPassable ? getPrecipitation(humidity, current, next) : humidity;
|
||||
precipitation[current] += cellPrec;
|
||||
const evaporation = cellPrec > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere
|
||||
humidity = isPassable ? minmax(humidity - cellPrec + evaporation, 0, maxPrec) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPrecipitation(humidity, i, n) {
|
||||
const normalLoss = Math.max(humidity / (10 * modifier), 1); // precipitation in normal conditions
|
||||
const diff = Math.max(cells.h[i + n] - cells.h[i], 0); // difference in height
|
||||
const mod = (cells.h[i + n] / 70) ** 2; // 50 stands for hills, 70 for mountains
|
||||
return minmax(normalLoss + diff * mod, 1, humidity);
|
||||
}
|
||||
|
||||
void (function drawWindDirection() {
|
||||
const wind = prec.append("g").attr("id", "wind");
|
||||
|
||||
d3.range(0, 6).forEach(function (t) {
|
||||
if (westerly.length > 1) {
|
||||
const west = westerly.filter(w => w[2] === t);
|
||||
if (west && west.length > 3) {
|
||||
const from = west[0][0],
|
||||
to = west[west.length - 1][0];
|
||||
const y = (grid.points[from][1] + grid.points[to][1]) / 2;
|
||||
wind.append("text").attr("x", 20).attr("y", y).text("\u21C9");
|
||||
}
|
||||
}
|
||||
if (easterly.length > 1) {
|
||||
const east = easterly.filter(w => w[2] === t);
|
||||
if (east && east.length > 3) {
|
||||
const from = east[0][0],
|
||||
to = east[east.length - 1][0];
|
||||
const y = (grid.points[from][1] + grid.points[to][1]) / 2;
|
||||
wind
|
||||
.append("text")
|
||||
.attr("x", graphWidth - 52)
|
||||
.attr("y", y)
|
||||
.text("\u21C7");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (northerly)
|
||||
wind
|
||||
.append("text")
|
||||
.attr("x", graphWidth / 2)
|
||||
.attr("y", 42)
|
||||
.text("\u21CA");
|
||||
if (southerly)
|
||||
wind
|
||||
.append("text")
|
||||
.attr("x", graphWidth / 2)
|
||||
.attr("y", graphHeight - 20)
|
||||
.text("\u21C8");
|
||||
})();
|
||||
|
||||
TIME && console.timeEnd("generatePrecipitation");
|
||||
return precipitation;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue