I'am trying to utilize osm2po as java lib for calculation of distances matrix between some set of points (lat/lon) and for each pair of points I call the following method that code is based on sample provided at osm2po.de web-site:
public int getDistance(GeoPoint source, GeoPoint target) {
int res = Integer.MAX_VALUE;
int sourceId = graph.findClosestVertexId(source.getLatitude(), source.getLongitude(), 1);
int targetId = graph.findClosestVertexId(target.getLatitude(), target.getLongitude(), 1);
router.traverse(graph, sourceId, targetId, Float.MAX_VALUE, params);
if (router.isVisited(targetId)) { // Found!
int[] path = router.makePath(targetId);
float distKm = 0.0f;
for (int segmentId : path) {
RoutingResultSegment rrs = graph.lookupSegment(segmentId);
distKm = distKm + rrs.getKm();
}
res = (int)(distKm * 1000);
}
router.reset();
return res;
But I noticed that it takes about 2-3 seconds per one point to calculate whole distance matrix (I have 10-25 points per matrix in average) that looks not too fast (30-60secs per matrix). Could someone advice what could be improved here - especially I am not sure in correct usage of reset() call - when actually it should be done? - it's not too much documentation on osm2po usage within java...
Also I would appreciate any performance tips to improve this code. One more guess I have is that findClosestVertexId() is expensive enough call and cashing its results for subsequent calls could improve the situation.
Answer
package de.cm.osm2po.test;
import java.io.File;
import java.util.Arrays;
import de.cm.osm2po.logging.Log;
import de.cm.osm2po.logging.Log2poConsoleWriter;
import de.cm.osm2po.model.LatLon;
import de.cm.osm2po.routing.Graph;
import de.cm.osm2po.routing.MultiTargetRouter;
import de.cm.osm2po.routing.PoiRouter;
public class MatrixDemo {
// ###################### Demo Main ##############################
public static void main(String[] args) {
File graphFile = new File("D:/work/osm2po/hh/hh_2po.gph");
MatrixDemo matrixDemo = new MatrixDemo(graphFile);
int[] vertexIds = matrixDemo.findClosestVertexIds(
new LatLon(53.5, 10.1),
new LatLon(53.4, 10.0),
new LatLon(53.5, 9.9));
float[][] matrix = matrixDemo.createMatrix(vertexIds);
matrixDemo.close();
for (int i = 0; i < matrix.length; i++) {
System.out.println(Arrays.toString(matrix[i]));
}
}
// ##################### Intrinsic Clazz #########################
private Graph graph;
private MultiTargetRouter router;
public MatrixDemo(File graphFile) {
Log log = new Log(Log.LEVEL_DEBUG).addLogWriter(new Log2poConsoleWriter());
graph = new Graph(graphFile, log, Graph.SUPPORT_LATLON);
router = new PoiRouter();
}
public void close() {
graph.close();
}
public int[] findClosestVertexIds(LatLon... latLons) {
int[] vertexIds = new int[latLons.length];
for (int i = 0; i < latLons.length; i++) {
vertexIds[i] = graph.findClosestVertexId(
(float)latLons[i].getLat(), (float)latLons[i].getLon());
}
return vertexIds;
}
public float[][] createMatrix(int... vertexIds) {
int n = vertexIds.length;
int[] cpVertexIds = Arrays.copyOf(vertexIds, n);
float[][] matrix = new float[n][n];
for (int y = 0; y < n; y++) {
int swap = cpVertexIds[0];
cpVertexIds[0] = cpVertexIds[y];
cpVertexIds[y] = swap;
int sourceId = cpVertexIds[0];
int[] targetIds = Arrays.copyOfRange(cpVertexIds, 1, n -1);
router.reset();
router.traverse(graph, sourceId, targetIds, Float.MAX_VALUE, null);
for (int z = 0; z < n; z++) {
int x = z + y;
if (x >= n) x -= n;
matrix[y][x] = Float.MAX_VALUE;
if (router.isVisited(vertexIds[x])) {
matrix[y][x] = router.getCost(vertexIds[x]);
}
}
}
return matrix;
}
}
If you have big data but only need the matrix for a small region, you can improve the performance by setting the MaxCost-Parameter to sth. smaller than Float.MAXVALUE
. Tipp: Mostly it is sufficient to call a full traversal using MaxValue twice or thrice. After these loops the longest path should be found and you can replace the MaxValue with the cost *
router.traverse(graph, sourceId, targetIds, longestPathCost * 1.5, null);
The last parameter (null
) are optional additional properties.
Properties params = new Properties();
params.setProperty("findShortestPath", "true");
router.traverse(graph, sourceId, targetIds, Float.MAX_VALUE, params);
No comments:
Post a Comment