@@ -183,18 +183,29 @@ public MatchResult doWork(List<GPXEntry> gpxList) {
183
183
// now find each of the entries in the graph:
184
184
final EdgeFilter edgeFilter = new DefaultEdgeFilter (algoOptions .getWeighting ().getFlagEncoder ());
185
185
186
- List <List <QueryResult >> queriesPerEntry = lookupGPXEntries (filteredGPXEntries , edgeFilter );
186
+ List <Collection <QueryResult >> queriesPerEntry =
187
+ lookupGPXEntries (filteredGPXEntries , edgeFilter );
187
188
188
- // now look up the entries up in the graph:
189
+ // Add virtual nodes and edges to the graph so that candidates on edges can be represented
190
+ // by virtual nodes.
189
191
final QueryGraph queryGraph = new QueryGraph (routingGraph ).setUseEdgeExplorerCache (true );
190
192
List <QueryResult > allQueryResults = new ArrayList <>();
191
- for (List <QueryResult > qrs : queriesPerEntry )
193
+ for (Collection <QueryResult > qrs : queriesPerEntry )
192
194
allQueryResults .addAll (qrs );
193
195
queryGraph .lookup (allQueryResults );
194
196
197
+ // Different QueryResults can have the same tower node as their closest node.
198
+ // Hence, we now dedupe the query results of each GPX entry by their closest node (#91).
199
+ // This must be done after calling queryGraph.lookup() since this replaces some of the
200
+ // QueryResult nodes with virtual nodes. Virtual nodes are not deduped since there is at
201
+ // most one QueryResult per edge and virtual nodes are inserted into the middle of an edge.
202
+ // Reducing the number of QueryResults improves performance since less shortest/fastest
203
+ // routes need to be computed.
204
+ queriesPerEntry = dedupeQueryResultsByClosestNode (queriesPerEntry );
205
+
195
206
logger .debug ("================= Query results =================" );
196
207
int i = 1 ;
197
- for (List <QueryResult > entries : queriesPerEntry ) {
208
+ for (Collection <QueryResult > entries : queriesPerEntry ) {
198
209
logger .debug ("Query results for GPX entry {}" , i ++);
199
210
for (QueryResult qr : entries ) {
200
211
logger .debug ("Node id: {}, virtual: {}, snapped on: {}, pos: {},{}, "
@@ -269,26 +280,41 @@ private List<GPXEntry> filterGPXEntries(List<GPXEntry> gpxList) {
269
280
}
270
281
271
282
/**
272
- * Find the possible locations of each qpxEntry in the graph.
283
+ * Find the possible locations (edges) of each GPXEntry in the graph.
273
284
*/
274
- private List <List <QueryResult >> lookupGPXEntries (List <GPXEntry > gpxList ,
285
+ private List <Collection <QueryResult >> lookupGPXEntries (List <GPXEntry > gpxList ,
275
286
EdgeFilter edgeFilter ) {
276
287
277
- List <List <QueryResult >> gpxEntryLocations = new ArrayList <>();
288
+ final List <Collection <QueryResult >> gpxEntryLocations = new ArrayList <>();
278
289
for (GPXEntry gpxEntry : gpxList ) {
279
- gpxEntryLocations .add (locationIndex .findNClosest (gpxEntry .lat , gpxEntry .lon , edgeFilter ,
280
- measurementErrorSigma ));
290
+ final List <QueryResult > queryResults = locationIndex .findNClosest (
291
+ gpxEntry .lat , gpxEntry .lon , edgeFilter , measurementErrorSigma );
292
+ gpxEntryLocations .add (queryResults );
281
293
}
282
294
return gpxEntryLocations ;
283
295
}
284
296
297
+ private List <Collection <QueryResult >> dedupeQueryResultsByClosestNode (
298
+ List <Collection <QueryResult >> queriesPerEntry ) {
299
+ final List <Collection <QueryResult >> result = new ArrayList <>(queriesPerEntry .size ());
300
+
301
+ for (Collection <QueryResult > queryResults : queriesPerEntry ) {
302
+ final Map <Integer , QueryResult > dedupedQueryResults = new HashMap <>();
303
+ for (QueryResult qr : queryResults ) {
304
+ dedupedQueryResults .put (qr .getClosestNode (), qr );
305
+ }
306
+ result .add (dedupedQueryResults .values ());
307
+ }
308
+ return result ;
309
+ }
310
+
285
311
/**
286
312
* Creates TimeSteps with candidates for the GPX entries but does not create emission or
287
313
* transition probabilities. Creates directed candidates for virtual nodes and undirected
288
314
* candidates for real nodes.
289
315
*/
290
316
private List <TimeStep <GPXExtension , GPXEntry , Path >> createTimeSteps (
291
- List <GPXEntry > filteredGPXEntries , List <List <QueryResult >> queriesPerEntry ,
317
+ List <GPXEntry > filteredGPXEntries , List <Collection <QueryResult >> queriesPerEntry ,
292
318
QueryGraph queryGraph ) {
293
319
final int n = filteredGPXEntries .size ();
294
320
if (queriesPerEntry .size () != n ) {
@@ -300,7 +326,7 @@ private List<TimeStep<GPXExtension, GPXEntry, Path>> createTimeSteps(
300
326
for (int i = 0 ; i < n ; i ++) {
301
327
302
328
GPXEntry gpxEntry = filteredGPXEntries .get (i );
303
- List <QueryResult > queryResults = queriesPerEntry .get (i );
329
+ final Collection <QueryResult > queryResults = queriesPerEntry .get (i );
304
330
305
331
List <GPXExtension > candidates = new ArrayList <>();
306
332
for (QueryResult qr : queryResults ) {
@@ -512,7 +538,7 @@ private double penalizedPathDistance(Path path,
512
538
513
539
private MatchResult computeMatchResult (List <SequenceState <GPXExtension , GPXEntry , Path >> seq ,
514
540
List <GPXEntry > gpxList ,
515
- List <List <QueryResult >> queriesPerEntry ,
541
+ List <Collection <QueryResult >> queriesPerEntry ,
516
542
EdgeExplorer explorer ) {
517
543
final Map <String , EdgeIteratorState > virtualEdgesMap = createVirtualEdgesMap (
518
544
queriesPerEntry , explorer );
@@ -611,10 +637,10 @@ private boolean isVirtualNode(int node) {
611
637
* Returns a map where every virtual edge maps to its real edge with correct orientation.
612
638
*/
613
639
private Map <String , EdgeIteratorState > createVirtualEdgesMap (
614
- List <List <QueryResult >> queriesPerEntry , EdgeExplorer explorer ) {
640
+ List <Collection <QueryResult >> queriesPerEntry , EdgeExplorer explorer ) {
615
641
// TODO For map key, use the traversal key instead of string!
616
642
Map <String , EdgeIteratorState > virtualEdgesMap = new HashMap <>();
617
- for (List <QueryResult > queryResults : queriesPerEntry ) {
643
+ for (Collection <QueryResult > queryResults : queriesPerEntry ) {
618
644
for (QueryResult qr : queryResults ) {
619
645
if (isVirtualNode (qr .getClosestNode ())) {
620
646
EdgeIterator iter = explorer .setBaseNode (qr .getClosestNode ());
0 commit comments