diff --git a/backend/package-lock.json b/backend/package-lock.json index 9cccf654..8abe865c 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -25,6 +25,7 @@ "nestjs-knex": "^2.0.0", "papaparse": "^5.4.1", "pg": "^8.11.3", + "polyline": "^0.2.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "sharp": "^0.33.0", @@ -11953,6 +11954,15 @@ "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==", "dev": true }, + "node_modules/polyline": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/polyline/-/polyline-0.2.0.tgz", + "integrity": "sha512-rCJSkIHWZ/HOUoEWgjZ1DrRjLpTeTjgaktyJV0yhm8PugM5sKoavNjUHtI/amjsTn/Tq+Q3IIAuBD/dUSsWwxQ==", + "deprecated": "This module is now under the @mapbox namespace: install @mapbox/polyline instead", + "engines": { + "node": "*" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -23302,6 +23312,11 @@ "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==", "dev": true }, + "polyline": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/polyline/-/polyline-0.2.0.tgz", + "integrity": "sha512-rCJSkIHWZ/HOUoEWgjZ1DrRjLpTeTjgaktyJV0yhm8PugM5sKoavNjUHtI/amjsTn/Tq+Q3IIAuBD/dUSsWwxQ==" + }, "postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", diff --git a/backend/package.json b/backend/package.json index ed6d9f6b..f8637107 100644 --- a/backend/package.json +++ b/backend/package.json @@ -37,6 +37,7 @@ "nestjs-knex": "^2.0.0", "papaparse": "^5.4.1", "pg": "^8.11.3", + "polyline": "^0.2.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "sharp": "^0.33.0", diff --git a/backend/src/upload/upload.ts b/backend/src/upload/upload.ts index af60ce45..bee7409b 100644 --- a/backend/src/upload/upload.ts +++ b/backend/src/upload/upload.ts @@ -194,10 +194,15 @@ export function extractCoordinatesFromRSP(rspFilePath: string): LatLng[] { for (let i = 0; i < datas.length; i++) { const row = datas[i]; - coordinates.push({ - lng: Number(`${parseFloat(row[6])}`), - lat: Number(`${parseFloat(row[5])}`), - }); + // to fix bugged RSP file of Ballerup + const exist = coordinates.find( + (c) => c.lat == parseFloat(row[5]) && c.lng == parseFloat(row[6]), + ); + if (!exist) + coordinates.push({ + lng: Number(`${parseFloat(row[6])}`), + lat: Number(`${parseFloat(row[5])}`), + }); } return coordinates; diff --git a/backend/src/upload/valhalla.ts b/backend/src/upload/valhalla.ts index f28d680f..3dd83cba 100644 --- a/backend/src/upload/valhalla.ts +++ b/backend/src/upload/valhalla.ts @@ -1,4 +1,5 @@ import { LatLng } from '../models'; +import * as polyline from 'polyline'; /** * Get the coordinates of the point at the given distance along the path @@ -101,41 +102,81 @@ export async function valhalla( shape: data.map((v) => ({ lat: v.lat, lon: v.lng })), costing: 'auto', shape_match: 'map_snap', - filters: { - attributes: [ - 'edge.way_id', - 'edge.length', - 'matched.distance_from_trace_point', - 'matched.point', - 'matched.type', - 'matched.edge_index', - 'matched.distance_along_edge', - ], - action: 'include', + directions_options: { + units: 'km', }, + // filters: { + // attributes: [ + // 'edge.way_id', + // 'edge.length', + // 'matched.distance_from_trace_point', + // 'matched.point', + // 'matched.type', + // 'matched.edge_index', + // 'matched.distance_along_edge', + // 'edge.begin_shape_index', + // 'edge.end_shape_index', + // ], + // action: 'include', + // }, }; return fetch(process.env.VALHALLA_ENDPOINT + '/trace_attributes', { method: 'POST', body: JSON.stringify(request), headers: { 'Content-Type': 'application/json' }, - }).then(async (res) => { - const json = await res.json(); - - if (json.error) return false; - - return json.matched_points.map( - (p: { - edge_index: number; - distance_along_edge: number; - lat: number; - lon: number; - }) => ({ - way_id: json.edges[p.edge_index]?.way_id, - distance_way: - p.distance_along_edge * json.edges[p.edge_index]?.length * 1000, - coordinates: { lat: p.lat, lng: p.lon }, - }), - ); - }); + }) + .then(async (res) => { + const json = await res.json(); + + if (json.error) return false; + + let lastValidEdgeIndex = 0; + + let shape = polyline.decode(json.shape, 6); + console.debug(shape); + + return json.matched_points.map( + (p: { + edge_index: number; + distance_along_edge: number; + lat: number; + lon: number; + }) => { + // homemade fix for https://github.com/valhalla/valhalla/issues/3699 + if (p.edge_index != 18446744073709551615) + lastValidEdgeIndex = p.edge_index; + + const edge: null | { + way_id: number; + begin_shape_index: number; + end_shape_index: number; + length: number; + } = json.edges[lastValidEdgeIndex]; + + const distanceOfEdgeToBeginningOfWay = json.edges.filter( + (e: { + way_id: number; + begin_shape_index: number; + end_shape_index: number; + length: number; + }) => + e.way_id == json.edges[lastValidEdgeIndex]?.way_id && + e.end_shape_index <= edge.begin_shape_index, + ); + + return { + way_id: edge?.way_id, + distance_way: + distanceOfEdgeToBeginningOfWay + + p.distance_along_edge * edge?.length * 1000, + coordinates: { lat: p.lat, lng: p.lon }, + }; + }, + ); + }) + .catch((err) => { + console.error("Error while fetching Valhalla's API: ", err); + return false; + }); }