mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-11-01 20:19:39 +00:00
* wasm first steps * parsing start * parsing continued * progress * progress * progress * progress * progress * progress * progress * progress * fixes * reorganize * change type * fix * progress * refactoring * progress * progress * progress * keep style info * progress * progress * remove (copy) in name * progress * merge methods into 1 * splice * progress * progress * progress * cleaning * progress * progress * progress * visibility * progress * progress * progress * progress * progress * fixes * progress * fix markers * fix * progress * progress * progress * progress * progress * progress * small fix * use engine info * fix popups * small fix * progress * progress * progress * clean tool * handle self closing elements * reduce data exchanges across boundary * copy on wasm side to avoid any data corruption * speed fix * routing * refactoring * reverse * reverse * crop * split * merge * progress * time tool * fix bounds for waypoints * reduce * fix reactivity * handle corrupt time data * export * progress * remove gpx js package * remove todo * update readme * cleaning * progress * fix link fields * remove unused fields * refactoring and tests * import and export of routes, ref #192 * per-chunk categories storage * cross-tab sync * outdated state * refactoring * reorder methods * refactoring * fix * improve flow * renaming * progress * progress * fix * progress * per file history * keep original flag * use history variant * fix * progress * file explorer * progress * fix * sticky folders * improved sticky folders * fix sortable * fix sortable * fix * fix tab size * no file delete on desktop * fix routing on other file * fix sorting * remember language * open links in browser * commit missing changes * avoid selecting on resize * clarify filename * explorer actions * fix folder styling * drop anywhere in folder * cleaning * fixes * remove focus-ring * full screen * small fix * consistent highlight color * improved preview * performance improvements * sparser data transfers * sparser data transfers * show popup once data is loaded * fix routing control size * fix * sparse desktop build * remove custom ign styles * use new endpoint for openhikingmap * strip native menu * reorder context menu items * route full support * route - track conversion * create route file action * route export, filter out anchors at high zoom level * clarify name handling * move hide & center to view * routes continued * update docs * fix power format, closes #378 * lint fixes * fix display of additional data with gaps, closes #361 * fix linting issues * fix import modules * fix multidrag * change base to resolve * fix type errors * fix layer typings * fix last type error * each keys * improve typings * deploy to cloudflare --------- Co-authored-by: vcoppe <vcoppe@hexaly.com>
72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
const metersPerDegree = 111320;
|
|
|
|
/**
|
|
* Index of the point of a polyline (flat `[lng, lat, ...]` coordinates) that is the closest to
|
|
* `point`, among the two ends of the segment of the polyline that passes the closest to it.
|
|
* `undefined` for an empty polyline. Planar approximation, like the one used to simplify tracks.
|
|
*/
|
|
export function closestPointIndex(
|
|
coordinates: ArrayLike<number>,
|
|
point: { lng: number; lat: number }
|
|
): number | undefined {
|
|
return closestIndex(
|
|
Math.floor(coordinates.length / 2),
|
|
(i) => coordinates[2 * i],
|
|
(i) => coordinates[2 * i + 1],
|
|
point
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Like `closestPointIndex`, for the points `from` (included) to `to` (excluded) of a polyline
|
|
* given as the arrays of its longitudes and latitudes. The index is the one in the arrays.
|
|
*/
|
|
export function closestPointIndexIn(
|
|
lng: ArrayLike<number>,
|
|
lat: ArrayLike<number>,
|
|
from: number,
|
|
to: number,
|
|
point: { lng: number; lat: number }
|
|
): number | undefined {
|
|
const closest = closestIndex(
|
|
Math.max(0, to - from),
|
|
(i) => lng[from + i],
|
|
(i) => lat[from + i],
|
|
point
|
|
);
|
|
return closest === undefined ? undefined : from + closest;
|
|
}
|
|
|
|
function closestIndex(
|
|
count: number,
|
|
lngAt: (index: number) => number,
|
|
latAt: (index: number) => number,
|
|
point: { lng: number; lat: number }
|
|
): number | undefined {
|
|
if (count === 0) {
|
|
return undefined;
|
|
}
|
|
const kx = Math.cos((point.lat * Math.PI) / 180) * metersPerDegree;
|
|
const ky = metersPerDegree;
|
|
const px = point.lng * kx;
|
|
const py = point.lat * ky;
|
|
const x = (i: number) => lngAt(i) * kx - px;
|
|
const y = (i: number) => latAt(i) * ky - py;
|
|
|
|
let best = 0;
|
|
let bestDistance = Number.MAX_VALUE;
|
|
for (let i = 0; i < count - 1; i++) {
|
|
const [ax, ay, bx, by] = [x(i), y(i), x(i + 1), y(i + 1)];
|
|
const [dx, dy] = [bx - ax, by - ay];
|
|
const length = dx * dx + dy * dy;
|
|
// the point is at the origin: the closest position on the segment, as a ratio
|
|
const t = length === 0 ? 0 : Math.max(0, Math.min(1, -(ax * dx + ay * dy) / length));
|
|
const distance = Math.hypot(ax + t * dx, ay + t * dy);
|
|
if (distance < bestDistance) {
|
|
bestDistance = distance;
|
|
best = t < 0.5 ? i : i + 1;
|
|
}
|
|
}
|
|
return best;
|
|
}
|