-
Notifications
You must be signed in to change notification settings - Fork 33
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
Offline routing #1636
Comments
Valhalla has a |
globus.software seems to be the owner of the GetYourMap GitHub account. The GetYourMap website, https://getyourmap.com/, redirects to https://globus.software/. |
@bmarcco @cigone-openindoor if you have any pointers related to this issue it would be great :-) I saw that you posted something on maplibre repo... I'm using cordova in this project. |
I've found this discussion about Valhalla for offline usage, maybe we could try to post a solution there. |
Relevant findings:
Bottom line, both Valhalla and Graphhopper has their drawbacks :-( |
The Valhalla doc say (my annotation in bold):
Therefore I think that as far as routing is concerned, a 30-meter DEM is good enough. As discussed on the phone, augmenting the routing result with 30-meter elevation information in offline mode would differ differ from a future 10-meter online augmentation. This would be similar to the difference in the elevation graph between planned routes and recorded tracks. |
I don't think that's a correct conclusion - from my understanding if the road is long the segment is sampled more times to avoid long segments that are sampled only at the beginning or at the end, but if you have segments that are shorter than 30 meters the precision of the DEM is relevant. Having said that, I agree that offline routing can be less accurate in terms of elevation, Valhalla currently only support their elevation provider and does not return the elevation for each node in the route. See the following thread: |
Stating the obvious: Using the TerrainRGB for elevation will avoid the need for additional storage on the device, but will require adding a different elevation provider. Perhaps this repository can help. If you plan to implement such an elevation provider, note that the WGS84 coordinates used by Valhalla and hgt need to converted to the Transverse Mercator projection used by TerrainRGB. |
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days |
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days |
Another interesting alternative might be: |
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days |
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days |
It might be better to support a "poor man solution" just for when the reception isn't great. |
Recent thoughts on this matter:
The above code shouldn't be too complicated I hope and it will allow a good enough solution when a call to the server for routing fails. |
Sorry for dropping the conversation on this! I think it'd be really cool to seed |
Thanks for reaching out! Basically what I has in mind is that we already have the tiles in a local database on the device (for this specific use case), fetching them and parsing them should be possible with exiting tools that are already part of maplibre-gl-js (i.e. @mapbox/vector-tile-js). once read into memory one could filter by layer and other properties and then get the geometry out for the method you mentioned. |
Definitely! Building a graph from MVT on-the-fly is something I want to try to do anyway,dabreegster/route_snapper#4 (comment). If you can get to the point of feeding in a bunch of line-strings, I can write something in JS or Rust->WASM->JS to turn it into the graph, and we can see how performant / correct the results look |
@dabreegster the following is a very simple typescript code that extracts features from a specific tile and filters only the highways (at the moment): |
I've stumbled across the following library which might solve the missing part here: |
Initial POC seems to be working, this is very rudimentary obviously, but shows that this can be done with relatively little code (a lot of the code is for presentation in the below stackblitz): |
@psociety if you have any insights in order to avoid some of the problems you probably solved it can be great! |
@HarelM i can't help much, i worked on this some years ago and never touched it again. <script src="/js/path-finder.js?v=6"></script> <!-- grabbed using https://bundle.run/[email protected] -->
<script src="/js/leaflet.geometryutil.js"></script> class Coordinates {
constructor (lat, lon) {
this.latitude = lat;
this.longitude = lon;
}
toArray () {
return [this.latitude, this.longitude];
}
}
class Geo {
static EARTH_RADIUS = 6371008.8;
static deg2rad(degrees) {
return degrees * (Math.PI / 180);
}
static distanceHaversine(from, to)
{
const $lat1 = Geo.deg2rad(from.latitude),
$lng1 = Geo.deg2rad(from.longitude),
$lat2 = Geo.deg2rad(to.latitude),
$lng2 = Geo.deg2rad(to.longitude);
const $dLat = $lat2 - $lat1,
$dLon = $lng2 - $lng1;
const $a = Math.sin($dLat / 2) * Math.sin($dLat / 2) +
Math.cos($lat1) * Math.cos($lat2) *
Math.sin($dLon / 2) * Math.sin($dLon / 2);
const $c = 2 * Math.atan2(Math.sqrt($a), Math.sqrt(1 - $a));
return Geo.EARTH_RADIUS * $c;
}
}
// following the given coords, it will find the nearest coords IN our geoJsons
getClosestCoordsAndLayer (coordinates) {
const closestLayer = L.GeometryUtil.closestLayerSnap(this.map, this.connectionsLayer.getLayers(), coordinates);
if (closestLayer === null) {
return null;
}
const closestPoint = L.GeometryUtil.closest(this.map, closestLayer.layer, coordinates);
let nearestPoint = null;
let distance = 9999999999;
let layerCoords = {
lat: [],
lon: [],
};
closestLayer.layer.getLatLngs().forEach(latlng => {
layerCoords.lat.push(latlng.lat);
layerCoords.lon.push(latlng.lng);
let dist = Geo.distanceHaversine(new Coordinates(closestPoint.lat, closestPoint.lng), new Coordinates(latlng.lat, latlng.lng));
if (dist < distance) {
distance = dist;
nearestPoint = latlng;
}
});
return {
nearestPoint: nearestPoint,
closestPoint: closestPoint,
distance: distance,
layerCoords: layerCoords
};
}
onMouseMove (coordinates) {
if (this.selectedUnit === null) {
return;
}
// preview unit path
const mouseCoords = this.getClosestCoordsAndLayer(coordinates);
if (mouseCoords === null) {
return;
}
const unitCoords = this.getClosestCoordsAndLayer(this.selectedUnit.marker.getLatLng());
if (unitCoords === null) {
return;
}
const nearestPoint = mouseCoords.nearestPoint;
const layerCoords = mouseCoords.layerCoords;
const closestPoint = mouseCoords.closestPoint;
const bestPath = this.pathFinder.findPath({
geometry: {
coordinates: [unitCoords.nearestPoint.lng, unitCoords.nearestPoint.lat]
}
}, {
geometry: {
coordinates: [nearestPoint.lng, nearestPoint.lat]
}
});
if (bestPath === null) {
return;
}
let paths = [];
const totalEntries = bestPath.path.length;
const len = totalEntries - 1;
bestPath.path.forEach((coords, i) => {
if (i == len && totalEntries > 1) {
let prv = bestPath.path[i - 1];
let previousPoint = new Coordinates(prv[1], prv[0]);
if (Geo.distanceHaversine(new Coordinates(coords[1], coords[0]), previousPoint) < Geo.distanceHaversine(new Coordinates(closestPoint.lat, closestPoint.lng), previousPoint) ||
layerCoords.lat.indexOf(previousPoint.latitude) !== layerCoords.lon.indexOf(previousPoint.longitude) ||
layerCoords.lat.indexOf(previousPoint.latitude) === -1
) {
paths.push([coords[1], coords[0]]);
}
} else {
paths.push([coords[1], coords[0]]);
}
});
paths.push([closestPoint.lat, closestPoint.lng]);
this.selectedPath = paths;
if (typeof this.selectedUnit.line === "undefined") {
this.selectedUnit.line = L.polyline.antPath(paths);
}
this.selectedUnit.line.setLatLngs(paths);
this.selectedUnit.line.addTo(this.map);
} |
The solution to this issue is probably removing the lines that are outside the tile boundaries using this method - lineintersect and linesplit: |
Further investigation into this reveals that the problem here is the data in the tiles, I'm guessing that this data is simplified for the rendering, so it removes the points in straight lines, which removed the intersection point in the רקפות street in this case, causing the routing to go around... |
I've added a simple solution to this case: go over every line ending and see if it is part of another line. |
This seems to be working, there are still issues with routing through the edge of a tile, I'll see if I can find the root cause of this. |
Closed this issue as this will be released shortly. |
Feature
As a user who doesn't have network connection I would like to still be able to plan a route on my mobile device.
Technical research so far:
The text was updated successfully, but these errors were encountered: