Skip to content

Commit 83ffeec

Browse files
committed
map: fix survey transect connector detouring to polygon corner
With no turnaround distance, consecutive transects were joined by walking the polygon ring in fixed vertex order, which always inserted the next corner between lines and sent the vehicle out to a far corner and back before resuming the correct line. moveAlongEdge now returns only the ring vertices between the two boundary points along the shorter direction, and none when they share an edge, so connectors become direct hops that stay inside the survey area.
1 parent e74c9cb commit 83ffeec

1 file changed

Lines changed: 54 additions & 39 deletions

File tree

src/libs/map/utils-map.ts

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as turf from '@turf/turf'
2-
import type { Feature, Polygon } from 'geojson'
2+
import type { Feature, Point, Polygon, Position } from 'geojson'
33
import * as L from 'leaflet'
44

55
import { bearingBetween, calculateHaversineDistance, deltaBearing } from '@/libs/mission/general-estimates'
@@ -381,7 +381,7 @@ export const generateSurveyPath = (
381381

382382
if (continuousPath.length > 0 && turnaroundDistance === 0) {
383383
const lastPoint = continuousPath[continuousPath.length - 1]
384-
const edgePath = moveAlongEdge(poly, lastPoint, linePoints[0], diagonal)
384+
const edgePath = moveAlongEdge(poly, lastPoint, linePoints[0])
385385
continuousPath.push(...edgePath)
386386
}
387387

@@ -421,50 +421,65 @@ export const generateSurveyPath = (
421421
}
422422

423423
/**
424-
* Moves along the edge of a polygon from start to end point.
425-
* @param {Feature<Polygon>} polygon - The polygon to move along.
424+
* Finds the index of the polygon ring edge (the segment from coords[i] to coords[i + 1]) that a point lies on.
425+
* @param {Feature<Point>} point - The point to locate.
426+
* @param {Position[]} coords - The polygon ring coordinates (closed, first equals last).
427+
* @returns {number} The edge index, or -1 if the point does not lie on any edge.
428+
*/
429+
const findRingEdgeIndex = (point: Feature<Point>, coords: Position[]): number => {
430+
for (let i = 0; i < coords.length - 1; i++) {
431+
// Small epsilon so floating-point drift on clipped boundary points still matches their edge.
432+
if (turf.booleanPointOnLine(point, turf.lineString([coords[i], coords[i + 1]]), { epsilon: 1e-6 })) return i
433+
}
434+
return -1
435+
}
436+
437+
/**
438+
* Total length of the path start -> vertices -> end, in kilometers.
426439
* @param {L.LatLng} start - The starting point.
440+
* @param {Position[]} vertices - The intermediate ring vertices.
427441
* @param {L.LatLng} end - The ending point.
428-
* @param {number} maxDistance - The maximum distance to move.
429-
* @returns {L.LatLng[]} The path along the edge.
442+
* @returns {number} The path length, in kilometers.
430443
*/
431-
export const moveAlongEdge = (
432-
polygon: Feature<Polygon>,
433-
start: L.LatLng,
434-
end: L.LatLng,
435-
maxDistance: number
436-
): L.LatLng[] => {
444+
const pathLengthThroughVertices = (start: L.LatLng, vertices: Position[], end: L.LatLng): number =>
445+
turf.length(turf.lineString([[start.lng, start.lat], ...vertices, [end.lng, end.lat]]))
446+
447+
/**
448+
* Finds the shortest path hugging a polygon's boundary between two points that lie on that boundary, so
449+
* consecutive survey transects are connected without overshooting into a far corner.
450+
* @param {Feature<Polygon>} polygon - The polygon to move along.
451+
* @param {L.LatLng} start - The starting point, expected to lie on the polygon boundary.
452+
* @param {L.LatLng} end - The ending point, expected to lie on the polygon boundary.
453+
* @returns {L.LatLng[]} The intermediate ring vertices between start and end, in the shorter direction. Empty
454+
* when both points lie on the same edge, so the caller connects them with a direct segment.
455+
*/
456+
const moveAlongEdge = (polygon: Feature<Polygon>, start: L.LatLng, end: L.LatLng): L.LatLng[] => {
437457
const coords = polygon.geometry.coordinates[0]
438-
const path: L.LatLng[] = []
439-
let remainingDistance = maxDistance
440-
let currentPoint = turf.point([start.lng, start.lat])
441-
442-
for (let i = 0; i < coords.length; i++) {
443-
const nextPoint = turf.point(coords[(i + 1) % coords.length])
444-
const edgeLine = turf.lineString([coords[i], coords[(i + 1) % coords.length]])
445-
446-
if (turf.booleanPointOnLine(currentPoint, edgeLine)) {
447-
while (remainingDistance > 0) {
448-
const distance = turf.distance(currentPoint, nextPoint)
449-
if (distance <= remainingDistance) {
450-
path.push(L.latLng(nextPoint.geometry.coordinates[1], nextPoint.geometry.coordinates[0]))
451-
remainingDistance -= distance
452-
currentPoint = nextPoint
453-
break
454-
} else {
455-
const move = turf.along(edgeLine, remainingDistance, { units: 'kilometers' })
456-
path.push(L.latLng(move.geometry.coordinates[1], move.geometry.coordinates[0]))
457-
break
458-
}
459-
}
460-
}
458+
const startEdge = findRingEdgeIndex(turf.point([start.lng, start.lat]), coords)
459+
const endEdge = findRingEdgeIndex(turf.point([end.lng, end.lat]), coords)
461460

462-
if (turf.booleanPointOnLine(turf.point([end.lng, end.lat]), edgeLine)) {
463-
break
464-
}
461+
if (startEdge === -1 || endEdge === -1 || startEdge === endEdge) return []
462+
463+
const vertexCount = coords.length - 1 // Ring is closed, so the last coordinate duplicates the first.
464+
465+
const forwardVertices: Position[] = []
466+
for (let i = (startEdge + 1) % vertexCount; ; i = (i + 1) % vertexCount) {
467+
forwardVertices.push(coords[i])
468+
if (i === endEdge) break
465469
}
466470

467-
return path
471+
const backwardVertices: Position[] = []
472+
for (let i = startEdge; ; i = (i - 1 + vertexCount) % vertexCount) {
473+
backwardVertices.push(coords[i])
474+
if (i === (endEdge + 1) % vertexCount) break
475+
}
476+
477+
const shorterVertices =
478+
pathLengthThroughVertices(start, forwardVertices, end) <= pathLengthThroughVertices(start, backwardVertices, end)
479+
? forwardVertices
480+
: backwardVertices
481+
482+
return shorterVertices.map((c) => L.latLng(c[1], c[0]))
468483
}
469484

470485
/**

0 commit comments

Comments
 (0)