Graphhopper: Cannot create location index when graph has invalid bounds - graphhopper

I am using graphhopper 0.8 via maven in my java project. I create a network with the folling code
FlagEncoder encoder = new CarFlagEncoder();
EncodingManager em = new EncodingManager(encoder);
// Creating and saving the graph
GraphBuilder gb = new GraphBuilder(em).
setLocation(testDir).
setStore(true).
setCHGraph(new FastestWeighting(encoder));
GraphHopperStorage graph = gb.create();
for (Node node : ALL NODES OF MY NETWORK) {
graph.getNodeAccess().setNode(uniqueNodeId, nodeX, nodeY);
}
for (Link link : ALL LINKS OF MY NETWORK) {
EdgeIteratorState edge = graph.edge(fromNodeId, toNodeId);
edge.setDistance(linkLength);
edge.setFlags(encoder.setProperties(linkSpeedInMeterPerSecond * 3.6, true, false));
}
Weighting weighting = new FastestWeighting(encoder);
PrepareContractionHierarchies pch = new PrepareContractionHierarchies(graph.getDirectory(), graph, graph.getGraph(CHGraph.class), weighting, TraversalMode.NODE_BASED);
pch.doWork();
graph.flush();
LocationIndex index = new LocationIndexTree(graph.getBaseGraph(), graph.getDirectory());
index.prepareIndex();
index.flush();
At this point, the bounding box saved in the graph shows the correct numbers. Files are written to disk including the "location_index". However, reloading the data gets me the following error
Exception in thread "main" java.lang.IllegalStateException: Cannot create location index when graph has invalid bounds: 1.7976931348623157E308,1.7976931348623157E308,1.7976931348623157E308,1.7976931348623157E308
at com.graphhopper.storage.index.LocationIndexTree.prepareAlgo(LocationIndexTree.java:132)
at com.graphhopper.storage.index.LocationIndexTree.prepareIndex(LocationIndexTree.java:287)
The reading is done with the following code
FlagEncoder encoder = new CarFlagEncoder();
EncodingManager em = new EncodingManager(encoder);
GraphBuilder gb = new GraphBuilder(em).
setLocation(testDir).
setStore(true).
setCHGraph(new FastestWeighting(encoder));
// Load and use the graph
GraphHopperStorage graph = gb.load();
// Load the index
LocationIndex index = new LocationIndexTree(graph.getBaseGraph(), graph.getDirectory());
if (!index.loadExisting()) {
index.prepareIndex();
}
So LocationIndexTree.loadExisting runs fine until entering prepareAlgo. At this point, the graph is loaded. However, the bounding box is not set and kept at the defaults?! Reading the location index does not update the bounding box. Hence, the error downstreams. What am I doing wrong? How do I preserve the bounding box in the first place? How to reconstruct the bbox?

TL;DR Don't use cartesian coordinates but stick to the WGS84 used by OSM.
A cartesian coordinate system like e.g. EPSG:25832 may have coordinates in the range of millions. After performing some math the coordinates may further increase in magnitude. Eventually, Graphhopper will store the coordinates as integers. That is, all coordinates may end up as Integer.MAX_VALUE. Hence, an invalid bounding box.

Related

Maps into Forge Viewer

Trying to follow the steps https://forge.autodesk.com/blog/add-mapbox-google-maps-forge-viewer but i can't place the model correctly on the map.
I am running the functions listed here: https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system:
LatLongToPixelXY(latitude, longitude, 7, out pixelX, out pixelY);
PixelXYToTileXY(pixelX, pixelY, out tileX, out tileY);
The result pixelX = 16225, pixelY = 12249, tileX = 63, tileY = 47.
I substitute the previous values:
map.position.set(16225,12249,-45);
class MapPlaneNode extends MapNode {
constructor(parentNode = null, mapView = null, location = MapNode.ROOT, level = 7, x = 63, y = 47)
The result is that the model comes out small and not positioned correctly. In the image, the red arrow is where the model is inserted, and the green arrow is where it should be.
image of result
What am I doing wrong?
Thank you very much
Positioning the model is a little tricky.
In the demo I created, I originally used world coordinates, where I set the root tile as level 0, and used the correct lat/long coordinate utils function to position the revit model in the correct location.
Unfortunately, the precision caused a rendering problem with the post-renderer (line edges were missing, and some strange z-fighting precision issues)...
so, I decided to hack the level, and move the map into the position I wanted and center the revit model at origin 0,0,0.
This made things a lot more manual and rather tricky, but it got around the rendering issue and also limited the user into a small area in the world, which I preferred.
I suggest changing the root tile back to zero, and adjusting the model position globaloffset to the value of the lat/long W84 utils. See the blog post and also the coordinates section of the geo-three repo, for more details here: https://github.com/tentone/geo-three#coordinates
Found a trick to adjust the map. It is still manual but it's fairly quick:
Calculate Tile X and Y (you did that step already, it's just for reference):
Copy the TileSystem class from the the link bing-maps-tile-system you posted into https://dotnetfiddle.net/
(you'll also need to add: using System.Text)
Change the main as follows
public static void Main()
{
int pixelX, pixelY, tileX, tileY;
TileSystem.LatLongToPixelXY(YOUR LAT HERE, YOUR LONG HERE, 7, out pixelX, out pixelY);
Console.WriteLine("LatLongToPixelXY: " + pixelX.ToString() + ", " + pixelY.ToString());
TileSystem.PixelXYToTileXY(pixelX, pixelY, out tileX, out tileY);
Console.WriteLine("PixelXYToTileXY: " + tileX.ToString() + ", " + tileY.ToString());
}
This will give you the TileX and Tile Y that you'll need to replace in the Extension.
Calculate Position
In the Extension set the X, Y position to 0,0, and the adjust the Z so that the map is below your model
map.position.set(0, 0, z);
Run the Extension and see where your project lands on the map. Now locate this landing point in Google maps (I found it useful at this stage to search the map using a corner between two streets by entering for example: Parker St & Wilson Rd). When you've found it, click on the landing point in Google map to place a Marker, then right-click on the marker and select Measure Distance. You will have to measure the distance to your destination both vertically, and horizontally (not directly to it). For example you'll get dH = 43.5km and dV = 17.8km
And this is were the magic happens: Multiply both numbers by 3400 if your distance is in km (or by 2113 if you distance is in miles) and set the position with those values:
dH * 3400 = 147900
dV * 3400 = 60520
If your destination is to the E or S use positive values.
If your destination is to the W or N use negative values
map.position.set(147900, -60520, z);
Now it won't be perfect, but it'll be close enough to finish adjusting the value manually.

GLTF file not well positioned by Cesium

I want to display a hurricane (big isosurface object) in Cesium. For this I converted an OBJ file with longitude, latitude, altitude columns for each vertex of the isosurface representing the hurricane, in a new OBJ file reprojected in ECEF (Earth Centered) projection.So the final OBJ file contains now X,Y,Z for each vertex instead of longitude, latitude, altitude. After final reformat by obj2gltf, I try to display the GLTF "hurricane" file in Cesium.JS using the code below:
console.log('loading hurricane.gltf';
var mymodel = viewer.scene.primitives.add(Cesium.Model.fromGltf({
url : 'data/hurricane.gltf',
modelMatrix : Cesium.Matrix4.IDENTITY,
asynchronous: false
}));
I can see my hurricane on the earth, but not at the good position. I suspect a problem of matrix. IDENTITY matrix seems not to be the good one. I could try to make a new matrix but I can't find enough informations about the axes orientation used by Cesium.
I verified the X,Y,Z ECEF coordinates, they are good. Does anyone already meet this problem ?
If your glTF model origin is at the center of the hurricane, you can place it using a Cesium Entity, something like this:
// Longitude degrees, Latitude degrees, height in meters
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
var heading = Cesium.Math.toRadians(0);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
name : 'Hurricane',
position : position,
orientation : orientation,
model : {
uri : 'data/hurricane.gltf'
}
});
viewer.trackedEntity = entity;
There are more complete working demos of this on Sandcastle.
But, if your hurricane is visible on the surface of the Earth using the identity matrix, that likely means that the origin of that model is nowhere near the center of the hurricane. You may need to edit the glTF file, to make sure that the model is centered on its own origin, and does not have some fixed Earth location pre-baked into the model's internal transformations.

How can I scale my map to fit my svg size with d3 and geojson path data

I am trying to create a d3 SVG that draws a map of New York State and scale it so that it fits the size of my SVG, the issue I am having is that when I use .fitSize([height, width], mapObject) it only returns a NaN error in the console.
the topoJSON file of NYS I am using
I am able to get the map to display without scaling but of course, it is not optimized and needs to be scaled
I have attempted what is said in this post but I have not figured out the correct solution
var map = d3.json('./ny.json')
Promise.all([map]).then(data => {
var height = 800;
var width = 800;
var mapData = data[0]
// original geoJSON to that works without scaling
// var geoData = topojson.feature(mapData, mapData.objects["cb_2015_new_york_county_20m"]).features
//
var geoData = topojson.feature(mapData, {
type:"GeometryCollection",
geometries: mapData.objects["cb_2015_new_york_county_20m"].geometries,
})
var projection = d3.geoMercator()
.fitSize([width, height], geoData)
var path = d3.geoPath()
.projection(projection)
d3.select('svg')
.attr('height', height)
.attr('width', width)
.selectAll('.county')
.data(geoData)
.enter()
.append('path')
.classed('.county', true)
.attr('d', path)
})
I am pretty sure this is a formatting error on my part, but I am unsure of what data .fitSize() or .fitExtent() is trying to compare against.
right now the way the code site I receive no error outputted to the console but I also have no data append to the SVG
The issue is that fitSize takes a geojson object while selectAll.data() takes an array, you are using one of these two for both in geoData. This leaves two solutions:
Solution 1:
If we use
var geoData = topojson.feature(mapData, mapData.objects["cb_2015_new_york_county_20m"]).features
var projection = d3.geoMercator()
.fitSize([width, height], geoData)
We get NaN errors because the projection is not set properly as we aren't passing a geojson object, just an array of geojson objects. We could solve this by making a feature collection with geoData and passing that to fitSize:
var geoData = topojson.feature(mapData, mapData.objects["cb_2015_new_york_county_20m"]).features
var projection = d3.geoMercator()
.fitSize([width, height], {type:"FeatureCollection", features: geoData})
Now we are passing a geojson feature collection to fitSize, we're all go on the projection, and since geoData is still an array, we can pass that to selectAll.data() unchanged.
Here's a block.
Solution 2:
If we use:
var geoData = topojson.feature(mapData, {
type:"GeometryCollection",
geometries: mapData.objects["cb_2015_new_york_county_20m"].geometries,
})
We get a geojson object, projection.fitSize works, but selectAll().data(geoData) doesn't add any features as it isn't an array - the enter selection is empty. We can substitute in selectAll().data(geoData.features) to solve this and enter one path per feature (alternatively we could use .data([geoData]) to enter one feature for all the paths).
Here's a block.
Both blocks are drawn at the correct scale - the map exceeds the block bounds as I didn't alter your 800x800 dimensions

How to remove duplicate vertices and their vertex handles when performing hole filling in OpenFlipper based on OpenMesh

Recently, I am using the plugin "hole filling" of OpenFlipper, and have entirely compiled the OpenFlipper. However, the new mesh has a large number of duplicate vertices, when I tried to add the filling patch to the original mesh. I used the following codes to perform the adding operation:
// filling_patch: newly created filling mesh
// mesh_ori: the original mesh before hole filling
class MeshT::FaceHandle fh;
class MeshT::FaceIter f_it, f_end;
class MeshT::FaceVertexIter fv_it;
for(f_it = filling_patch->faces_begin(), f_end = fill_patch ->faces_end(); f_it != f_end; f_it++)
{
// ith face
fh = *f_it;
// Check whether it is valid
if(!fh.is_valid())
{
return;
}
// Store its three vertices
std::vector<class MeshT::VertexHandle> face_vhandles;
face_vhandles.clear();
// Iterate each vertex of this face
for(fv_it = mesh_ori->fv_iter(fh); fv_it.is_valid(); fv_it++)
{
// Get the 3D point
class MeshT::Point p = filling_patch->point(*fv_it);
// Add this point to original mesh. Note: vh is a new vertevHandle, differ to *fv_it
class MeshT::VertexHandle vh = mesh_ori->add_vertex(p);
face_vhandles.push_back(vh);
}
// Save the face to mesh
mesh_ori->add_face(face_vhandles);
}
So, I am not sure whether there is an existing function that can be used to fix this problem in OpenMesh.
Does someone give me some advice?
Thanks a lot.

Fetching all the coordinates along a route generated by Directions Service in Google Maps Apiv3

My application allows a user to select two points on the map and find a route between them using the Directions Service of the Google maps Apiv3. Then the coordinates along this route has to be saved to the database. I could successfully write all the code to accomplish this. However I am left out with an issue.
I know that there are several other questions in StackOverflow- One, Two on the same, but I think surely either they or me has missed out something here.
Sample Code:
function getCoordinates(result) {
var currentRouteArray = result.routes[0]; //Returns a complex object containing the results of the current route
var currentRoute = currentRouteArray.overview_path; //Returns a simplified version of all the coordinates on the path
obj_newPolyline = new google.maps.Polyline({ map: map }); //a polyline just to verify my code is fetching the coordinates
var path = obj_newPolyline.getPath();
for (var x = 0; x < currentRoute.length; x++) {
var pos = new google.maps.LatLng(currentRoute[x].kb, currentRoute[x].lb)
latArray[x] = currentRoute[x].kb; //Returns the latitude
lngArray[x] = currentRoute[x].lb; //Returns the longitude
path.push(pos);
}
}
The above code works perfect except that the kb and lb properties of the overview path which seem to hold the lat and lng coordinates are not always the same. The last time I made the code, it was kb and lb for few days, and later it changed to mb, nb and today jb and kb.
I dont see any other properties in the object that can provide me the latlng's other than the above. Answers to other similar questions dint mention this issue. Am I missing something here? Any reliable solutions please.
do not use kb and lb which are minified names and undocumented. Use only the documented properties .lat() and .lng()
Another option is to decode the "points" string:
http://home.provide.net/~bratliff/routes/
It is a lot faster than using the lat() / lng() methods for every individual point.