emergency: select routes that pass near the start city

This commit is contained in:
Richard Zink committed 2026-10-13 07:31:29 +02:00
1 parent 4cb1e3a704
commit f06c50409a
1 file changed
+49 -18
+49 -18
View File
@@ -3549,15 +3549,35 @@ function emergencyCollectCandidates(net, netKey, startCity, minKm, maxKm, nearLi
var lastX = net.pts[last], lastZ = net.pts[last + 1], lastD = net.pts[last + 2]; var lastX = net.pts[last], lastZ = net.pts[last + 1], lastD = net.pts[last + 2];
var len = Math.max(0, lastD - firstD); var len = Math.max(0, lastD - firstD);
var lenKm = len * KM_PER_TILE; var lenKm = len * KM_PER_TILE;
var dStart = Math.hypot(firstX - startCity.x, firstZ - startCity.z); if (lenKm >= minKm && lenKm <= maxKm) {
var dEnd = Math.hypot(lastX - startCity.x, lastZ - startCity.z); var near = Math.hypot(firstX - startCity.x, firstZ - startCity.z);
var near = Math.min(dStart, dEnd); var startD = 0;
if (near <= nearLimit && lenKm >= minKm && lenKm <= maxKm) { var dEnd = Math.hypot(lastX - startCity.x, lastZ - startCity.z);
out.push({ if (dEnd < near) {
net: net, netKey: netKey, ci: ci, len: len, lenKm: lenKm, near: near, near = dEnd;
score: Math.abs(lenKm - targetKm) + near * 18, startD = len;
reverse: dEnd < dStart }
}); // A long road can pass close to the start city even when both
// of its endpoints are far away. Sample the chain coarsely.
if (near > nearLimit && n > 4) {
var step = Math.max(1, Math.floor(n / 16));
for (var q = step; q < n - step; q += step) {
var off = k + q * 3;
var dd = Math.hypot(net.pts[off] - startCity.x, net.pts[off + 1] - startCity.z);
if (dd < near) {
near = dd;
startD = Math.max(0, Math.min(len, net.pts[off + 2] - firstD));
}
}
}
if (near <= nearLimit) {
out.push({
net: net, netKey: netKey, ci: ci, len: len, lenKm: lenKm,
near: near, startD: startD,
score: Math.abs(lenKm - targetKm) + near * 18,
reverse: false
});
}
} }
k += n * 3; k += n * 3;
} }
@@ -3620,11 +3640,7 @@ function selectEmergencyRoutes() {
if (used[usedKey]) continue; if (used[usedKey]) continue;
used[usedKey] = true; used[usedKey] = true;
var route = emergencyChainAt(cand.net, cand.ci); var route = emergencyChainAt(cand.net, cand.ci);
if (cand.reverse) { if (route.length) {
route.reverse();
var maxD = route.length ? route[0].d : 0;
for (var rp = 0; rp < route.length; rp++) route[rp].d = maxD - route[rp].d;
} else if (route.length) {
var base = route[0].d; var base = route[0].d;
for (var rp2 = 0; rp2 < route.length; rp2++) route[rp2].d -= base; for (var rp2 = 0; rp2 < route.length; rp2++) route[rp2].d -= base;
} }
@@ -3637,12 +3653,20 @@ function selectEmergencyRoutes() {
}); });
continue; continue;
} }
emergencyRoutes.push({ pts: route, len: len, lenKm: len * KM_PER_TILE, nearKm: cand.near * KM_PER_TILE }); emergencyRoutes.push({
pts: route, len: len, lenKm: len * KM_PER_TILE,
nearKm: cand.near * KM_PER_TILE,
startD: Math.max(0, Math.min(len, cand.startD || 0))
});
} }
for (var v = 0; v < emergencyRoutes.length; v++) { for (var v = 0; v < emergencyRoutes.length; v++) {
var rr = emergencyRoutes[v];
var spread = rr.len * 0.18;
var d = (rr.startD || 0) + (Math.random() - 0.5) * spread;
d = Math.max(0, Math.min(rr.len, d));
emergencyVehicles.push({ emergencyVehicles.push({
route: v, route: v,
d: emergencyRoutes[v].len * (0.05 + 0.85 * Math.random()), d: d,
dir: Math.random() < 0.5 ? 1 : -1, dir: Math.random() < 0.5 ? 1 : -1,
seed: Math.random() seed: Math.random()
}); });
@@ -3662,12 +3686,19 @@ function selectEmergencyRoutes() {
candidateSample: top.slice(0, 5).map(function (c) { candidateSample: top.slice(0, 5).map(function (c) {
return { return {
netKey: c.netKey, ci: c.ci, lenKm: +c.lenKm.toFixed(1), netKey: c.netKey, ci: c.ci, lenKm: +c.lenKm.toFixed(1),
nearKm: +(c.near * KM_PER_TILE).toFixed(1), reverse: c.reverse nearKm: +(c.near * KM_PER_TILE).toFixed(1),
startKm: +((c.startD || 0) * KM_PER_TILE).toFixed(1)
}; };
}), }),
routeFailures: routeFailures.slice(0, 5), routeFailures: routeFailures.slice(0, 5),
networks: nets.map(function (n) { return { key: n.key, chains: n.net.cnts.length }; }), networks: nets.map(function (n) { return { key: n.key, chains: n.net.cnts.length }; }),
routes: emergencyRoutes.map(function (r) { return { km: +r.lenKm.toFixed(1), nearKm: +r.nearKm.toFixed(1) }; }) routes: emergencyRoutes.map(function (r) {
return {
km: +r.lenKm.toFixed(1),
nearKm: +r.nearKm.toFixed(1),
startKm: +(r.startD * KM_PER_TILE).toFixed(1)
};
})
}; };
} }