'TurfJS: Efficiently locate the nearest point on a line string

Edit: The quicksort algorithm isn't actually working...😳

CODESANDBOX

SITUATION

I have a line string with up to 2000 points. I am trying to find the nearest point on the line from the user's location. This operation is executed roughly every 5 seconds and failing to optimise it would unnecessarily drain the users battery.

The source code shows that the distance operation is conducted on every point on the line string - not good for my users.

I would like to implement a quick-sort style algorithm to get the nearest point and reduce the number of the operations. The example below is working quite well and produces a point on the line with far fewer operations (for a list of 1700 points it takes 14 operations to locate the closest point).

PROBLEM

I cannot determine an elegant way to track the index of the result. Once I have the nearest point, I do not want to have to search the original list again to find it's index.

first operation - 0 | median

second - fHalf (0 | median of fHalf) | sHalf (median of list | median of sHalf)

third - at this point it becomes a mess to track

What I have so far:

import distance from "@turf/distance";
import { point } from "@turf/helpers";

const user = point([-77.037076, 38.884017]);

function getMedian(list) {
  return Math.ceil(list.length / 2);
}

function getHalves(list) {
  const median = getMedian(list);
  const firstHalf = list.slice(0, median);
  const secondHalf = list.slice(-median);
  return { firstHalf, secondHalf };
}

function getClosest(list) {
  const to = point(list[0]);
  const meters = distance(user, to, { units: "meters" });
  return meters;
}

let operations = 0; // used in development to track operations

function selectHalf(list) {
  operations += 1;
  const { firstHalf, secondHalf } = getHalves(list);
  const firstDistance = getClosest(firstHalf);
  const secondDistance = getClosest(secondHalf);
  const nextList = firstDistance < secondDistance ? firstHalf : secondHalf;
  if (list.length === 1)
    console.log("operations:", operations, "closest point:", nextList);
  else selectHalf(nextList);
}

const morePoints = `-37.0467378013181,145.1634433308106
-37.04674949407303,145.1634394751351
-37.04676521014147,145.1634369605642
-37.04678021374815,145.1634352003645
-37.04679207414114,145.1634343621742
-37.04680510800057,145.1634334401648
// Full list is available in the codesandbox link below
`
  .split("\n")
  .map((p) => p.split(",").map((n) => parseFloat(n)));

selectHalf(morePoints);



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source