From 01fc0062e0b4aabbde75135cce1f9cbadec631b0 Mon Sep 17 00:00:00 2001 From: Benoit Simard Date: Fri, 5 Jul 2024 14:16:00 +0200 Subject: [PATCH] front: allow multiline on nearestpointonline function Fix #7363 --- front/src/utils/geometry.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/front/src/utils/geometry.ts b/front/src/utils/geometry.ts index 63307462173..d2591eac83b 100644 --- a/front/src/utils/geometry.ts +++ b/front/src/utils/geometry.ts @@ -4,7 +4,7 @@ import turfDistance from '@turf/distance'; import { point, type Position, featureCollection, lineString, type Units } from '@turf/helpers'; import { getCoord } from '@turf/invariant'; import length from '@turf/length'; -import type { Feature, Point, FeatureCollection, LineString } from 'geojson'; +import type { Feature, Point, FeatureCollection, LineString, MultiLineString } from 'geojson'; import { minBy } from 'lodash'; import type { GeoJsonLineString } from 'common/api/osrdEditoastApi'; @@ -53,8 +53,7 @@ export interface NearestPointOnLine extends Feature { }; } /** - * This function has the same signature than the one of turf (except for multilines), - * but it is more precise. + * This function has the same signature than the one of turf, but it is more precise. * * You can check those links for references : * - https://github.com/Turfjs/turf/issues/1440 @@ -69,13 +68,28 @@ export interface NearestPointOnLine extends Feature { * Angle of vertex B (cosines law) is `AngleB = arccos((AB² + BC² - AC²) / (2 * AB * BC))` */ export function nearestPointOnLine( - line: Feature | LineString, + line: Feature | LineString | Feature | MultiLineString, inPoint: Feature | Point | Position, options?: { units?: Units } ): NearestPointOnLine { + // Handle multilines + if ( + line.type === 'MultiLineString' || + (line.type === 'Feature' && line.geometry.type === 'MultiLineString') + ) { + const linesCoords = + line.type === 'MultiLineString' + ? line.coordinates + : (line as Feature).geometry.coordinates; + const nearestPoints = linesCoords.map((lineCoords) => + nearestPointOnLine({ type: 'LineString', coordinates: lineCoords }, inPoint, options) + ); + return minBy(nearestPoints, (i) => i.properties.dist) || nearestPoints[0]; + } + const pointA = getCoord(inPoint); const lineCoords: Position[] = - line.type === 'Feature' ? line.geometry.coordinates : line.coordinates; + line.type === 'Feature' ? (line as Feature).geometry.coordinates : line.coordinates; const closestPointPerSegment: Array<{ point: Position; dist: number; index: number }> = []; for (let n = 1; n < lineCoords.length; n += 1) {