fix(preview): derive signals from OSM controls

This commit is contained in:
2026-08-07 09:05:27 +08:00
parent 950cd1c4cd
commit 1c077a312e
7 changed files with 315 additions and 73 deletions

View File

@@ -1,6 +1,7 @@
"use strict";
const fs = require("fs");
const { parseOsm } = require("./osm");
const MAX_ROUTES = 5;
const MAX_PATH_EDGES = 7;
@@ -26,49 +27,6 @@ function buildVehicleRoute(osmPath) {
};
}
function parseOsm(xml) {
const boundsMatch = xml.match(/<bounds\b([^>]*)\/?\s*>/);
const boundsAttrs = boundsMatch ? xmlAttrs(boundsMatch[1]) : {};
const bounds = {
minLon: Number(boundsAttrs.minlon), minLat: Number(boundsAttrs.minlat),
maxLon: Number(boundsAttrs.maxlon), maxLat: Number(boundsAttrs.maxlat),
};
const validBounds = Object.values(bounds).every(Number.isFinite) ? bounds : null;
const nodes = new Map();
for (const match of xml.matchAll(/<node\b([^>]*)\/?\s*>/g)) {
const attrs = xmlAttrs(match[1]);
if (!attrs.id || attrs.lon === undefined || attrs.lat === undefined) continue;
const coord = [Number(attrs.lon), Number(attrs.lat)];
if (coord.every(Number.isFinite)) nodes.set(attrs.id, coord);
}
const ways = [];
for (const match of xml.matchAll(/<way\b([^>]*)>([\s\S]*?)<\/way>/g)) {
const attrs = xmlAttrs(match[1]);
const body = match[2];
const tags = {};
for (const tagMatch of body.matchAll(/<tag\b([^>]*)\/?\s*>/g)) {
const tag = xmlAttrs(tagMatch[1]);
if (tag.k) tags[tag.k] = tag.v || "";
}
if (!isCruiseHighway(tags)) continue;
const refs = [];
for (const ndMatch of body.matchAll(/<nd\b([^>]*)\/?\s*>/g)) {
const ref = xmlAttrs(ndMatch[1]).ref;
if (ref && nodes.has(ref)) refs.push(ref);
}
if (refs.length >= 2) ways.push({ id: attrs.id || `way-${ways.length + 1}`, refs, tags });
}
return { bounds: validBounds, nodes, ways };
}
function xmlAttrs(text) {
const attrs = {};
for (const match of text.matchAll(/([:\w-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g)) {
attrs[match[1]] = match[2] !== undefined ? match[2] : match[3];
}
return attrs;
}
function isCruiseHighway(tags) {
const highway = tags.highway || "";
if (!highway || tags.area === "yes") return false;
@@ -81,6 +39,7 @@ function isCruiseHighway(tags) {
function directedRoadEdges(ways, nodes, bounds) {
const edges = [];
for (const way of ways) {
if (!isCruiseHighway(way.tags)) continue;
const refs = compactRefs(way.refs);
if (refs.length < 2) continue;
const coords = refs.map((ref) => nodes.get(ref));