diff --git a/vendor/clouds3d.js b/vendor/clouds3d.js index d1162b9..c4ed5a1 100644 --- a/vendor/clouds3d.js +++ b/vendor/clouds3d.js @@ -3726,20 +3726,20 @@ function selectEmergencyRoutes() { emergencyStartCities = emergencyCollectCities(); var nets = emergencyNetworks(); var pool = [], seenChain = {}, poolMode = 'none'; - var wantCandidates = Math.max(EMERGENCY_COUNT * 8, 800); + var targetPool = Math.max(EMERGENCY_COUNT * 3, 300); var passes = [ { minKm: EMERGENCY_MIN_KM, maxKm: EMERGENCY_MAX_KM, near: 1.2, mode: 'strict' }, - { minKm: EMERGENCY_MIN_KM * 0.55, maxKm: EMERGENCY_MAX_KM * 1.45, near: 1.8, mode: 'relaxed' }, - { minKm: 10, maxKm: 160, near: 3.0, mode: 'fallback' }, - { minKm: 3, maxKm: 220, near: 6.0, mode: 'wide' }, - { minKm: 0.5, maxKm: 400, near: 12.0, mode: 'last-resort' } + { minKm: EMERGENCY_MIN_KM * 0.65, maxKm: EMERGENCY_MAX_KM * 1.35, near: 1.8, mode: 'relaxed' }, + { minKm: 15, maxKm: 160, near: 3.0, mode: 'fallback' }, + { minKm: 8, maxKm: 220, near: 6.0, mode: 'wide' }, + { minKm: 3, maxKm: 400, near: 12.0, mode: 'last-resort' } ]; - for (var p = 0; p < passes.length && pool.length < wantCandidates; p++) { + for (var p = 0; p < passes.length && pool.length < targetPool; p++) { var cell = Math.max(0.5, passes[p].near); var grid = emergencyBuildCityGrid(emergencyStartCities, cell); - for (var ni = 0; ni < nets.length && pool.length < wantCandidates; ni++) { + for (var ni = 0; ni < nets.length && pool.length < targetPool; ni++) { var part = emergencyCollectMapCandidates(nets[ni].net, nets[ni].key, emergencyStartCities, grid, cell, - passes[p].minKm, passes[p].maxKm, passes[p].near, wantCandidates, 180000); + passes[p].minKm, passes[p].maxKm, passes[p].near, targetPool, 220000); for (var pi = 0; pi < part.length; pi++) { var key = part[pi].netKey + ':' + part[pi].ci; if (!seenChain[key]) { @@ -3750,8 +3750,15 @@ function selectEmergencyRoutes() { if (part.length) poolMode = passes[p].mode + ':' + nets[ni].key; } } - pool.sort(function (a, b) { return a.score - b.score; }); - var top = pool.slice(0, Math.max(EMERGENCY_COUNT * 12, 240)); + var goodKm = EMERGENCY_MIN_KM * 0.65; + var good = pool.filter(function (c) { return c.lenKm >= goodKm; }); + var usePool = good; + if (usePool.length < EMERGENCY_COUNT) { + usePool = usePool.concat(pool.filter(function (c) { return c.lenKm >= EMERGENCY_MIN_KM * 0.35; })); + } + if (usePool.length < EMERGENCY_COUNT) usePool = pool; + usePool.sort(function (a, b) { return a.score - b.score; }); + var top = usePool.slice(0, Math.max(EMERGENCY_COUNT * 6, 120)); emergencyShuffle(top); var used = {}, cityUse = {}, routeFailures = []; for (var r = 0; r < top.length && emergencyRoutes.length < EMERGENCY_COUNT; r++) { @@ -3759,7 +3766,7 @@ function selectEmergencyRoutes() { var usedKey = cand.netKey + ':' + cand.ci; if (used[usedKey]) continue; var cityKey = cand.city ? (Math.round(cand.city.x * 4) + '_' + Math.round(cand.city.z * 4)) : 'none'; - if ((cityUse[cityKey] || 0) >= 3) continue; + if ((cityUse[cityKey] || 0) >= 2) continue; used[usedKey] = true; cityUse[cityKey] = (cityUse[cityKey] || 0) + 1; var route = emergencyChainAtOffset(cand.net, cand.offset, cand.n); @@ -3820,6 +3827,7 @@ function selectEmergencyRoutes() { startCities: emergencyStartCities.length, poolMode: poolMode, candidates: pool.length, + goodCandidates: good.length, candidateSample: top.slice(0, 5).map(function (c) { return { netKey: c.netKey, ci: c.ci, lenKm: +c.lenKm.toFixed(1),