graphhopper / map-matching

The map matching functionality is now located in the main repository https://github.com/graphhopper/graphhopper#map-matching
https://www.graphhopper.com/open-source/
Apache License 2.0
785 stars 274 forks source link

prevent inner-link U-turns #83

Closed kodonnell closed 7 years ago

kodonnell commented 7 years ago

See #70

WIP. Things to note (@stefanholder)

I'm still not sure how the logic is going to work. To clarify, consider

     v1    v2 
 A------X------B

with nodes A,B and a GPX position at X (i.e. the virtual node), and virtual edges v1 and v2. What is being done in this PR is creating two candidates for this GPX point: both with closestNode = X, but one with incoming=v1 and outgoing=v2, and the other with that reversed. When we route, we simply unfavor the incoming/outgoing edge to force the other to be used. E.g. if X is the from candidate, then we'd have

candidate 1: incoming=v1 (unfavored), outgoing=v2

     v1    v2 
 AxxxxxxX--->--B

candidate 2: incoming=v2 (unfavored), outgoing=v1

     v1    v2 
 A--<---XxxxxxxB

We can do similar for the to candidate but unfavor the outgoing edge.

However, how do we actually prevent inner-link U-turns with this? When X is the to timestep, we have a candidate

     v1    v2 
 A-->---XxxxxxxB

and when it's the from timestep we have a candidate

     v1    v2 
 A--<---XxxxxxxB

in other words the inner-link U-turn is still possible:

 A-->---XxxxxxxB
 A--<---XxxxxxxB

@stefanholder - how were you planning to get around this when you said:

If a candidate is a virtual node + direction, we can enforce the direction during routing with QueryGraph.enforceHeadingByEdgeId. We can store the direction as the outgoing virtual edge id.

Since we don't know the direction of the 'right' to candidate we can't enforce the 'right' direction to start with.

If you agree it's not resolvable, then I think an 'online' (i.e. step by step) solution might be best: we calculate the best sequence up to the give point, and the we can enforce that as the direction at the start of the route to all other candidates.

stefanholder commented 7 years ago

However, how do we actually prevent inner-link U-turns with this?

In the result of the Viterbi algorithm (List<SequenceState<GPXExtension, GPXEntry, Path>>) we have exactly one candidate for each GPS position, so in the Viterbi result the "to" candidate of a transition always equals the "from" candidate of the following transition. Without this property of the Viterbi algorithm, we wouldn't even obtain a continuous map matching route from the first to the last GPS position.

kodonnell commented 7 years ago

In the result of the Viterbi algorithm ...

Yes, but that's not how the process currently works - as per here, we compute transition probabilities between all possible from timestep candidates to all possible to timestep candidates, regardless of the state of the viterbi algorithm. If you were meaning that we'd need to change the process so that we compute the virterbi next step and then use the output as the from candidate for the next step (hence we only have one and know it's direction), then great - that's what I was meaning with 'online' in the final paragraph above. As an aside, this should (?) also speed things up a lot, as we'll only have one from candidate instead of many. Only question - is the viterbi algorithm set up for this? I.e. does it go through step-by-step, or does it require the entire history first?

Hmmm ... though I'm not sure the 'online' method will work well, as it won't know a U-turn is about to happen until it's too late ...

Aside - new commit passes the test (though still fails others).

stefanholder commented 7 years ago

we compute transition probabilities between all possible from timestep candidates to all possible to timestep candidates, regardless of the state of the viterbi algorithm

The Viterbi algorithm needs the transition probabilities between all pairs of subsequent candidates as input. After this input is provided for all time steps, the Viterbi algorithm can compute the most likely sequence of candidates (i.e. the sequence of candidates with highest probability). All this input is needed because the probability of a candidate sequence is defined as the product of all transition and emission probabilities within this candidate sequence. If we have t time steps and n candidates per time step (in practice the number of candidates can vary) then we have nt different candidate sequences. Because the Viterbi algorithm uses dynamic programming, it does not store or compute the probabilities of all these different candidate sequences but it is still guaranteed to find the most likely sequence of candidates. The Viterbi algorithm is similar to Dijkstra's algorithm, which also uses dynamic programming to find the shortest path between two nodes A and B out of all possible paths between A and B in the graph.

this should (?) also speed things up a lot, as we'll only have one from candidate instead of many

Only after all GPS positions (and all transition and emission probabilities) have been seen, the Viterbi algorithm decides on the most likely candidate sequence. This is because GPS positions of later time steps can contain information about the correct candidate of the current time step. Imagine a T intersection where we have a GPS position nearby the intersection node and because of GPS noise are not sure yet which of the two possible roads was taken (so which is the correct candidate assuming we have one candidate per real edge). After further GPS positions we can easily decide this. This is why the Viterbi algorithm gives better results than online map matching algorithms if the entire GPS sequence is already known.

kodonnell commented 7 years ago

Great - that confirms what I read over the weekend. With that in mind, I'm still not following your comment - if we don't know any final candidates until the end, how can we know the 'actual' direction when we're calculating transition probabilities part-way through?

stefanholder commented 7 years ago

Let me use your previous example where we have three GPS position at A, B and C.

            |   |
            ^   v
            | B |
            ^   v
            |   |
            ^   v
            |   |
-->-A->-->-->-->-->-->-C->--

Let's assume we only have one real node candidate at position A and C, respectively. For B we have two candidates for the same virtual node, one in north direction and one in south direction.

Hence, we have two possible candidate sequences:

The shortest route from A to B_north goes from A to the junction node, to B_north. The shortest route from A to B_south goes from A to the junction node, to the next real node north of B and then back to B_south (assuming that the router does not allow inner-link U-turns). We have similar shortest route paths from B_north/B_south to C. Hence, both candidate sequence are not doing an inner-link U-turn at B but are only permitted to do a U-turn at the next real node north of B. If we had another candidate for B at the junction node then the candidate sequence A -> junction node -> C might have highest probability.

@karussell: This raises one question for me: What does actually happen when we make a virtual edge unfavored? Does this effectively remove the edge? If yes then we wouldn't even find a shortest route between A and B_south because the incoming virtual edge to B from the junction node would be missing.

So what we need is a way to find the shortest route starting at the beginning of a virtual edge and ending at the end of another virtual edge without removing virtual edges completely. We could also achieve this by routing from/to all real nodes adjacent to virtual node candidates and doing the last part of the route length computation ourselves. However, this requires the computation of multiple routes per transition.

karussell commented 7 years ago

Does this effectively remove the edge?

Yes, or at least puts a penalty on it.

So what we need is a way to find the shortest route starting at the beginning of a virtual edge and ending at the end of another virtual edge

This is possible with the edge based traversal (like how we support turn costs), then we wouldn't need any previous information where we come from, but could use this start edge ID being avoided in the next routing call. (As the edge ID is often virtual this is a bit more complex as we need to find the 'opposite' edge, which should be avoided too, but we could find a solution there too)

karussell commented 7 years ago

Hence, we have two possible candidate sequences:

I do not understand this example. If we have two virtual nodes then it would be like

So all virtual edges and nodes are visible to other graph explorations. At least this is what we do when we call QueryGraph.lookup only once (and not separately for every routing)

kodonnell commented 7 years ago

Hence, both candidate sequence are not doing an inner-link U-turn at B but are only permitted to do a U-turn at the next real node north of B.

Currently I think it's still perfectly viable to go A -> B via B_north, then B -> C via B_south, and hence get an inner-link U-turns. That said, I think I see the key difference in our approaches. In the case

   ia    oa          ib    ob
------A------ ... ------B------

I was thinking when we route to A we use the incoming edge (ia) as the to edge, and then when we route from A to B we use oa to ib, and then B onward we use ob, etc. However, what I think you're saying is we share the same incoming/outgoing edge, so e.g. routing to and from A both use e.g. ia. That way we can enforce direction as the edge is actually the same. That said, it means having four candidate edges (i.e. virtual edge pair either side of the virtual node). See new commit where I've implemented this ... it seems to pass more of the tests (including matching the routes - only for non-CH ... - unlike previous test cases).

@stefanholder - if you know how to do it, then it might be quicker to just cut some code instead of waiting for @karussell and I to catch up.

stefanholder commented 7 years ago

If we have two virtual nodes then it would be like A -> B_north -> B_south -> C

For GPS point B we have the two candidates B_north and B_south. For each time step (=each GPS position), the Viterbi algorithm picks exactly one candidate. So each candidate sequence has the same length (3 in this example). But you're right in that the shortest path of the transition B_north -> C also go through B_south.

if you know how to do it, then it might be quicker to just cut some code instead of waiting for @karussell and I to catch up

OK, here is how I will try do it:

@kodonnell, can you please remove the last 3 commits with git reset --hard HEAD~3 and squash the first 2 commits into one using git rebase -i? I will then add further commits on your squashed commit. One more remark: Please use spaces instead of tabs. Otherwise reviews are hard with Github since it shows tabs as 8 spaces.

kodonnell commented 7 years ago

@kodonnell, can you please ...

Blindly did what you suggested - hopefully that's OK? If not, it might be better for you to (I assume you've got push permission?)

stefanholder commented 7 years ago

If not, it might be better for you to

OK, no problem.

@karussell, when EdgeExplorer.setBaseNode is called for a virtual node, does the iterator go through all 4 edges that are connected to the virtual node? If yes, how do I find out the direction of a virtual edge? Should this be done with VirtualEdgeIteratorState.getOriginalTraversalKey?

karussell commented 7 years ago

does the iterator go through all 4 edges that are connected to the virtual node

yes

If yes, how do I find out the direction of a virtual edge?

The same as with the normal edges, so you can use the DefaultEdgeFilter with outgoing=true to get just the outgoing

Should this be done with VirtualEdgeIteratorState.getOriginalTraversalKey?

This will return the original edge id but converted into the traversal key which considers the direction.

BTW: The traversal key stuff is relative simple: you have an edgeID but we want to add the 'heading' so we could just use - and + but instead we use edgeID*2+0 and edgeID*2+1 for the two directions. This way we also do the edge based traversal. See GHUtility.createEdgeKey

stefanholder commented 7 years ago

The same as with the normal edges, so you can use the DefaultEdgeFilter with outgoing=true to get just the outgoing

To individually check the direction of virtual edges, I can also call EdgeIteratorState.isForward/isBackward, right? How is then "forward" defined, does this mean from BaseNode to AdjNode?

karussell commented 7 years ago

I can also call EdgeIteratorState.isForward/isBackward, right?

Yes, under the hood DefaultEdgeFilter does this for you.

How is then "forward" defined, does this mean from BaseNode to AdjNode?

yes, exactly. forward and backward is always relative to the direction "base node to adjacent node".

kodonnell commented 7 years ago

To individually check the direction of virtual edges ... How is then "forward" defined

For the sake of clarity, it's worth pointing out that (I think) isForward and isBackward usually mean 'does the given encoder support travel on the given edge in the given direction' - so 'forward' depends on adj/base nodes and OSM properties about the edge and the encoder. That's different to the 'direction' of the virtual edge (which is just related to base/adj node and 'forward' is an undefined concept). @karussell, correct me if I'm wrong ...

karussell commented 7 years ago

(which is just related to base/adj node and 'forward' is an undefined concept)

You are right. We just copy the flags from the original edge into the virtual edge and reverse the flags for the reverse virtual edge. So this means that a "forward" virtual edge can have "backward" access property, but this all does not really matter: the algorithm always has a defined encoder&weighting and should care only about what it sees.

Hmmh, maybe I discovered a minor suboptimality when thinking about this: the foot encoder would then return for all 4 virtual edges "access=true".

stefanholder commented 7 years ago

That's different to the 'direction' of the virtual edge (which is just related to base/adj node and 'forward' is an undefined concept).

So is the direction of a virtual edge always from base to adj node? I thought the base node of an edge is always the node passed to EdgeExplorer.setBaseNode, so all 4 virtual edges returned by EdgeExplorer.setBaseNode(x) should have virtual node x as their base node.

karussell commented 7 years ago

so all 4 virtual edges returned by EdgeExplorer.setBaseNode(x) should have virtual node x as their base node

Yes, this is correct.

kodonnell commented 7 years ago

Yes, this is correct.

Then how does one distinguish the direction of the incoming virtual edge from the outgoing, if they've both got the same base/adj node? I thought the two outgoing virtual edges would have base node = x and the two outgoing would have adj node = x ...

karussell commented 7 years ago

Sorry for the confusion, you are right in your recent comment: 2 virtual edges returned by EdgeExplorer.setBaseNode(x) have the virtual node x as their base node, the other two have it as adjacent node.

stefanholder commented 7 years ago

2 virtual edges returned by EdgeExplorer.setBaseNode(x) have virtual node x as their base node, the other two have it as adjacent node.

Thanks! The name of the method EdgeExplorer.setBaseNode is then somewhat confusing.

karussell commented 7 years ago

Oh, my. I shouldn't do so many things in parallel. Sorry.

My last comment is wrong (!) and EdgeExplorer.setBaseNode(x) sets the base node at which it should explore the graph, i.e. it will return all edges where base_node==x

     v0        v2
A -------> x -----> B
  <-------   <-----
     v1        v3

See in QueryGraph the indices correspond to the following naming scheme:

final static int VE_BASE = 0, VE_BASE_REV = 1, VE_ADJ = 2, VE_ADJ_REV = 3;

(VE=virtual edge) (BASE=virtual edge where base node is the base node of the real edge) (BASE_REV=same as 'base' but opposite direction) (ADJ=adjacent)

Update: I found a simpler description of these edges in the comment of 'virtualEdges': base-snap, snap-base, snap-adj, adj-snap.

And with these indices you know the indices of the QueryGraph.virtualEdges array and also the virtual edge IDs (mainGraph.maxId+virtualId). Probably this partially answers how you know about the direction of those virtual edges.

This is also the reason that the real edge of every QueryResult has to be in a defined order. So that every virtual node creates virtual edges with the same orientation towards the real edge (and A<-B is never used).

Then how does one distinguish the direction of the incoming virtual edge from the outgoing, if they've both got the same base/adj node

What use case do you have in mind? If you use a flag encoder here, you can already filter the edges via isForward and isBackward.

kodonnell commented 7 years ago

Ah, methinks I am confused.

What use case you have in mind?

In your above diagram, how do I distinguish v0 from v1? That's pretty critical to the whole inner-link U-turn business.

karussell commented 7 years ago

In your above diagram, how do I distinguish v0 from v1? That's pretty critical to the whole inner-link U-turn business

Why is this necessary? (Currently you can only distinguish via internals of QueryGraph)

Can't we just block all 'base' edges when we came from A? Or how would this work if we would have only 2 bidirectional, virtual edges?

karussell commented 7 years ago

Ah, methinks I am confused.

I'm sorry again :) ... please let me know more details that I should explain!

kodonnell commented 7 years ago

I'm sorry again :)

No problem at all. I'll look into the details later.

Why is this necessary?

I'll leave it to @stefanholder given he's currently working on it - I risk confusing things.

stefanholder commented 7 years ago

Let's assume a bidirectional real edge is split by a virtual node into 4 virtual edges. According to the forward/backward access flags, can each of the 4 virtual edges be traveled in both directions? If yes then we would have two virtual edges per direction (two edges from x to A and two from x to B). Since we have one candidate per possible edge direction, we would even have 4 candidates for one virtual node.

If v0 and v1 actually contain the same forward/backward information, it would be better to only consider one of them. We would then only have 2 candidates per virtual node.

stefanholder commented 7 years ago

According to the forward/backward access flags, can each of the 4 virtual edges be traveled in both directions?

@karussell, can you please answer this? Moreover, if all direction information is in the forward/backward flags, wouldn't it be enough to have only one vitual edge between the virtual node and any neighbor node?

karussell commented 7 years ago

According to the forward/backward access flags, can each of the 4 virtual edges be traveled in both directions?

I'm not sure how you mean this. Assume again X as virtual node and A and B as real nodes:

A---X---B

If there is e.g. a one way A->B for car you have only 2 outgoing virtual edges (X->B and X->A) but still you can access the other 2 edges from X (B->X and A->X) via the 'incoming' filter. This is important to make bidirectional Dijkstra working. If the flags are independent on the direction the only difference between A->X and X->A is the geometry and the base/adj node assignment I think.

Moreover, if all direction information is in the forward/backward flags, wouldn't it be enough to have only one vitual edge between the virtual node and any neighbor node?

Yes, one virtual edge would be sufficient (for A-X) but it was simpler to implement (no need to switch "on-demand" you can just put them in an array and return them via explicit edge IDs).

stefanholder commented 7 years ago

If there is e.g. a one way A->B for car

So what if there's a bidirectional real edge A-B (e.g. for car), which is split by virtual node X? If I call EdgeExplorer.setBaseNode on X with outgoing filter, do I get 2 or 4 virtual edges? From what you explained I would expect 4 edges because each virtual edge adjacent to X should have the forward and the backward flag.

karussell commented 7 years ago

If I call EdgeExplorer.setBaseNode on X with outgoing filter, do I get 2 or 4 virtual edges?

Good question :) ... in theory it should be indeed 4 but there are only 2 - the outgoing ones, not sure why the incoming are not added. Maybe a bug or not necessary.

karussell commented 7 years ago

Yes, they are not necessary. It is like you thought: an 'incoming' filter for X would also add X->A as the flags are fine. But then it is confusing why we need A->X ... probably to avoid the overhead of reverting the geometry for A<-X everytime A is accessed. For clarity we should fix this.

stefanholder commented 7 years ago

For clarity we should fix this.

Yes, the current behavior is quite confusing. Should we create a separate Github issue for this?

karussell commented 7 years ago

Created https://github.com/graphhopper/graphhopper/issues/892

stefanholder commented 7 years ago

Good question :) ... in theory it should be indeed 4 but there are only 2 - the outgoing ones, not sure why the incoming are not added. Maybe a bug or not necessary.

I had a deeper look at @kodonnell's first commit 31e1d6d368f7c7f0f9aa5c3db751c4a2dad1878e since I think that this is a good starting point. It is asserted there that we always get 2 virtual edges per virtual node and we are using a DefaultEdgeFilter that does not do any forward/backward filtering. Hence, to me it seems that QueryGraph behaves as if there is only one virtual edge between a virtual node and each of its neighbors (in our example there is only A-X and X-B). However, since we can access the same virtual edge from each of its two neighboring nodes, each virtual edge is stored twice with reversed base node / adj node. For each virtual node X, only the edges are stored and returned where X is the base node.

stefanholder commented 7 years ago

I tried to prevent inner-link U-turns as described above but this turned out to be complicated than I thought, so I think we should stick to unfavor virtual edges.

In 31e1d6d368f7c7f0f9aa5c3db751c4a2dad1878e, I tried to narrow down the unit test failures by generating a single undirected candidate for each virtual node (i.e. removing this). This should be equivalent to what happened before this pull request but still 8 tests failed. @kodonnell, can you please check and fix this? Afterwards we have a good foundation to finish this PR. (I would suggest to create a new branch from 31e1d6d368f7c7f0f9aa5c3db751c4a2dad1878e and to then use this new branch in this PR).

I'm not sure if we need to unfavor both virtual edges between A and X. If we do, we can retrieve the other edge just before setUnfavored(true) instead of using VirtualEdgePair.

kodonnell commented 7 years ago

See here, which seems relevant to your comment ... and maybe implies that the last commit is worth a look too = ) Note that there should (?) be a check (after the above selection) that the edges are actually unique ...

kodonnell commented 7 years ago

@kodonnell, can you please check and fix this?

I'm not sure what I'm checking, sorry. Are you saying that if I remove that code it should work (and tests just need tweaking), or you think it should work if I remove the code but you don't know why it isn't?

Afterwards we have a good foundation to finish this PR

I thought that original commit was fundamentally wrong = )

stefanholder commented 7 years ago

Currently I think it's still perfectly viable to go A -> B via B_north, then B -> C via B_south, and hence get an inner-link U-turns.

It's important to distinguish between GPS positions and candidates. (I should have made the distinction more clear for A and C.) We never go to GPS positions such as B (in general these can't even be reached because they are not on the road). There can only be A -> B_north -> C or A -> B_south -> C but not A -> B_north -> B -> B_south -> C.

I think you're saying is we share the same incoming/outgoing edge

Correct. This is ensured because in each candidate sequence (including the final most likely sequence) there is one candidate per time step.

stefanholder commented 7 years ago

I'm not sure what I'm checking, sorry. Are you saying that if I remove that code it should work (and tests just need tweaking), or you think it should work if I remove the code but you don't know why it isn't?

You did some refactoring to MapMatching.java such as introducing filterGPXEntries before actually creating directed candidates for virtual nodes. When I tried to remove the latter, I still got unit test errors. So we should first make sure that the refactorings pass all unit tests before adding new functionality. This means splitting 31e1d6d368f7c7f0f9aa5c3db751c4a2dad1878e into a refactoring and a "directed candidate" commit.

stefanholder commented 7 years ago

See here, which seems relevant to your comment

I think that unfavoring 3 out of the 4 virtual edges is too much since we want to unfavor only one travel direction. If we have A-X-B then we need to unfavor either A-X or X-B. In case of A-X this means unfavoring X->A and maybe also A->X, where "->" means base node -> adj node.

I think that there is a bug in reversing the virtual edge here. The commented out code line above should be correct. If needed, this can be used just before setUnfavored(true), so we don't need to create a VirtualEdgePair or DirectedVirtualEdgeQuadruple.

kodonnell commented 7 years ago

So we should first make sure that the refactorings pass all unit tests before adding new functionality

OK, known bug (which I referred to right at the start and was fixed in later commits) - here should have gpxList instead of filteredGPXList. That said, I think the unit tests are not helpfully constructed anyway (i.e. comparing the distance calculated from the GPX and the matched route).

I think that unfavoring 3 out of the 4 virtual edges is too much since we want to unfavor only one travel direction

I believe my thinking was that if we have A---X---B, and want to favour X->B, then we have to unfavour A-->X and X-->A, as well as B-->X. Maybe it's redundant ... dunno.

I think that there is a bug in reversing the virtual edge here. The comment line above should be correct.

It's bed time here in NZ - how about you make the changes you see fit, and I'll check in the morning?

karussell commented 7 years ago

That said, I think the unit tests are not helpfully constructed anyway (i.e. comparing the distance calculated from the GPX and the matched route).

Please try to be constructive. I.e. please continue to show where you have problems (!), but also describe how you would improve this or even provide a PR :). Without this - it won't improve.

stefanholder commented 7 years ago

here should have gpxList instead of filteredGPXList

Thanks, this fixed it.

I used QueryGraph.enforceHeadingByEdgeId to unfavor virtual edge pairs. The testIssue70 unit test is now successful but the mm-uturns*.txt examples still have U-turns for some gps_accuracy values (including default value). I will have a closer look at the generated candidates to better understand what's going on. It's really strange that in these examples U-turns are either present or absent for different gps_accuracy values.

karussell commented 7 years ago

It's really strange that in these examples U-turns are either present or absent for different gps_accuracy values

maybe with a big gps_accuracy value we get candidates not only from the edge but also from neighbouring edges and those the hmm can avoid going directly to the node. Would this explain your observations?

kodonnell commented 7 years ago

Please try to be constructive

Fair point - though it is noted in the PR. As above, I'm kind of ignoring this side of things until we know the inner link stuff will (or won't) work - which I'm still not clear on.

but the mm-uturns*.txt examples still have U-turns for some gps_accuracy values

Doesn't this go back to my first comment in the PR? I.e. I still don't see how (with the current approach) we can enforce directions on a given timestep when we don't know the actual direction to enforce it to.

stefanholder commented 7 years ago

maybe with a big gps_accuracy value we get candidates not only from the edge but also from neighbouring edges and those the hmm can avoid going directly to the node. Would this explain your observations?

The U-turn in mm-uturns1.txt should already be avoided with gps_accuracy=50. Maybe not all candidates are generated as they should.

Doesn't this go back to my first comment in the PR? I.e. I still don't see how (with the current approach) we can enforce directions on a given timestep when we don't know the actual direction to enforce it to.

Sorry, I don't know how else to explain this. Each virtual node candidate stores its direction via its incoming/outgoing edge and hence we know which directions to enforce (by unfavoring edges) when routing between adjacent candidates. The fact that the final candidate sequence is only computed in the end doesn't matter since in each step we route between all possible pairs of subsequent candidates.

kodonnell commented 7 years ago

Sorry, I don't know how else to explain this ...

I still don't understand, sorry! Oh well - if you can get it working, I'll see if I can figure it out from the code.

stefanholder commented 7 years ago

I still don't understand, sorry!

No worries!

if you can get it working, I'll see if I can figure it out from the code.

OK, let's try this.

stefanholder commented 7 years ago

Interestingly, running unit test testIssue70 and matching the same GPX file from the command line using the entire Serbia map gives different matching results even if sigma and beta are the same. With gps_accuracy=40, testIssue70 works while the command line doesn't.

Maybe unfavoring edges doesn't work for the routing configured in MapMatchingMain.java?

@kodonnell, @karussell, can you please explain to me how to use the same routing settings in MapMatchingMain.java as in testIssue70 (or maybe better change this in an additional commit)?