API-Changes between releases - What to use in v0.8.2

I am using map-matching to snap gps tracks onto OSM ways.
Everything worked well with the v0.5 release, but since it is a bit old (and since I have problems reading one very dirty GPS file with v0.5) I want to switch to v0.8.2

Most of the changes were not hard to do, but when it comes to the public API of the map matching class, things are a bit different… maxSearchMultiplier and forceRepair, but these options are gone in v0.8.2.

The new release is not able to match all my gps data, so I get some IllegalStateExceptions when calling the mapMatching.doWork method.

My test cases look like this:

	@BeforeClass
	public void setup() throws IOException {
		final CmdArgs cmdArgs = CmdArgs.readFromConfig(DEFAULT_CONFIG, "-Dgraphhopper.config");
		cmdArgs.put("datareader.file", TestHelper.OSM_PBF); // this references northern italy -> nord-est-latest.odm.pbf (downloaded from geofabrik on 12.12.2016)
		cmdArgs.put("graph.flag_encoders", FLAG_ENCODER); // "car"

		hopper = new GraphHopperOSM();
		hopper.init(cmdArgs);
		hopper.importOrLoad();
	}
	@Test
	public void testMatchingFromEntries6() {
		final List<GPXEntry> gpxEntries = new ArrayList<>(8);
		// CHECKSTYLE:OFF MagicNumber
		gpxEntries.add(new GPXEntry(46.5512487944, 11.5802821890, 1240.24, 1435593069000L));
		gpxEntries.add(new GPXEntry(46.5509882849, 11.5804614779, 1243.12, 1435593083000L));
		gpxEntries.add(new GPXEntry(46.5507211536, 11.5805916488, 1246.01, 1435593097000L));
		gpxEntries.add(new GPXEntry(46.5504538547, 11.5807677526, 1249.37, 1435593112000L));
		gpxEntries.add(new GPXEntry(46.5502403677, 11.5810426790, 1252.25, 1435593127000L));
		gpxEntries.add(new GPXEntry(46.5501144715, 11.5813252330, 1254.66, 1435593139000L));
		gpxEntries.add(new GPXEntry(46.5499776788, 11.5817076992, 1258.02, 1435593155000L));
		gpxEntries.add(new GPXEntry(46.5498498548, 11.5820614994, 1260.43, 1435593170000L));
		// CHECKSTYLE:ON MagicNumber

		final FlagEncoder encoder = hopper.getEncodingManager().getEncoder(FLAG_ENCODER);
		final AlgorithmOptions opt = AlgorithmOptions.start().weighting(new ShortestWeighting(encoder)).build();
		final MapMatching mapMatching = new MapMatching(hopper, opt);
		mapMatching.setDistanceCalc(Helper.DIST_EARTH);
//		mapMatching.setMeasurementErrorSigma(500d);

		int nrFound = 0;
		int nrSkipped = 0;
		try {
			final MatchResult mr = mapMatching.doWork(gpxEntries);
			final List<EdgeMatch> edgeMatches = mr.getEdgeMatches();
			nrFound += edgeMatches.size();
		} catch (final IllegalArgumentException | IllegalStateException e) {
			// Skip track parts, which could not be matched to an edge in OSM}
			nrSkipped++;
		}

		Assert.assertEquals(nrSkipped, 0, "No edge was found during mapMatching");
		Assert.assertEquals(nrFound, 1, "Number of found edges is invalid (multiple edges found?)");
	}

As a result I get one skipped edge and therefore “No edge was found during mapMatching”.
If I print my points on a map then it looks like it could be matched easily. I also tried to increase measurementErrorSigma really high (which helped for some other gpxEntryLists, but not the one referenced above).

Could someone please explain to me, why this map matching does not work (and why it did work with v0.5).

Cheers,
Niko

What is the stacktrace that you get?

The stacktrace looks like this:

java.lang.IllegalStateException: No edge matches found for path. Too short? Sequence size 3
	at com.graphhopper.matching.MapMatching.computeMatchedEdges(MapMatching.java:367) ~[graphhopper-map-matching-core-0.8.2.jar:?]
	at com.graphhopper.matching.MapMatching.computeMatchResult(MapMatching.java:327) ~[graphhopper-map-matching-core-0.8.2.jar:?]
	at com.graphhopper.matching.MapMatching.doWork(MapMatching.java:189) ~[graphhopper-map-matching-core-0.8.2.jar:?]
	at com.graphhopper.util.profile.MapMatchingTest.testMatchingFromEntries6(MapMatchingTest.java:210) [bin/:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_91]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_91]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104) [testng-6.10.jar:?]
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:645) [testng-6.10.jar:?]
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851) [testng-6.10.jar:?]
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177) [testng-6.10.jar:?]
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129) [testng-6.10.jar:?]
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112) [testng-6.10.jar:?]
	at org.testng.TestRunner.privateRun(TestRunner.java:756) [testng-6.10.jar:?]
	at org.testng.TestRunner.run(TestRunner.java:610) [testng-6.10.jar:?]
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:387) [testng-6.10.jar:?]
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:382) [testng-6.10.jar:?]
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:340) [testng-6.10.jar:?]
	at org.testng.SuiteRunner.run(SuiteRunner.java:289) [testng-6.10.jar:?]
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) [testng-6.10.jar:?]
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) [testng-6.10.jar:?]
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1293) [testng-6.10.jar:?]
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1218) [testng-6.10.jar:?]
	at org.testng.TestNG.runSuites(TestNG.java:1133) [testng-6.10.jar:?]
	at org.testng.TestNG.run(TestNG.java:1104) [testng-6.10.jar:?]
	at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:126) [testng-remote.jar:?]
	at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:152) [testng-remote.jar:?]
	at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:57) [testng-remote.jar:?]

It could be that these are too few and too close points. Can you decrease gpx_accuracy or add a point with a bigger distance than 2*gpx_accuracy to one of the other points?

For me this does not seem to help. If I am correct gpx_accuracy is set as measurementErrorSigma (I took that information from the MapMatchingMain.class… as you can see above I use the MapMatching class directly).
Setting this to very low values and adding a point a bit more off does not solve the problem.

I added the point

new GPXEntry(46.5502144715, 11.5815252330, 1254.66, 1435593149000L);

and tried to set

mapMatching.setMeasurementErrorSigma(1.0d);

which did not help. Also setting the errorSigma to values far below one (or to 5.0d) did not change anything.

If I am correct gpx_accuracy is set as measurementErrorSigma

yes

What is the error message you get?

Can you try

  • 46.551261,11.580325 and 46.550992,11.580518 with 10m?
  • and 46.551877,11.579279 and 46.550992,11.580518 with 10m?

The error message for my previous change (comment #5; after adding the GPXEntry) is:

java.lang.IllegalStateException: No edge matches found for path. Too short? Sequence size 9
at com.graphhopper.matching.MapMatching.computeMatchedEdges(MapMatching.java:367) ~[graphhopper-map-matching-core-0.8.2.jar:?]
at com.graphhopper.matching.MapMatching.computeMatchResult(MapMatching.java:327) ~[graphhopper-map-matching-core-0.8.2.jar:?]
... continuing with the same entries as in the stacktrace above

When adding the points you suggested (with an errorSigma of 10m) the matching works.
The first two points result in 3 edges while the second two points result in 5 edges (which is fine for me as long as something is found).

Even when not setting the errorSigma (and using the default provided) both matchings work (finding 3 edges in both cases).

What does this mean (and how can it solve my issue)?

I guess, the issue is that there are too few gps input entries and all in a too close position to each other. So at the end our algorithm just has one match and does not know what to do with it as it needs two to connect them.

Is this from a real world example?

You can create a new issue for this, maybe we just avoid the matching algorithm in these cases and return the single edge although this could be very error-prone.

The measurements were recorded during a bike trip… so yes… this is real-world data.
However, the whole GPS track has been split into single parts (one part each 200m), so this might be too short (which is related to the elevation estimations which is done once per split point. Increasing the split size will decrease my elevation estimation…)

I am still a bit surprised about this finding, because this split size worked will map matching v0.5…

EDIT:
I just thought about that in more detail. I could pass the whole (unsplitted) gpx track to the map matching process, if I could easily match the original (measured/recorded) gpxentries to the matched edges. I know that I can get the matched edges using the MatchResults’s getEdgeMatches. Is there an easy way to match measured/recorded points to the points in the edge matches (and what is the best way to do… simply by calculating distances?)?

The underlying algorithm completely changed and we did not have a test case or requirement for your samples. Again, if you like to see support for this at some point, please do not hesitate to create an issue for it or even provide a pull request with the necessary changes, if you have some time to share :slight_smile:

Is there an easy way to match measured/recorded points to the points in the edge matches

This is a frequent requirement and we want this too :slight_smile: … see Association of all provided GPXEntry to the corresponding EdgeMatch · Issue #64 · graphhopper/map-matching · GitHub