cars: add time-based traffic profile with weekend and Sunday peaks

This commit is contained in:
Richard Zink committed 2026-10-12 21:54:43 +02:00
1 parent 19a2759685
commit e3250a34da
2 files changed
+77 -22

No files matched your search

+22 -1
View File
@@ -317,7 +317,28 @@ window.CONFIG = {
spreadFloor: 0.30, // share that far side roads keep
speed: 1.0, // flow speed multiplier
density: 1.0, // vehicle density multiplier
brightness: 1.3 // vehicle light intensity
brightness: 1.3, // vehicle light intensity
// Time-based traffic profile. Values are multipliers around the
// configured density. Times are local scene-clock hours.
timeProfile: {
enabled: true,
weekday: 1.0, // Mon-Fri base traffic
saturday: 0.65, // weekend reduction
sunday: 0.55, // weekend reduction
morningPeak: 7.7, // rush-hour morning peak
morningWidth: 1.2, // gaussian sigma in hours
morningGain: 0.55, // +55 % at the peak
eveningPeak: 17.5, // rush-hour evening peak
eveningWidth: 1.4,
eveningGain: 0.75, // +75 % at the peak
fridayEveningGain: 0.35,
sundayEveningPeak: 18.5,
sundayEveningWidth: 1.8,
sundayEveningGain: 0.85, // commuter return traffic
nightReduction: 0.70 // deep-night traffic reduced to 30 %
// timeProfile: { enabled: false }
// timeProfile: { morningGain: 0.8, eveningGain: 1.0, nightReduction: 0.85 }
}
// speed: 2.0, density: 0.6, brightness: 1.0
},
+55 -21
View File
@@ -3359,6 +3359,58 @@ var CAR_LANE_PX = CAR_TUN.lanePx || 2.6;
var CAR_BRIGHT = CAR_TUN.brightness || 1.3;
var CAR_SPEED = CAR_TUN.speed || 1;
var CAR_DENS = CAR_TUN.density || 1;
var CAR_TIME_CFG = CAR_TUN.timeProfile || {};
var CAR_TIME_ON = CAR_TIME_CFG.enabled !== false;
function carSmoothstep(a, b, x) {
var t = Math.max(0, Math.min(1, (x - a) / Math.max(1e-6, b - a)));
return t * t * (3 - 2 * t);
}
function carGaussian(hh, center, width) {
var d = hh - center;
if (d > 12) d -= 24;
if (d < -12) d += 24;
var w = Math.max(0.25, width);
return Math.exp(-(d * d) / (2 * w * w));
}
function carWeekendFactor(dow, hh) {
var sat = (typeof CAR_TIME_CFG.saturday === 'number') ? CAR_TIME_CFG.saturday : 0.65;
var sun = (typeof CAR_TIME_CFG.sunday === 'number') ? CAR_TIME_CFG.sunday : 0.55;
var work = (typeof CAR_TIME_CFG.weekday === 'number') ? CAR_TIME_CFG.weekday : 1.0;
function wOf(d) { return d === 0 ? sun : (d === 6 ? sat : work); }
var f = wOf(dow);
if (hh >= 23) f = f + (wOf((dow + 1) % 7) - f) * (hh - 23);
else if (hh < 1) f = wOf((dow + 6) % 7) + (f - wOf((dow + 6) % 7)) * hh;
return Math.max(0.15, Math.min(1.5, f));
}
function carRushFactor(hh, dow) {
if (!CAR_TIME_ON || typeof hh !== 'number') return 1;
var morningPeak = (typeof CAR_TIME_CFG.morningPeak === 'number') ? CAR_TIME_CFG.morningPeak : 7.7;
var morningWidth = (typeof CAR_TIME_CFG.morningWidth === 'number') ? CAR_TIME_CFG.morningWidth : 1.2;
var morningGain = (typeof CAR_TIME_CFG.morningGain === 'number') ? CAR_TIME_CFG.morningGain : 0.55;
var eveningPeak = (typeof CAR_TIME_CFG.eveningPeak === 'number') ? CAR_TIME_CFG.eveningPeak : 17.5;
var eveningWidth = (typeof CAR_TIME_CFG.eveningWidth === 'number') ? CAR_TIME_CFG.eveningWidth : 1.4;
var eveningGain = (typeof CAR_TIME_CFG.eveningGain === 'number') ? CAR_TIME_CFG.eveningGain : 0.75;
var nightReduction = (typeof CAR_TIME_CFG.nightReduction === 'number') ? CAR_TIME_CFG.nightReduction : 0.70;
var fridayGain = (typeof CAR_TIME_CFG.fridayEveningGain === 'number') ? CAR_TIME_CFG.fridayEveningGain : 0.35;
var sundayEveningPeak = (typeof CAR_TIME_CFG.sundayEveningPeak === 'number') ? CAR_TIME_CFG.sundayEveningPeak : 18.5;
var sundayEveningWidth = (typeof CAR_TIME_CFG.sundayEveningWidth === 'number') ? CAR_TIME_CFG.sundayEveningWidth : 1.8;
var sundayEveningGain = (typeof CAR_TIME_CFG.sundayEveningGain === 'number') ? CAR_TIME_CFG.sundayEveningGain : 0.85;
var rush = 1;
rush += morningGain * carGaussian(hh, morningPeak, morningWidth);
rush += eveningGain * carGaussian(hh, eveningPeak, eveningWidth);
if (dow === 5) rush += fridayGain * carGaussian(hh, 18.0, 1.6);
if (dow === 0) rush += sundayEveningGain * carGaussian(hh, sundayEveningPeak, sundayEveningWidth);
var nightEdge = -1;
if (hh >= 22) nightEdge = carSmoothstep(22, 24, hh);
else if (hh < 5) nightEdge = 1 - carSmoothstep(3, 5, hh);
if (nightEdge >= 0) rush *= 1 - nightReduction * nightEdge;
if (typeof dow === 'number') rush *= carWeekendFactor(dow, hh);
return Math.max(0.12, Math.min(2.2, rush));
}
// Gaussian spread of traffic around the motorway network: sigma (spreadKm)
// and the floor that distant side roads keep (spreadFloor).
var CAR_SIGMA = carMetres((CAR_TUN.spreadKm || 25) * 1000);
@@ -6590,30 +6642,12 @@ window.clouds3dRender = function(target) {
var carPxScale = Math.max(0.45, Math.min(1.25, gl.drawingBufferHeight / 1080));
var tCurve = Math.max(0, Math.min(1, (carNight - 0.10) / 0.40));
tCurve = tCurve * tCurve * (3 - 2 * tCurve); // smoothstep
// rush-hour shaping: busy evening/early morning, quiet 23:00-04:00
// Time-based traffic profile: weekday rush peaks, quiet deep night,
// reduced weekend traffic, and a Sunday-evening commuter bump.
var rush = 1;
var tDay = window.__currentDayProgress;
if (typeof tDay === 'number') {
var hh = tDay * 24;
var nightPos = hh >= 23 ? (hh - 23) / 5 : (hh < 4 ? (hh + 1) / 5 : -1);
if (nightPos >= 0) {
var edge = Math.min(1, Math.min(nightPos, 1 - nightPos) * 5);
edge = edge * edge * (3 - 2 * edge);
rush = 1 - 0.65 * edge; // dips to 0.35
}
// weekend factor (window.__flightDow: 0=Sun..6=Sat), blended
// smoothly over the hour around midnight so nothing pops
var dow = window.__flightDow;
if (typeof dow === 'number') {
var wOf = function (d) { return d === 0 ? 0.55 : (d === 6 ? 0.65 : 1); };
var fNow = wOf(dow);
if (hh >= 23) {
fNow = fNow + (wOf((dow + 1) % 7) - fNow) * (hh - 23);
} else if (hh < 1) {
fNow = wOf((dow + 6) % 7) + (fNow - wOf((dow + 6) % 7)) * hh;
}
rush *= fNow;
}
rush = carRushFactor(tDay * 24, window.__flightDow);
}
gl.useProgram(carProg);
gl.uniformMatrix4fv(carUniforms.proj, false, proj);