initial commit of BRouter Version 0.98

This commit is contained in:
Arndt Brenschede 2014-01-18 15:29:05 +01:00
parent e4ae2b37d3
commit 91e62f1164
120 changed files with 15382 additions and 0 deletions

View file

@ -0,0 +1,166 @@
/**
* common base class for the map-filters
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener
{
private DataOutputStream[] tileOutStreams;
protected File outTileDir;
protected HashMap<String,String> tags;
public void putTag( String key, String value )
{
if ( tags == null ) tags = new HashMap<String,String>();
tags.put( key, value );
}
public String getTag( String key )
{
return tags == null ? null : tags.get( key );
}
public HashMap<String,String> getTagsOrNull()
{
return tags;
}
public void setTags( HashMap<String,String> tags )
{
this.tags = tags;
}
protected static long readId( DataInputStream is) throws IOException
{
int offset = is.readByte();
if ( offset == 32 ) return -1;
long i = is.readInt();
i = i << 5;
return i | offset;
}
protected static void writeId( DataOutputStream o, long id ) throws IOException
{
if ( id == -1 )
{
o.writeByte( 32 );
return;
}
int offset = (int)( id & 0x1f );
int i = (int)( id >> 5 );
o.writeByte( offset );
o.writeInt( i );
}
protected static File[] sortBySizeAsc( File[] files )
{
int n = files.length;
long[] sizes = new long[n];
File[] sorted = new File[n];
for( int i=0; i<n; i++ ) sizes[i] = files[i].length();
for(int nf=0; nf<n; nf++)
{
int idx = -1;
long min = -1;
for( int i=0; i<n; i++ )
{
if ( sizes[i] != -1 && ( idx == -1 || sizes[i] < min ) )
{
min = sizes[i];
idx = i;
}
}
sizes[idx] = -1;
sorted[nf] = files[idx];
}
return sorted;
}
protected File fileFromTemplate( File template, File dir, String suffix )
{
String filename = template.getName();
filename = filename.substring( 0, filename.length() - 3 ) + suffix;
return new File( dir, filename );
}
protected DataInputStream createInStream( File inFile ) throws IOException
{
return new DataInputStream( new BufferedInputStream ( new FileInputStream( inFile ) ) );
}
protected DataOutputStream createOutStream( File outFile ) throws IOException
{
return new DataOutputStream( new BufferedOutputStream( new FileOutputStream( outFile ) ) );
}
protected DataOutputStream getOutStreamForTile( int tileIndex ) throws Exception
{
if ( tileOutStreams == null )
{
tileOutStreams = new DataOutputStream[64];
}
if ( tileOutStreams[tileIndex] == null )
{
tileOutStreams[tileIndex] = createOutStream( new File( outTileDir, getNameForTile( tileIndex ) ) );
}
return tileOutStreams[tileIndex];
}
protected String getNameForTile( int tileIndex )
{
throw new IllegalArgumentException( "getNameForTile not implemented" );
}
protected void closeTileOutStreams() throws Exception
{
if ( tileOutStreams == null )
{
return;
}
for( int tileIndex=0; tileIndex<tileOutStreams.length; tileIndex++ )
{
if ( tileOutStreams[tileIndex] != null ) tileOutStreams[tileIndex].close();
tileOutStreams[tileIndex] = null;
}
}
// interface dummys
@Override
public void nodeFileStart( File nodefile ) throws Exception {}
@Override
public void nextNode( NodeData n ) throws Exception {}
@Override
public void nodeFileEnd( File nodefile ) throws Exception {}
@Override
public void wayFileStart( File wayfile ) throws Exception {}
@Override
public void nextWay( WayData data ) throws Exception {}
@Override
public void wayFileEnd( File wayfile ) throws Exception {}
@Override
public void nextRelation( RelationData data ) throws Exception {}
}

View file

@ -0,0 +1,87 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
/**
* NodeCutter does 1 step in map-processing:
*
* - cuts the 45*30 node tiles into 5*5 pieces
*
* @author ab
*/
public class NodeCutter extends MapCreatorBase
{
private int lonoffset;
private int latoffset;
public static void main(String[] args) throws Exception
{
System.out.println("*** NodeCutter: Cut big node-tiles into 5x5 tiles");
if (args.length != 2)
{
System.out.println("usage: java NodeCutter <node-tiles-in> <node-tiles-out>" );
return;
}
new NodeCutter().process( new File( args[0] ), new File( args[1] ) );
}
public void process( File nodeTilesIn, File nodeTilesOut ) throws Exception
{
this.outTileDir = nodeTilesOut;
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tlf" );
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
lonoffset = -1;
latoffset = -1;
}
@Override
public void nextNode( NodeData n ) throws Exception
{
n.writeTo( getOutStreamForTile( getTileIndex( n.ilon, n.ilat ) ) );
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
closeTileOutStreams();
}
private int getTileIndex( int ilon, int ilat )
{
int lonoff = (ilon / 45000000 ) * 45;
int latoff = (ilat / 30000000 ) * 30;
if ( lonoffset == -1 ) lonoffset = lonoff;
if ( latoffset == -1 ) latoffset = latoff;
if ( lonoff != lonoffset || latoff != latoffset )
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
int lon = (ilon / 5000000) % 9;
int lat = (ilat / 5000000) % 6;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat );
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 5 + lonoffset - 180;
int lat = (tileIndex % 6 ) * 5 + latoffset - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".n5d";
}
}

View file

@ -0,0 +1,55 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Container for node data on the preprocessor level
*
* @author ab
*/
public class NodeData extends MapCreatorBase
{
public long nid;
public int ilon;
public int ilat;
public long description;
public short selev = Short.MIN_VALUE;
public NodeData( long id, double lon, double lat )
{
nid = id;
ilat = (int)( ( lat + 90. )*1000000. + 0.5);
ilon = (int)( ( lon + 180. )*1000000. + 0.5);
}
public NodeData( DataInputStream dis ) throws Exception
{
nid = readId( dis );
ilon = dis.readInt();
ilat = dis.readInt();
int mode = dis.readByte();
if ( ( mode & 1 ) != 0 ) description = dis.readLong();
if ( ( mode & 2 ) != 0 ) selev = dis.readShort();
}
public void writeTo( DataOutputStream dos ) throws Exception
{
writeId( dos, nid );
dos.writeInt( ilon );
dos.writeInt( ilat );
int mode = ( description == 0L ? 0 : 1 ) | ( selev == Short.MIN_VALUE ? 0 : 2 );
dos.writeByte( (byte)mode );
if ( ( mode & 1 ) != 0 ) dos.writeLong( description );
if ( ( mode & 2 ) != 0 ) dos.writeShort( selev );
}
}

View file

@ -0,0 +1,86 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* NodeFilter does 1 step in map-processing:
*
* - filters out unused nodes according to the way file
*
* @author ab
*/
public class NodeFilter extends MapCreatorBase
{
private DataOutputStream nodesOutStream;
private File nodeTilesOut;
protected DenseLongMap nodebitmap;
public static void main(String[] args) throws Exception
{
System.out.println("*** NodeFilter: Filter way related nodes");
if (args.length != 3)
{
System.out.println("usage: java NodeFilter <node-tiles-in> <way-file-in> <node-tiles-out>" );
return;
}
new NodeFilter().process( new File( args[0] ), new File( args[1] ), new File( args[2] ) );
}
public void process( File nodeTilesIn, File wayFileIn, File nodeTilesOut ) throws Exception
{
this.nodeTilesOut = nodeTilesOut;
// read the wayfile into a bitmap of used nodes
nodebitmap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 1 ) : new TinyDenseLongMap();
new WayIterator( this, false ).processFile( wayFileIn );
// finally filter all node files
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tls" );
}
@Override
public void nextWay( WayData data ) throws Exception
{
int nnodes = data.nodes.size();
for (int i=0; i<nnodes; i++ )
{
nodebitmap.put( data.nodes.get(i), 0 );
}
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
String filename = nodefile.getName();
filename = filename.substring( 0, filename.length() - 3 ) + "tlf";
File outfile = new File( nodeTilesOut, filename );
nodesOutStream = new DataOutputStream( new BufferedOutputStream ( new FileOutputStream( outfile ) ) );
}
@Override
public void nextNode( NodeData n ) throws Exception
{
// check if node passes bitmap
if ( nodebitmap.getInt( n.nid ) == 0 ) // 0 -> bit set, -1 -> unset
{
n.writeTo( nodesOutStream );
}
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
nodesOutStream.close();
}
}

View file

@ -0,0 +1,76 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Iterate over a singe nodefile or a directory
* of nodetiles and feed the nodes to the callback listener
*
* @author ab
*/
public class NodeIterator extends MapCreatorBase
{
private NodeListener listener;
private boolean delete;
public NodeIterator( NodeListener nodeListener, boolean deleteAfterReading )
{
listener = nodeListener;
delete = deleteAfterReading;
}
public void processDir( File indir, String inSuffix ) throws Exception
{
if ( !indir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + indir );
}
File[] af = sortBySizeAsc( indir.listFiles() );
for( int i=0; i<af.length; i++ )
{
File nodefile = af[i];
if ( nodefile.getName().endsWith( inSuffix ) )
{
processFile( nodefile );
}
}
}
public void processFile(File nodefile) throws Exception
{
System.out.println( "*** NodeIterator reading: " + nodefile );
listener.nodeFileStart( nodefile );
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( nodefile ) ) );
try
{
for(;;)
{
NodeData n = new NodeData( di );
listener.nextNode( n );
}
}
catch( EOFException eof )
{
di.close();
}
listener.nodeFileEnd( nodefile );
if ( delete && "true".equals( System.getProperty( "deletetmpfiles" ) ))
{
nodefile.delete();
}
}
}

View file

@ -0,0 +1,17 @@
package btools.mapcreator;
import java.io.File;
/**
* Callbacklistener for NodeIterator
*
* @author ab
*/
public interface NodeListener
{
void nodeFileStart( File nodefile ) throws Exception;
void nextNode( NodeData data ) throws Exception;
void nodeFileEnd( File nodefile ) throws Exception;
}

View file

@ -0,0 +1,205 @@
/**
* This program
* - reads an *.osm from stdin
* - writes 45*30 degree node tiles + a way file + a rel file
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
import btools.expressions.BExpressionContext;
public class OsmCutter extends MapCreatorBase
{
private long recordCnt;
private long nodesParsed;
private long waysParsed;
private long relsParsed;
private long changesetsParsed;
private DataOutputStream wayDos;
private DataOutputStream cyclewayDos;
public static void main(String[] args) throws Exception
{
System.out.println("*** OsmCutter: cut an osm map in node-tiles + a way file");
if (args.length != 4 && args.length != 5)
{
System.out.println("usage: bzip2 -dc <map> | java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file>");
System.out.println("or : java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <inputfile>");
return;
}
new OsmCutter().process(
new File( args[0] )
, new File( args[1] )
, new File( args[2] )
, new File( args[3] )
, args.length > 4 ? new File( args[4] ) : null );
}
private BExpressionContext _expctxWay;
private BExpressionContext _expctxNode;
public void process (File lookupFile, File outTileDir, File wayFile, File relFile, File mapFile) throws Exception
{
if ( !lookupFile.exists() )
{
throw new IllegalArgumentException( "lookup-file: " + lookupFile + " does not exist" );
}
_expctxWay = new BExpressionContext("way");
_expctxWay.readMetaData( lookupFile );
_expctxNode = new BExpressionContext("node");
_expctxNode.readMetaData( lookupFile );
this.outTileDir = outTileDir;
if ( !outTileDir.isDirectory() ) throw new RuntimeException( "out tile directory " + outTileDir + " does not exist" );
wayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( wayFile ) ) );
cyclewayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( relFile ) ) );
// read the osm map into memory
long t0 = System.currentTimeMillis();
new OsmParser().readMap( mapFile, this, this, this );
long t1 = System.currentTimeMillis();
System.out.println( "parsing time (ms) =" + (t1-t0) );
// close all files
closeTileOutStreams();
wayDos.close();
cyclewayDos.close();
/* System.out.println( "-------- way-statistics -------- " );
_expctxWay.dumpStatistics();
System.out.println( "-------- node-statistics -------- " );
_expctxNode.dumpStatistics();
*/
System.out.println( statsLine() );
}
private void checkStats()
{
if ( (++recordCnt % 100000) == 0 ) System.out.println( statsLine() );
}
private String statsLine()
{
return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed;
}
@Override
public void nextNode( NodeData n ) throws Exception
{
nodesParsed++;
checkStats();
if ( n.getTagsOrNull() != null )
{
int[] lookupData = _expctxNode.createNewLookupData();
for( String key : n.getTagsOrNull().keySet() )
{
String value = n.getTag( key );
_expctxNode.addLookupValue( key, value, lookupData );
}
n.description = _expctxNode.encode(lookupData);
}
// write node to file
int tileIndex = getTileIndex( n.ilon, n.ilat );
if ( tileIndex >= 0 )
{
DataOutputStream dos = getOutStreamForTile( tileIndex );
n.writeTo( dos );
}
}
@Override
public void nextWay( WayData w ) throws Exception
{
waysParsed++;
checkStats();
// filter out non-highway ways
if ( w.getTag( "highway" ) == null )
{
// ... but eventually fake a ferry tag
if ( "ferry".equals( w.getTag( "route" ) ) )
{
w.putTag( "highway", "ferry" );
}
else
{
return;
}
}
// encode tags
if ( w.getTagsOrNull() != null )
{
int[] lookupData = _expctxWay.createNewLookupData();
for( String key : w.getTagsOrNull().keySet() )
{
String value = w.getTag( key );
_expctxWay.addLookupValue( key, value, lookupData );
}
w.description = _expctxWay.encode(lookupData);
}
w.writeTo( wayDos );
}
@Override
public void nextRelation( RelationData r ) throws Exception
{
relsParsed++;
checkStats();
// filter out non-cycle relations
if ( ! "bicycle".equals( r.getTag( "route" ) ) )
{
return;
}
for ( int i=0; i<r.ways.size();i++ )
{
long wid = r.ways.get(i);
writeId( cyclewayDos, wid );
}
}
private int getTileIndex( int ilon, int ilat )
{
int lon = ilon / 45000000;
int lat = ilat / 30000000;
if ( lon < 0 || lon > 7 || lat < 0 || lat > 5 )
{
System.out.println( "warning: ignoring illegal pos: " + ilon + "," + ilat );
return -1;
}
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 45 - 180;
int lat = (tileIndex % 6 ) * 30 - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".tls";
}
}

View file

@ -0,0 +1,29 @@
/**
* Container for link between two Osm nodes (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
public final class OsmLinkP
{
/**
* The description bitmap is mainly the way description
* used to calculate the costfactor
*/
public long descriptionBitmap;
/**
* The target is either the next link or the target node
*/
public OsmNodeP targetNode;
public OsmLinkP next;
public boolean counterLinkWritten( )
{
return descriptionBitmap == 0L;
}
}

View file

@ -0,0 +1,243 @@
/**
* Container for an osm node (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class OsmNodeP implements Comparable<OsmNodeP>
{
public static final int EXTERNAL_BITMASK = 0x80;
public static final int FIRSTFORWAY_BITMASK = 0x40;
public static final int TRANSFERNODE_BITMASK = 0x20;
public static final int WRITEDESC_BITMASK = 0x10;
public static final int SKIPDETAILS_BITMASK = 0x08;
public static final int NODEDESC_BITMASK = 0x04;
/**
* The latitude
*/
public int ilat;
/**
* The longitude
*/
public int ilon;
/**
* The links to other nodes
*/
public OsmLinkP firstlink = null;
/**
* The elevation
*/
public short selev;
public boolean isBorder = false;
public byte wayAndBits = -1; // use for bridge/tunnel logic
// interface OsmPos
public int getILat()
{
return ilat;
}
public int getILon()
{
return ilon;
}
public short getSElev()
{
// if all bridge or all tunnel, elevation=no-data
return (wayAndBits & 24) == 0 ? selev : Short.MIN_VALUE;
}
public double getElev()
{
return selev / 4.;
}
public void addLink( OsmLinkP link )
{
if ( firstlink != null ) link.next = firstlink;
firstlink = link;
}
public long getNodeDecsription()
{
return 0L;
}
public void writeNodeData( DataOutputStream os ) throws IOException
{
int lonIdx = ilon/62500;
int latIdx = ilat/62500;
// buffer the body to first calc size
ByteArrayOutputStream bos = new ByteArrayOutputStream( );
DataOutputStream os2 = new DataOutputStream( bos );
os2.writeShort( getSElev() );
int nlinks = 0;
// hack: write node-desc as link tag (copy cycleway-bits)
long nodeDescription = getNodeDecsription();
for( OsmLinkP link0 = firstlink; link0 != null; link0 = link0.next )
{
nlinks++;
OsmLinkP link = link0;
OsmNodeP origin = this;
int skipDetailBit = link0.counterLinkWritten() ? SKIPDETAILS_BITMASK : 0;
// first pass just to see if that link is consistent
while( link != null )
{
OsmNodeP target = link.targetNode;
if ( !target.isTransferNode() )
{
break;
}
// next link is the one (of two), does does'nt point back
for( link = target.firstlink; link != null; link = link.next )
{
if ( link.targetNode != origin ) break;
}
origin = target;
}
if ( link == null ) continue; // dead end
if ( skipDetailBit == 0)
{
link = link0;
}
origin = this;
long lastDescription = 0;
while( link != null )
{
OsmNodeP target = link.targetNode;
int tranferbit = target.isTransferNode() ? TRANSFERNODE_BITMASK : 0;
int writedescbit = link.descriptionBitmap != lastDescription ? WRITEDESC_BITMASK : 0;
int nodedescbit = nodeDescription != 0L ? NODEDESC_BITMASK : 0;
if ( skipDetailBit != 0 )
{
writedescbit = 0;
}
int targetLonIdx = target.ilon/62500;
int targetLatIdx = target.ilat/62500;
if ( targetLonIdx == lonIdx && targetLatIdx == latIdx )
{
// reduced position for internal target
os2.writeByte( tranferbit | writedescbit | nodedescbit | skipDetailBit );
os2.writeShort( (short)(target.ilon - lonIdx*62500 - 31250) );
os2.writeShort( (short)(target.ilat - latIdx*62500 - 31250) );
}
else
{
// full position for external target
os2.writeByte( tranferbit | writedescbit | nodedescbit | skipDetailBit | EXTERNAL_BITMASK );
os2.writeInt( target.ilon );
os2.writeInt( target.ilat );
}
if ( writedescbit != 0 )
{
os2.writeLong( link.descriptionBitmap );
}
if ( nodedescbit != 0 )
{
os2.writeLong( nodeDescription );
nodeDescription = 0L;
}
lastDescription = link.descriptionBitmap;
if ( tranferbit == 0)
{
target.markLinkWritten( origin );
break;
}
os2.writeShort( target.getSElev() );
// next link is the one (of two), does does'nt point back
for( link = target.firstlink; link != null; link = link.next )
{
if ( link.targetNode != origin ) break;
}
if ( link == null ) throw new RuntimeException( "follow-up link not found for transfer-node!" );
origin = target;
}
}
// calculate the body size
int bodySize = bos.size();
os.writeShort( (short)(ilon - lonIdx*62500 - 31250) );
os.writeShort( (short)(ilat - latIdx*62500 - 31250) );
os.writeInt( bodySize );
bos.writeTo( os );
}
public String toString2()
{
return (ilon-180000000) + "_" + (ilat-90000000) + "_" + (selev/4);
}
public long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
}
public boolean isTransferNode()
{
return (!isBorder) && _linkCnt() == 2;
}
private int _linkCnt()
{
int cnt = 0;
for( OsmLinkP link = firstlink; link != null; link = link.next )
{
cnt++;
}
return cnt;
}
// mark the link to the given node as written,
// don't want to write the counter-direction
// in full details
public void markLinkWritten( OsmNodeP t )
{
for( OsmLinkP link = firstlink; link != null; link = link.next )
{
if ( link.targetNode == t) link.descriptionBitmap = 0L;
}
}
/**
* Compares two OsmNodes for position ordering.
*
* @return -1,0,1 depending an comparson result
*/
public int compareTo( OsmNodeP n )
{
long id1 = getIdFromPos();
long id2 = n.getIdFromPos();
if ( id1 < id2 ) return -1;
if ( id1 > id2 ) return 1;
return 0;
}
}

View file

@ -0,0 +1,39 @@
/**
* Container for an osm node with tags (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class OsmNodePT extends OsmNodeP
{
public long descriptionBits;
public byte wayOrBits = 0; // used to propagate bike networks to nodes
public OsmNodePT()
{
}
public OsmNodePT( long descriptionBits )
{
this.descriptionBits = descriptionBits;
}
@Override
public long getNodeDecsription()
{
return descriptionBits | (long)( (wayOrBits & 6) >> 1 );
}
@Override
public boolean isTransferNode()
{
return false; // always have descriptionBits so never transfernode
}
}

View file

@ -0,0 +1,240 @@
package btools.mapcreator;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
/**
* Parser for OSM data
*
* @author ab
*/
public class OsmParser extends MapCreatorBase
{
private BufferedReader _br;
private NodeListener nListener;
private WayListener wListener;
private RelationListener rListener;
public void readMap( File mapFile,
NodeListener nListener,
WayListener wListener,
RelationListener rListener ) throws Exception
{
this.nListener = nListener;
this.wListener = wListener;
this.rListener = rListener;
if ( mapFile == null )
{
_br = new BufferedReader(new InputStreamReader(System.in));
}
else
{
if ( mapFile.getName().endsWith( ".gz" ) )
{
_br = new BufferedReader(new InputStreamReader( new GZIPInputStream( new FileInputStream( mapFile ) ) ) );
}
else
{
_br = new BufferedReader(new InputStreamReader( new FileInputStream( mapFile ) ) );
}
}
for(;;)
{
String line = _br.readLine();
if ( line == null ) break;
if ( checkNode( line ) ) continue;
if ( checkWay( line ) ) continue;
if ( checkRelation( line ) ) continue;
if ( checkChangeset( line ) ) continue;
}
if ( mapFile != null )
{
_br.close();
}
}
private boolean checkNode( String line ) throws Exception
{
int idx0 = line.indexOf( "<node id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 10;
int idx1 = line.indexOf( '"', idx0 );
long nodeId = Long.parseLong( line.substring( idx0, idx1 ) );
int idx2 = line.indexOf( " lat=\"" );
if ( idx2 < 0 ) return false;
idx2 += 6;
int idx3 = line.indexOf( '"', idx2 );
double lat = Double.parseDouble( line.substring( idx2, idx3 ) );
int idx4 = line.indexOf( " lon=\"" );
if ( idx4 < 0 ) return false;
idx4 += 6;
int idx5 = line.indexOf( '"', idx4 );
double lon = Double.parseDouble( line.substring( idx4, idx5 ) );
NodeData n = new NodeData( nodeId, lon, lat );
if ( !line.endsWith( "/>" ) )
{
// read additional tags
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
n.putTag( key, value );
}
}
else if ( l2.indexOf( "</node>" ) >= 0 )
{ // end-tag
break;
}
}
}
nListener.nextNode( n );
return true;
}
private boolean checkWay( String line ) throws Exception
{
int idx0 = line.indexOf( "<way id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 9;
int idx1 = line.indexOf( '"', idx0 );
long id = Long.parseLong( line.substring( idx0, idx1 ) );
WayData w = new WayData( id );
// read the nodes
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<nd ref=\"" )) >= 0 )
{ // node reference
i2 += 9;
int ri2 = l2.indexOf( '"', i2 );
long nid = Long.parseLong( l2.substring( i2, ri2 ) );
w.nodes.add( nid );
}
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
w.putTag( key, value );
}
}
else if ( l2.indexOf( "</way>" ) >= 0 )
{ // end-tag
break;
}
}
wListener.nextWay( w );
return true;
}
private boolean checkChangeset( String line ) throws Exception
{
int idx0 = line.indexOf( "<changeset id=\"" );
if ( idx0 < 0 ) return false;
if ( !line.endsWith( "/>" ) )
{
int loopcheck = 0;
for(;;)
{
String l2 = _br.readLine();
if ( l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000 ) break;
}
}
return true;
}
private boolean checkRelation( String line ) throws Exception
{
int idx0 = line.indexOf( "<relation id=\"" );
if ( idx0 < 0 ) return false;
idx0 += 14;
int idx1 = line.indexOf( '"', idx0 );
long rid = Long.parseLong( line.substring( idx0, idx1 ) );
RelationData r = new RelationData( rid );
// read the nodes
for(;;)
{
String l2 = _br.readLine();
if ( l2 == null ) return false;
int i2;
if ( (i2 = l2.indexOf( "<member type=\"way\" ref=\"" )) >= 0 )
{ // node reference
i2 += 24;
int ri2 = l2.indexOf( '"', i2 );
long wid = Long.parseLong( l2.substring( i2, ri2 ) );
r.ways.add( wid );
}
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8;
int ri2 = l2.indexOf( '"', i2 );
String key = l2.substring( i2, ri2 );
i2 = l2.indexOf( " v=\"", ri2 );
if ( i2 >= 0 )
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 );
String value = l2.substring( i2, ri3 );
r.putTag( key, value );
}
}
else if ( l2.indexOf( "</relation>" ) >= 0 )
{ // end-tag
break;
}
}
rListener.nextRelation( r );
return true;
}
}

View file

@ -0,0 +1,203 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.CompactLongSet;
import btools.util.CompactLongMap;
import btools.util.FrozenLongSet;
import btools.util.FrozenLongMap;
/**
* PosUnifier does 3 steps in map-processing:
*
* - unify positions
* - add srtm elevation data
* - make a bordernodes file containing net data
* from the bordernids-file just containing ids
*
* @author ab
*/
public class PosUnifier extends MapCreatorBase
{
private DataOutputStream nodesOutStream;
private DataOutputStream borderNodesOut;
private File nodeTilesOut;
private CompactLongSet positionSet;
private HashMap<String,SrtmData> srtmmap ;
private int lastStrmLonIdx;
private int lastStrmLatIdx;
private SrtmData lastSrtmData;
private String srtmdir;
private int totalLatSteps = 0;
private int totalLonSteps = 0;
private CompactLongSet borderNids;
public static void main(String[] args) throws Exception
{
System.out.println("*** PosUnifier: Unify position values and enhance elevation");
if (args.length != 5)
{
System.out.println("usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <strm-data-dir>" );
return;
}
new PosUnifier().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), args[4] );
}
public void process( File nodeTilesIn, File nodeTilesOut, File bordernidsinfile, File bordernodesoutfile, String srtmdir ) throws Exception
{
this.nodeTilesOut = nodeTilesOut;
this.srtmdir = srtmdir;
// read border nids set
DataInputStream dis = createInStream( bordernidsinfile );
borderNids = new CompactLongSet();
try
{
for(;;)
{
long nid = readId( dis );
if ( !borderNids.contains( nid ) ) borderNids.fastAdd( nid );
}
}
catch( EOFException eof )
{
dis.close();
}
borderNids = new FrozenLongSet( borderNids );
// process all files
borderNodesOut = createOutStream( bordernodesoutfile );
new NodeIterator( this, true ).processDir( nodeTilesIn, ".n5d" );
borderNodesOut.close();
}
@Override
public void nodeFileStart( File nodefile ) throws Exception
{
resetSrtm();
nodesOutStream = createOutStream( fileFromTemplate( nodefile, nodeTilesOut, "u5d" ) );
positionSet = new CompactLongSet();
}
@Override
public void nextNode( NodeData n ) throws Exception
{
SrtmData srtm = srtmForNode( n.ilon, n.ilat );
n.selev = srtm == null ? Short.MIN_VALUE : srtm.getElevation( n.ilon, n.ilat);
findUniquePos( n );
n.writeTo( nodesOutStream );
if ( borderNids.contains( n.nid ) )
{
n.writeTo( borderNodesOut );
}
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
nodesOutStream.close();
}
private void findUniquePos( NodeData n )
{
// fix the position for uniqueness
int lonmod = n.ilon % 1000000;
int londelta = lonmod < 500000 ? 1 : -1;
int latmod = n.ilat % 1000000;
int latdelta = latmod < 500000 ? 1 : -1;
for(int latsteps = 0; latsteps < 100; latsteps++)
{
for(int lonsteps = 0; lonsteps <= latsteps; lonsteps++)
{
int lon = n.ilon + lonsteps*londelta;
int lat = n.ilat + latsteps*latdelta;
long pid = ((long)lon)<<32 | lat; // id from position
if ( !positionSet.contains( pid ) )
{
totalLonSteps += lonsteps;
totalLatSteps += latsteps;
positionSet.fastAdd( pid );
n.ilon = lon;
n.ilat = lat;
return;
}
}
}
System.out.println( "*** WARNING: cannot unify position for: " + n.ilon + " " + n.ilat );
}
/**
* get the srtm data set for a position
* srtm coords are srtm_<srtmLon>_<srtmLat>
* where srtmLon = 180 + lon, srtmLat = 60 - lat
*/
private SrtmData srtmForNode( int ilon, int ilat ) throws Exception
{
int srtmLonIdx = (ilon+5000000)/5000000;
int srtmLatIdx = (154999999-ilat)/5000000;
if ( srtmLatIdx < 1 || srtmLatIdx > 24 || srtmLonIdx < 1 || srtmLonIdx > 72 )
{
return null;
}
if ( srtmLonIdx == lastStrmLonIdx && srtmLatIdx == lastStrmLatIdx )
{
return lastSrtmData;
}
lastStrmLonIdx = srtmLonIdx;
lastStrmLatIdx = srtmLatIdx;
StringBuilder sb = new StringBuilder( 16 );
sb.append( "srtm_" );
sb.append( (char)('0' + srtmLonIdx/10 ) ).append( (char)('0' + srtmLonIdx%10 ) ).append( '_' );
sb.append( (char)('0' + srtmLatIdx/10 ) ).append( (char)('0' + srtmLatIdx%10 ) ).append( ".zip" );
String filename = sb.toString();
lastSrtmData = srtmmap.get( filename );
if ( lastSrtmData == null && !srtmmap.containsKey( filename ) )
{
File f = new File( new File( srtmdir ), filename );
System.out.println( "reading: " + f + " ilon=" + ilon + " ilat=" + ilat );
if ( f.exists() )
{
try
{
lastSrtmData = new SrtmData( f );
}
catch( Exception e )
{
System.out.println( "**** ERROR reading " + f + " ****" );
}
}
srtmmap.put( filename, lastSrtmData );
}
return lastSrtmData;
}
private void resetSrtm()
{
srtmmap = new HashMap<String,SrtmData>();
lastStrmLonIdx = -1;
lastStrmLatIdx = -1;
lastSrtmData = null;
}
}

View file

@ -0,0 +1,37 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Container for relation data on the preprocessor level
*
* @author ab
*/
public class RelationData extends MapCreatorBase
{
public long rid;
public long description;
public LongList ways;
public RelationData( long id )
{
rid = id;
ways = new LongList( 16 );
}
public RelationData( long id, LongList ways )
{
rid = id;
this.ways = ways;
}
}

View file

@ -0,0 +1,13 @@
package btools.mapcreator;
import java.io.File;
/**
* Callbacklistener for Relations
*
* @author ab
*/
public interface RelationListener
{
void nextRelation( RelationData data ) throws Exception;
}

View file

@ -0,0 +1,174 @@
/**
* This is a wrapper for a 5*5 degree srtm file in ascii/zip-format
*
* - filter out unused nodes according to the way file
* - enhance with SRTM elevation data
* - split further in smaller (5*5 degree) tiles
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class SrtmData
{
public int ncols;
public int nrows;
public double xllcorner;
public double yllcorner;
public double cellsize;
public int nodata_value;
public short[] eval_array;
private double minlon;
private double maxlon;
private double minlat;
private double maxlat;
public void init()
{
minlon = xllcorner;
maxlon = minlon + cellsize*ncols;
minlat = yllcorner;
maxlat = minlat + cellsize*nrows;
}
private boolean missingData = false;
public short getElevation( int ilon, int ilat )
{
double lon = ilon / 1000000. - 180.;
double lat = ilat / 1000000. - 90.;
double dcol = (lon - minlon)/cellsize -0.5;
double drow = (lat - minlat)/cellsize -0.5;
int row = (int)drow;
int col = (int)dcol;
if ( col < 0 ) col = 0;
if ( col >= ncols-1 ) col = ncols - 2;
if ( row < 0 ) row = 0;
if ( row >= nrows-1 ) row = nrows - 2;
double wrow = drow-row;
double wcol = dcol-col;
missingData = false;
double eval = (1.-wrow)*(1.-wcol)*get(row ,col )
+ ( wrow)*(1.-wcol)*get(row+1,col )
+ (1.-wrow)*( wcol)*get(row ,col+1)
+ ( wrow)*( wcol)*get(row+1,col+1);
return missingData ? Short.MIN_VALUE : (short)(eval);
}
private short get( int r, int c )
{
short e = eval_array[r*ncols + c ];
if ( e == Short.MIN_VALUE ) missingData = true;
return e;
}
public SrtmData( File file ) throws Exception
{
ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) );
try
{
for(;;)
{
ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".asc" ) )
{
readFromStream( zis );
/* // test
int[] ca = new int[]{ 50477121, 8051915, // 181
50477742, 8047408, // 154
50477189, 8047308, // 159
};
for( int i=0; i<ca.length; i+=2 )
{
int lat=ca[i] + 90000000;
int lon=ca[i+1] + 180000000;
System.err.println( "lat=" + lat + " lon=" + lon + " elev=" + getElevation( lon, lat )/4. );
}
// end test
*/
return;
}
}
}
finally
{
zis.close();
}
}
public void readFromStream( InputStream is ) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(is));
int linenr = 0;
for(;;)
{
linenr++;
if ( linenr <= 6 )
{
String line = br.readLine();
if ( linenr == 1 ) ncols = Integer.parseInt( line.substring(14) );
else if ( linenr == 2 ) nrows = Integer.parseInt( line.substring(14) );
else if ( linenr == 3 ) xllcorner = Double.parseDouble( line.substring(14) );
else if ( linenr == 4 ) yllcorner = Double.parseDouble( line.substring(14) );
else if ( linenr == 5 ) cellsize = Double.parseDouble( line.substring(14) );
else if ( linenr == 6 )
{
nodata_value = Integer.parseInt( line.substring(14) );
eval_array = new short[ncols * nrows];
}
}
else
{
int row = 0;
int col = 0;
int n = 0;
boolean negative = false;
for(;;)
{
int c = br.read();
if ( c < 0 ) break;
if ( c == ' ' )
{
if ( negative ) n = -n;
short val = n == nodata_value ? Short.MIN_VALUE : (short)(n*4);
if ( val < -1000 ) val = Short.MIN_VALUE;
eval_array[ (nrows-1-row)*ncols + col ] = val;
if (++col == ncols )
{
col = 0;
++row;
}
n = 0;
negative = false;
}
else if ( c >= '0' && c <= '9' )
{
n = 10*n + (c-'0');
}
else if ( c == '-' )
{
negative = true;
}
}
break;
}
}
init();
br.close();
}
}

View file

@ -0,0 +1,127 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* WayCutter does 2 step in map-processing:
*
* - cut the way file into 45*30 - pieces
* - enrich ways with relation information
*
* @author ab
*/
public class WayCutter extends MapCreatorBase
{
private CompactLongSet cyclewayset;
private DenseLongMap tileIndexMap;
public static void main(String[] args) throws Exception
{
System.out.println("*** WayCutter: Soft-Cut way-data into tiles");
if (args.length != 4)
{
System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out> <relation-file>" );
return;
}
new WayCutter().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ) );
}
public void process( File nodeTilesIn, File wayFileIn, File wayTilesOut, File relationFileIn ) throws Exception
{
this.outTileDir = wayTilesOut;
// *** read the relation file into a set (currently cycleway processing only)
cyclewayset = new CompactLongSet();
DataInputStream dis = createInStream( relationFileIn );
try
{
for(;;)
{
long wid = readId( dis );
if ( !cyclewayset.contains( wid ) ) cyclewayset.add( wid );
}
}
catch( EOFException eof )
{
dis.close();
}
System.out.println( "marked cycleways: " + cyclewayset.size() );
// *** read all nodes into tileIndexMap
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 6 ) : new TinyDenseLongMap();
new NodeIterator( this, false ).processDir( nodeTilesIn, ".tlf" );
// *** finally process the way-file, cutting into pieces
new WayIterator( this, true ).processFile( wayFileIn );
closeTileOutStreams();
}
@Override
public void nextNode( NodeData n ) throws Exception
{
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) );
}
@Override
public void nextWay( WayData data ) throws Exception
{
// propagate the cycleway-bit
if ( cyclewayset.contains( data.wid ) )
{
data.description |= 2;
}
long waytileset = 0;
int nnodes = data.nodes.size();
// determine the tile-index for each node
for (int i=0; i<nnodes; i++ )
{
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) );
if ( tileIndex != -1 )
{
waytileset |= ( 1L << tileIndex );
}
}
// now write way to all tiles hit
for( int tileIndex=0; tileIndex<54; tileIndex++ )
{
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{
continue;
}
data.writeTo( getOutStreamForTile( tileIndex ) );
}
}
private int getTileIndex( int ilon, int ilat )
{
int lon = ilon / 45000000;
int lat = ilat / 30000000;
if ( lon < 0 || lon > 7 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat );
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 45 - 180;
int lat = (tileIndex % 6 ) * 30 - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".wtl";
}
}

View file

@ -0,0 +1,146 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* WayCutter5 does 2 step in map-processing:
*
* - cut the 45*30 way files into 5*5 pieces
* - create a file containing all border node ids
*
* @author ab
*/
public class WayCutter5 extends MapCreatorBase
{
private DataOutputStream borderNidsOutStream;
private DenseLongMap tileIndexMap;
private File nodeTilesIn;
private int lonoffset;
private int latoffset;
public static void main(String[] args) throws Exception
{
System.out.println("*** WayCutter5: Soft-Cut way-data into tiles");
if (args.length != 4)
{
System.out.println("usage: java WayCutter5 <node-tiles-in> <way-tiles-in> <way-tiles-out> <border-nids-out>" );
return;
}
new WayCutter5().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ) );
}
public void process( File nodeTilesIn, File wayTilesIn, File wayTilesOut, File borderNidsOut ) throws Exception
{
this.nodeTilesIn = nodeTilesIn;
this.outTileDir = wayTilesOut;
borderNidsOutStream = createOutStream( borderNidsOut );
new WayIterator( this, true ).processDir( wayTilesIn, ".wtl" );
borderNidsOutStream.close();
}
@Override
public void wayFileStart( File wayfile ) throws Exception
{
// read corresponding node-file into tileIndexMap
String name = wayfile.getName();
String nodefilename = name.substring( 0, name.length()-3 ) + "tlf";
File nodefile = new File( nodeTilesIn, nodefilename );
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 6 ) : new TinyDenseLongMap();
lonoffset = -1;
latoffset = -1;
new NodeIterator( this, false ).processFile( nodefile );
}
@Override
public void nextNode( NodeData n ) throws Exception
{
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) );
}
@Override
public void nextWay( WayData data ) throws Exception
{
long waytileset = 0;
int nnodes = data.nodes.size();
int[] tiForNode = new int[nnodes];
// determine the tile-index for each node
for (int i=0; i<nnodes; i++ )
{
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) );
if ( tileIndex != -1 )
{
waytileset |= ( 1L << tileIndex );
}
tiForNode[i] = tileIndex;
}
// now write way to all tiles hit
for( int tileIndex=0; tileIndex<54; tileIndex++ )
{
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{
continue;
}
data.writeTo( getOutStreamForTile( tileIndex ) );
}
// and write edge nodes to the border-nid file
for( int i=0; i < nnodes; i++ )
{
int ti = tiForNode[i];
if ( ti != -1 )
{
if ( ( i > 0 && tiForNode[i-1] != ti ) || (i+1 < nnodes && tiForNode[i+1] != ti ) )
{
writeId( borderNidsOutStream, data.nodes.get(i) );
}
}
}
}
@Override
public void wayFileEnd( File wayFile ) throws Exception
{
closeTileOutStreams();
}
private int getTileIndex( int ilon, int ilat )
{
int lonoff = (ilon / 45000000 ) * 45;
int latoff = (ilat / 30000000 ) * 30;
if ( lonoffset == -1 ) lonoffset = lonoff;
if ( latoffset == -1 ) latoffset = latoff;
if ( lonoff != lonoffset || latoff != latoffset )
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
int lon = (ilon / 5000000) % 9;
int lat = (ilat / 5000000) % 6;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat );
return lon*6 + lat;
}
protected String getNameForTile( int tileIndex )
{
int lon = (tileIndex / 6 ) * 5 + lonoffset - 180;
int lat = (tileIndex % 6 ) * 5 + latoffset - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".wt5";
}
}

View file

@ -0,0 +1,62 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Container for waydata on the preprocessor level
*
* @author ab
*/
public class WayData extends MapCreatorBase
{
public long wid;
public long description;
public LongList nodes;
public WayData( long id )
{
wid = id;
nodes = new LongList( 16 );
}
public WayData( long id, LongList nodes )
{
wid = id;
this.nodes = nodes;
}
public WayData( DataInputStream di ) throws Exception
{
nodes = new LongList( 16 );
wid = readId( di) ;
description = di.readLong();
for (;;)
{
long nid = readId( di );
if ( nid == -1 ) break;
nodes.add( nid );
}
}
public void writeTo( DataOutputStream dos ) throws Exception
{
writeId( dos, wid );
dos.writeLong( description );
int size = nodes.size();
for( int i=0; i < size; i++ )
{
writeId( dos, nodes.get( i ) );
}
writeId( dos, -1 ); // stopbyte
}
}

View file

@ -0,0 +1,76 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import btools.util.*;
/**
* Iterate over a singe wayfile or a directory
* of waytiles and feed the ways to the callback listener
*
* @author ab
*/
public class WayIterator extends MapCreatorBase
{
private WayListener listener;
private boolean delete;
public WayIterator( WayListener wayListener, boolean deleteAfterReading )
{
listener = wayListener;
delete = deleteAfterReading;
}
public void processDir( File indir, String inSuffix ) throws Exception
{
if ( !indir.isDirectory() )
{
throw new IllegalArgumentException( "not a directory: " + indir );
}
File[] af = sortBySizeAsc( indir.listFiles() );
for( int i=0; i<af.length; i++ )
{
File wayfile = af[i];
if ( wayfile.getName().endsWith( inSuffix ) )
{
processFile( wayfile );
}
}
}
public void processFile(File wayfile) throws Exception
{
System.out.println( "*** WayIterator reading: " + wayfile );
listener.wayFileStart( wayfile );
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( wayfile ) ) );
try
{
for(;;)
{
WayData w = new WayData( di );
listener.nextWay( w );
}
}
catch( EOFException eof )
{
di.close();
}
listener.wayFileEnd( wayfile );
if ( delete && "true".equals( System.getProperty( "deletetmpfiles" ) ))
{
wayfile.delete();
}
}
}

View file

@ -0,0 +1,289 @@
package btools.mapcreator;
import java.io.*;
import java.util.*;
import btools.util.*;
import btools.expressions.BExpressionContext;
/**
* WayLinker finally puts the pieces together
* to create the rd5 files. For each 5*5 tile,
* the corresponding nodefile and wayfile is read,
* plus the (global) bordernodes file, and an rd5
* is written
*
* @author ab
*/
public class WayLinker extends MapCreatorBase
{
private File nodeTilesIn;
private File dataTilesOut;
private File borderFileIn;
private String dataTilesSuffix;
private boolean readingBorder;
private CompactLongMap<OsmNodeP> nodesMap;
private List<OsmNodeP> nodesList;
private CompactLongSet borderSet;
private short lookupVersion;
private BExpressionContext expctxWay;
private int minLon;
private int minLat;
private void reset()
{
minLon = -1;
minLat = -1;
nodesMap = new CompactLongMap<OsmNodeP>();
borderSet = new CompactLongSet();
}
public static void main(String[] args) throws Exception
{
System.out.println("*** WayLinker: Format a regionof an OSM map for routing");
if (args.length != 7)
{
System.out.println("usage: java WayLinker <node-tiles-in> <way-tiles-in> <bordernodes> <lookup-file> <profile-file> <data-tiles-out> <data-tiles-suffix> ");
return;
}
new WayLinker().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), new File( args[4] ), new File( args[5] ), args[6] );
}
public void process( File nodeTilesIn, File wayTilesIn, File borderFileIn, File lookupFile, File profileFile, File dataTilesOut, String dataTilesSuffix ) throws Exception
{
this.nodeTilesIn = nodeTilesIn;
this.dataTilesOut = dataTilesOut;
this.borderFileIn = borderFileIn;
this.dataTilesSuffix = dataTilesSuffix;
// read lookup file to get the lookup-version
expctxWay = new BExpressionContext("way");
expctxWay.readMetaData( lookupFile );
lookupVersion = expctxWay.lookupVersion;
expctxWay.parseFile( profileFile, "global" );
// then process all segments
new WayIterator( this, true ).processDir( wayTilesIn, ".wt5" );
}
@Override
public void wayFileStart( File wayfile ) throws Exception
{
// process corresponding node-file, if any
File nodeFile = fileFromTemplate( wayfile, nodeTilesIn, "u5d" );
if ( nodeFile.exists() )
{
reset();
// read the border file
readingBorder = true;
new NodeIterator( this, false ).processFile( borderFileIn );
borderSet = new FrozenLongSet( borderSet );
// read this tile's nodes
readingBorder = false;
new NodeIterator( this, false ).processFile( nodeFile );
// freeze the nodes-map
FrozenLongMap<OsmNodeP> nodesMapFrozen = new FrozenLongMap<OsmNodeP>( nodesMap );
nodesMap = nodesMapFrozen;
nodesList = nodesMapFrozen.getValueList();
}
}
@Override
public void nextNode( NodeData data ) throws Exception
{
OsmNodeP n = data.description == 0L ? new OsmNodeP() : new OsmNodePT(data.description);
n.ilon = data.ilon;
n.ilat = data.ilat;
n.selev = data.selev;
n.isBorder = readingBorder;
if ( readingBorder || (!borderSet.contains( data.nid )) )
{
nodesMap.fastPut( data.nid, n );
}
if ( readingBorder )
{
borderSet.fastAdd( data.nid );
return;
}
// remember the segment coords
int min_lon = (n.ilon / 5000000 ) * 5000000;
int min_lat = (n.ilat / 5000000 ) * 5000000;
if ( minLon == -1 ) minLon = min_lon;
if ( minLat == -1 ) minLat = min_lat;
if ( minLat != min_lat || minLon != min_lon )
throw new IllegalArgumentException( "inconsistent node: " + n.ilon + " " + n.ilat );
}
@Override
public void nextWay( WayData way ) throws Exception
{
long description = way.description;
long reverseDescription = description | 1L; // (add reverse bit)
// filter according to profile
expctxWay.evaluate( description, null );
boolean ok = expctxWay.getCostfactor() < 10000.;
expctxWay.evaluate( reverseDescription, null );
ok |= expctxWay.getCostfactor() < 10000.;
if ( !ok ) return;
byte lowbyte = (byte)description;
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 )
{
OsmLinkP l1 = new OsmLinkP();
l1.targetNode = n2;
l1.descriptionBitmap = description;
n1.addLink( l1 );
OsmLinkP l2 = new OsmLinkP();
l2.targetNode = n1;
l2.descriptionBitmap = reverseDescription;
n2.addLink( l2 );
}
if ( n2 != null )
{
n2.wayAndBits &= lowbyte;
if ( n2 instanceof OsmNodePT ) ((OsmNodePT)n2).wayOrBits |= lowbyte;
}
}
}
@Override
public void wayFileEnd( File wayfile ) throws Exception
{
nodesMap = null;
borderSet = null;
int maxLon = minLon + 5000000;
int maxLat = minLat + 5000000;
// write segment data to individual files
{
int nLonSegs = (maxLon - minLon)/1000000;
int nLatSegs = (maxLat - minLat)/1000000;
// sort the nodes into segments
LazyArrayOfLists<OsmNodeP> seglists = new LazyArrayOfLists<OsmNodeP>(nLonSegs*nLatSegs);
for( OsmNodeP n : nodesList )
{
if ( n == null || n.firstlink == null || n.isTransferNode() ) continue;
if ( n.ilon < minLon || n.ilon >= maxLon
|| n.ilat < minLat || n.ilat >= maxLat ) continue;
int lonIdx = (n.ilon-minLon)/1000000;
int latIdx = (n.ilat-minLat)/1000000;
int tileIndex = lonIdx * nLatSegs + latIdx;
seglists.getList(tileIndex).add( n );
}
nodesList = null;
seglists.trimAll();
// open the output file
File outfile = fileFromTemplate( wayfile, dataTilesOut, dataTilesSuffix );
DataOutputStream os = createOutStream( outfile );
// write 5*5 index dummy
long[] fileIndex = new long[25];
for( int i55=0; i55<25; i55++)
{
os.writeLong( 0 );
}
long filepos = 200L;
// sort further in 1/80-degree squares
for( int lonIdx = 0; lonIdx < nLonSegs; lonIdx++ )
{
for( int latIdx = 0; latIdx < nLatSegs; latIdx++ )
{
int tileIndex = lonIdx * nLatSegs + latIdx;
if ( seglists.getSize(tileIndex) > 0 )
{
List<OsmNodeP> nlist = seglists.getList(tileIndex);
LazyArrayOfLists<OsmNodeP> subs = new LazyArrayOfLists<OsmNodeP>(6400);
byte[][] subByteArrays = new byte[6400][];
for( int ni=0; ni<nlist.size(); ni++ )
{
OsmNodeP n = nlist.get(ni);
int subLonIdx = (n.ilon - minLon) / 12500 - 80*lonIdx;
int subLatIdx = (n.ilat - minLat) / 12500 - 80*latIdx;
int si = subLatIdx*80 + subLonIdx;
subs.getList(si).add( n );
}
subs.trimAll();
int[] posIdx = new int[6400];
int pos = 25600;
for( int si=0; si<6400; si++)
{
List<OsmNodeP> subList = subs.getList(si);
if ( subList.size() > 0 )
{
Collections.sort( subList );
ByteArrayOutputStream bos = new ByteArrayOutputStream( );
DataOutputStream dos = new DataOutputStream( bos );
dos.writeInt( subList.size() );
for( int ni=0; ni<subList.size(); ni++ )
{
OsmNodeP n = subList.get(ni);
n.writeNodeData( dos );
}
dos.close();
byte[] subBytes = bos.toByteArray();
pos += subBytes.length;
subByteArrays[si] = subBytes;
}
posIdx[si] = pos;
}
for( int si=0; si<6400; si++)
{
os.writeInt( posIdx[si] );
}
for( int si=0; si<6400; si++)
{
if ( subByteArrays[si] != null )
{
os.write( subByteArrays[si] );
}
}
filepos += pos;
}
fileIndex[ tileIndex ] = filepos;
}
}
os.close();
// re-open random-access to write file-index
RandomAccessFile ra = new RandomAccessFile( outfile, "rw" );
long versionPrefix = lookupVersion;
versionPrefix <<= 48;
for( int i55=0; i55<25; i55++)
{
ra.writeLong( fileIndex[i55] | versionPrefix );
}
ra.close();
}
}
}

View file

@ -0,0 +1,17 @@
package btools.mapcreator;
import java.io.File;
/**
* Callbacklistener for WayIterator
*
* @author ab
*/
public interface WayListener
{
void wayFileStart( File wayfile ) throws Exception;
void nextWay( WayData data ) throws Exception;
void wayFileEnd( File wayfile ) throws Exception;
}