Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting a path along a river on a LineLayer with multiple rivers? #88

Open
Tasemu opened this issue Apr 27, 2023 · 8 comments
Open

Getting a path along a river on a LineLayer with multiple rivers? #88

Tasemu opened this issue Apr 27, 2023 · 8 comments

Comments

@Tasemu
Copy link

Tasemu commented Apr 27, 2023

Hiya, I am using this geojson data source which supplied canals in the UK.

https://data-canalrivertrust.opendata.arcgis.com/datasets/CanalRiverTrust::canals-km-view-public/explore

I was hoping to be able to use this library to be able to highlight a section of one of the rivers to show for example a "cruise" between two locations. However when trying to run the function I receive undefined from the return value of findPath().

Am i doing something wrong, or is there a way to achieve this? Thanks so much for any and all advice!

Code:

import {
  Feature,
  FeatureCollection,
  LineString,
  Point,
  nearestPointOnLine,
  point,
} from "@turf/turf";

// Here is the pathFinder import
import PathFinder, { pathToGeoJSON } from "geojson-path-finder";

// Custom LatLngAlt type
type LatLngAlt = {
  lat: number;
  lng: number;
  alt?: number;
};

// This is just to get the coords for the below function
const toCoordinate = (latlng: LatLngAlt): [number, number] => {
  return [latlng.lng, latlng.lat];
};

/* I found this function in another issue, it just ensures that the points get snapped to the nearest line just in case the GPS coords are slightly off */
const insertProjectedPointToClosestLine = (
  latlng: LatLngAlt,
  collection: FeatureCollection<LineString>
) => {
  let closestLine = null;
  let nearestPoint = null;
  let minimalDistance = Infinity;
  let coordinates = toCoordinate(latlng);

  for (let feature of collection.features) {
    let point = nearestPointOnLine(feature, coordinates);

    if (point.properties.dist < minimalDistance) {
      minimalDistance = point.properties.dist;
      closestLine = feature;
      nearestPoint = point;
    }
  }

  closestLine.geometry.coordinates.splice(
    nearestPoint.properties.index + 1,
    0,
    nearestPoint.geometry.coordinates
  );

  return nearestPoint.geometry.coordinates as [number, number];
};

// This is the function that is returning undefined from findPath()
export function getShortestPath(
  lineData: FeatureCollection<LineString>,
  start: Feature<Point>,
  end: Feature<Point>
) {
  const pathFinder = new PathFinder(lineData);

  const startPointCoords = insertProjectedPointToClosestLine(
    { lat: start.geometry.coordinates[1], lng: start.geometry.coordinates[0] },
    lineData
  );
  const endPointCoords = insertProjectedPointToClosestLine(
    { lat: end.geometry.coordinates[1], lng: end.geometry.coordinates[0] },
    lineData
  );

  const startPointFeature = point(startPointCoords);
  const endPointFeature = point(endPointCoords);

  const pathResult = pathFinder.findPath(startPointFeature, endPointFeature);

  if (!pathResult) {
    console.error("Path not found");
  }

  return pathToGeoJSON(pathResult);
}

@Tasemu
Copy link
Author

Tasemu commented Apr 27, 2023

Looks like it was just a matter of changing the tolerance to 1e-3! Though it does simplify the line a little so it doesn't hug the original line when zoomed in unfortunately. I guess there's no way around this?

@pbvahlst
Copy link

pbvahlst commented Apr 27, 2023

If the original lines' vertices snap it should work without adjusting the tolerance

@Tasemu
Copy link
Author

Tasemu commented Apr 27, 2023

If the original lines' vertices snap it should work without adjusting the tolerance

I'm honestly not sure, i'm quite certain that the points have snapped as when viewing them visually on maximum zoom, they are dead centre on the line. But without adjusting the tolerance i just get back an undefined value. Maybe its the lineString itself... I'm a little lost. :)

@pbvahlst
Copy link

It is not enough that the vertex of one line snaps to the somewhere on another line between two vertices on that line. They need to meet on a vertex.

This is not enough...

         x
         |
x--------|
         |
         x

Needs to be...

        x       
        |
x-------x
        |
        x

@Tasemu
Copy link
Author

Tasemu commented Apr 28, 2023

It is not enough that the vertex of one line snaps to the somewhere on another line between two vertices on that line. They need to meet on a vertex.

This is not enough...

         x
         |
x--------|
         |
         x

Needs to be...

        x       
        |
x-------x
        |
        x

I think I understand, i'm required to increase the tolerance because the line data i'm using from the url has minute gaps between each segment of the line, or at least do not share vertices?

@pbvahlst
Copy link

Yes, to get accuracy the lines need to have the same vertices. Increasing tolerance expands the radius so two vertices close to each other is considered equal but this the reduces accuracy.
Maybe you can preprocess the data with turf.js adding extra vertices on every overlapning lines.

@Tasemu
Copy link
Author

Tasemu commented May 4, 2023

Yes, to get accuracy the lines need to have the same vertices. Increasing tolerance expands the radius so two vertices close to each other is considered equal but this the reduces accuracy. Maybe you can preprocess the data with turf.js adding extra vertices on every overlapning lines.

I've been working on it and have been preprocessing the data, it turns out there are no overlapping lines and i cannot see any gaps at all. Could this issue be the start/end points being too far away from the lines?

@pbvahlst
Copy link

pbvahlst commented May 4, 2023

The coordinate of start and endpoints should also be a vertex on the line.

This is good (notice they meet at (0.1))

line1: [(0,0), (0,1), (0,2)]
line2: [(-1,1), (0,1), (1.1)]

this is not good (they cross but do not have the same identical coordinate where they meet which is needed to for the path-finder to join them)

line1: [(0,0), (0,1), (0,2)]
line2: [(-1,1), (1.1), (2,1)]

I expect that your data i suffering from this. The start/end-point is on the line but there is no vertex where they meet on the line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants