-
Notifications
You must be signed in to change notification settings - Fork 275
Enable GPS-precise map matching #51
Changes from 5 commits
7005e9c
60b4515
9606f2f
3119df8
389f448
379112f
3cfe587
2cef7f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,8 @@ | |
package com.graphhopper.matching; | ||
|
||
import com.graphhopper.util.EdgeIteratorState; | ||
import com.graphhopper.util.PointList; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
|
@@ -28,9 +30,11 @@ public class EdgeMatch { | |
|
||
private final EdgeIteratorState edgeState; | ||
private final List<GPXExtension> gpxExtensions; | ||
private final PointList wayGeometry; | ||
|
||
public EdgeMatch(EdgeIteratorState edgeState, List<GPXExtension> gpxExtension) { | ||
public EdgeMatch(EdgeIteratorState edgeState, List<GPXExtension> gpxExtension, PointList wayGeometry) { | ||
this.edgeState = edgeState; | ||
this.wayGeometry = wayGeometry; | ||
|
||
if (edgeState == null) { | ||
throw new IllegalStateException("Cannot fetch null EdgeState"); | ||
|
@@ -42,6 +46,10 @@ public EdgeMatch(EdgeIteratorState edgeState, List<GPXExtension> gpxExtension) { | |
} | ||
} | ||
|
||
public EdgeMatch(EdgeIteratorState edgeState, List<GPXExtension> gpxExtension){ | ||
this(edgeState, gpxExtension, null); | ||
} | ||
|
||
public boolean isEmpty() { | ||
return gpxExtensions.isEmpty(); | ||
} | ||
|
@@ -68,6 +76,38 @@ public double getMinDistance() { | |
return min; | ||
} | ||
|
||
/** | ||
* For OSM a way is often a curve not just a straight line. These nodes are called pillar nodes | ||
* and are between tower nodes (which are used for routing), they are necessary to have a more | ||
* exact geometry. Updates to the returned list are not reflected in the graph, for that you've | ||
* to use setWayGeometry. | ||
* <p> | ||
* @param mode can be <ul> <li>0 = only pillar nodes, no tower nodes</li> <li>1 = inclusive the | ||
* base tower node only</li> <li>2 = inclusive the adjacent tower node only</li> <li>3 = | ||
* inclusive the base and adjacent tower node</li> </ul> | ||
* @return pillar nodes | ||
*/ | ||
public PointList getWayGeometry(int mode){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here I would use the same naming 'fetchWayGeometry' as in the edge interface because it is also here not always a cheap 'get' (?) |
||
if(wayGeometry != null) | ||
switch (mode){ | ||
case 0: | ||
return wayGeometry.copy(1,wayGeometry.size() - 1); | ||
case 1: | ||
return wayGeometry.copy(0,wayGeometry.size() - 1); | ||
case 2: | ||
return wayGeometry.copy(1,wayGeometry.size()); | ||
case 3: | ||
default: | ||
return wayGeometry; | ||
} | ||
else | ||
return edgeState.fetchWayGeometry(mode); | ||
} | ||
|
||
public PointList getWayGeometry() { | ||
return getWayGeometry(3); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "edge:" + edgeState + ", extensions:" + gpxExtensions; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ | |
import java.util.List; | ||
import org.junit.AfterClass; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNotNull; | ||
import static org.junit.Assert.assertTrue; | ||
import org.junit.BeforeClass; | ||
import org.junit.Test; | ||
|
@@ -289,6 +290,81 @@ public void testRepairUTurn() { | |
mm.checkOrCleanup(res, false); | ||
} | ||
|
||
@Test | ||
public void testWayGeometryAtStartAndEndPoint() { | ||
GraphHopperStorage graph = hopper.getGraphHopperStorage(); | ||
LocationIndexMatch locationIndex = new LocationIndexMatch(graph, | ||
(LocationIndexTree) hopper.getLocationIndex()); | ||
MapMatching mapMatching = new MapMatching(graph, locationIndex, encoder); | ||
|
||
// https://graphhopper.com/maps/?point=51.341708%2C12.385272&point=51.340622%2C12.388405&locale=de-DE&vehicle=car&weighting=fastest&elevation=true&layer=Omniscale | ||
List<GPXEntry> inputGPXEntries = new GPXFile().doImport("./src/test/resources/testStartEndGeometry.gpx").getEntries(); | ||
MatchResult mr = mapMatching.doWork(inputGPXEntries,true); | ||
|
||
NodeAccess nodeAccess = graph.getNodeAccess(); | ||
|
||
List<EdgeMatch> edgeMatches = mr.getEdgeMatches(); | ||
for (int i = 0; i < edgeMatches.size(); i++) { | ||
EdgeMatch match = edgeMatches.get(i); | ||
assertNotNull(match.getWayGeometry()); | ||
if (i == 0) { | ||
assertEquals(2, match.getWayGeometry().size()); | ||
assertEquals(51.341708, match.getWayGeometry().getLat(0), 1E-5); | ||
assertEquals(12.385272, match.getWayGeometry().getLon(0), 1E-5); | ||
assertEquals(nodeAccess.getLat(mr.getEdgeMatches().get(0).getEdgeState().getAdjNode()), match.getWayGeometry().getLat(1), 1E-5); | ||
assertEquals(nodeAccess.getLon(mr.getEdgeMatches().get(0).getEdgeState().getAdjNode()), match.getWayGeometry().getLon(1), 1E-5); | ||
} else if (i == edgeMatches.size() - 1) { | ||
assertEquals(2, match.getWayGeometry().size()); | ||
assertEquals(nodeAccess.getLat(mr.getEdgeMatches().get(mr.getEdgeMatches().size() - 1).getEdgeState().getBaseNode()), match.getWayGeometry().getLat(0), 1E-5); | ||
assertEquals(nodeAccess.getLon(mr.getEdgeMatches().get(mr.getEdgeMatches().size() - 1).getEdgeState().getBaseNode()), match.getWayGeometry().getLon(0), 1E-5); | ||
assertEquals(51.340622, match.getWayGeometry().getLat(1), 1E-5); | ||
assertEquals(12.388405, match.getWayGeometry().getLon(1), 1E-5); | ||
} | ||
} | ||
|
||
assertEquals(mr.getGpxEntriesLength(), mr.getMatchLength(), 1); | ||
// TODO why is there such a big difference for millis? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean with this TODO and compared to which value this is a 'big' difference? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the Mapmatched paths is 24sec different in length (I don't remember if shorter or longer) -> see the third param of the assertEquals. Acctually I don't know why that is the case. But the other tests also have such a difference (and such a ToDo-comment, that I copied from there). |
||
assertEquals(mr.getGpxEntriesMillis(), mr.getMatchMillis(), 24000); | ||
} | ||
|
||
@Test | ||
public void testWayGeometryAtStartAndEndPoint2() { | ||
GraphHopperStorage graph = hopper.getGraphHopperStorage(); | ||
LocationIndexMatch locationIndex = new LocationIndexMatch(graph, | ||
(LocationIndexTree) hopper.getLocationIndex()); | ||
MapMatching mapMatching = new MapMatching(graph, locationIndex, encoder); | ||
|
||
// https://graphhopper.com/maps/?point=51.328198%2C12.335672&point=51.364285%2C12.459623&locale=de-DE&vehicle=car&weighting=fastest&elevation=true&layer=Omniscale | ||
List<GPXEntry> inputGPXEntries = new GPXFile().doImport("./src/test/resources/testStartEndGeometry2.gpx").getEntries(); | ||
MatchResult mr = mapMatching.doWork(inputGPXEntries,true); | ||
|
||
|
||
NodeAccess nodeAccess = graph.getNodeAccess(); | ||
|
||
List<EdgeMatch> edgeMatches = mr.getEdgeMatches(); | ||
for (int i = 0; i < edgeMatches.size(); i++) { | ||
EdgeMatch match = edgeMatches.get(i); | ||
assertNotNull(match.getWayGeometry()); | ||
if (i == 0) { | ||
assertEquals(2, match.getWayGeometry().size()); | ||
assertEquals(51.328439, match.getWayGeometry().getLat(0), 1E-5); | ||
assertEquals(12.335785, match.getWayGeometry().getLon(0), 1E-5); | ||
assertEquals(nodeAccess.getLat(mr.getEdgeMatches().get(0).getEdgeState().getAdjNode()), match.getWayGeometry().getLat(1), 1E-5); | ||
assertEquals(nodeAccess.getLon(mr.getEdgeMatches().get(0).getEdgeState().getAdjNode()), match.getWayGeometry().getLon(1), 1E-5); | ||
} else if (i == edgeMatches.size() - 1) { | ||
assertEquals(4, match.getWayGeometry().size()); | ||
assertEquals(nodeAccess.getLat(mr.getEdgeMatches().get(mr.getEdgeMatches().size() - 1).getEdgeState().getBaseNode()), match.getWayGeometry().getLat(0), 1E-5); | ||
assertEquals(nodeAccess.getLon(mr.getEdgeMatches().get(mr.getEdgeMatches().size() - 1).getEdgeState().getBaseNode()), match.getWayGeometry().getLon(0), 1E-5); | ||
assertEquals(51.364306, match.getWayGeometry().getLat(3), 1E-5); | ||
assertEquals(12.459582, match.getWayGeometry().getLon(3), 1E-5); | ||
} | ||
} | ||
|
||
assertEquals(mr.getGpxEntriesLength(), mr.getMatchLength(), 4); | ||
// TODO why is there such a big difference for millis? | ||
assertEquals(mr.getGpxEntriesMillis(), mr.getMatchMillis(), 242175); | ||
} | ||
|
||
List<String> fetchStreets(List<EdgeMatch> emList) { | ||
List<String> list = new ArrayList<String>(); | ||
int prevNode = -1; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?><gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creator="Graphhopper version 0.7" version="1.1" xmlns:gh="https://graphhopper.com/public/schema/gpx/1.1"> | ||
<metadata><copyright author="OpenStreetMap contributors"/><link href="http://graphhopper.com"><text>GraphHopper GPX</text></link><time>2016-05-13T07:08:02Z</time></metadata> | ||
<trk><name>GraphHopper Track</name><trkseg> | ||
<trkpt lat="51.341708" lon="12.385276"><ele>116.0</ele><time>2016-05-13T07:08:02Z</time></trkpt> | ||
<trkpt lat="51.341198" lon="12.38534"><ele>115.8</ele><time>2016-05-13T07:08:10Z</time></trkpt> | ||
<trkpt lat="51.341074" lon="12.38777"><ele>115.2</ele><time>2016-05-13T07:08:48Z</time></trkpt> | ||
<trkpt lat="51.341034" lon="12.388462"><ele>115.0</ele><time>2016-05-13T07:08:59Z</time></trkpt> | ||
<trkpt lat="51.340752" lon="12.388414"><ele>116.8</ele><time>2016-05-13T07:09:06Z</time></trkpt> | ||
<trkpt lat="51.340623" lon="12.388395"><ele>116.8</ele><time>2016-05-13T07:09:10Z</time></trkpt> | ||
</trkseg> | ||
</trk> | ||
</gpx> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmh, I would prefer a setWayGeometry, this way we can init the EdgeMatch and call setWayGeometry for the certain conditions. Which will make "Match Phase (4)" a little less indirect - i.e. we can avoid
PointList wayGeometry = null;