add new anchors by clicking on the temporary one

This commit is contained in:
vcoppe
2024-09-04 14:42:26 +02:00
parent 2612eb2e91
commit 5be02d1c36
3 changed files with 105 additions and 4 deletions

View File

@@ -102,3 +102,54 @@ function bearing(latA: number, lonA: number, latB: number, lonB: number): number
return Math.atan2(Math.sin(lonB - lonA) * Math.cos(latB),
Math.cos(latA) * Math.sin(latB) - Math.sin(latA) * Math.cos(latB) * Math.cos(lonB - lonA));
}
export function projectedPoint(point1: TrackPoint, point2: TrackPoint, point3: TrackPoint | Coordinates): Coordinates {
return projected(point1.getCoordinates(), point2.getCoordinates(), point3 instanceof TrackPoint ? point3.getCoordinates() : point3);
}
function projected(coord1: Coordinates, coord2: Coordinates, coord3: Coordinates): Coordinates {
// Calculates the point on the line defined by p1 and p2
// that is closest to the third point, p3.
// Input lat1,lon1,lat2,lon2,lat3,lon3 in degrees.
const rad = Math.PI / 180;
const lat1 = coord1.lat * rad;
const lat2 = coord2.lat * rad;
const lat3 = coord3.lat * rad;
const lon1 = coord1.lon * rad;
const lon2 = coord2.lon * rad;
const lon3 = coord3.lon * rad;
// Prerequisites for the formulas
const bear12 = bearing(lat1, lon1, lat2, lon2);
const bear13 = bearing(lat1, lon1, lat3, lon3);
let dis13 = distance(lat1, lon1, lat3, lon3);
let diff = Math.abs(bear13 - bear12);
if (diff > Math.PI) {
diff = 2 * Math.PI - diff;
}
// Is relative bearing obtuse?
if (diff > (Math.PI / 2)) {
return coord1;
}
// Find the cross-track distance.
let dxt = Math.asin(Math.sin(dis13 / earthRadius) * Math.sin(bear13 - bear12)) * earthRadius;
// Is p4 beyond the arc?
let dis12 = distance(lat1, lon1, lat2, lon2);
let dis14 = Math.acos(Math.cos(dis13 / earthRadius) / Math.cos(dxt / earthRadius)) * earthRadius;
if (dis14 > dis12) {
return coord2;
} else {
// Determine the closest point (p4) on the great circle
const f = dis14 / earthRadius;
const lat4 = Math.asin(Math.sin(lat1) * Math.cos(f) + Math.cos(lat1) * Math.sin(f) * Math.cos(bear12));
const lon4 = lon1 + Math.atan2(Math.sin(bear12) * Math.sin(f) * Math.cos(lat1), Math.cos(f) - Math.sin(lat1) * Math.sin(lat4));
return { lat: lat4 / rad, lon: lon4 / rad };
}
}

View File

@@ -1,4 +1,4 @@
import { distance, type Coordinates, TrackPoint, TrackSegment, Track, crossarcDistance } from "gpx";
import { distance, type Coordinates, TrackPoint, TrackSegment, Track, projectedPoint } from "gpx";
import { get, writable, type Readable } from "svelte/store";
import mapboxgl from "mapbox-gl";
import { route } from "./Routing";
@@ -10,7 +10,7 @@ import { dbUtils, type GPXFileWithStatistics } from "$lib/db";
import { getOrderedSelection, selection } from "$lib/components/file-list/Selection";
import { ListFileItem, ListTrackItem, ListTrackSegmentItem } from "$lib/components/file-list/FileList";
import { currentTool, streetViewEnabled, Tool } from "$lib/stores";
import { getClosestLinePoint, resetCursor, setGrabbingCursor } from "$lib/utils";
import { getClosestLinePoint, getElevation, resetCursor, setGrabbingCursor } from "$lib/utils";
export const canChangeStart = writable(false);
@@ -185,11 +185,13 @@ export class RoutingControls {
return (e: any) => {
e.preventDefault();
e.stopPropagation();
if (marker === this.temporaryAnchor.marker) {
if (Date.now() - this.lastDragEvent < 100) { // Prevent click event during drag
return;
}
if (Date.now() - this.lastDragEvent < 100) { // Prevent click event during drag
if (marker === this.temporaryAnchor.marker) {
this.turnIntoPermanentAnchor();
return;
}
@@ -364,6 +366,52 @@ export class RoutingControls {
return minAnchor;
}
turnIntoPermanentAnchor() {
let file = get(this.file)?.file;
// Find the point closest to the temporary anchor
let minDetails: any = { distance: Number.MAX_VALUE };
let minInfo = {
point: this.temporaryAnchor.point,
trackIndex: -1,
segmentIndex: -1,
trkptIndex: -1
};
file?.forEachSegment((segment, trackIndex, segmentIndex) => {
if (get(selection).hasAnyParent(new ListTrackSegmentItem(this.fileId, trackIndex, segmentIndex))) {
let details: any = {};
getClosestLinePoint(segment.trkpt, this.temporaryAnchor.point, details);
if (details.distance < minDetails.distance) {
minDetails = details;
let before = details.before ? details.index : details.index - 1;
let projectedPt = projectedPoint(segment.trkpt[before], segment.trkpt[before + 1], this.temporaryAnchor.point);
let ratio = distance(segment.trkpt[before], projectedPt) / distance(segment.trkpt[before], segment.trkpt[before + 1]);
minInfo = {
point: new TrackPoint({
attributes: projectedPt,
ele: (1 - ratio) * (segment.trkpt[before].ele ?? 0) + ratio * (segment.trkpt[before + 1].ele ?? 0),
time: (segment.trkpt[before].time && segment.trkpt[before + 1].time) ? new Date((1 - ratio) * segment.trkpt[before].time.getTime() + ratio * segment.trkpt[before + 1].time.getTime()) : undefined,
_data: {
anchor: true,
zoom: 0
}
}),
trackIndex,
segmentIndex,
trkptIndex: before + 1
};
}
}
});
if (minInfo.trackIndex !== -1) {
dbUtils.applyToFile(this.fileId, (file) => file.replaceTrackPoints(minInfo.trackIndex, minInfo.segmentIndex, minInfo.trkptIndex, minInfo.trkptIndex - 1, [minInfo.point]));
}
}
getDeleteAnchor(anchor: Anchor) {
return () => this.deleteAnchor(anchor);
}

View File

@@ -78,9 +78,11 @@ export function getClosestLinePoint(points: TrackPoint[], point: TrackPoint | Co
if (distance(points[i], point) <= distance(points[i + 1], point)) {
closest = points[i];
details['before'] = true;
details['index'] = i;
} else {
closest = points[i + 1];
details['before'] = false;
details['index'] = i + 1;
}
}
}