brouter/brouter-mem-router/src/main/java/btools/memrouter/GraphLoader.java

317 lines
9.1 KiB
Java

package btools.memrouter;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
import btools.mapaccess.OsmPos;
import btools.mapcreator.MapCreatorBase;
import btools.mapcreator.NodeData;
import btools.mapcreator.NodeIterator;
import btools.mapcreator.WayData;
import btools.mapcreator.WayIterator;
import btools.util.ByteArrayUnifier;
import btools.util.CompactLongMap;
import btools.util.FrozenLongMap;
import btools.util.LazyArrayOfLists;
/**
* GraphLoader loads the routing graph from
* the nodes+way files (much like mapcreator.WayLinker)
*
* @author ab
*/
public class GraphLoader extends MapCreatorBase
{
private CompactLongMap<OsmNodeP> nodesMap;
private Map<String, StationNode> stationMap;
private BExpressionContextWay expctxWay;
private ByteArrayUnifier abUnifier;
private int currentTile;
private long linksLoaded = 0L;
private long nodesLoaded = 0L;
private static final int MAXTILES = 2592;
private List<LazyArrayOfLists<OsmNodeP>> seglistsArray = new ArrayList<LazyArrayOfLists<OsmNodeP>>(2592);
public static void main(String[] args) throws Exception
{
System.out.println("*** GraphLoader: load a routing graph in memory");
if (args.length != 5)
{
System.out.println("usage: java GraphLoader <node-tiles-in> <way-tiles-in> <lookup-file> <profile-file> <fahtplan-file>");
return;
}
BExpressionMetaData meta = new BExpressionMetaData();
// read lookup + profile for lookup-version + access-filter
BExpressionContextWay expctxWay = new BExpressionContextWay(meta);
File lookupFile = new File( args[2] );
File profileFile = new File( args[3] );
meta.readMetaData( lookupFile );
expctxWay.parseFile( profileFile, "global" );
GraphLoader graph = new GraphLoader();
File[] fahrplanFiles = new File[2];
fahrplanFiles[0] = new File( args[4] );
fahrplanFiles[1] = new File( args[5] );
graph.process( new File( args[0] ), new File( args[1] ), fahrplanFiles, expctxWay );
}
public void process( File nodeTilesIn, File wayTilesIn, File[] fahrplanFiles, BExpressionContextWay expctxWay ) throws Exception
{
this.expctxWay = expctxWay;
seglistsArray = new ArrayList<LazyArrayOfLists<OsmNodeP>>(MAXTILES);
for( int i=0; i < MAXTILES; i++ )
{
seglistsArray.add( null );
}
abUnifier = new ByteArrayUnifier( 16384, false );
nodesMap = new CompactLongMap<OsmNodeP>();
// read all nodes
new NodeIterator( this, false ).processDir( nodeTilesIn, ".u5d" );
// freeze the nodes-map
nodesMap = new FrozenLongMap<OsmNodeP>( nodesMap );
// trim the list array
for( int i=0; i<MAXTILES; i++ )
{
if ( seglistsArray.get(i) != null )
{
seglistsArray.get(i).trimAll();
}
}
// then read the ways
new WayIterator( this, false ).processDir( wayTilesIn, ".wt5" );
nodesMap = null; // don't need that anymore
System.out.println( "nodesLoaded=" + nodesLoaded + " linksLoaded=" + linksLoaded );
// now load the train-schedules
stationMap = ScheduleParser.parseTrainTable( fahrplanFiles, this, expctxWay );
System.gc();
long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
System.out.println( "memory after graph loading: " + mem / 1024 / 1024 + " MB" );
}
public OsmNodeP matchNodeForPosition( OsmPos pos, BExpressionContextWay wayCtx, boolean transitonly )
{
if ( transitonly )
{
return matchStationForPosition( pos );
}
int ilon = pos.getILon();
int ilat = pos.getILat();
List<OsmNodeP> nodes = new ArrayList<OsmNodeP>();
nodes.addAll( subListForPos( ilon-6125, ilat-6125 ) );
nodes.addAll( subListForPos( ilon-6125, ilat+6125 ) );
nodes.addAll( subListForPos( ilon+6125, ilat-6125 ) );
nodes.addAll( subListForPos( ilon+6125, ilat+6125 ) );
int mindist = Integer.MAX_VALUE;
OsmNodeP bestmatch = null;
for( OsmNodeP node : nodes )
{
if ( transitonly )
{
StationNode sn = getStationNode( node );
if ( sn != null )
{
int dist = pos.calcDistance( sn );
if ( dist < mindist )
{
mindist = dist;
bestmatch = sn;
}
}
continue;
}
int dist = pos.calcDistance( node );
if ( dist < mindist )
{
if ( wayCtx == null || hasRoutableLinks(node, wayCtx) )
{
mindist = dist;
bestmatch = node;
}
}
}
return bestmatch;
}
private StationNode getStationNode( OsmNodeP node )
{
for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) )
{
OsmNodeP tn = link.getTarget( node );
if ( tn instanceof StationNode )
{
return (StationNode)tn;
}
}
return null;
}
public OsmNodeP matchStationForPosition( OsmPos pos )
{
int mindist = Integer.MAX_VALUE;
OsmNodeP bestmatch = null;
for( OsmNodeP node : stationMap.values() )
{
int dist = pos.calcDistance( node );
if ( dist < mindist )
{
mindist = dist;
bestmatch = node;
}
}
return bestmatch;
}
private boolean hasRoutableLinks( OsmNodeP node, BExpressionContextWay wayCtx )
{
for( OsmLinkP link = node.getFirstLink(); link != null; link = link.getNext( node ) )
{
if ( link.isWayLink() )
{
wayCtx.evaluate( false, link.descriptionBitmap );
if ( wayCtx.getCostfactor() < 10000.f )
{
return true;
}
}
}
return false;
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
currentTile = tileForFilename( nodefile.getName() );
seglistsArray.set(currentTile, new LazyArrayOfLists<OsmNodeP>(160000) );
System.out.println( "nodes currentTile=" + currentTile );
}
@Override
public void nextNode( NodeData data ) throws Exception
{
OsmNodeP n = data.description == null ? new OsmNodeP() : new OsmNodePT(data.description);
n.ilon = data.ilon;
n.ilat = data.ilat;
n.selev = data.selev;
// add to the map
nodesMap.fastPut( data.nid, n );
// add also to the list array
subListForPos( n.ilon, n.ilat ).add( n );
nodesLoaded++;
}
@Override
public boolean wayFileStart( File wayfile ) throws Exception
{
currentTile = tileForFilename( wayfile.getName() );
System.out.println( "ways currentTile=" + currentTile );
return true;
}
@Override
public void nextWay( WayData way ) throws Exception
{
byte[] description = abUnifier.unify( way.description );
byte wayBits = 0;
expctxWay.decode( description );
if ( !expctxWay.getBooleanLookupValue( "bridge" ) ) wayBits |= OsmNodeP.NO_BRIDGE_BIT;
if ( !expctxWay.getBooleanLookupValue( "tunnel" ) ) wayBits |= OsmNodeP.NO_TUNNEL_BIT;
OsmNodeP n1 = null;
OsmNodeP n2 = null;
for (int i=0; i<way.nodes.size(); i++)
{
long nid = way.nodes.get(i);
n1 = n2;
n2 = nodesMap.get( nid );
if ( n1 != null && n2 != null && n1 != n2 )
{
if ( tileForPos( n1.ilon, n1.ilat ) == currentTile )
{
OsmLinkP link = n2.createLink(n1);
link.descriptionBitmap = description;
linksLoaded++;
}
}
if ( n2 != null )
{
n2.wayBits |= wayBits;
}
}
}
// from BInstallerView.java
private int tileForFilename( String filename )
{
String basename = filename.substring( 0, filename.length() - 4 );
String uname = basename.toUpperCase();
int idx = uname.indexOf( "_" );
if ( idx < 0 ) return -1;
String slon = uname.substring( 0, idx );
String slat = uname.substring( idx+1 );
int ilon = slon.charAt(0) == 'W' ? -Integer.valueOf( slon.substring(1) ) :
( slon.charAt(0) == 'E' ? Integer.valueOf( slon.substring(1) ) : -1 );
int ilat = slat.charAt(0) == 'S' ? -Integer.valueOf( slat.substring(1) ) :
( slat.charAt(0) == 'N' ? Integer.valueOf( slat.substring(1) ) : -1 );
if ( ilon < -180 || ilon >= 180 || ilon % 5 != 0 ) return -1;
if ( ilat < - 90 || ilat >= 90 || ilat % 5 != 0 ) return -1;
return (ilon+180) / 5 + 72*((ilat+90)/5);
}
private int tileForPos( int ilon, int ilat )
{
return ilon / 5000000 + 72 * ( ilat / 5000000 );
}
private int subIdxForPos( int ilon, int ilat )
{
int lonModulo = ilon % 5000000;
int latModulo = ilat % 5000000;
return ( lonModulo / 12500 ) + 400 * (latModulo / 12500);
}
private List<OsmNodeP> subListForPos( int ilon, int ilat )
{
if ( ilon < 0 || ilon >= 360000000 || ilat < 0 || ilat >= 180000000 )
{
throw new IllegalArgumentException( "illegal position: " + ilon + " " + ilat );
}
int tileNr = tileForPos( ilon, ilat );
if ( seglistsArray.get(tileNr) == null ) return new ArrayList<OsmNodeP>();
return seglistsArray.get(tileNr).getList( subIdxForPos( ilon, ilat ) );
}
}