Split network into segments and report distance
This commit is contained in:
parent
082270831d
commit
8e98819c38
|
@ -12,7 +12,8 @@
|
|||
* the `script/update-network` script.
|
||||
*/
|
||||
|
||||
const {choosePlural, joinSentence} = require('../util');
|
||||
const geolib = require('geolib');
|
||||
const util = require('../util');
|
||||
const osm = require('./sources/osm');
|
||||
const tam = require('./sources/tam');
|
||||
|
||||
|
@ -163,6 +164,9 @@ out body qt;
|
|||
// All transport lines of the network
|
||||
const lines = {};
|
||||
|
||||
// All segments leading from one stop to another
|
||||
const segments = {};
|
||||
|
||||
for (let routeMaster of routeMasters)
|
||||
{
|
||||
const lineRef = routeMaster.tags.ref;
|
||||
|
@ -236,9 +240,9 @@ URI: ${osm.viewNode(stop.id)}
|
|||
{
|
||||
console.warn(`\
|
||||
— Stop ${candidate.stopRef} with name “${candidate.name}” used by \
|
||||
${choosePlural(candidate.lines.length, 'line', '.s')} \
|
||||
${joinSentence(Array.from(candidate.lines), ', ', ' and ')} going to \
|
||||
${joinSentence(Array.from(candidate.directions), ', ', ' or ')}
|
||||
${util.choosePlural(candidate.lines.length, 'line', '.s')} \
|
||||
${util.joinSentence(Array.from(candidate.lines), ', ', ' and ')} going to \
|
||||
${util.joinSentence(Array.from(candidate.directions), ', ', ' or ')}
|
||||
Apply in JOSM: ${osm.addTagsToNode(stop.id, ['ref=' + candidate.stopRef])}
|
||||
`);
|
||||
}
|
||||
|
@ -368,22 +372,65 @@ ${name} is one-way and cannot be used in reverse.`);
|
|||
}
|
||||
|
||||
// Split the path into segments between stops
|
||||
const segments = [];
|
||||
|
||||
for (let stopIndex = 0; stopIndex + 1 < stops.length; ++stopIndex)
|
||||
{
|
||||
segments.push(path.slice(
|
||||
const begin = elements[stops[stopIndex]].tags.ref;
|
||||
const end = elements[stops[stopIndex + 1]].tags.ref;
|
||||
|
||||
const id = `${begin}-${end}`;
|
||||
const nodes = path.slice(
|
||||
path.indexOf(stops[stopIndex]),
|
||||
path.indexOf(stops[stopIndex + 1]) + 1,
|
||||
).map(id => ({
|
||||
);
|
||||
|
||||
if (id in segments)
|
||||
{
|
||||
if (!util.arraysEqual(nodes, segments[id].nodes))
|
||||
{
|
||||
throw new Error(`Segment ${id} is defined as a
|
||||
different sequence of nodes in two or more lines.`);
|
||||
}
|
||||
|
||||
segments[id].lines.add(lineRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
const points = nodes.map(id => ({
|
||||
lat: elements[id].lat,
|
||||
lon: elements[id].lon
|
||||
})));
|
||||
}));
|
||||
|
||||
if (points.length)
|
||||
{
|
||||
// Augment each point with the distance to the start
|
||||
points[0].distance = 0;
|
||||
|
||||
for (let i = 1; i < points.length; ++i)
|
||||
{
|
||||
const len = geolib.getPreciseDistance(
|
||||
...[points[i - 1], points[i]]
|
||||
.map(({lat, lon}) => ({
|
||||
latitude: lat,
|
||||
longitude: lon
|
||||
})),
|
||||
);
|
||||
|
||||
points[i].distance = points[i - 1].distance + len;
|
||||
}
|
||||
}
|
||||
|
||||
segments[id] = {
|
||||
// Keep track of the original sequence of nodes to
|
||||
// compare with duplicates
|
||||
nodes,
|
||||
points,
|
||||
lines: new Set([lineRef]),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
routes.push({
|
||||
from, to, name,
|
||||
segments,
|
||||
stops: stops.map(id => elements[id].tags.ref),
|
||||
});
|
||||
}
|
||||
|
@ -394,7 +441,13 @@ ${name} is one-way and cannot be used in reverse.`);
|
|||
};
|
||||
}
|
||||
|
||||
return {stops, lines};
|
||||
// Remove OSM nodes from segments that were only used for checking validity
|
||||
for (let segment of Object.values(segments))
|
||||
{
|
||||
delete segment.nodes;
|
||||
}
|
||||
|
||||
return {stops, lines, segments};
|
||||
};
|
||||
|
||||
exports.fetch = fetch;
|
||||
|
|
55142
back/data/network.json
55142
back/data/network.json
File diff suppressed because it is too large
Load Diff
|
@ -22,8 +22,10 @@ const {isObject} = require('../../util');
|
|||
const runQuery = (
|
||||
query,
|
||||
endpoint = 'https://lz4.overpass-api.de/api/interpreter'
|
||||
) => axios.post(endpoint, 'data=' + query)
|
||||
.then(res => res.data);
|
||||
) => (
|
||||
axios.post(endpoint, 'data=' + query)
|
||||
.then(res => res.data)
|
||||
);
|
||||
|
||||
exports.runQuery = runQuery;
|
||||
|
||||
|
@ -37,12 +39,13 @@ exports.runQuery = runQuery;
|
|||
* @param tags List of tags to add, in the `key=value` format.
|
||||
* @return Link for remotely adding the tags.
|
||||
*/
|
||||
const addTagsToNode = (id, tags) =>
|
||||
const addTagsToNode = (id, tags) => (
|
||||
'http://127.0.0.1:8111/load_object?' + [
|
||||
`objects=n${id}`,
|
||||
'new_layer=false',
|
||||
'addtags=' + tags.join('%7C'),
|
||||
].join('&');
|
||||
].join('&')
|
||||
);
|
||||
|
||||
exports.addTagsToNode = addTagsToNode;
|
||||
|
||||
|
@ -64,11 +67,12 @@ exports.viewNode = viewNode;
|
|||
* @param tags Set of tags of the way.
|
||||
* @return True iff. the way is one-way.
|
||||
*/
|
||||
const isOneWay = object =>
|
||||
const isOneWay = object => (
|
||||
object.type === 'way'
|
||||
&& isObject(object.tags)
|
||||
&& (object.tags.oneway === 'yes' || object.tags.junction === 'roundabout'
|
||||
|| object.tags.highway === 'motorway');
|
||||
|| object.tags.highway === 'motorway')
|
||||
);
|
||||
|
||||
exports.isOneWay = isOneWay;
|
||||
|
||||
|
@ -81,9 +85,10 @@ exports.isOneWay = isOneWay;
|
|||
* @param object OSM object.
|
||||
* @return True iff. the relation is a public transport line.
|
||||
*/
|
||||
const isTransportLine = object =>
|
||||
const isTransportLine = object => (
|
||||
object.type === 'relation'
|
||||
&& isObject(object.tags)
|
||||
&& object.tags.type === 'route_master';
|
||||
&& object.tags.type === 'route_master'
|
||||
);
|
||||
|
||||
exports.isTransportLine = isTransportLine;
|
||||
|
|
20
back/util.js
20
back/util.js
|
@ -52,9 +52,11 @@ const joinSentence = (array, separator, lastSeparator) =>
|
|||
return array.join(lastSeparator);
|
||||
}
|
||||
|
||||
return array.slice(0, -1).join(separator)
|
||||
return (
|
||||
array.slice(0, -1).join(separator)
|
||||
+ lastSeparator
|
||||
+ array[array.length - 1];
|
||||
+ array[array.length - 1]
|
||||
);
|
||||
};
|
||||
|
||||
exports.joinSentence = joinSentence;
|
||||
|
@ -68,3 +70,17 @@ exports.joinSentence = joinSentence;
|
|||
const isObject = value => value !== null && typeof value === 'object';
|
||||
|
||||
exports.isObject = isObject;
|
||||
|
||||
/**
|
||||
* Check if two arrays are equal in a shallow manner.
|
||||
*
|
||||
* @param array1 First array.
|
||||
* @param array2 Second array.
|
||||
* @return True iff. the two arrays are equal.
|
||||
*/
|
||||
const arraysEqual = (array1, array2) => (
|
||||
array1.length === array2.length
|
||||
&& array1.every((elt1, index) => elt1 === array2[index])
|
||||
);
|
||||
|
||||
exports.arraysEqual = arraysEqual;
|
||||
|
|
22
front/map.js
22
front/map.js
|
@ -29,23 +29,21 @@ const makeDataSources = async () =>
|
|||
const stopsSource = new VectorSource();
|
||||
|
||||
segmentsSource.addFeatures(
|
||||
Object.values(network.lines).flatMap(({color, routes}) =>
|
||||
routes.map(({segments}) =>
|
||||
Object.values(network.segments).map(({lines, points}) =>
|
||||
new Feature({
|
||||
color,
|
||||
geometry: new LineString(segments.flat().map(
|
||||
colors: lines.map(line => network.lines[line].color),
|
||||
geometry: new LineString(points.map(
|
||||
({lat, lon}) => proj.fromLonLat([lon, lat])
|
||||
)),
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
stopsSource.addFeatures(
|
||||
Object.entries(network.stops).map(([stopId, stop]) =>
|
||||
Object.values(network.stops).map(({lines, lon, lat}) =>
|
||||
new Feature({
|
||||
color: network.lines[stop.lines[0]].color,
|
||||
geometry: new Point(proj.fromLonLat([stop.lon, stop.lat])),
|
||||
colors: lines.map(line => network.lines[line].color),
|
||||
geometry: new Point(proj.fromLonLat([lon, lat])),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -62,14 +60,14 @@ const makeBorderColor = mainColor =>
|
|||
|
||||
const segmentsBorderStyle = feature => new Style({
|
||||
stroke: new Stroke({
|
||||
color: makeBorderColor(feature.get('color')),
|
||||
color: makeBorderColor(feature.get('colors')[0]),
|
||||
width: 8,
|
||||
}),
|
||||
});
|
||||
|
||||
const segmentsInnerStyle = feature => new Style({
|
||||
stroke: new Stroke({
|
||||
color: feature.get('color'),
|
||||
color: feature.get('colors')[0],
|
||||
width: 6,
|
||||
}),
|
||||
});
|
||||
|
@ -77,10 +75,10 @@ const segmentsInnerStyle = feature => new Style({
|
|||
const stopsStyle = feature => new Style({
|
||||
image: new Circle({
|
||||
fill: new Fill({
|
||||
color: feature.get('color'),
|
||||
color: feature.get('colors')[0],
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: makeBorderColor(feature.get('color')),
|
||||
color: makeBorderColor(feature.get('colors')[0]),
|
||||
width: 1.5,
|
||||
}),
|
||||
radius: 6,
|
||||
|
|
Loading…
Reference in New Issue