hmm
This commit is contained in:
parent
112e6bf86b
commit
f2d0306d96
13 changed files with 1434 additions and 516 deletions
125
mapTransport.js
125
mapTransport.js
|
|
@ -10,12 +10,15 @@ import {
|
|||
makeSpatialIndex,
|
||||
makeUnionFind,
|
||||
meanFieldAround as meanFieldAroundBase,
|
||||
nearestNetworkPoint,
|
||||
packDebugField,
|
||||
pathCumulativeLengths,
|
||||
pathAverageField,
|
||||
pathEndpoints,
|
||||
pathLengthCells,
|
||||
pointAtPathDistance,
|
||||
sampledNetworkCells as sampledNetworkCellsBase,
|
||||
splitPathToValidCells as splitPathToValidCellsBase,
|
||||
squaredDistance,
|
||||
TRANSPORT_ROUTE_POLICIES,
|
||||
} from "./mapTransportUtils.js";
|
||||
|
|
@ -1332,55 +1335,20 @@ export function buildDensityFlowRoadTransportSystem(ctx) {
|
|||
|
||||
function stitchRasterNearContacts() {
|
||||
const debug = { expressway: 0, national: 0, localToNational: 0, local: 0, broadNearMisses: 0 };
|
||||
function sampledCells(paths, step = 1) {
|
||||
const cells = [];
|
||||
for (let pathId = 0; pathId < (paths || []).length; pathId++) {
|
||||
const path = paths[pathId];
|
||||
for (let k = 0; k < path.length; k += step) {
|
||||
const [x, y] = path[k];
|
||||
if (inside(x, y) && !sea[indexOf(x, y)]) cells.push({ x, y, pathId });
|
||||
}
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
function endpointListWithIds(paths) {
|
||||
const out = [];
|
||||
for (let pathId = 0; pathId < (paths || []).length; pathId++) {
|
||||
const p = paths[pathId];
|
||||
if (!p || p.length < 2) continue;
|
||||
out.push({ x: p[0][0], y: p[0][1], pathId });
|
||||
const q = p[p.length - 1];
|
||||
out.push({ x: q[0], y: q[1], pathId });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function nearestWithin(source, targets, radius, excludeSamePath = true) {
|
||||
let best = null;
|
||||
let bestD = radius + 1;
|
||||
for (const t of targets) {
|
||||
if (excludeSamePath && source.pathId != null && t.pathId === source.pathId) continue;
|
||||
const d = Math.hypot(source.x - t.x, source.y - t.y);
|
||||
if (d > 0.01 && d < bestD) {
|
||||
bestD = d;
|
||||
best = t;
|
||||
}
|
||||
}
|
||||
return best ? { target: best, d: bestD } : null;
|
||||
}
|
||||
function stitchEndpoints(paths, mode, targets, maxAdds, radius, probability = 1) {
|
||||
let added = 0;
|
||||
const endpoints = endpointListWithIds(paths);
|
||||
const endpoints = pathEndpoints(paths);
|
||||
for (const ep of endpoints) {
|
||||
if (added >= maxAdds) break;
|
||||
if (probability < 1 && hash2(ep.x, ep.y, seed + 18331 + added * 17) > probability) continue;
|
||||
const near = nearestWithin(ep, targets, radius, true);
|
||||
const near = nearestNetworkPoint(ep, targets, radius);
|
||||
if (near && addShortConnector(paths, ep, near.target, mode)) added++;
|
||||
}
|
||||
return added;
|
||||
}
|
||||
const expresswayCells = sampledCells(expressways, 1);
|
||||
const nationalCells = sampledCells([...nationalRoads, ...externalRoads], 1);
|
||||
const localCells = sampledCells(minorRoads, 1);
|
||||
const expresswayCells = sampledNetworkCellsBase(expressways, 1, sea);
|
||||
const nationalCells = sampledNetworkCellsBase([...nationalRoads, ...externalRoads], 1, sea);
|
||||
const localCells = sampledNetworkCellsBase(minorRoads, 1, sea);
|
||||
debug.expressway += stitchEndpoints(expressways, "expressway", expresswayCells, 14, 46.0, 0.62);
|
||||
debug.national += stitchEndpoints(nationalRoads, "national", nationalCells, 48, 14.0);
|
||||
debug.localToNational += stitchEndpoints(minorRoads, "local", nationalCells, 240, 20.0);
|
||||
|
|
@ -1390,11 +1358,11 @@ export function buildDensityFlowRoadTransportSystem(ctx) {
|
|||
// not share a raster cell. This addresses line simplification and diagonal
|
||||
// near-contact cases not caught by endpoint-only repair.
|
||||
const allLocalTargets = [...nationalCells, ...localCells];
|
||||
const candidates = sampledCells([...nationalRoads, ...minorRoads], 3)
|
||||
const candidates = sampledNetworkCellsBase([...nationalRoads, ...minorRoads], 3, sea)
|
||||
.sort((a, b) => hash2(a.x, a.y, seed + 18377) - hash2(b.x, b.y, seed + 18377));
|
||||
for (const c of candidates) {
|
||||
if (debug.broadNearMisses >= 260) break;
|
||||
const near = nearestWithin(c, allLocalTargets, 4.75, true);
|
||||
const near = nearestNetworkPoint(c, allLocalTargets, 4.75);
|
||||
if (!near) continue;
|
||||
const out = c.pathId < nationalRoads.length ? nationalRoads : minorRoads;
|
||||
const mode = out === nationalRoads ? "national" : "local";
|
||||
|
|
@ -1410,56 +1378,21 @@ export function buildDensityFlowRoadTransportSystem(ctx) {
|
|||
|
||||
function stitchLongLocalBranches() {
|
||||
const debug = { localToTrunk: 0, localToLocal: 0 };
|
||||
function cells(paths, step = 2) {
|
||||
const out = [];
|
||||
for (let pathId = 0; pathId < (paths || []).length; pathId++) {
|
||||
const path = paths[pathId];
|
||||
for (let k = 0; k < path.length; k += step) {
|
||||
const [x, y] = path[k];
|
||||
if (inside(x, y) && !sea[indexOf(x, y)]) out.push({ x, y, pathId });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function endpoints(paths) {
|
||||
const out = [];
|
||||
for (let pathId = 0; pathId < (paths || []).length; pathId++) {
|
||||
const p = paths[pathId];
|
||||
if (!p || p.length < 2) continue;
|
||||
out.push({ x: p[0][0], y: p[0][1], pathId });
|
||||
const q = p[p.length - 1];
|
||||
out.push({ x: q[0], y: q[1], pathId });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function nearest(source, targets, radius, excludePath = null) {
|
||||
let best = null;
|
||||
let bestD = radius + 1;
|
||||
for (const t of targets) {
|
||||
if (excludePath != null && t.pathId === excludePath) continue;
|
||||
const d = Math.hypot(source.x - t.x, source.y - t.y);
|
||||
if (d > 0.01 && d < bestD) {
|
||||
bestD = d;
|
||||
best = t;
|
||||
}
|
||||
}
|
||||
return best ? { ...best, d: bestD } : null;
|
||||
}
|
||||
const trunkCells = cells([...nationalRoads, ...externalRoads], 2);
|
||||
const localCells = cells(minorRoads, 2);
|
||||
const eps = endpoints(minorRoads)
|
||||
const trunkCells = sampledNetworkCellsBase([...nationalRoads, ...externalRoads], 2, sea);
|
||||
const localCells = sampledNetworkCellsBase(minorRoads, 2, sea);
|
||||
const eps = pathEndpoints(minorRoads)
|
||||
.sort((a, b) => hash2(a.x, a.y, seed + 18491) - hash2(b.x, b.y, seed + 18491));
|
||||
for (const ep of eps) {
|
||||
if (debug.localToTrunk >= 160) break;
|
||||
const hit = nearest(ep, trunkCells, 20, null);
|
||||
const hit = nearestNetworkPoint(ep, trunkCells, 20, { excludeSamePath: false });
|
||||
if (!hit) continue;
|
||||
if (addShortConnector(minorRoads, ep, hit, "local")) debug.localToTrunk++;
|
||||
}
|
||||
const eps2 = endpoints(minorRoads)
|
||||
const eps2 = pathEndpoints(minorRoads)
|
||||
.sort((a, b) => hash2(a.x, a.y, seed + 18493) - hash2(b.x, b.y, seed + 18493));
|
||||
for (const ep of eps2) {
|
||||
if (debug.localToLocal >= 150) break;
|
||||
const hit = nearest(ep, localCells, 17, ep.pathId);
|
||||
const hit = nearestNetworkPoint(ep, localCells, 17, { excludePath: ep.pathId });
|
||||
if (!hit) continue;
|
||||
if (addShortConnector(minorRoads, ep, hit, "local")) debug.localToLocal++;
|
||||
}
|
||||
|
|
@ -1929,33 +1862,11 @@ export function buildDensityFlowRoadTransportSystem(ctx) {
|
|||
return transportFields.local;
|
||||
}
|
||||
function splitPathToValidCells(path, costField, minCells = 2) {
|
||||
const chunks = [];
|
||||
let cur = [];
|
||||
function valid(x, y) {
|
||||
return splitPathToValidCellsBase(path, (x, y) => {
|
||||
if (!inside(x, y)) return false;
|
||||
const i = indexOf(x, y);
|
||||
return !sea[i] && !highAltitudeRoadClosed(i) && costField[i] < INF;
|
||||
}
|
||||
function pushPoint(x, y) {
|
||||
if (!valid(x, y)) {
|
||||
if (cur.length >= minCells) chunks.push(cur);
|
||||
cur = [];
|
||||
return;
|
||||
}
|
||||
if (!cur.length || cur[cur.length - 1][0] !== x || cur[cur.length - 1][1] !== y) cur.push([x, y]);
|
||||
}
|
||||
for (let k = 0; k < (path?.length || 0); k++) {
|
||||
const a = path[k];
|
||||
const b = path[Math.min(k + 1, path.length - 1)];
|
||||
const steps = Math.max(1, Math.ceil(Math.hypot(b[0] - a[0], b[1] - a[1])));
|
||||
for (let s = 0; s <= steps; s++) {
|
||||
if (k > 0 && s === 0) continue;
|
||||
const t = s / steps;
|
||||
pushPoint(Math.round(a[0] + (b[0] - a[0]) * t), Math.round(a[1] + (b[1] - a[1]) * t));
|
||||
}
|
||||
}
|
||||
if (cur.length >= minCells) chunks.push(cur);
|
||||
return chunks;
|
||||
}, minCells);
|
||||
}
|
||||
function normalizeRoadGroups() {
|
||||
const groups = roadGroups();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue