diff --git a/brouter-codec/src/main/java/btools/codec/MicroCache2.java b/brouter-codec/src/main/java/btools/codec/MicroCache2.java index fae63f3..ca3c1b3 100644 --- a/brouter-codec/src/main/java/btools/codec/MicroCache2.java +++ b/brouter-codec/src/main/java/btools/codec/MicroCache2.java @@ -170,9 +170,15 @@ public final class MicroCache2 extends MicroCache if ( !isReverse ) // write geometry for forward links only { WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher; - if ( matcher != null ) matcher.startNode( ilon, ilat, wayTags.data ); int ilontarget = ilon + dlon_remaining; int ilattarget = ilat + dlat_remaining; + if ( matcher != null ) + { + if ( !matcher.start( ilon, ilat, ilontarget, ilattarget ) ) + { + matcher = null; + } + } int transcount = bc.decodeVarBits(); if ( debug ) System.out.println( "*** decoding geometry with count=" + transcount ); @@ -194,7 +200,7 @@ public final class MicroCache2 extends MicroCache if ( matcher != null ) matcher.transferNode( ilontarget - dlon_remaining, ilattarget - dlat_remaining ); } - if ( matcher != null ) matcher.endNode( ilontarget, ilattarget ); + if ( matcher != null ) matcher.end(); } if ( wayTags != null ) { diff --git a/brouter-codec/src/main/java/btools/codec/WaypointMatcher.java b/brouter-codec/src/main/java/btools/codec/WaypointMatcher.java index f71cc52..f7770e0 100644 --- a/brouter-codec/src/main/java/btools/codec/WaypointMatcher.java +++ b/brouter-codec/src/main/java/btools/codec/WaypointMatcher.java @@ -7,7 +7,7 @@ package btools.codec; */ public interface WaypointMatcher { - void startNode( int ilon, int ilat, byte[] wayTags ); + boolean start( int ilonStart, int ilatStart, int ilonTarget, int ilatTarget ); void transferNode( int ilon, int ilat ); - void endNode( int ilon, int ilat ); + void end(); } diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java index 7a08e3f..4c28dde 100644 --- a/brouter-core/src/main/java/btools/router/RoutingEngine.java +++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java @@ -15,6 +15,7 @@ import btools.mapaccess.NodesCache; import btools.mapaccess.OsmLink; import btools.mapaccess.OsmLinkHolder; import btools.mapaccess.OsmNode; +import btools.mapaccess.OsmNodePairSet; import btools.mapaccess.OsmNodesMap; import btools.util.SortedHeap; import btools.util.StackSampler; @@ -31,6 +32,8 @@ public class RoutingEngine extends Thread private int linksProcessed = 0; private int nodeLimit; // used for target island search + private int MAXNODES_ISLAND_CHECK = 500; + private OsmNodePairSet islandNodePairs = new OsmNodePairSet(MAXNODES_ISLAND_CHECK); protected OsmTrack foundTrack = new OsmTrack(); private OsmTrack foundRawTrack = null; @@ -329,9 +332,24 @@ public class RoutingEngine extends Thread terminate(); } - - private OsmTrack findTrack( OsmTrack[] refTracks, OsmTrack[] lastTracks ) + { + for(;;) + { + try + { + return tryFindTrack( refTracks, lastTracks ); + } + catch( RoutingIslandException rie ) + { + islandNodePairs.freezeTempPairs(); + nodesCache.clean( true ); + matchedWaypoints = null; + } + } + } + + private OsmTrack tryFindTrack( OsmTrack[] refTracks, OsmTrack[] lastTracks ) { OsmTrack totaltrack = new OsmTrack(); int nUnmatched = waypoints.size(); @@ -378,7 +396,7 @@ public class RoutingEngine extends Thread airDistanceCostFactor = 0.; for( int i=0; i unmatchedWaypoints ) { resetCache( false ); - nodesCache.waypointMatcher = new WaypointMatcherImpl( unmatchedWaypoints, 250. ); + nodesCache.waypointMatcher = new WaypointMatcherImpl( unmatchedWaypoints, 250., islandNodePairs ); for( MatchedWaypoint mwp : unmatchedWaypoints ) { preloadPosition( mwp.waypoint ); @@ -468,7 +486,10 @@ public class RoutingEngine extends Thread for( int idxLat=-1; idxLat<=1; idxLat++ ) for( int idxLon=-1; idxLon<=1; idxLon++ ) { - nodesCache.loadSegmentFor( n.ilon + d*idxLon , n.ilat +d*idxLat ); + if ( idxLon != 0 || idxLat != 0 ) + { + nodesCache.loadSegmentFor( n.ilon + d*idxLon , n.ilat +d*idxLat ); + } } } @@ -609,6 +630,7 @@ public class RoutingEngine extends Thread long maxmem = routingContext.memoryclass * 131072L; // 1/8 of total nodesCache = new NodesCache(segmentDir, nodesMap, routingContext.expctxWay, routingContext.forceSecondaryData, maxmem, nodesCache, detailed ); + islandNodePairs.clearTempPairs(); } private OsmNode getStartNode( long startId ) @@ -742,7 +764,7 @@ public class RoutingEngine extends Thread } finally { - nodesCache.cleanNonVirgin(); + nodesCache.clean( false ); // clean only non-virgin caches } } @@ -879,6 +901,10 @@ public class RoutingEngine extends Thread OsmNode currentNode = path.getTargetNode(); long currentNodeId = currentNode.getIdFromPos(); + long sourceNodeId = sourceNode.getIdFromPos(); + + islandNodePairs.addTempPair( sourceNodeId, currentNodeId ); + if ( path.treedepth != 1 ) { if ( path.treedepth == 0 ) // hack: sameSegment Paths marked treedepth=0 to pass above check @@ -886,7 +912,6 @@ public class RoutingEngine extends Thread path.treedepth = 1; } - long sourceNodeId = sourceNode.getIdFromPos(); if ( ( sourceNodeId == endNodeId1 && currentNodeId == endNodeId2 ) || ( sourceNodeId == endNodeId2 && currentNodeId == endNodeId1 ) ) { @@ -1126,6 +1151,12 @@ public class RoutingEngine extends Thread path.unregisterUpTree( routingContext ); } + + if ( nodesVisited < MAXNODES_ISLAND_CHECK && islandNodePairs.getFreezeCount() < 5 ) + { + throw new RoutingIslandException(); + } + return null; } diff --git a/brouter-core/src/main/java/btools/router/RoutingIslandException.java b/brouter-core/src/main/java/btools/router/RoutingIslandException.java new file mode 100644 index 0000000..2475227 --- /dev/null +++ b/brouter-core/src/main/java/btools/router/RoutingIslandException.java @@ -0,0 +1,5 @@ +package btools.router; + +public class RoutingIslandException extends RuntimeException +{ +} diff --git a/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java b/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java index 4266dd3..626b758 100644 --- a/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java +++ b/brouter-core/src/main/java/btools/router/WaypointMatcherImpl.java @@ -4,6 +4,7 @@ import java.util.List; import btools.codec.WaypointMatcher; import btools.mapaccess.OsmNode; +import btools.mapaccess.OsmNodePairSet; /** * the WaypointMatcher is feeded by the decoder with geoemtries of ways that are @@ -15,16 +16,20 @@ import btools.mapaccess.OsmNode; public final class WaypointMatcherImpl implements WaypointMatcher { private List waypoints; + private OsmNodePairSet islandPairs; private int lonStart; private int latStart; + private int lonTarget; + private int latTarget; private boolean anyUpdate; private int lonLast; private int latLast; - public WaypointMatcherImpl( List waypoints, double maxDistance ) + public WaypointMatcherImpl( List waypoints, double maxDistance, OsmNodePairSet islandPairs ) { this.waypoints = waypoints; + this.islandPairs = islandPairs; for ( MatchedWaypoint mwp : waypoints ) { mwp.radius = maxDistance * 110984.; // 6378000. / 57.3; @@ -105,11 +110,23 @@ public final class WaypointMatcherImpl implements WaypointMatcher } @Override - public void startNode( int ilon, int ilat, byte[] wayTags ) + public boolean start( int ilonStart, int ilatStart, int ilonTarget, int ilatTarget ) { - lonLast = lonStart = ilon; - latLast = latStart = ilat; + if ( islandPairs.size() > 0 ) + { + long n1 = ( (long) ilonStart ) << 32 | ilatStart; + long n2 = ( (long) ilonTarget ) << 32 | ilatTarget; + if ( islandPairs.hasPair( n1, n2 ) ) + { + return false; + } + } + lonLast = lonStart = ilonStart; + latLast = latStart = ilatStart; + lonTarget = ilonTarget; + latTarget = ilatTarget; anyUpdate = false; + return true; } @Override @@ -121,9 +138,9 @@ public final class WaypointMatcherImpl implements WaypointMatcher } @Override - public void endNode( int ilon, int ilat ) + public void end() { - checkSegment( lonLast, latLast, ilon, ilat ); + checkSegment( lonLast, latLast, lonTarget, latTarget ); if ( anyUpdate ) { for ( MatchedWaypoint mwp : waypoints ) @@ -132,7 +149,7 @@ public final class WaypointMatcherImpl implements WaypointMatcher { mwp.hasUpdate = false; mwp.node1 = new OsmNode( lonStart, latStart ); - mwp.node2 = new OsmNode( ilon, ilat ); + mwp.node2 = new OsmNode( lonTarget, latTarget ); } } } diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java b/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java index 976a443..3efa97f 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java @@ -110,7 +110,7 @@ public final class NodesCache ghostSum = cacheSum; } - public void cleanNonVirgin() + public void clean( boolean all ) { for ( OsmFile[] fileRow : fileRows ) { @@ -118,7 +118,7 @@ public final class NodesCache continue; for ( OsmFile osmf : fileRow ) { - osmf.cleanNonVirgin(); + osmf.clean( all); } } } diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java index 9f4461f..f548fa8 100644 --- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmFile.java @@ -217,7 +217,7 @@ final class OsmFile return deleted; } - void cleanNonVirgin() + void clean( boolean all ) { int nc = microCaches == null ? 0 : microCaches.length; for ( int i = 0; i < nc; i++ ) @@ -225,7 +225,7 @@ final class OsmFile MicroCache mc = microCaches[i]; if ( mc == null ) continue; - if ( !mc.virgin ) + if ( all || !mc.virgin ) { microCaches[i] = null; } diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNodePairSet.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNodePairSet.java new file mode 100644 index 0000000..7e930b3 --- /dev/null +++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNodePairSet.java @@ -0,0 +1,122 @@ +/** + * Set holding pairs of osm nodes + * + * @author ab + */ +package btools.mapaccess; + +import btools.util.CompactLongMap; + +public class OsmNodePairSet +{ + private long[] n1a; + private long[] n2a; + private int tempNodes = 0; + private int maxTempNodes = 0; + private int npairs = 0; + private int freezecount = 0; + + public OsmNodePairSet( int maxTempNodeCount ) + { + maxTempNodes = maxTempNodeCount; + n1a = new long[maxTempNodes]; + n2a = new long[maxTempNodes]; + } + + private static class OsmNodePair + { + public long node2; + public OsmNodePair next; + } + + private CompactLongMap map; + + public void addTempPair( long n1, long n2 ) + { + if ( tempNodes < maxTempNodes ) + { + n1a[tempNodes] = n1; + n2a[tempNodes] = n2; + tempNodes++; + } + } + + public void freezeTempPairs() + { + freezecount++; + for( int i=0; i(); + } + npairs++; + + OsmNodePair e = getElement( n1, n2 ); + if ( e == null ) + { + e = new OsmNodePair(); + e.node2 = n2; + + OsmNodePair e0 = map.get( n1 ); + if ( e0 != null ) + { + while( e0.next != null ) + { + e0 = e0.next; + } + e0.next = e; + } + else + { + map.fastPut( n1, e ); + } + } + } + + public int size() + { + return npairs; + } + + public int tempSize() + { + return tempNodes; + } + + public int getFreezeCount() + { + return freezecount; + } + + public boolean hasPair( long n1, long n2 ) + { + return map != null && ( getElement( n1, n2 ) != null || getElement( n2, n1 ) != null ); + } + + private OsmNodePair getElement( long n1, long n2 ) + { + OsmNodePair e = map.get( n1 ); + while (e != null) + { + if ( e.node2 == n2 ) + { + return e; + } + e = e.next; + } + return null; + } +}