Migrate geolib to turf, reduce bundle size
This commit is contained in:
parent
3b8a0de9b0
commit
35cd0e1e72
File diff suppressed because it is too large
Load Diff
|
@ -13,12 +13,14 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@turf/along": "^6.0.1",
|
||||||
|
"@turf/helpers": "^6.1.4",
|
||||||
|
"@turf/length": "^6.0.2",
|
||||||
"@turf/turf": "^5.1.6",
|
"@turf/turf": "^5.1.6",
|
||||||
"axios": "^0.19.2",
|
"axios": "^0.19.2",
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"csv-parse": "^4.8.3",
|
"csv-parse": "^4.8.3",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"geolib": "^3.2.1",
|
|
||||||
"ol": "^6.1.1",
|
"ol": "^6.1.1",
|
||||||
"unzip-stream": "^0.3.0"
|
"unzip-stream": "^0.3.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,9 @@ require('ol/ol.css');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const {Map, View} = require('ol');
|
const {Map, View} = require('ol');
|
||||||
|
|
||||||
|
const GeoJSON = require('ol/format/GeoJSON').default;
|
||||||
|
const reader = new GeoJSON({featureProjection: 'EPSG:3857'});
|
||||||
|
|
||||||
const TileLayer = require('ol/layer/Tile').default;
|
const TileLayer = require('ol/layer/Tile').default;
|
||||||
const XYZSource = require('ol/source/XYZ').default;
|
const XYZSource = require('ol/source/XYZ').default;
|
||||||
|
|
||||||
|
@ -25,22 +28,6 @@ h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`;
|
||||||
const simulation = require('../tam/simulation');
|
const simulation = require('../tam/simulation');
|
||||||
const network = require('../tam/network.json');
|
const network = require('../tam/network.json');
|
||||||
|
|
||||||
const getRoutesLines = routes => routes.filter(
|
|
||||||
// Only consider normal routes (excluding alternate routes)
|
|
||||||
([lineRef, routeRef]) =>
|
|
||||||
network.lines[lineRef].routes[routeRef].state === 'normal'
|
|
||||||
).map(([lineRef]) => lineRef);
|
|
||||||
|
|
||||||
const getLinesColors = lines =>
|
|
||||||
{
|
|
||||||
if (lines.length >= 1)
|
|
||||||
{
|
|
||||||
return lines.map(lineRef => network.lines[lineRef].color);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['#FFFFFF'];
|
|
||||||
};
|
|
||||||
|
|
||||||
const lineFeaturesOrder = (feature1, feature2) =>
|
const lineFeaturesOrder = (feature1, feature2) =>
|
||||||
{
|
{
|
||||||
const lines1 = feature1.get('lines');
|
const lines1 = feature1.get('lines');
|
||||||
|
@ -65,28 +52,29 @@ const makeDataSources = () =>
|
||||||
const segmentsSource = new VectorSource();
|
const segmentsSource = new VectorSource();
|
||||||
const stopsSource = new VectorSource();
|
const stopsSource = new VectorSource();
|
||||||
|
|
||||||
segmentsSource.addFeatures(
|
const readFeatures = hash => Object.values(hash).map(json =>
|
||||||
Object.values(network.segments).map(({routes, nodes}) =>
|
{
|
||||||
new Feature({
|
json.properties.lines = json.properties.routes.filter(
|
||||||
lines: getRoutesLines(routes),
|
// Only consider normal routes (excluding alternate routes)
|
||||||
colors: getLinesColors(getRoutesLines(routes)),
|
([lineRef, routeRef]) =>
|
||||||
geometry: new LineString(nodes.map(
|
network.lines[lineRef].routes[routeRef].state === 'normal'
|
||||||
({lat, lon}) => proj.fromLonLat([lon, lat])
|
).map(([lineRef]) => lineRef);
|
||||||
)),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
stopsSource.addFeatures(
|
if (json.properties.lines.length >= 1)
|
||||||
Object.values(network.stops).map(({routes, lon, lat}) =>
|
{
|
||||||
new Feature({
|
json.properties.colors = json.properties.lines.map(
|
||||||
lines: getRoutesLines(routes),
|
lineRef => network.lines[lineRef].color);
|
||||||
colors: getLinesColors(getRoutesLines(routes)),
|
}
|
||||||
geometry: new Point(proj.fromLonLat([lon, lat])),
|
else
|
||||||
})
|
{
|
||||||
)
|
json.properties.colors = ['#FFFFFF'];
|
||||||
);
|
}
|
||||||
|
|
||||||
|
return reader.readFeature(json);
|
||||||
|
});
|
||||||
|
|
||||||
|
segmentsSource.addFeatures(readFeatures(network.segments));
|
||||||
|
stopsSource.addFeatures(readFeatures(network.stops));
|
||||||
return {segmentsSource, stopsSource};
|
return {segmentsSource, stopsSource};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
* the `script/update-network` script.
|
* the `script/update-network` script.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const geolib = require('geolib');
|
const turfHelpers = require('@turf/helpers');
|
||||||
|
const turfLength = require('@turf/length').default;
|
||||||
const util = require('../util');
|
const util = require('../util');
|
||||||
const osm = require('./sources/osm');
|
const osm = require('./sources/osm');
|
||||||
const tam = require('./sources/tam');
|
const tam = require('./sources/tam');
|
||||||
|
@ -89,16 +90,20 @@ a “ref” tag`);
|
||||||
|
|
||||||
if (!(stop.tags.ref in stops))
|
if (!(stop.tags.ref in stops))
|
||||||
{
|
{
|
||||||
stops[stop.tags.ref] = {
|
stops[stop.tags.ref] = turfHelpers.point([
|
||||||
lat: stop.lat,
|
stop.lon,
|
||||||
lon: stop.lon,
|
stop.lat
|
||||||
|
], {
|
||||||
name: stop.tags.name,
|
name: stop.tags.name,
|
||||||
routes: [[lineRef, routeRef]],
|
routes: [[lineRef, routeRef]],
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stops[stop.tags.ref].routes.push([lineRef, routeRef]);
|
stops[stop.tags.ref].properties.routes.push([
|
||||||
|
lineRef,
|
||||||
|
routeRef
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,42 +220,31 @@ ${name} is one-way and cannot be used in reverse.`);
|
||||||
|
|
||||||
if (id in segments)
|
if (id in segments)
|
||||||
{
|
{
|
||||||
if (!util.arraysEqual(nodesIds, segments[id].nodesIds))
|
if (!util.arraysEqual(
|
||||||
|
nodesIds,
|
||||||
|
segments[id].properties.nodesIds
|
||||||
|
))
|
||||||
{
|
{
|
||||||
throw new Error(`Segment ${id} is defined as a
|
throw new Error(`Segment ${id} is defined as a
|
||||||
different sequence of nodes in two or more lines.`);
|
different sequence of nodes in two or more lines.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
segments[id].routes.push([lineRef, routeRef]);
|
segments[id].properties.routes.push([lineRef, routeRef]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const nodes = nodesIds.map(id => ({
|
segments[id] = turfHelpers.lineString(nodesIds.map(id => [
|
||||||
lat: elements[id].lat,
|
elements[id].lon,
|
||||||
lon: elements[id].lon
|
elements[id].lat
|
||||||
}));
|
]), {
|
||||||
|
|
||||||
if (nodes.length)
|
|
||||||
{
|
|
||||||
// Augment each node with the distance to the start
|
|
||||||
nodes[0].distance = 0;
|
|
||||||
|
|
||||||
for (let i = 1; i < nodes.length; ++i)
|
|
||||||
{
|
|
||||||
nodes[i].distance = geolib.getPreciseDistance(
|
|
||||||
nodes[i - 1],
|
|
||||||
nodes[i],
|
|
||||||
) + nodes[i - 1].distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
segments[id] = {
|
|
||||||
// Keep track of the original sequence of nodes to
|
// Keep track of the original sequence of nodes to
|
||||||
// compare with duplicates
|
// compare with duplicates
|
||||||
nodesIds,
|
nodesIds,
|
||||||
nodes,
|
|
||||||
routes: [[lineRef, routeRef]],
|
routes: [[lineRef, routeRef]],
|
||||||
};
|
});
|
||||||
|
|
||||||
|
segments[id].properties.length = (
|
||||||
|
1000 * turfLength(segments[id]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +263,7 @@ different sequence of nodes in two or more lines.`);
|
||||||
// Remove OSM nodes from segments that were only used for checking validity
|
// Remove OSM nodes from segments that were only used for checking validity
|
||||||
for (let segment of Object.values(segments))
|
for (let segment of Object.values(segments))
|
||||||
{
|
{
|
||||||
delete segment.nodesIds;
|
delete segment.properties.nodesIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {stops, lines, segments};
|
return {stops, lines, segments};
|
||||||
|
|
61432
src/tam/network.json
61432
src/tam/network.json
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,6 @@
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const turf = require('@turf/turf');
|
const turfAlong = require('@turf/along').default;
|
||||||
|
const turfProjection = require('@turf/projection');
|
||||||
const network = require('./network.json');
|
const network = require('./network.json');
|
||||||
|
|
||||||
const server = 'http://localhost:4321';
|
const server = 'http://localhost:4321';
|
||||||
|
@ -137,78 +138,36 @@ class Course
|
||||||
|
|
||||||
tick(time)
|
tick(time)
|
||||||
{
|
{
|
||||||
if (this.state === null)
|
if (this.state === 'moving')
|
||||||
{
|
|
||||||
// Ignore uninitalized courses
|
|
||||||
}
|
|
||||||
else if (this.state === 'moving')
|
|
||||||
{
|
{
|
||||||
// Integrate current speed in travelled distance
|
// Integrate current speed in travelled distance
|
||||||
const delta = this.speed * time;
|
this.traveledDistance += this.speed * time;
|
||||||
|
|
||||||
const segment = this.currentSegment;
|
const segment = this.currentSegment;
|
||||||
const length = segment.nodes[segment.nodes.length - 1].distance;
|
|
||||||
this.traveledDistance += delta;
|
|
||||||
|
|
||||||
if (this.traveledDistance >= length)
|
if (this.traveledDistance >= segment.properties.length)
|
||||||
{
|
{
|
||||||
this.arriveToStop(this.arrivalStop);
|
this.arriveToStop(this.arrivalStop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute updated position
|
// Compute updated position and angle based on a small step
|
||||||
const departureStop = network.stops[this.departureStop];
|
const step = 10; // In meters
|
||||||
const arrivalStop = network.stops[this.arrivalStop];
|
|
||||||
const nextNodeIndex = segment.nodes.findIndex(
|
|
||||||
({distance}) => distance >= this.traveledDistance);
|
|
||||||
|
|
||||||
if (nextNodeIndex === 0)
|
const positions = [
|
||||||
{
|
Math.max(0, this.traveledDistance - step / 2),
|
||||||
this.position = turf.toMercator([
|
this.traveledDistance,
|
||||||
departureStop.lon,
|
this.traveledDistance + step / 2
|
||||||
departureStop.lat
|
].map(distance => turfProjection.toMercator(turfAlong(
|
||||||
]);
|
segment,
|
||||||
}
|
distance / 1000
|
||||||
else
|
)).geometry.coordinates);
|
||||||
{
|
|
||||||
const previousNode = segment.nodes[nextNodeIndex - 1];
|
|
||||||
const nextNode = segment.nodes[nextNodeIndex];
|
|
||||||
|
|
||||||
const previousPoint = turf.toMercator([
|
this.angle = Math.atan2(
|
||||||
previousNode.lon,
|
positions[0][1] - positions[2][1],
|
||||||
previousNode.lat
|
positions[2][0] - positions[0][0],
|
||||||
]);
|
);
|
||||||
|
|
||||||
const nextPoint = turf.toMercator([
|
this.position = positions[1];
|
||||||
nextNode.lon,
|
|
||||||
nextNode.lat
|
|
||||||
]);
|
|
||||||
|
|
||||||
const curLength = this.traveledDistance
|
|
||||||
- previousNode.distance;
|
|
||||||
const totalLength = nextNode.distance
|
|
||||||
- previousNode.distance;
|
|
||||||
const t = curLength / totalLength;
|
|
||||||
|
|
||||||
this.position = [
|
|
||||||
t * nextPoint[0] + (1 - t) * previousPoint[0],
|
|
||||||
t * nextPoint[1] + (1 - t) * previousPoint[1],
|
|
||||||
];
|
|
||||||
|
|
||||||
this.angle = Math.atan2(
|
|
||||||
previousPoint[1] - nextPoint[1],
|
|
||||||
nextPoint[0] - previousPoint[0],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // this.state === 'stopped'
|
|
||||||
{
|
|
||||||
const currentNode = network.stops[this.currentStop];
|
|
||||||
|
|
||||||
this.position = turf.toMercator([
|
|
||||||
currentNode.lon,
|
|
||||||
currentNode.lat
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,10 +180,9 @@ class Course
|
||||||
{
|
{
|
||||||
this.state = 'stopped';
|
this.state = 'stopped';
|
||||||
this.currentStop = stop;
|
this.currentStop = stop;
|
||||||
this.position = turf.toMercator([
|
this.position = (
|
||||||
network.stops[this.currentStop].lon,
|
turfProjection.toMercator(network.stops[stop])
|
||||||
network.stops[this.currentStop].lat,
|
.geometry.coordinates);
|
||||||
]);
|
|
||||||
this.history.push(['arriveToStop', stop]);
|
this.history.push(['arriveToStop', stop]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +208,6 @@ ${this.currentStop} to stop ${stop}. Teleporting to ${stop}`);
|
||||||
this.arrivalTime = arrivalTime;
|
this.arrivalTime = arrivalTime;
|
||||||
this.traveledDistance = 0;
|
this.traveledDistance = 0;
|
||||||
this.speed = 0;
|
this.speed = 0;
|
||||||
this.position = turf.toMercator([
|
|
||||||
network.stops[this.departureStop].lon,
|
|
||||||
network.stops[this.departureStop].lat,
|
|
||||||
]);
|
|
||||||
this.history.push(['moveToStop', stop, arrivalTime]);
|
this.history.push(['moveToStop', stop, arrivalTime]);
|
||||||
|
|
||||||
console.info(`Course ${this.id} leaving stop ${this.currentStop} \
|
console.info(`Course ${this.id} leaving stop ${this.currentStop} \
|
||||||
|
@ -271,10 +225,10 @@ with initial speed ${this.computeTheoreticalSpeed() * 3600} km/h`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const segment = this.currentSegment;
|
const segment = this.currentSegment;
|
||||||
const length = segment.nodes[segment.nodes.length - 1].distance;
|
|
||||||
|
|
||||||
const remainingTime = this.arrivalTime - Date.now();
|
const remainingTime = this.arrivalTime - Date.now();
|
||||||
const remainingDistance = length - this.traveledDistance;
|
const remainingDistance = (
|
||||||
|
segment.properties.length - this.traveledDistance
|
||||||
|
);
|
||||||
|
|
||||||
if (remainingDistance <= 0)
|
if (remainingDistance <= 0)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue