Skip to content

Commit

Permalink
mission-planning: Add survey generation functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaellehmkuhl committed Sep 19, 2024
1 parent be39969 commit ca93c82
Show file tree
Hide file tree
Showing 2 changed files with 439 additions and 6 deletions.
125 changes: 125 additions & 0 deletions src/libs/utils-map.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import * as turf from '@turf/turf'
import type { Feature, Polygon } from 'geojson'
import * as L from 'leaflet'

import type { WaypointCoordinates } from '@/types/mission'

/**
Expand Down Expand Up @@ -158,3 +162,124 @@ export class TargetFollower {
this.onTargetChange(this.target)
}
}

/**
* Generates a survey path based on the given polygon and parameters.
* @param {L.LatLng[]} polygonPoints - The points of the polygon.
* @param {number} distanceBetweenLines - The distance between survey lines in meters.
* @param {number} linesAngle - The angle of the survey lines in degrees.
* @returns {L.LatLng[]} The generated survey path.
*/
export const generateSurveyPath = (
polygonPoints: L.LatLng[],
distanceBetweenLines: number,
linesAngle: number
): L.LatLng[] => {
if (polygonPoints.length < 4) return []

const polygonCoords = polygonPoints.map((p) => [p.lng, p.lat])
if (
polygonCoords[0][0] !== polygonCoords[polygonCoords.length - 1][0] ||
polygonCoords[0][1] !== polygonCoords[polygonCoords.length - 1][1]
) {
polygonCoords.push(polygonCoords[0])
}

try {
const poly = turf.polygon([polygonCoords])
const bbox = turf.bbox(poly)
const [minX, minY, maxX, maxY] = bbox
const diagonal = Math.sqrt(Math.pow(maxX - minX, 2) + Math.pow(maxY - minY, 2))

const adjustedAngle = linesAngle + 90
const angleRad = (adjustedAngle * Math.PI) / 180

const continuousPath: L.LatLng[] = []
let d = -diagonal
let isReverse = false

while (d <= diagonal * 2) {
const lineStart = [
minX + d * Math.cos(angleRad) - diagonal * Math.sin(angleRad),
minY + d * Math.sin(angleRad) + diagonal * Math.cos(angleRad),
]
const lineEnd = [
minX + d * Math.cos(angleRad) + diagonal * Math.sin(angleRad),
minY + d * Math.sin(angleRad) - diagonal * Math.cos(angleRad),
]

const line = turf.lineString([lineStart, lineEnd])
const clipped = turf.lineIntersect(poly, line)

if (clipped.features.length >= 2) {
const coords = clipped.features.map((f) => f.geometry.coordinates)
if (isReverse) coords.reverse()

const linePoints = coords.map((c) => L.latLng(c[1], c[0]))

if (continuousPath.length > 0) {
const lastPoint = continuousPath[continuousPath.length - 1]
const edgePath = moveAlongEdge(poly, lastPoint, linePoints[0], distanceBetweenLines / 111000)
continuousPath.push(...edgePath)
}

continuousPath.push(...linePoints)
isReverse = !isReverse
}

d += distanceBetweenLines / 111000
}

return continuousPath
} catch (error) {
console.error('Error in generateSurveyPath:', error)
return []
}
}

/**
* Moves along the edge of a polygon from start to end point.
* @param {Feature<Polygon>} polygon - The polygon to move along.
* @param {L.LatLng} start - The starting point.
* @param {L.LatLng} end - The ending point.
* @param {number} maxDistance - The maximum distance to move.
* @returns {L.LatLng[]} The path along the edge.
*/
export const moveAlongEdge = (
polygon: Feature<Polygon>,
start: L.LatLng,
end: L.LatLng,
maxDistance: number
): L.LatLng[] => {
const coords = polygon.geometry.coordinates[0]
const path: L.LatLng[] = []
let remainingDistance = maxDistance
let currentPoint = turf.point([start.lng, start.lat])

for (let i = 0; i < coords.length; i++) {
const nextPoint = turf.point(coords[(i + 1) % coords.length])
const edgeLine = turf.lineString([coords[i], coords[(i + 1) % coords.length]])

if (turf.booleanPointOnLine(currentPoint, edgeLine)) {
while (remainingDistance > 0) {
const distance = turf.distance(currentPoint, nextPoint)
if (distance <= remainingDistance) {
path.push(L.latLng(nextPoint.geometry.coordinates[1], nextPoint.geometry.coordinates[0]))
remainingDistance -= distance
currentPoint = nextPoint
break
} else {
const move = turf.along(edgeLine, remainingDistance, { units: 'kilometers' })
path.push(L.latLng(move.geometry.coordinates[1], move.geometry.coordinates[0]))
break
}
}
}

if (turf.booleanPointOnLine(turf.point([end.lng, end.lat]), edgeLine)) {
break
}
}

return path
}
Loading

0 comments on commit ca93c82

Please sign in to comment.