precipitation generation - minor fix

This commit is contained in:
Azgaar 2021-08-21 23:05:15 +03:00
parent 01116addfc
commit 0de5b7c6cd

59
main.js
View file

@ -957,27 +957,32 @@ function calculateTemperatures() {
function generatePrecipitation() { function generatePrecipitation() {
TIME && console.time("generatePrecipitation"); TIME && console.time("generatePrecipitation");
prec.selectAll("*").remove(); prec.selectAll("*").remove();
const cells = grid.cells; const {cells, cellsX, cellsY} = grid;
cells.prec = new Uint8Array(cells.i.length); // precipitation array cells.prec = new Uint8Array(cells.i.length); // precipitation array
const modifier = precInput.value / 100; // user's input const modifier = precInput.value / 100; // user's input
const cellsX = grid.cellsX, const {winds} = options;
cellsY = grid.cellsY;
const MAX_PASSABLE_ELEVATION = 85;
let westerly = [], let westerly = [],
easterly = [], easterly = [],
southerly = 0, southerly = 0,
northerly = 0; northerly = 0;
{ const isWest = tier => winds[tier] > 40 && winds[tier] < 140;
// latitude bands const isEast = tier => winds[tier] > 220 && winds[tier] < 320;
// x4 = 0-5 latitude: wet through the year (rising zone) const isSouth = tier => winds[tier] > 100 && winds[tier] < 260;
// x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone) const isNorth = tier => winds[tier] > 280 && winds[tier] < 80;
// x1 = 20-30 latitude: dry all year (sinking zone)
// x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone) // latitude bands info
// x3 = 50-60 latitude: wet all year (rising zone) // x4 = 0-5 latitude: wet through the year (rising zone)
// x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone) // x2 = 5-20 latitude: wet summer (rising zone), dry winter (sinking zone)
// x1 = 70-90 latitude: dry all year (sinking zone) // x1 = 20-30 latitude: dry all year (sinking zone)
} // x2 = 30-50 latitude: wet winter (rising zone), dry summer (sinking zone)
const lalitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5]; // by 5d step // x3 = 50-60 latitude: wet all year (rising zone)
// x2 = 60-70 latitude: wet summer (rising zone), dry winter (sinking zone)
// x1 = 70-90 latitude: dry all year (sinking zone)
const lalitudeModifier = [4, 2, 2, 2, 1, 1, 2, 2, 2, 2, 3, 3, 2, 2, 1, 1, 1, 0.5];
// difine wind directions based on cells latitude and prevailing winds there // difine wind directions based on cells latitude and prevailing winds there
d3.range(0, cells.i.length, cellsX).forEach(function (c, i) { d3.range(0, cells.i.length, cellsX).forEach(function (c, i) {
@ -985,15 +990,17 @@ function generatePrecipitation() {
const band = ((Math.abs(lat) - 1) / 5) | 0; const band = ((Math.abs(lat) - 1) / 5) | 0;
const latMod = lalitudeModifier[band]; const latMod = lalitudeModifier[band];
const tier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S const tier = (Math.abs(lat - 89) / 30) | 0; // 30d tiers from 0 to 5 from N to S
if (options.winds[tier] > 40 && options.winds[tier] < 140) westerly.push([c, latMod, tier]);
else if (options.winds[tier] > 220 && options.winds[tier] < 320) easterly.push([c + cellsX - 1, latMod, tier]); if (isWest(tier)) westerly.push([c, latMod, tier]);
if (options.winds[tier] > 100 && options.winds[tier] < 260) northerly++; else if (isEast(tier)) easterly.push([c + cellsX - 1, latMod, tier]);
else if (options.winds[tier] > 280 || options.winds[tier] < 80) southerly++; if (isSouth(tier)) northerly++;
if (isNorth(tier)) southerly++;
}); });
// distribute winds by direction // distribute winds by direction
if (westerly.length) passWind(westerly, 120 * modifier, 1, cellsX); if (westerly.length) passWind(westerly, 120 * modifier, 1, cellsX);
if (easterly.length) passWind(easterly, 120 * modifier, -1, cellsX); if (easterly.length) passWind(easterly, 120 * modifier, -1, cellsX);
const vertT = southerly + northerly; const vertT = southerly + northerly;
if (northerly) { if (northerly) {
const bandN = ((Math.abs(mapCoordinates.latN) - 1) / 5) | 0; const bandN = ((Math.abs(mapCoordinates.latN) - 1) / 5) | 0;
@ -1001,6 +1008,7 @@ function generatePrecipitation() {
const maxPrecN = (northerly / vertT) * 60 * modifier * latModN; const maxPrecN = (northerly / vertT) * 60 * modifier * latModN;
passWind(d3.range(0, cellsX, 1), maxPrecN, cellsX, cellsY); passWind(d3.range(0, cellsX, 1), maxPrecN, cellsX, cellsY);
} }
if (southerly) { if (southerly) {
const bandS = ((Math.abs(mapCoordinates.latS) - 1) / 5) | 0; const bandS = ((Math.abs(mapCoordinates.latS) - 1) / 5) | 0;
const latModS = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandS]; const latModS = mapCoordinates.latT > 60 ? d3.mean(lalitudeModifier) : lalitudeModifier[bandS];
@ -1010,18 +1018,21 @@ function generatePrecipitation() {
function passWind(source, maxPrec, next, steps) { function passWind(source, maxPrec, next, steps) {
const maxPrecInit = maxPrec; const maxPrecInit = maxPrec;
for (let first of source) { for (let first of source) {
if (first[0]) { if (first[0]) {
maxPrec = Math.min(maxPrecInit * first[1], 255); maxPrec = Math.min(maxPrecInit * first[1], 255);
first = first[0]; first = first[0];
} }
let humidity = maxPrec - cells.h[first]; // initial water amount let humidity = maxPrec - cells.h[first]; // initial water amount
if (humidity <= 0) continue; // if first cell in row is too elevated cosdired wind dry if (humidity <= 0) continue; // if first cell in row is too elevated cosdired wind dry
for (let s = 0, current = first; s < steps; s++, current += next) { for (let s = 0, current = first; s < steps; s++, current += next) {
// no flux on permafrost if (cells.temp[current] < -5) continue; // no flux in permafrost
if (cells.temp[current] < -5) continue;
// water cell
if (cells.h[current] < 20) { if (cells.h[current] < 20) {
// water cell
if (cells.h[current + next] >= 20) { if (cells.h[current + next] >= 20) {
cells.prec[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation cells.prec[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation
} else { } else {
@ -1032,16 +1043,16 @@ function generatePrecipitation() {
} }
// land cell // land cell
const precipitation = getPrecipitation(humidity, current, next); const isPassable = cells.h[current + next] <= MAX_PASSABLE_ELEVATION;
const precipitation = isPassable ? getPrecipitation(humidity, current, next) : humidity;
cells.prec[current] += precipitation; cells.prec[current] += precipitation;
const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere
humidity = Math.min(Math.max(humidity - precipitation + evaporation, 0), maxPrec); humidity = isPassable ? Math.min(Math.max(humidity - precipitation + evaporation, 0), maxPrec) : 0;
} }
} }
} }
function getPrecipitation(humidity, i, n) { function getPrecipitation(humidity, i, n) {
if (cells.h[i + n] > 85) return humidity; // 85 is max passable height
const normalLoss = Math.max(humidity / (10 * modifier), 1); // precipitation in normal conditions 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 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 const mod = (cells.h[i + n] / 70) ** 2; // 50 stands for hills, 70 for mountains