diff --git a/brouter-codec/pom.xml b/brouter-codec/pom.xml
index 6436e1e..daf0ce4 100644
--- a/brouter-codec/pom.xml
+++ b/brouter-codec/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-codec
diff --git a/brouter-codec/src/main/java/btools/codec/MicroCache2.java b/brouter-codec/src/main/java/btools/codec/MicroCache2.java
index 01675d0..79291bb 100644
--- a/brouter-codec/src/main/java/btools/codec/MicroCache2.java
+++ b/brouter-codec/src/main/java/btools/codec/MicroCache2.java
@@ -56,6 +56,8 @@ public final class MicroCache2 extends MicroCache
faid = size > dataBuffers.ibuf2.length ? new int[size] : dataBuffers.ibuf2;
fapos = size > dataBuffers.ibuf3.length ? new int[size] : dataBuffers.ibuf3;
+
+
int[] alon = size > dataBuffers.alon.length ? new int[size] : dataBuffers.alon;
int[] alat = size > dataBuffers.alat.length ? new int[size] : dataBuffers.alat;
@@ -73,7 +75,9 @@ public final class MicroCache2 extends MicroCache
int netdatasize = bc.decodeNoisyNumber( 10 );
ab = netdatasize > dataBuffers.bbuf1.length ? new byte[netdatasize] : dataBuffers.bbuf1;
aboffset = 0;
- BitSet validNodes = new BitSet( size );
+
+ int[] validBits = new int[(size+31)>>5];
+
int finaldatasize = 0;
LinkedListContainer reverseLinks = new LinkedListContainer( size, dataBuffers.ibuf1 );
@@ -130,12 +134,12 @@ public final class MicroCache2 extends MicroCache
writeVarLengthSigned( dlon_remaining );
writeVarLengthSigned( dlat_remaining );
- validNodes.set( n, true ); // mark source-node valid
+ validBits[ n >> 5 ] |= 1 << n; // mark source-node valid
if ( nodeIdx != n ) // valid internal (forward-) link
{
reverseLinks.addDataElement( nodeIdx, n ); // register reverse link
finaldatasize += 1 + aboffset-startPointer; // reserve place for reverse
- validNodes.set( nodeIdx, true ); // mark target-node valid
+ validBits[ nodeIdx >> 5 ] |= 1 << nodeIdx; // mark target-node valid
}
writeModeAndDesc( isReverse, wayTags.data );
}
@@ -179,15 +183,16 @@ public final class MicroCache2 extends MicroCache
// calculate final data size
int finalsize = 0;
+ int startpos = 0;
for( int i=0; i 0 ? fapos[i-1] : 0;
int endpos = fapos[i];
- if ( validNodes.get( i ) )
+ if ( ( validBits[ i >> 5 ] & (1 << i ) ) != 0 )
{
finaldatasize += endpos-startpos;
finalsize++;
}
+ startpos = endpos;
}
// append the reverse links at the end of each node
byte[] abOld = ab;
@@ -200,34 +205,36 @@ public final class MicroCache2 extends MicroCache
aboffset = 0;
size = 0;
- for( int n=0; n 0 ? faposOld[n-1] : 0;
int endpos = faposOld[n];
- int len = endpos-startpos;
- System.arraycopy( abOld, startpos, ab, aboffset, len );
- if ( debug ) System.out.println( "*** copied " + len + " bytes from " + aboffset + " for node " + n );
- aboffset += len;
-
- int cnt = reverseLinks.initList( n );
- if ( debug ) System.out.println( "*** appending " + cnt + " reverse links for node " + n );
-
- for( int ri = 0; ri < cnt; ri++ )
+ if ( ( validBits[ n >> 5 ] & (1 << n ) ) != 0 )
{
- int nodeIdx = reverseLinks.getDataElement();
- int sizeoffset = writeSizePlaceHolder();
- writeVarLengthSigned( alon[nodeIdx] - alon[n] );
- writeVarLengthSigned( alat[nodeIdx] - alat[n] );
- writeModeAndDesc( true, null );
- injectSize( sizeoffset );
+ int len = endpos - startpos;
+ System.arraycopy( abOld, startpos, ab, aboffset, len );
+ if ( debug )
+ System.out.println( "*** copied " + len + " bytes from " + aboffset + " for node " + n );
+ aboffset += len;
+
+ int cnt = reverseLinks.initList( n );
+ if ( debug )
+ System.out.println( "*** appending " + cnt + " reverse links for node " + n );
+
+ for ( int ri = 0; ri < cnt; ri++ )
+ {
+ int nodeIdx = reverseLinks.getDataElement();
+ int sizeoffset = writeSizePlaceHolder();
+ writeVarLengthSigned( alon[nodeIdx] - alon[n] );
+ writeVarLengthSigned( alat[nodeIdx] - alat[n] );
+ writeModeAndDesc( true, null );
+ injectSize( sizeoffset );
+ }
+ faid[size] = faidOld[n];
+ fapos[size] = aboffset;
+ size++;
}
- faid[size] = faidOld[n];
- fapos[size] = aboffset;
- size++;
+ startpos = endpos;
}
init( size );
}
diff --git a/brouter-codec/src/main/java/btools/codec/TagValueValidator.java b/brouter-codec/src/main/java/btools/codec/TagValueValidator.java
index b5a1a2f..6cfb54c 100644
--- a/brouter-codec/src/main/java/btools/codec/TagValueValidator.java
+++ b/brouter-codec/src/main/java/btools/codec/TagValueValidator.java
@@ -13,4 +13,5 @@ public interface TagValueValidator
public boolean isLookupIdxUsed( int idx );
+ public void setDecodeForbidden( boolean decodeForbidden );
}
diff --git a/brouter-core/pom.xml b/brouter-core/pom.xml
index 090dae2..2d87404 100644
--- a/brouter-core/pom.xml
+++ b/brouter-core/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-core
diff --git a/brouter-core/src/main/java/btools/router/OsmPath.java b/brouter-core/src/main/java/btools/router/OsmPath.java
index 3e853cc..1c9a443 100644
--- a/brouter-core/src/main/java/btools/router/OsmPath.java
+++ b/brouter-core/src/main/java/btools/router/OsmPath.java
@@ -31,7 +31,9 @@ final class OsmPath implements OsmLinkHolder
public int airdistance = 0; // distance to endpos
- private OsmNode sourcenode;
+ private OsmNode sourceNode;
+ private OsmNode targetNode;
+
private OsmLink link;
public OsmPathElement originElement;
public OsmPathElement myElement;
@@ -86,10 +88,11 @@ final class OsmPath implements OsmLinkHolder
{
this();
this.link = link;
- this.selev = link.targetNode.getSElev();
+ targetNode = link.getTarget( null );
+ selev = targetNode.getSElev();
}
- OsmPath( OsmNode sourcenode, OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
+ OsmPath( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
{
this();
if ( origin.myElement == null )
@@ -98,7 +101,8 @@ final class OsmPath implements OsmLinkHolder
}
this.originElement = origin.myElement;
this.link = link;
- this.sourcenode = sourcenode;
+ this.sourceNode = origin.targetNode;
+ this.targetNode = link.getTarget( sourceNode );
this.cost = origin.cost;
this.ehbd = origin.ehbd;
this.ehbu = origin.ehbu;
@@ -120,7 +124,7 @@ final class OsmPath implements OsmLinkHolder
int lon0 = origin.originLon;
int lat0 = origin.originLat;
- OsmNode p1 = origin.link.targetNode;
+ OsmNode p1 = sourceNode;
int lon1 = p1.getILon();
int lat1 = p1.getILat();
short ele1 = origin.selev;
@@ -129,8 +133,10 @@ final class OsmPath implements OsmLinkHolder
MessageData msgData = recordMessageData ? new MessageData() : null;
+ boolean isReverse = link.isReverse( sourceNode );
+
// evaluate the way tags
- rc.expctxWay.evaluate( rc.inverseDirection ^ link.counterLinkWritten, description );
+ rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
// calculate the costfactor inputs
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
@@ -163,9 +169,8 @@ final class OsmPath implements OsmLinkHolder
// OsmTransferNode transferNode = link.decodeGeometry( p1, rc.byteDataReaderGeometry, rc.transferNodeCache );
OsmTransferNode transferNode = link.geometry == null ? null
- : rc.geometryDecoder.decodeGeometry( link.geometry, p1, link.targetNode, link.counterLinkWritten );
+ : rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
- OsmNode targetNode = link.targetNode;
for(;;)
{
originLon = lon1;
@@ -355,7 +360,7 @@ final class OsmPath implements OsmLinkHolder
msgData.lon = lon2;
msgData.lat = lat2;
msgData.ele = ele2;
- msgData.wayKeyValues = rc.expctxWay.getKeyValueDescription( link.counterLinkWritten, description );
+ msgData.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
}
if ( stopAtEndpoint )
@@ -379,7 +384,7 @@ final class OsmPath implements OsmLinkHolder
if ( transferNode == null )
{
// *** penalty for being part of the reference track
- if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( origin.link.targetNode ) )
+ if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( sourceNode ) )
{
int reftrackcost = linkdisttotal;
cost += reftrackcost;
@@ -465,7 +470,12 @@ final class OsmPath implements OsmLinkHolder
public OsmNode getSourceNode()
{
- return sourcenode;
+ return sourceNode;
+ }
+
+ public OsmNode getTargetNode()
+ {
+ return targetNode;
}
public OsmLink getLink()
diff --git a/brouter-core/src/main/java/btools/router/OsmPathElement.java b/brouter-core/src/main/java/btools/router/OsmPathElement.java
index f382479..d061ca7 100644
--- a/brouter-core/src/main/java/btools/router/OsmPathElement.java
+++ b/brouter-core/src/main/java/btools/router/OsmPathElement.java
@@ -67,7 +67,7 @@ public class OsmPathElement implements OsmPos
// construct a path element from a path
public static final OsmPathElement create( OsmPath path, boolean countTraffic )
{
- OsmNode n = path.getLink().targetNode;
+ OsmNode n = path.getTargetNode();
OsmPathElement pe = create( n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic );
pe.cost = path.cost;
pe.message = path.message;
diff --git a/brouter-core/src/main/java/btools/router/OsmTrack.java b/brouter-core/src/main/java/btools/router/OsmTrack.java
index 5e872c5..2678a1d 100644
--- a/brouter-core/src/main/java/btools/router/OsmTrack.java
+++ b/brouter-core/src/main/java/btools/router/OsmTrack.java
@@ -390,7 +390,7 @@ public final class OsmTrack
}
else
{
- sb.append( " creator=\"BRouter-1.4.4\" version=\"1.1\">\n" );
+ sb.append( " creator=\"BRouter-1.4.6\" version=\"1.1\">\n" );
}
if ( turnInstructionMode == 3) // osmand style
diff --git a/brouter-core/src/main/java/btools/router/RoutingContext.java b/brouter-core/src/main/java/btools/router/RoutingContext.java
index 053b954..59e9cc0 100644
--- a/brouter-core/src/main/java/btools/router/RoutingContext.java
+++ b/brouter-core/src/main/java/btools/router/RoutingContext.java
@@ -175,7 +175,7 @@ public final class RoutingContext
}
if ( goodGuy ) nogos.add( nogo );
}
- nogopoints = nogos;
+ nogopoints = nogos.isEmpty() ? null : nogos;
}
public long[] getNogoChecksums()
diff --git a/brouter-core/src/main/java/btools/router/RoutingEngine.java b/brouter-core/src/main/java/btools/router/RoutingEngine.java
index b51df5d..04755c9 100644
--- a/brouter-core/src/main/java/btools/router/RoutingEngine.java
+++ b/brouter-core/src/main/java/btools/router/RoutingEngine.java
@@ -58,6 +58,8 @@ public class RoutingEngine extends Thread
public boolean quite = false;
+ private Object[] extract;
+
public RoutingEngine( String outfileBase, String logfileBase, String segmentDir,
List waypoints, RoutingContext rc )
{
@@ -149,6 +151,7 @@ public class RoutingEngine extends Thread
routingContext.cleanNogolist( waypoints );
startTime = System.currentTimeMillis();
+ long startTime0 = startTime;
this.maxRunningTime = maxRunningTime;
int nsections = waypoints.size() - 1;
OsmTrack[] refTracks = new OsmTrack[nsections]; // used ways for alternatives
@@ -208,24 +211,21 @@ public class RoutingEngine extends Thread
break;
}
long endTime = System.currentTimeMillis();
- logInfo( "execution time = " + (endTime-startTime)/1000. + " seconds" );
+ logInfo( "execution time = " + (endTime-startTime0)/1000. + " seconds" );
}
catch( IllegalArgumentException e)
{
- errorMessage = e.getMessage();
- logInfo( "Exception (linksProcessed=" + linksProcessed + ": " + errorMessage );
+ logException( e );
}
catch( Exception e)
{
- errorMessage = e instanceof IllegalArgumentException ? e.getMessage() : e.toString();
- logInfo( "Exception (linksProcessed=" + linksProcessed + ": " + errorMessage );
+ logException( e );
logThrowable( e );
}
catch( Error e)
{
cleanOnOOM();
- errorMessage = e.toString();
- logInfo( "Error (linksProcessed=" + linksProcessed + ": " + errorMessage );
+ logException( e );
logThrowable( e );
}
finally
@@ -264,6 +264,13 @@ public class RoutingEngine extends Thread
}
}
+ private void logException( Throwable t )
+ {
+ errorMessage = t instanceof IllegalArgumentException ? t.getMessage() : t.toString();
+ logInfo( "Error (linksProcessed=" + linksProcessed + " open paths: " + openSet.getSize() + "): " + errorMessage );
+ }
+
+
public void doSearch()
{
try
@@ -280,20 +287,17 @@ public class RoutingEngine extends Thread
}
catch( IllegalArgumentException e)
{
- errorMessage = e.getMessage();
- logInfo( "Exception (linksProcessed=" + linksProcessed + ": " + errorMessage );
+ logException( e );
}
catch( Exception e)
{
- errorMessage = e instanceof IllegalArgumentException ? e.getMessage() : e.toString();
- logInfo( "Exception (linksProcessed=" + linksProcessed + ": " + errorMessage );
+ logException( e );
logThrowable( e );
}
catch( Error e)
{
cleanOnOOM();
- errorMessage = e.toString();
- logInfo( "Error (linksProcessed=" + linksProcessed + ": " + errorMessage );
+ logException( e );
logThrowable( e );
}
finally
@@ -404,7 +408,7 @@ public class RoutingEngine extends Thread
// geometric position matching finding the nearest routable way-section
private void matchWaypointsToNodes( List unmatchedWaypoints )
{
- resetCache();
+ resetCache( false );
nodesCache.waypointMatcher = new WaypointMatcherImpl( unmatchedWaypoints, 250. );
for( MatchedWaypoint mwp : unmatchedWaypoints )
{
@@ -446,9 +450,9 @@ public class RoutingEngine extends Thread
// expand hollow link targets and resolve reverse links
private void expandHollowLinkTargets( OsmNode n )
{
- for( OsmLink link = n.firstlink; link != null; link = link.next )
+ for( OsmLink link = n.firstlink; link != null; link = link.getNext( n ) )
{
- nodesCache.obtainNonHollowNode( link.targetNode );
+ nodesCache.obtainNonHollowNode( link.getTarget( n ) );
}
}
@@ -567,7 +571,7 @@ public class RoutingEngine extends Thread
}
- private void resetCache()
+ private void resetCache( boolean detailed )
{
if ( hasInfo() && nodesCache != null )
{
@@ -575,9 +579,9 @@ public class RoutingEngine extends Thread
}
nodesMap = new OsmNodesMap();
- long maxmem = routingContext.memoryclass * 131072L; // 1/4 of total
+ long maxmem = routingContext.memoryclass * 131072L; // 1/8 of total
- nodesCache = new NodesCache(segmentDir, nodesMap, routingContext.expctxWay, routingContext.forceSecondaryData, maxmem, nodesCache );
+ nodesCache = new NodesCache(segmentDir, nodesMap, routingContext.expctxWay, routingContext.forceSecondaryData, maxmem, nodesCache, detailed );
}
private OsmNode getStartNode( long startId )
@@ -645,21 +649,20 @@ public class RoutingEngine extends Thread
routingContext.setWaypoint( wp, false );
OsmPath bestPath = null;
OsmLink bestLink = null;
- OsmLink startLink = new OsmLink();
- startLink.targetNode = n1;
+ OsmLink startLink = new OsmLink( null, n1 );
OsmPath startPath = new OsmPath( startLink );
- startLink.addLinkHolder( startPath );
+ startLink.addLinkHolder( startPath, null );
double minradius = 1e10;
- for( OsmLink link = n1.firstlink; link != null; link = link.next )
+ for( OsmLink link = n1.firstlink; link != null; link = link.getNext( n1 ) )
{
- OsmNode nextNode = link.targetNode;
+ OsmNode nextNode = link.getTarget( n1 );
if ( nextNode.isHollow() ) continue; // border node?
if ( nextNode.firstlink == null ) continue; // don't care about dead ends
if ( nextNode == n1 ) continue; // ?
if ( nextNode != n2 ) continue; // just that link
wp.radius = 1e9;
- OsmPath testPath = new OsmPath( null, startPath, link, null, guideTrack != null, routingContext );
+ OsmPath testPath = new OsmPath( startPath, link, null, guideTrack != null, routingContext );
testPath.airdistance = endPos == null ? 0 : nextNode.calcDistance( endPos );
if ( wp.radius < minradius )
{
@@ -670,7 +673,7 @@ public class RoutingEngine extends Thread
}
if ( bestLink != null )
{
- bestLink.addLinkHolder( bestPath );
+ bestLink.addLinkHolder( bestPath, n1 );
}
bestPath.treedepth = 1;
@@ -687,14 +690,13 @@ public class RoutingEngine extends Thread
try
{
if ( wp != null ) routingContext.setWaypoint( wp, true );
- OsmLink startLink = new OsmLink();
- startLink.targetNode = n1;
+ OsmLink startLink = new OsmLink( null, n1 );
OsmPath startPath = new OsmPath( startLink );
- startLink.addLinkHolder( startPath );
+ startLink.addLinkHolder( startPath, null );
if ( wp != null ) wp.radius = 1e-5;
- return new OsmPath( n1, startPath, link, null, guideTrack != null, routingContext );
+ return new OsmPath( startPath, link, null, guideTrack != null, routingContext );
}
finally
{
@@ -706,7 +708,8 @@ public class RoutingEngine extends Thread
{
try
{
- resetCache();
+ boolean detailed = guideTrack != null;
+ resetCache( detailed );
return _findTrack( operationName, startWp, endWp, costCuttingTrack, refTrack, fastPartialRecalc );
}
finally
@@ -742,11 +745,11 @@ public class RoutingEngine extends Thread
OsmNode start1 = getStartNode( startNodeId1 );
if ( start1 == null ) return null;
OsmNode start2 = null;
- for( OsmLink link = start1.firstlink; link != null; link = link.next )
+ for( OsmLink link = start1.firstlink; link != null; link = link.getNext( start1 ) )
{
- if ( link.targetNode.getIdFromPos() == startNodeId2 )
+ if ( link.getTarget( start1 ).getIdFromPos() == startNodeId2 )
{
- start2 = link.targetNode;
+ start2 = link.getTarget( start1 );
break;
}
}
@@ -826,8 +829,8 @@ public class RoutingEngine extends Thread
linksProcessed++;
OsmLink currentLink = path.getLink();
- OsmNode currentNode = currentLink.targetNode;
OsmNode sourceNode = path.getSourceNode();
+ OsmNode currentNode = path.getTargetNode();
long currentNodeId = currentNode.getIdFromPos();
if ( sourceNode != null )
@@ -872,6 +875,21 @@ public class RoutingEngine extends Thread
}
}
+ OsmLinkHolder firstLinkHolder = currentLink.getFirstLinkHolder( sourceNode );
+ for( OsmLinkHolder linkHolder = firstLinkHolder; linkHolder != null; linkHolder = linkHolder.getNextForLink() )
+ {
+ ((OsmPath)linkHolder).airdistance = -1; // invalidate the entry in the open set;
+ }
+
+ boolean isBidir = currentLink.isBidirectional();
+ sourceNode.unlinkLink ( currentLink );
+
+ // if the counterlink is alive and does not yet have a path, remove it
+ if ( isBidir && currentLink.getFirstLinkHolder( currentNode ) == null )
+ {
+ currentNode.unlinkLink(currentLink);
+ }
+
// recheck cutoff before doing expensive stuff
if ( path.cost + path.airdistance > maxTotalCost + 10 )
{
@@ -879,19 +897,11 @@ public class RoutingEngine extends Thread
continue;
}
- expandHollowLinkTargets( currentNode );
-
- if ( sourceNode != null )
+ for( OsmLink link = currentNode.firstlink; link != null; link = link.getNext( currentNode) )
{
- sourceNode.unlinkLink ( currentLink );
- }
+ OsmNode nextNode = link.getTarget( currentNode );
- OsmLink counterLink = null;
- for( OsmLink link = currentNode.firstlink; link != null; link = link.next )
- {
- OsmNode nextNode = link.targetNode;
-
- if ( nextNode.isHollow() )
+ if ( ! nodesCache.obtainNonHollowNode( nextNode ) )
{
continue; // border node?
}
@@ -901,7 +911,6 @@ public class RoutingEngine extends Thread
}
if ( nextNode == sourceNode )
{
- counterLink = link;
continue; // border node?
}
@@ -919,7 +928,7 @@ public class RoutingEngine extends Thread
// not along the guide-track, discard, but register for voice-hint processing
if ( routingContext.turnInstructionMode > 0 )
{
- OsmPath detour = new OsmPath( currentNode, path, link, refTrack, true, routingContext );
+ OsmPath detour = new OsmPath( path, link, refTrack, true, routingContext );
if ( detour.cost >= 0. && nextId != startNodeId1 && nextId != startNodeId2 )
{
guideTrack.registerDetourForId( currentNode.getIdFromPos(), OsmPathElement.create( detour, false ) );
@@ -932,7 +941,7 @@ public class RoutingEngine extends Thread
OsmPath bestPath = null;
boolean isFinalLink = false;
- long targetNodeId = link.targetNode.getIdFromPos();
+ long targetNodeId = nextNode.getIdFromPos();
if ( currentNodeId == endNodeId1 || currentNodeId == endNodeId2 )
{
if ( targetNodeId == endNodeId1 || targetNodeId == endNodeId2 )
@@ -941,7 +950,7 @@ public class RoutingEngine extends Thread
}
}
- for( OsmLinkHolder linkHolder = currentLink.firstlinkholder; linkHolder != null; linkHolder = linkHolder.getNextForLink() )
+ for( OsmLinkHolder linkHolder = firstLinkHolder; linkHolder != null; linkHolder = linkHolder.getNextForLink() )
{
OsmPath otherPath = (OsmPath)linkHolder;
try
@@ -951,7 +960,7 @@ public class RoutingEngine extends Thread
endPos.radius = 1e-5;
routingContext.setWaypoint( endPos, true );
}
- OsmPath testPath = new OsmPath( currentNode, otherPath, link, refTrack, guideTrack != null, routingContext );
+ OsmPath testPath = new OsmPath( otherPath, link, refTrack, guideTrack != null, routingContext );
if ( testPath.cost >= 0 && ( bestPath == null || testPath.cost < bestPath.cost ) )
{
bestPath = testPath;
@@ -961,10 +970,6 @@ public class RoutingEngine extends Thread
{
routingContext.unsetWaypoint();
}
- if ( otherPath != path )
- {
- otherPath.airdistance = -1; // invalidate the entry in the open set
- }
}
if ( bestPath != null )
{
@@ -977,7 +982,7 @@ public class RoutingEngine extends Thread
if ( inRadius && ( isFinalLink || bestPath.cost + bestPath.airdistance <= maxTotalCost + 10 ) )
{
// add only if this may beat an existing path for that link
- OsmLinkHolder dominator = link.firstlinkholder;
+ OsmLinkHolder dominator = link.getFirstLinkHolder( currentNode );
while( !trafficSim && dominator != null )
{
if ( bestPath.definitlyWorseThan( (OsmPath)dominator, routingContext ) )
@@ -987,28 +992,24 @@ public class RoutingEngine extends Thread
dominator = dominator.getNextForLink();
}
- if ( dominator == null )
- {
+ if ( dominator == null )
+ {
if ( trafficSim && boundary != null && path.cost == 0 && bestPath.cost > 0 )
{
bestPath.airdistance += boundary.getBoundaryDistance( nextNode );
}
bestPath.treedepth = path.treedepth + 1;
- link.addLinkHolder( bestPath );
+ link.addLinkHolder( bestPath, currentNode );
synchronized( openSet )
{
addToOpenset( bestPath );
}
- }
+ }
}
}
}
- // if the counterlink does not yet have a path, remove it
- if ( counterLink != null && counterLink.firstlinkholder == null )
- {
- currentNode.unlinkLink(counterLink);
- }
+
path.unregisterUpTree( routingContext );
}
return null;
@@ -1023,22 +1024,6 @@ public class RoutingEngine extends Thread
}
}
- private int preloadRing( OsmNode n, int ring )
- {
- int d = 12500;
- int c = 0;
- for( int idxLat=-ring; idxLat<=ring; idxLat++ )
- for( int idxLon=-ring; idxLon<=ring; idxLon++ )
- {
- int absLat = idxLat < 0 ? -idxLat : idxLat;
- int absLon = idxLon < 0 ? -idxLon : idxLon;
- int max = absLat > absLon ? absLat : absLon;
- if ( max < ring ) continue;
- c += nodesCache.loadSegmentFor( n.ilon + d*idxLon , n.ilat +d*idxLat );
- }
- return c;
- }
-
private OsmTrack compileTrack( OsmPath path, boolean verbose )
{
OsmPathElement element = OsmPathElement.create( path, false );
@@ -1137,8 +1122,21 @@ public class RoutingEngine extends Thread
return track;
}
+ public int getPathPeak()
+ {
+ synchronized( openSet )
+ {
+ return openSet.getPeakSize();
+ }
+ }
+
public int[] getOpenSet()
{
+ if ( extract == null )
+ {
+ extract = new Object[500];
+ }
+
synchronized( openSet )
{
if ( guideTrack != null )
@@ -1154,14 +1152,15 @@ public class RoutingEngine extends Thread
return res;
}
- List extract = openSet.getExtract();
- int[] res = new int[extract.size() * 2];
- int i = 0;
- for( OsmPath p : extract )
+ int size = openSet.getExtract(extract);
+ int[] res = new int[size * 2];
+ for( int i=0, j=0; i
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-expressions
diff --git a/brouter-expressions/src/main/java/btools/expressions/BExpressionContextWay.java b/brouter-expressions/src/main/java/btools/expressions/BExpressionContextWay.java
index 77d3426..3adea96 100644
--- a/brouter-expressions/src/main/java/btools/expressions/BExpressionContextWay.java
+++ b/brouter-expressions/src/main/java/btools/expressions/BExpressionContextWay.java
@@ -8,10 +8,10 @@ package btools.expressions;
import btools.codec.TagValueValidator;
-
-
public final class BExpressionContextWay extends BExpressionContext implements TagValueValidator
{
+ private boolean decodeForbidden = true;
+
private static String[] buildInVariables =
{ "costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask" };
@@ -61,6 +61,12 @@ public final class BExpressionContextWay extends BExpressionContext implements T
minCostFactor = reverseCostFactor;
}
}
- return minCostFactor < 9999.f ? 2 : minCostFactor < 10000.f ? 1 : 0;
+ return minCostFactor < 9999.f ? 2 : decodeForbidden ? (minCostFactor < 10000.f ? 1 : 0) : 0;
+ }
+
+ @Override
+ public void setDecodeForbidden( boolean decodeForbidden )
+ {
+ this.decodeForbidden= decodeForbidden;
}
}
diff --git a/brouter-map-creator/pom.xml b/brouter-map-creator/pom.xml
index a7499b2..6b7e10f 100644
--- a/brouter-map-creator/pom.xml
+++ b/brouter-map-creator/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-map-creator
diff --git a/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java b/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java
index bbeb89e..bce6451 100644
--- a/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java
+++ b/brouter-map-creator/src/main/java/btools/mapcreator/OsmLinkP.java
@@ -68,7 +68,7 @@ public class OsmLinkP
return next;
}
else if ( targetNode == source )
- {
+ {
return previous;
}
else
diff --git a/brouter-mapaccess/pom.xml b/brouter-mapaccess/pom.xml
index 56ae527..8ee4a4f 100644
--- a/brouter-mapaccess/pom.xml
+++ b/brouter-mapaccess/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-mapaccess
diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java b/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java
index b36cb2c..976a443 100644
--- a/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java
+++ b/brouter-mapaccess/src/main/java/btools/mapaccess/NodesCache.java
@@ -38,6 +38,7 @@ public final class NodesCache
private long cacheSum = 0;
private long maxmem;
+ private boolean detailed;
private boolean garbageCollectionEnabled = false;
private boolean ghostCleaningDone = false;
@@ -52,7 +53,7 @@ public final class NodesCache
return "collecting=" + garbageCollectionEnabled + " noGhosts=" + ghostCleaningDone + " cacheSum=" + cacheSum + " cacheSumClean=" + cacheSumClean + " ghostSum=" + ghostSum + " ghostWakeup=" + ghostWakeup ;
}
- public NodesCache( String segmentDir, OsmNodesMap nodesMap, BExpressionContextWay ctxWay, boolean forceSecondaryData, long maxmem, NodesCache oldCache )
+ public NodesCache( String segmentDir, OsmNodesMap nodesMap, BExpressionContextWay ctxWay, boolean forceSecondaryData, long maxmem, NodesCache oldCache, boolean detailed )
{
this.segmentDir = new File( segmentDir );
this.nodesMap = nodesMap;
@@ -61,6 +62,12 @@ public final class NodesCache
this.lookupMinorVersion = ctxWay.meta.lookupMinorVersion;
this.forceSecondaryData = forceSecondaryData;
this.maxmem = maxmem;
+ this.detailed = detailed;
+
+ if ( ctxWay != null )
+ {
+ ctxWay.setDecodeForbidden( detailed );
+ }
first_file_access_failed = false;
first_file_access_name = null;
@@ -74,17 +81,24 @@ public final class NodesCache
dataBuffers = oldCache.dataBuffers;
secondarySegmentsDir = oldCache.secondarySegmentsDir;
- // re-use old, virgin caches
- fileRows = oldCache.fileRows;
- for ( OsmFile[] fileRow : fileRows )
+ // re-use old, virgin caches (if same detail-mode)
+ if ( oldCache.detailed == detailed)
{
- if ( fileRow == null )
- continue;
- for ( OsmFile osmf : fileRow )
+ fileRows = oldCache.fileRows;
+ for ( OsmFile[] fileRow : fileRows )
{
- cacheSum += osmf.setGhostState();
+ if ( fileRow == null )
+ continue;
+ for ( OsmFile osmf : fileRow )
+ {
+ cacheSum += osmf.setGhostState();
+ }
}
}
+ else
+ {
+ fileRows = new OsmFile[180][];
+ }
}
else
{
@@ -113,7 +127,7 @@ public final class NodesCache
// clean all ghosts and enable garbage collection
private void checkEnableCacheCleaning()
{
- if ( cacheSum < maxmem || ghostCleaningDone )
+ if ( cacheSum < maxmem )
{
return;
}
@@ -127,7 +141,7 @@ public final class NodesCache
}
for ( OsmFile osmf : fileRow )
{
- if ( garbageCollectionEnabled )
+ if ( garbageCollectionEnabled && !ghostCleaningDone )
{
cacheSum -= osmf.cleanGhosts();
}
@@ -141,6 +155,7 @@ public final class NodesCache
if ( garbageCollectionEnabled )
{
ghostCleaningDone = true;
+ maxmem *= 2;
}
else
{
diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java
index 11bfba6..bbaf9fe 100644
--- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java
+++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmLink.java
@@ -10,36 +10,168 @@ package btools.mapaccess;
public class OsmLink
{
/**
- * The description bitmap is mainly the way description
- * used to calculate the costfactor
+ * The description bitmap contains the waytags (valid for both directions)
*/
public byte[] descriptionBitmap;
- public OsmNode targetNode;
-
- public OsmLink next;
-
- public OsmLinkHolder firstlinkholder = null;
-
+ /**
+ * The geometry contains intermediate nodes, null for none (valid for both directions)
+ */
public byte[] geometry;
- public boolean counterLinkWritten;
+ // a link logically knows only its target, but for the reverse link, source and target are swapped
+ protected OsmNode n1;
+ protected OsmNode n2;
- public byte state;
+ // same for the next-link-for-node pointer: previous applies to the reverse link
+ protected OsmLink previous;
+ protected OsmLink next;
- public void setGeometry( byte[] geometry )
+ private OsmLinkHolder reverselinkholder = null;
+ private OsmLinkHolder firstlinkholder = null;
+
+ protected OsmLink()
{
- this.geometry = geometry;
}
- final public void addLinkHolder( OsmLinkHolder holder )
- {
- if ( firstlinkholder != null ) { holder.setNextForLink( firstlinkholder ); }
- firstlinkholder = holder;
- }
+ public OsmLink( OsmNode source, OsmNode target )
+ {
+ n1 = source;
+ n2 = target;
+ }
- public String toString()
+ /**
+ * Get the relevant target-node for the given source
+ */
+ public final OsmNode getTarget( OsmNode source )
+ {
+ return n2 != source && n2 != null ? n2 : n1;
+/* if ( n2 != null && n2 != source )
+ {
+ return n2;
+ }
+ else if ( n1 != null && n1 != source )
+ {
+ return n1;
+ }
+ else
+ {
+ new Throwable( "ups" ).printStackTrace();
+ throw new IllegalArgumentException( "internal error: getTarget: unknown source; " + source + " n1=" + n1 + " n2=" + n2 );
+ } */
+ }
+
+ /**
+ * Get the relevant next-pointer for the given source
+ */
+ public final OsmLink getNext( OsmNode source )
+ {
+ return n2 != source && n2 != null ? next : previous;
+/* if ( n2 != null && n2 != source )
+ {
+ return next;
+ }
+ else if ( n1 != null && n1 != source )
+ {
+ return previous;
+ }
+ else
+ {
+ throw new IllegalArgumentException( "internal error: gextNext: unknown source" );
+ } */
+ }
+
+ /**
+ * Reset this link for the given direction
+ */
+ protected final OsmLink clear( OsmNode source )
+ {
+ OsmLink n;
+ if ( n2 != null && n2 != source )
+ {
+ n = next;
+ next = null;
+ n2 = null;
+ firstlinkholder = null;
+ }
+ else if ( n1 != null && n1 != source )
+ {
+ n = previous;
+ previous = null;
+ n1 = null;
+ reverselinkholder = null;
+ }
+ else
+ {
+ throw new IllegalArgumentException( "internal error: setNext: unknown source" );
+ }
+ if ( n1 == null && n2 == null )
+ {
+ descriptionBitmap = null;
+ geometry = null;
+ }
+ return n;
+ }
+
+ public final void setFirstLinkHolder( OsmLinkHolder holder, OsmNode source )
+ {
+ if ( n2 != null && n2 != source )
+ {
+ firstlinkholder = holder;
+ }
+ else if ( n1 != null && n1 != source )
+ {
+ reverselinkholder = holder;
+ }
+ else
+ {
+ throw new IllegalArgumentException( "internal error: setFirstLinkHolder: unknown source" );
+ }
+ }
+
+ public final OsmLinkHolder getFirstLinkHolder( OsmNode source )
+ {
+ if ( n2 != null && n2 != source )
+ {
+ return firstlinkholder;
+ }
+ else if ( n1 != null && n1 != source )
+ {
+ return reverselinkholder;
+ }
+ else
+ {
+ throw new IllegalArgumentException( "internal error: getFirstLinkHolder: unknown source" );
+ }
+ }
+
+ public final boolean isReverse( OsmNode source )
+ {
+ return n1 != source && n1 != null;
+/* if ( n2 != null && n2 != source )
+ {
+ return false;
+ }
+ else if ( n1 != null && n1 != source )
{
- return "Link(target=" + targetNode.getIdFromPos() + " counterLinkWritten=" + counterLinkWritten + " state=" + state + ")";
- }
+ return true;
+ }
+ else
+ {
+ throw new IllegalArgumentException( "internal error: isReverse: unknown source" );
+ } */
+ }
+
+ public final boolean isBidirectional()
+ {
+ return n1 != null && n2 != null;
+ }
+
+ public final void addLinkHolder( OsmLinkHolder holder, OsmNode source )
+ {
+ OsmLinkHolder firstHolder = getFirstLinkHolder( source );
+ if ( firstHolder != null ) { holder.setNextForLink( firstHolder ); }
+ setFirstLinkHolder( holder, source );
+ }
+
}
diff --git a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
index 96bfb02..f68b27e 100644
--- a/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
+++ b/brouter-mapaccess/src/main/java/btools/mapaccess/OsmNode.java
@@ -11,8 +11,33 @@ import btools.expressions.BExpressionContextWay;
import btools.util.ByteArrayUnifier;
import btools.util.IByteArrayUnifier;
-public class OsmNode implements OsmPos
+public class OsmNode extends OsmLink implements OsmPos
{
+ /**
+ * The latitude
+ */
+ public int ilat;
+
+ /**
+ * The longitude
+ */
+ public int ilon;
+
+ /**
+ * The elevation
+ */
+ public short selev;
+
+ /**
+ * The node-tags, if any
+ */
+ public byte[] nodeDescription;
+
+ /**
+ * The links to other nodes
+ */
+ public OsmLink firstlink = null;
+
public OsmNode()
{
}
@@ -29,22 +54,6 @@ public class OsmNode implements OsmPos
ilat = (int) ( id & 0xffffffff );
}
- /**
- * The latitude
- */
- public int ilat;
-
- /**
- * The longitude
- */
- public int ilon;
-
- /**
- * The elevation
- */
- public short selev;
-
- public byte[] nodeDescription;
// interface OsmPos
public final int getILat()
@@ -67,58 +76,28 @@ public class OsmNode implements OsmPos
return selev / 4.;
}
- /**
- * The links to other nodes
- */
- public OsmLink firstlink = null;
-
- // preliminry in forward order to avoid regressions
- public final void addLink( OsmLink link )
+ private void addLink( OsmLink link, boolean isReverse, OsmNode tn )
{
- if ( firstlink == null )
+ if ( isReverse )
{
+ link.n1 = tn;
+ link.n2 = this;
+ link.next = tn.firstlink;
+ link.previous = firstlink;
+ tn.firstlink = link;
firstlink = link;
}
else
{
- OsmLink l = firstlink;
- while (l.next != null)
- l = l.next;
- l.next = link;
+ link.n1 = this;
+ link.n2 = tn;
+ link.next = firstlink;
+ link.previous = tn.firstlink;
+ tn.firstlink = link;
+ firstlink = link;
}
}
- private OsmLink getCompatibleLink( int ilon, int ilat, boolean counterLinkWritten, int state )
- {
- for ( OsmLink l = firstlink; l != null; l = l.next )
- {
- if ( counterLinkWritten == l.counterLinkWritten && l.state == state )
- {
- OsmNode t = l.targetNode;
- if ( t.ilon == ilon && t.ilat == ilat )
- {
- l.state = 0;
- return l;
- }
- }
- }
- // second try ignoring counterLinkWritten
- // (border links are written in both directions)
- for ( OsmLink l = firstlink; l != null; l = l.next )
- {
- if ( l.state == state )
- {
- OsmNode t = l.targetNode;
- if ( t.ilon == ilon && t.ilat == ilat )
- {
- l.state = 0;
- return l;
- }
- }
- }
- return null;
- }
-
public final int calcDistance( OsmPos p )
{
double l = ( ilat - 90000000 ) * 0.00000001234134;
@@ -154,6 +133,8 @@ public class OsmNode implements OsmPos
selev = mc.readShort();
int nodeDescSize = mc.readVarLengthUnsigned();
nodeDescription = nodeDescSize == 0 ? null : mc.readUnified( nodeDescSize, abUnifier );
+
+ OsmLink link0 = firstlink;
while (mc.hasMoreData())
{
@@ -176,47 +157,42 @@ public class OsmNode implements OsmPos
continue; // skip self-ref
}
- // first check the known links for that target
- OsmLink link = getCompatibleLink( linklon, linklat, isReverse, 2 );
- if ( link == null ) // .. not found, then check the hollow nodes
+ OsmNode tn = null; // find the target node
+ OsmLink link = null;
+
+ // ...in our known links
+ for ( OsmLink l = link0; l != null; l = l.getNext( this ) )
{
- OsmNode tn = hollowNodes.get( linklon, linklat ); // target node
+ OsmNode t = l.getTarget( this );
+ if ( t.ilon == linklon && t.ilat == linklat )
+ {
+ tn = t;
+ if ( isReverse || ( l.descriptionBitmap == null && !l.isReverse( this ) ) )
+ {
+ link = l; // the correct one that needs our data
+ break;
+ }
+ }
+ }
+ if ( tn == null ) // .. not found, then check the hollow nodes
+ {
+ tn = hollowNodes.get( linklon, linklat ); // target node
if ( tn == null ) // node not yet known, create a new hollow proxy
{
tn = new OsmNode( linklon, linklat );
tn.setHollow();
hollowNodes.put( tn );
+ addLink( link = tn, isReverse, tn ); // technical inheritance: link instance in node
}
- link = new OsmLink();
- link.targetNode = tn;
- link.counterLinkWritten = isReverse;
- link.state = 1;
- addLink( link );
}
-
- // now we have a link with a target node -> get the reverse link
- OsmLink rlink = link.targetNode.getCompatibleLink( ilon, ilat, !isReverse, 1 );
- if ( rlink == null ) // .. not found, create it
+ if ( link == null )
{
- rlink = new OsmLink();
- rlink.targetNode = this;
- rlink.counterLinkWritten = !isReverse;
- rlink.state = 2;
- link.targetNode.addLink( rlink );
+ addLink( link = new OsmLink(), isReverse, tn );
}
-
if ( !isReverse )
{
- // we have the data for that link, so fill both the link ..
link.descriptionBitmap = description;
- link.setGeometry( geometry );
-
- // .. and the reverse
- if ( rlink.counterLinkWritten )
- {
- rlink.descriptionBitmap = description;
- rlink.setGeometry( geometry );
- }
+ link.geometry = geometry;
}
}
hollowNodes.remove( this );
@@ -240,21 +216,41 @@ public class OsmNode implements OsmPos
public final void unlinkLink( OsmLink link )
{
+ OsmLink n = link.clear( this );
+
if ( link == firstlink )
{
- firstlink = link.next;
+ firstlink = n;
return;
}
- for ( OsmLink l = firstlink; l != null; l = l.next )
+ OsmLink l = firstlink;
+ while( l != null )
{
- if ( l.next == link )
+ // if ( l.isReverse( this ) )
+ if ( l.n1 != this && l.n1 != null ) // isReverse inline
{
- l.next = link.next;
- return;
+ OsmLink nl = l.previous;
+ if ( nl == link )
+ {
+ l.previous = n;
+ return;
+ }
+ l = nl;
+ }
+ else
+ {
+ OsmLink nl = l.next;
+ if ( nl == link )
+ {
+ l.next = n;
+ return;
+ }
+ l = nl;
}
}
}
+
@Override
public final boolean equals( Object o )
{
diff --git a/brouter-mem-router/pom.xml b/brouter-mem-router/pom.xml
index d55a5ed..11810b2 100644
--- a/brouter-mem-router/pom.xml
+++ b/brouter-mem-router/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-mem-router
diff --git a/brouter-routing-app/AndroidManifest.xml b/brouter-routing-app/AndroidManifest.xml
index c8250b3..c8ead41 100644
--- a/brouter-routing-app/AndroidManifest.xml
+++ b/brouter-routing-app/AndroidManifest.xml
@@ -1,8 +1,8 @@
+ android:versionCode="17"
+ android:versionName="1.4.6" package="btools.routingapp">
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-routing-app
diff --git a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
index 73b58b1..d041fc4 100644
--- a/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
+++ b/brouter-routing-app/src/main/java/btools/routingapp/BRouterView.java
@@ -766,7 +766,8 @@ public class BRouterView extends View
}
else
{
- String result = "version = BRouter-1.4.4\n" + "memory-class = " + memoryClass + "\ndistance = " + cr.getDistance() / 1000. + " km\n" + "filtered ascend = " + cr.getAscend()
+ String memstat = memoryClass + "mb pathPeak " + ((cr.getPathPeak()+500)/1000) + "k";
+ String result = "version = BRouter-1.4.6\n" + "mem = " + memstat + "\ndistance = " + cr.getDistance() / 1000. + " km\n" + "filtered ascend = " + cr.getAscend()
+ " m\n" + "plain ascend = " + cr.getPlainAscend();
rawTrack = cr.getFoundRawTrack();
diff --git a/brouter-server/pom.xml b/brouter-server/pom.xml
index 10aba25..096c06c 100644
--- a/brouter-server/pom.xml
+++ b/brouter-server/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-server
diff --git a/brouter-server/src/main/java/btools/server/BRouter.java b/brouter-server/src/main/java/btools/server/BRouter.java
index 85c9f49..a1acf05 100644
--- a/brouter-server/src/main/java/btools/server/BRouter.java
+++ b/brouter-server/src/main/java/btools/server/BRouter.java
@@ -88,7 +88,7 @@ public class BRouter
}
System.exit(0);
}
- System.out.println("BRouter 1.4.4 / 29082016 / abrensch");
+ System.out.println("BRouter 1.4.6 / 30092016 / abrensch");
if ( args.length < 6 )
{
System.out.println("Find routes in an OSM map");
@@ -155,6 +155,7 @@ public class BRouter
c.setAlternativeIdx( Integer.parseInt( args[6] ) );
}
}
+ c.memoryclass = (int) ( Runtime.getRuntime().maxMemory() / 1024 / 1024 );
return c;
}
}
diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java
index d46dca4..772c929 100644
--- a/brouter-server/src/main/java/btools/server/RouteServer.java
+++ b/brouter-server/src/main/java/btools/server/RouteServer.java
@@ -155,7 +155,7 @@ public class RouteServer extends Thread
public static void main(String[] args) throws Exception
{
- System.out.println("BRouter 1.4.4 / 29082016");
+ System.out.println("BRouter 1.4.6 / 30092016");
if ( args.length != 5 )
{
System.out.println("serve BRouter protocol");
diff --git a/brouter-util/pom.xml b/brouter-util/pom.xml
index 545a67d..8f6ce81 100644
--- a/brouter-util/pom.xml
+++ b/brouter-util/pom.xml
@@ -5,7 +5,7 @@
org.btools
brouter
- 1.4.4
+ 1.4.6
../pom.xml
brouter-util
diff --git a/brouter-util/src/main/java/btools/util/SortedHeap.java b/brouter-util/src/main/java/btools/util/SortedHeap.java
index e89ec85..0953a6a 100644
--- a/brouter-util/src/main/java/btools/util/SortedHeap.java
+++ b/brouter-util/src/main/java/btools/util/SortedHeap.java
@@ -1,30 +1,19 @@
package btools.util;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Random;
/**
- * Memory efficient Heap to get the lowest-key value of a set of key-object pairs
+ * Memory efficient and lightning fast heap to get the lowest-key value of a set of key-object pairs
*
* @author ab
*/
public final class SortedHeap
{
- private int[][] al;
- private int[] lv; // low values
-
- private int[] nextNonEmpty;
- private int firstNonEmpty;
-
- private int[] lp; // the low pointers
-
- private Object[][] vla; // value list array
-
- protected static final int MAXLISTS = 28; // enough for size = ca Integer.MAX_VALUE
-
private int size;
- private boolean isClear = false;
+ private int peaksize;
+ private SortedBin first;
+ private SortedBin second;
+ private SortedBin firstNonEmpty;
public SortedHeap()
{
@@ -36,66 +25,111 @@ public final class SortedHeap
*/
public V popLowestKeyValue()
{
- int idx = firstNonEmpty;
- if ( idx < 0 )
+ SortedBin bin = firstNonEmpty;
+ if ( bin == null )
{
return null;
}
size--;
- int minId = lv[idx];
- int minIdx = idx;
- for (;;)
+ int minId = bin.lv;
+ SortedBin minBin = bin;
+ while( ( bin = bin.nextNonEmpty ) != null )
{
- idx = nextNonEmpty[idx];
- if ( idx < 0 )
+ if ( bin.lv < minId )
{
- return dropLowest( minIdx );
- }
- if ( lv[idx] < minId )
- {
- minId = lv[idx];
- minIdx = idx;
+ minId = bin.lv;
+ minBin = bin;
}
}
+ return (V) minBin.dropLowest();
}
- private V dropLowest( int idx )
+ private static final class SortedBin
{
- int lp_old = lp[idx]++;
- int lp_new = lp_old+1;
- if ( lp_new == 4 << idx )
+ SortedHeap parent;
+ SortedBin next;
+ SortedBin nextNonEmpty;
+ int binsize;
+ int[] al; // key array
+ Object[] vla; // value array
+ int lv; // low value
+ int lp; // low pointer
+
+ SortedBin( int binsize, SortedHeap parent )
{
- unlinkIdx( idx );
+ this.binsize = binsize;
+ this.parent = parent;
+ al = new int[binsize];
+ vla = new Object[binsize];
+ lp = binsize;
}
- else
+
+ SortedBin next()
{
- lv[idx] = al[idx][lp_new];
- }
- Object[] vlai = vla[idx];
- V res = (V) vlai[lp_old];
- vlai[lp_old] = null;
- return res;
- }
-
- private void unlinkIdx( int idx )
- {
- if ( idx == firstNonEmpty )
- {
- firstNonEmpty = nextNonEmpty[idx];
- return;
- }
- int i = firstNonEmpty;
- for(;;)
- {
- if ( nextNonEmpty[i] == idx )
+ if ( next == null )
{
- nextNonEmpty[i] = nextNonEmpty[idx];
+ next = new SortedBin( binsize << 1, parent );
+ }
+ return next;
+ }
+
+ Object dropLowest()
+ {
+ int lpOld = lp;
+ if ( ++lp == binsize )
+ {
+ unlink();
+ }
+ else
+ {
+ lv = al[lp];
+ }
+ Object res = vla[lpOld];
+ vla[lpOld] = null;
+ return res;
+ }
+
+ void unlink()
+ {
+ SortedBin neBin = parent.firstNonEmpty;
+ if ( neBin == this )
+ {
+ parent.firstNonEmpty = nextNonEmpty;
return;
}
- i = nextNonEmpty[i];
+ for(;;)
+ {
+ SortedBin next = neBin.nextNonEmpty;
+ if ( next == this )
+ {
+ neBin.nextNonEmpty = nextNonEmpty;
+ return;
+ }
+ neBin = next;
+ }
}
- }
+ void add( int key, Object value )
+ {
+ int p = lp;
+ for(;;)
+ {
+ if ( p == binsize || key < al[p] )
+ {
+ al[p-1] = key;
+ vla[p-1] = value;
+ lv = al[--lp];
+ return;
+ }
+ al[p-1] = al[p];
+ vla[p-1] = vla[p];
+ p++;
+ }
+ }
+
+
+ }
+
/**
* add a key value pair to the heap
*
@@ -106,182 +140,139 @@ public final class SortedHeap
*/
public void add( int key, V value )
{
- isClear = false;
size++;
- if ( lp[0] == 0 )
+ if ( first.lp == 0 && second.lp == 0) // both full ?
{
sortUp();
}
- int lp0 = lp[0];
-
- int[] al0 = al[0];
- Object[] vla0 = vla[0];
-
- for(;;)
+ if ( first.lp > 0 )
{
- if ( lp0 == 4 || key < al0[lp0] )
+ first.add( key, value );
+ if ( firstNonEmpty != first )
{
- al0[lp0-1] = key;
- vla0[lp0-1] = value;
- lv[0] = al0[--lp[0]];
- if ( firstNonEmpty != 0 )
- {
- nextNonEmpty[0] = firstNonEmpty;
- firstNonEmpty = 0;
- }
- return;
+ first.nextNonEmpty = firstNonEmpty;
+ firstNonEmpty = first;
}
- al0[lp0-1] = al0[lp0];
- vla0[lp0-1] = vla0[lp0];
- lp0++;
}
+ else // second bin not full
+ {
+ second.add( key, value );
+ if ( first.nextNonEmpty != second )
+ {
+ second.nextNonEmpty = first.nextNonEmpty;
+ first.nextNonEmpty = second;
+ }
+ }
+
}
private void sortUp()
{
- // determine the first array big enough to take them all
- int cnt = 4; // value count up to idx
- int idx = 1;
- int n = 8;
- int nonEmptyCount = 1;
-
- for ( ;; )
+ if ( size > peaksize )
{
- int nentries = n - lp[idx];
+ peaksize = size;
+ }
+
+ // determine the first array big enough to take them all
+ int cnt = 8; // value count of first 2 bins is always 8
+ SortedBin tbin = second; // target bin
+ SortedBin lastNonEmpty = second;
+ do
+ {
+ tbin = tbin.next();
+ int nentries = tbin.binsize - tbin.lp;
if ( nentries > 0 )
{
- cnt += n - lp[idx];
- nonEmptyCount++;
+ cnt += nentries;
+ lastNonEmpty = tbin;
}
- if ( cnt <= n )
- {
- break;
- }
- idx++;
- n <<= 1;
}
+ while( cnt > tbin.binsize );
- // create, if not yet
- if ( al[idx] == null )
+ int[] al_t = tbin.al;
+ Object[] vla_t = tbin.vla;
+ int tp = tbin.binsize-cnt; // target pointer
+
+ // unlink any higher, non-empty arrays
+ SortedBin otherNonEmpty = lastNonEmpty.nextNonEmpty;
+ lastNonEmpty.nextNonEmpty = null;
+
+ // now merge the content of these non-empty bins into the target bin
+ while( firstNonEmpty != null )
{
- al[idx] = new int[n];
- vla[idx] = new Object[n];
- }
+ SortedBin ne = firstNonEmpty;
+ SortedBin minBin = ne;
+ int minId = minBin.lv;
- int[] al_t = al[idx];
- Object[] vla_t = vla[idx];
- int tp = n-cnt; // target pointer
-
- // now merge the contents of arrays 0...idx into idx
- while( nonEmptyCount > 1 )
- {
- int neIdx = firstNonEmpty;
- int minIdx = neIdx;
- int minId = lv[minIdx];
-
- for ( int i = 1; i < nonEmptyCount; i++ )
+ while ( ( ne = ne.nextNonEmpty ) != null )
{
- neIdx = nextNonEmpty[neIdx];
- if ( lv[neIdx] < minId )
+ if ( ne.lv < minId )
{
- minIdx = neIdx;
- minId = lv[neIdx];
+ minBin = ne;
+ minId = minBin.lv;
}
}
// current minimum found, copy to target array
al_t[tp] = minId;
- vla_t[tp++] = dropLowest( minIdx );
-
- if ( lp[minIdx] == 4 << minIdx )
- {
- nonEmptyCount--;
- }
+ vla_t[tp++] = minBin.dropLowest();
}
- // only one non-empty index left, so just copy the remaining entries
- if ( firstNonEmpty != idx ) // no self-copy needed
- {
- int[] al_s = al[firstNonEmpty];
- Object[] vla_s = vla[firstNonEmpty];
- int sp = lp[firstNonEmpty]; // source-pointer
- while( sp < 4 << firstNonEmpty )
- {
- al_t[tp] = al_s[sp];
- vla_t[tp++] = vla_s[sp];
- vla_s[sp++] = null;
- }
- lp[firstNonEmpty] = sp;
- }
- unlinkIdx( firstNonEmpty );
- lp[idx] = n-cnt; // new target low pointer
- lv[idx] = al[idx][lp[idx]];
- nextNonEmpty[idx] = firstNonEmpty;
- firstNonEmpty = idx;
+ tp = tbin.binsize-cnt;
+ tbin.lp = tp; // new target low pointer
+ tbin.lv = tbin.al[tp];
+ tbin.nextNonEmpty = otherNonEmpty;
+ firstNonEmpty = tbin;
}
public void clear()
{
- if ( !isClear )
- {
- isClear = true;
- size = 0;
-
- lp = new int[MAXLISTS];
-
- // allocate key lists
- al = new int[MAXLISTS][];
- al[0] = new int[4]; // make the first array
-
- // same for the values
- vla = new Object[MAXLISTS][];
- vla[0] = new Object[4];
-
- lv = new int[MAXLISTS];
- nextNonEmpty = new int[MAXLISTS];
-
- firstNonEmpty = -1;
-
- int n = 4;
- for ( int idx = 0; idx < MAXLISTS; idx++ )
- {
- lp[idx] = n;
- n <<= 1;
- nextNonEmpty[idx] = -1; // no next
- }
- }
+ size = 0;
+ first = new SortedBin( 4, this );
+ second = new SortedBin( 4, this );
+ firstNonEmpty = null;
+ }
+
+ public int getSize()
+ {
+ return size;
}
- public List getExtract()
+ public int getPeakSize()
{
- int div = size / 1000 + 1;
+ return peaksize;
+ }
+
+ public int getExtract( Object[] targetArray )
+ {
+ int tsize = targetArray.length;
+ int div = size / tsize + 1;
+ int tp = 0;
- ArrayList res = new ArrayList( size / div + 1 );
int lpi = 0;
- for ( int i = 1;; i++ )
+ SortedBin bin = firstNonEmpty;
+ while( bin != null )
{
- int[] ali = al[i];
- if ( ali == null )
- break;
- lpi += lp[i];
- Object[] vlai = vla[i];
- int n = 4 << i;
+ lpi += bin.lp;
+ Object[] vlai = bin.vla;
+ int n = bin.binsize;
while (lpi < n)
{
- res.add( (V) vla[i][lpi] );
+ targetArray[tp++] = vlai[lpi];
lpi += div;
}
lpi -= n;
+ bin = bin.nextNonEmpty;
}
- return res;
+ return tp;
}
public static void main(String[] args)
{
SortedHeap sh = new SortedHeap();
Random rnd = new Random();
- for( int i = 0; i< 100; i++ )
+ for( int i = 0; i< 1000; i++ )
{
int val = rnd.nextInt( 1000000 );
sh.add( val, "" + val );
diff --git a/pom.xml b/pom.xml
index 7f7d333..7a0cd96 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
org.btools
brouter
- 1.4.4
+ 1.4.6
pom
http://brouter.de/brouter/
brouter