Merge pull request #449 from zod/reformat-codebase

Reformat codebase
This commit is contained in:
afischerdev 2022-10-03 17:49:04 +02:00 committed by GitHub
commit 9662e50a43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
164 changed files with 15131 additions and 18545 deletions

View file

@ -7,3 +7,6 @@
# Reformat brouter-routing-app using Android Studio
54d5c5e9439be2c3df4c95b6fc12d33fdcc9b389
# Reformat whole codebase using Android Studio
c15913c1ab9befd8d583d4a7716d5043d2966f64

View file

@ -5,11 +5,10 @@ import btools.util.BitCoderContext;
/**
* Container for some re-usable databuffers for the decoder
*/
public final class DataBuffers
{
public final class DataBuffers {
public byte[] iobuffer;
public byte[] tagbuf1 = new byte[256];
public BitCoderContext bctx1 = new BitCoderContext( tagbuf1 );
public BitCoderContext bctx1 = new BitCoderContext(tagbuf1);
public byte[] bbuf1 = new byte[65636];
public int[] ibuf1 = new int[4096];
public int[] ibuf2 = new int[2048];
@ -17,17 +16,15 @@ public final class DataBuffers
public int[] alon = new int[2048];
public int[] alat = new int[2048];
public DataBuffers()
{
this( new byte[65636] );
public DataBuffers() {
this(new byte[65636]);
}
/**
* construct a set of databuffers except
* for 'iobuffer', where the given array is used
*/
public DataBuffers( byte[] iobuffer )
{
public DataBuffers(byte[] iobuffer) {
this.iobuffer = iobuffer;
}

View file

@ -3,16 +3,14 @@ package btools.codec;
/**
* Special integer fifo suitable for 3-pass encoding
*/
public class IntegerFifo3Pass
{
public class IntegerFifo3Pass {
private int[] a;
private int size;
private int pos;
private int pass;
public IntegerFifo3Pass( int capacity )
{
public IntegerFifo3Pass(int capacity) {
a = capacity < 4 ? new int[4] : new int[capacity];
}
@ -20,8 +18,7 @@ public class IntegerFifo3Pass
* Starts a new encoding pass and resets the reading pointer
* from the stats collected in pass2 and writes that to the given context
*/
public void init()
{
public void init() {
pass++;
pos = 0;
}
@ -29,14 +26,11 @@ public class IntegerFifo3Pass
/**
* writes to the fifo in pass2
*/
public void add( int value )
{
if ( pass == 2 )
{
if ( size == a.length )
{
public void add(int value) {
if (pass == 2) {
if (size == a.length) {
int[] aa = new int[2 * size];
System.arraycopy( a, 0, aa, 0, size );
System.arraycopy(a, 0, aa, 0, size);
a = aa;
}
a[size++] = value;
@ -46,16 +40,13 @@ public class IntegerFifo3Pass
/**
* reads from the fifo in pass3 (in pass1/2 returns just 1)
*/
public int getNext()
{
return pass == 3 ? get( pos++ ) : 1;
public int getNext() {
return pass == 3 ? get(pos++) : 1;
}
private int get( int idx )
{
if ( idx >= size )
{
throw new IndexOutOfBoundsException( "list size=" + size + " idx=" + idx );
private int get(int idx) {
if (idx >= size) {
throw new IndexOutOfBoundsException("list size=" + size + " idx=" + idx);
}
return a[idx];
}

View file

@ -3,8 +3,7 @@ package btools.codec;
/**
* Simple container for a list of lists of integers
*/
public class LinkedListContainer
{
public class LinkedListContainer {
private int[] ia; // prev, data, prev, data, ...
private int size;
private int[] startpointer; // 0=void, odd=head-data-cell
@ -12,49 +11,44 @@ public class LinkedListContainer
/**
* Construct a container for the given number of lists
*
* <p>
* If no default-buffer is given, an int[nlists*4] is constructed,
* able to hold 2 entries per list on average
*
* @param nlists the number of lists
* @param nlists the number of lists
* @param defaultbuffer an optional data array for re-use (gets replaced if too small)
*/
public LinkedListContainer( int nlists, int[] defaultbuffer )
{
ia = defaultbuffer == null ? new int[nlists*4] : defaultbuffer;
startpointer = new int[nlists];
public LinkedListContainer(int nlists, int[] defaultbuffer) {
ia = defaultbuffer == null ? new int[nlists * 4] : defaultbuffer;
startpointer = new int[nlists];
}
/**
* Add a data element to the given list
*
* @param listNr the list to add the data to
* @param data the data value
* @param data the data value
*/
public void addDataElement( int listNr, int data )
{
if ( size + 2 > ia.length )
{
public void addDataElement(int listNr, int data) {
if (size + 2 > ia.length) {
resize();
}
ia[size++] = startpointer[ listNr ];
startpointer[ listNr ] = size;
ia[size++] = startpointer[listNr];
startpointer[listNr] = size;
ia[size++] = data;
}
/**
* Initialize a list for reading
*
* @param listNr the list to initialize
* @return the number of entries in that list
*/
public int initList( int listNr )
{
public int initList(int listNr) {
int cnt = 0;
int lp = listpointer = startpointer[ listNr ];
while( lp != 0 )
{
lp = ia[ lp-1 ];
int lp = listpointer = startpointer[listNr];
while (lp != 0) {
lp = ia[lp - 1];
cnt++;
}
return cnt;
@ -67,21 +61,18 @@ public class LinkedListContainer
* @return the data element
* @throws IllegalArgumentException if no more element
*/
public int getDataElement()
{
if ( listpointer == 0 )
{
throw new IllegalArgumentException( "no more element!" );
public int getDataElement() {
if (listpointer == 0) {
throw new IllegalArgumentException("no more element!");
}
int data = ia[ listpointer ];
listpointer = ia[ listpointer-1 ];
int data = ia[listpointer];
listpointer = ia[listpointer - 1];
return data;
}
private void resize()
{
int[] ia2 = new int[2*ia.length];
System.arraycopy( ia, 0, ia2, 0, ia.length );
private void resize() {
int[] ia2 = new int[2 * ia.length];
System.arraycopy(ia, 0, ia2, 0, ia.length);
ia = ia2;
}
}

View file

@ -5,21 +5,20 @@ import btools.util.ByteDataWriter;
/**
* a micro-cache is a data cache for an area of some square kilometers or some
* hundreds or thousands nodes
*
* <p>
* This is the basic io-unit: always a full microcache is loaded from the
* data-file if a node is requested at a position not yet covered by the caches
* already loaded
*
* <p>
* The nodes are represented in a compact way (typical 20-50 bytes per node),
* but in a way that they do not depend on each other, and garbage collection is
* supported to remove the nodes already consumed from the cache.
*
* <p>
* The cache-internal data representation is different from that in the
* data-files, where a cache is encoded as a whole, allowing more
* redundancy-removal for a more compact encoding
*/
public class MicroCache extends ByteDataWriter
{
public class MicroCache extends ByteDataWriter {
protected int[] faid;
protected int[] fapos;
protected int size = 0;
@ -35,25 +34,21 @@ public class MicroCache extends ByteDataWriter
public static boolean debug = false;
protected MicroCache( byte[] ab )
{
super( ab );
protected MicroCache(byte[] ab) {
super(ab);
}
public final static MicroCache emptyNonVirgin = new MicroCache( null );
public final static MicroCache emptyNonVirgin = new MicroCache(null);
static
{
static {
emptyNonVirgin.virgin = false;
}
public static MicroCache emptyCache()
{
return new MicroCache( null ); // TODO: singleton?
public static MicroCache emptyCache() {
return new MicroCache(null); // TODO: singleton?
}
protected void init( int size )
{
protected void init(int size) {
this.size = size;
delcount = 0;
delbytes = 0;
@ -62,35 +57,31 @@ public class MicroCache extends ByteDataWriter
p2size >>= 1;
}
public final void finishNode( long id )
{
public final void finishNode(long id) {
fapos[size] = aboffset;
faid[size] = shrinkId( id );
faid[size] = shrinkId(id);
size++;
}
public final void discardNode()
{
aboffset = startPos( size );
public final void discardNode() {
aboffset = startPos(size);
}
public final int getSize()
{
public final int getSize() {
return size;
}
public final int getDataSize()
{
public final int getDataSize() {
return ab == null ? 0 : ab.length;
}
/**
* Set the internal reader (aboffset, aboffsetEnd) to the body data for the given id
*
* <p>
* If a node is not found in an empty cache, this is usually an edge-effect
* (data-file does not exist or neighboured data-files of differnt age),
* but is can as well be a symptom of a node-identity breaking bug.
*
* <p>
* Current implementation always returns false for not-found, however, for
* regression testing, at least for the case that is most likely a bug
* (node found but marked as deleted = ready for garbage collection
@ -98,38 +89,31 @@ public class MicroCache extends ByteDataWriter
*
* @return true if id was found
*/
public final boolean getAndClear( long id64 )
{
if ( size == 0 )
{
public final boolean getAndClear(long id64) {
if (size == 0) {
return false;
}
int id = shrinkId( id64 );
int id = shrinkId(id64);
int[] a = faid;
int offset = p2size;
int n = 0;
while (offset > 0)
{
while (offset > 0) {
int nn = n + offset;
if ( nn < size && a[nn] <= id )
{
if (nn < size && a[nn] <= id) {
n = nn;
}
offset >>= 1;
}
if ( a[n] == id )
{
if ( ( fapos[n] & 0x80000000 ) == 0 )
{
aboffset = startPos( n );
if (a[n] == id) {
if ((fapos[n] & 0x80000000) == 0) {
aboffset = startPos(n);
aboffsetEnd = fapos[n];
fapos[n] |= 0x80000000; // mark deleted
delbytes += aboffsetEnd - aboffset;
delcount++;
return true;
}
else // .. marked as deleted
} else // .. marked as deleted
{
// throw new RuntimeException( "MicroCache: node already consumed: id=" + id );
}
@ -137,43 +121,35 @@ public class MicroCache extends ByteDataWriter
return false;
}
protected final int startPos( int n )
{
protected final int startPos(int n) {
return n > 0 ? fapos[n - 1] & 0x7fffffff : 0;
}
public final int collect( int threshold )
{
if ( delcount <= threshold )
{
public final int collect(int threshold) {
if (delcount <= threshold) {
return 0;
}
virgin = false;
int nsize = size - delcount;
if ( nsize == 0 )
{
if (nsize == 0) {
faid = null;
fapos = null;
}
else
{
} else {
int[] nfaid = new int[nsize];
int[] nfapos = new int[nsize];
int idx = 0;
byte[] nab = new byte[ab.length - delbytes];
int nab_off = 0;
for ( int i = 0; i < size; i++ )
{
for (int i = 0; i < size; i++) {
int pos = fapos[i];
if ( ( pos & 0x80000000 ) == 0 )
{
int start = startPos( i );
if ((pos & 0x80000000) == 0) {
int start = startPos(i);
int end = fapos[i];
int len = end - start;
System.arraycopy( ab, start, nab, nab_off, len );
System.arraycopy(ab, start, nab, nab_off, len);
nfaid[idx] = faid[i];
nab_off += len;
nfapos[idx] = nab_off;
@ -185,17 +161,15 @@ public class MicroCache extends ByteDataWriter
ab = nab;
}
int deleted = delbytes;
init( nsize );
init(nsize);
return deleted;
}
public final void unGhost()
{
public final void unGhost() {
ghost = false;
delcount = 0;
delbytes = 0;
for ( int i = 0; i < size; i++ )
{
for (int i = 0; i < size; i++) {
fapos[i] &= 0x7fffffff; // clear deleted flags
}
}
@ -203,201 +177,168 @@ public class MicroCache extends ByteDataWriter
/**
* @return the 64-bit global id for the given cache-position
*/
public final long getIdForIndex( int i )
{
public final long getIdForIndex(int i) {
int id32 = faid[i];
return expandId( id32 );
return expandId(id32);
}
/**
* expand a 32-bit micro-cache-internal id into a 64-bit (lon|lat) global-id
*
*
* @see #shrinkId
*/
public long expandId( int id32 )
{
throw new IllegalArgumentException( "expandId for empty cache" );
public long expandId(int id32) {
throw new IllegalArgumentException("expandId for empty cache");
}
/**
* shrink a 64-bit (lon|lat) global-id into a a 32-bit micro-cache-internal id
*
*
* @see #expandId
*/
public int shrinkId( long id64 )
{
throw new IllegalArgumentException( "shrinkId for empty cache" );
public int shrinkId(long id64) {
throw new IllegalArgumentException("shrinkId for empty cache");
}
/**
* @return true if the given lon/lat position is internal for that micro-cache
*/
public boolean isInternal( int ilon, int ilat )
{
throw new IllegalArgumentException( "isInternal for empty cache" );
public boolean isInternal(int ilon, int ilat) {
throw new IllegalArgumentException("isInternal for empty cache");
}
/**
* (stasticially) encode the micro-cache into the format used in the datafiles
*
* @param buffer
* byte array to encode into (considered big enough)
*
* @param buffer byte array to encode into (considered big enough)
* @return the size of the encoded data
*/
public int encodeMicroCache( byte[] buffer )
{
throw new IllegalArgumentException( "encodeMicroCache for empty cache" );
public int encodeMicroCache(byte[] buffer) {
throw new IllegalArgumentException("encodeMicroCache for empty cache");
}
/**
* Compare the content of this microcache to another
*
*
* @return null if equals, else a diff-report
*/
public String compareWith( MicroCache mc )
{
String msg = _compareWith( mc );
if ( msg != null )
{
StringBuilder sb = new StringBuilder( msg );
sb.append( "\nencode cache:\n" ).append( summary() );
sb.append( "\ndecode cache:\n" ).append( mc.summary() );
public String compareWith(MicroCache mc) {
String msg = _compareWith(mc);
if (msg != null) {
StringBuilder sb = new StringBuilder(msg);
sb.append("\nencode cache:\n").append(summary());
sb.append("\ndecode cache:\n").append(mc.summary());
return sb.toString();
}
return null;
}
private String summary()
{
StringBuilder sb = new StringBuilder( "size=" + size + " aboffset=" + aboffset );
for ( int i = 0; i < size; i++ )
{
sb.append( "\nidx=" + i + " faid=" + faid[i] + " fapos=" + fapos[i] );
private String summary() {
StringBuilder sb = new StringBuilder("size=" + size + " aboffset=" + aboffset);
for (int i = 0; i < size; i++) {
sb.append("\nidx=" + i + " faid=" + faid[i] + " fapos=" + fapos[i]);
}
return sb.toString();
}
private String _compareWith( MicroCache mc )
{
if ( size != mc.size )
{
private String _compareWith(MicroCache mc) {
if (size != mc.size) {
return "size missmatch: " + size + "->" + mc.size;
}
for ( int i = 0; i < size; i++ )
{
if ( faid[i] != mc.faid[i] )
{
for (int i = 0; i < size; i++) {
if (faid[i] != mc.faid[i]) {
return "faid missmatch at index " + i + ":" + faid[i] + "->" + mc.faid[i];
}
int start = i > 0 ? fapos[i - 1] : 0;
int end = fapos[i] < mc.fapos[i] ? fapos[i] : mc.fapos[i];
int len = end - start;
for ( int offset = 0; offset < len; offset++ )
{
if ( mc.ab.length <= start + offset )
{
for (int offset = 0; offset < len; offset++) {
if (mc.ab.length <= start + offset) {
return "data buffer too small";
}
if ( ab[start + offset] != mc.ab[start + offset] )
{
if (ab[start + offset] != mc.ab[start + offset]) {
return "data missmatch at index " + i + " offset=" + offset;
}
}
if ( fapos[i] != mc.fapos[i] )
{
if (fapos[i] != mc.fapos[i]) {
return "fapos missmatch at index " + i + ":" + fapos[i] + "->" + mc.fapos[i];
}
}
if ( aboffset != mc.aboffset )
{
if (aboffset != mc.aboffset) {
return "datasize missmatch: " + aboffset + "->" + mc.aboffset;
}
return null;
}
public void calcDelta( MicroCache mc1, MicroCache mc2 )
{
int idx1 = 0;
int idx2 = 0;
public void calcDelta(MicroCache mc1, MicroCache mc2) {
int idx1 = 0;
int idx2 = 0;
while( idx1 < mc1.size || idx2 < mc2.size )
{
int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE;
int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE;
int id;
if ( id1 >= id2 )
{
id = id2;
int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
int len2 = mc2.fapos[idx2++] - start2;
while (idx1 < mc1.size || idx2 < mc2.size) {
int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE;
int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE;
int id;
if (id1 >= id2) {
id = id2;
int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
int len2 = mc2.fapos[idx2++] - start2;
if ( id1 == id2 )
{
// id exists in both caches, compare data
int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0;
int len1 = mc1.fapos[idx1++] - start1;
if ( len1 == len2 )
{
int i = 0;
while( i<len1 )
{
if ( mc1.ab[start1+i] != mc2.ab[start2+i] )
{
break;
}
i++;
}
if ( i == len1 )
{
continue; // same data -> do nothing
}
}
}
write( mc2.ab, start2, len2 );
}
else
{
idx1++;
id = id1; // deleted node
}
fapos[size] = aboffset;
faid[size] = id;
size++;
}
if (id1 == id2) {
// id exists in both caches, compare data
int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0;
int len1 = mc1.fapos[idx1++] - start1;
if (len1 == len2) {
int i = 0;
while (i < len1) {
if (mc1.ab[start1 + i] != mc2.ab[start2 + i]) {
break;
}
i++;
}
if (i == len1) {
continue; // same data -> do nothing
}
}
}
write(mc2.ab, start2, len2);
} else {
idx1++;
id = id1; // deleted node
}
fapos[size] = aboffset;
faid[size] = id;
size++;
}
}
public void addDelta( MicroCache mc1, MicroCache mc2, boolean keepEmptyNodes )
{
int idx1 = 0;
int idx2 = 0;
public void addDelta(MicroCache mc1, MicroCache mc2, boolean keepEmptyNodes) {
int idx1 = 0;
int idx2 = 0;
while( idx1 < mc1.size || idx2 < mc2.size )
{
int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE;
int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE;
if ( id1 >= id2 ) // data from diff file wins
{
int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
int len2 = mc2.fapos[idx2++] - start2;
if ( keepEmptyNodes || len2 > 0 )
{
write( mc2.ab, start2, len2 );
fapos[size] = aboffset;
faid[size++] = id2;
}
if ( id1 == id2 ) // // id exists in both caches
{
idx1++;
}
}
else // use data from base file
{
int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0;
int len1 = mc1.fapos[idx1++] - start1;
write( mc1.ab, start1, len1 );
fapos[size] = aboffset;
faid[size++] = id1;
}
}
while (idx1 < mc1.size || idx2 < mc2.size) {
int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE;
int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE;
if (id1 >= id2) // data from diff file wins
{
int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
int len2 = mc2.fapos[idx2++] - start2;
if (keepEmptyNodes || len2 > 0) {
write(mc2.ab, start2, len2);
fapos[size] = aboffset;
faid[size++] = id2;
}
if (id1 == id2) // // id exists in both caches
{
idx1++;
}
} else // use data from base file
{
int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0;
int len1 = mc1.fapos[idx1++] - start1;
write(mc1.ab, start1, len1);
fapos[size] = aboffset;
faid[size++] = id1;
}
}
}
}

View file

@ -9,222 +9,204 @@ import btools.util.IByteArrayUnifier;
* MicroCache2 is the new format that uses statistical encoding and
* is able to do access filtering and waypoint matching during encoding
*/
public final class MicroCache2 extends MicroCache
{
public final class MicroCache2 extends MicroCache {
private int lonBase;
private int latBase;
private int cellsize;
public MicroCache2( int size, byte[] databuffer, int lonIdx, int latIdx, int divisor )
{
super( databuffer ); // sets ab=databuffer, aboffset=0
public MicroCache2(int size, byte[] databuffer, int lonIdx, int latIdx, int divisor) {
super(databuffer); // sets ab=databuffer, aboffset=0
faid = new int[size];
fapos = new int[size];
this.size = 0;
cellsize = 1000000 / divisor;
lonBase = lonIdx*cellsize;
latBase = latIdx*cellsize;
}
public byte[] readUnified( int len, IByteArrayUnifier u )
{
byte[] b = u.unify( ab, aboffset, len );
aboffset += len;
return b;
lonBase = lonIdx * cellsize;
latBase = latIdx * cellsize;
}
public MicroCache2( StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher )
{
super( null );
public byte[] readUnified(int len, IByteArrayUnifier u) {
byte[] b = u.unify(ab, aboffset, len);
aboffset += len;
return b;
}
public MicroCache2(StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher) {
super(null);
cellsize = 1000000 / divisor;
lonBase = lonIdx*cellsize;
latBase = latIdx*cellsize;
lonBase = lonIdx * cellsize;
latBase = latIdx * cellsize;
TagValueCoder wayTagCoder = new TagValueCoder( bc, dataBuffers, wayValidator );
TagValueCoder nodeTagCoder = new TagValueCoder( bc, dataBuffers, null );
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder( bc );
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder( bc );
TagValueCoder wayTagCoder = new TagValueCoder(bc, dataBuffers, wayValidator);
TagValueCoder nodeTagCoder = new TagValueCoder(bc, dataBuffers, null);
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLatDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder transEleDiff = new NoisyDiffCoder( bc );
NoisyDiffCoder transEleDiff = new NoisyDiffCoder(bc);
size = bc.decodeNoisyNumber( 5 );
size = bc.decodeNoisyNumber(5);
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;
if ( debug ) System.out.println( "*** decoding cache of size=" + size + " for lonIdx=" + lonIdx + " latIdx=" + latIdx );
bc.decodeSortedArray( faid, 0, size, 29, 0 );
for( int n = 0; n<size; n++ )
{
long id64 = expandId( faid[n] );
alon[n] = (int)(id64 >> 32);
alat[n] = (int)(id64 & 0xffffffff);
int[] alon = size > dataBuffers.alon.length ? new int[size] : dataBuffers.alon;
int[] alat = size > dataBuffers.alat.length ? new int[size] : dataBuffers.alat;
if (debug)
System.out.println("*** decoding cache of size=" + size + " for lonIdx=" + lonIdx + " latIdx=" + latIdx);
bc.decodeSortedArray(faid, 0, size, 29, 0);
for (int n = 0; n < size; n++) {
long id64 = expandId(faid[n]);
alon[n] = (int) (id64 >> 32);
alat[n] = (int) (id64 & 0xffffffff);
}
int netdatasize = bc.decodeNoisyNumber( 10 );
int netdatasize = bc.decodeNoisyNumber(10);
ab = netdatasize > dataBuffers.bbuf1.length ? new byte[netdatasize] : dataBuffers.bbuf1;
aboffset = 0;
int[] validBits = new int[(size+31)>>5];
int[] validBits = new int[(size + 31) >> 5];
int finaldatasize = 0;
LinkedListContainer reverseLinks = new LinkedListContainer( size, dataBuffers.ibuf1 );
LinkedListContainer reverseLinks = new LinkedListContainer(size, dataBuffers.ibuf1);
int selev = 0;
for( int n=0; n<size; n++ ) // loop over nodes
{
for (int n = 0; n < size; n++) // loop over nodes
{
int ilon = alon[n];
int ilat = alat[n];
// future escapes (turn restrictions?)
short trExceptions = 0;
int featureId = bc.decodeVarBits();
if ( featureId == 13 )
{
if (featureId == 13) {
fapos[n] = aboffset;
validBits[ n >> 5 ] |= 1 << n; // mark dummy-node valid
validBits[n >> 5] |= 1 << n; // mark dummy-node valid
continue; // empty node escape (delta files only)
}
while( featureId != 0 )
{
int bitsize = bc.decodeNoisyNumber( 5 );
while (featureId != 0) {
int bitsize = bc.decodeNoisyNumber(5);
if ( featureId == 2 ) // exceptions to turn-restriction
if (featureId == 2) // exceptions to turn-restriction
{
trExceptions = (short)bc.decodeBounded( 1023 );
}
else if ( featureId == 1 ) // turn-restriction
trExceptions = (short) bc.decodeBounded(1023);
} else if (featureId == 1) // turn-restriction
{
writeBoolean( true );
writeShort( trExceptions ); // exceptions from previous feature
writeBoolean(true);
writeShort(trExceptions); // exceptions from previous feature
trExceptions = 0;
writeBoolean( bc.decodeBit() ); // isPositive
writeInt( ilon + bc.decodeNoisyDiff( 10 ) ); // fromLon
writeInt( ilat + bc.decodeNoisyDiff( 10 ) ); // fromLat
writeInt( ilon + bc.decodeNoisyDiff( 10 ) ); // toLon
writeInt( ilat + bc.decodeNoisyDiff( 10 ) ); // toLat
}
else
{
for( int i=0; i< bitsize; i++ ) bc.decodeBit(); // unknown feature, just skip
writeBoolean(bc.decodeBit()); // isPositive
writeInt(ilon + bc.decodeNoisyDiff(10)); // fromLon
writeInt(ilat + bc.decodeNoisyDiff(10)); // fromLat
writeInt(ilon + bc.decodeNoisyDiff(10)); // toLon
writeInt(ilat + bc.decodeNoisyDiff(10)); // toLat
} else {
for (int i = 0; i < bitsize; i++) bc.decodeBit(); // unknown feature, just skip
}
featureId = bc.decodeVarBits();
}
writeBoolean( false );
writeBoolean(false);
selev += nodeEleDiff.decodeSignedValue();
writeShort( (short) selev );
writeShort((short) selev);
TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet();
writeVarBytes( nodeTags == null ? null : nodeTags.data );
writeVarBytes(nodeTags == null ? null : nodeTags.data);
int links = bc.decodeNoisyNumber( 1 );
if ( debug ) System.out.println( "*** decoding node " + ilon + "/" + ilat + " with links=" + links );
for( int li=0; li<links; li++ )
{
int links = bc.decodeNoisyNumber(1);
if (debug)
System.out.println("*** decoding node " + ilon + "/" + ilat + " with links=" + links);
for (int li = 0; li < links; li++) {
int sizeoffset = 0;
int nodeIdx = n + nodeIdxDiff.decodeSignedValue();
int dlon_remaining;
int dlat_remaining;
boolean isReverse = false;
if ( nodeIdx != n ) // internal (forward-) link
if (nodeIdx != n) // internal (forward-) link
{
dlon_remaining = alon[nodeIdx] - ilon;
dlat_remaining = alat[nodeIdx] - ilat;
}
else
{
} else {
isReverse = bc.decodeBit();
dlon_remaining = extLonDiff.decodeSignedValue();
dlat_remaining = extLatDiff.decodeSignedValue();
}
if ( debug ) System.out.println( "*** decoding link to " + (ilon+dlon_remaining) + "/" + (ilat+dlat_remaining) + " extern=" + (nodeIdx == n) );
if (debug)
System.out.println("*** decoding link to " + (ilon + dlon_remaining) + "/" + (ilat + dlat_remaining) + " extern=" + (nodeIdx == n));
TagValueWrapper wayTags = wayTagCoder.decodeTagValueSet();
boolean linkValid = wayTags != null || wayValidator == null;
if ( linkValid )
{
if (linkValid) {
int startPointer = aboffset;
sizeoffset = writeSizePlaceHolder();
writeVarLengthSigned( dlon_remaining );
writeVarLengthSigned( dlat_remaining );
writeVarLengthSigned(dlon_remaining);
writeVarLengthSigned(dlat_remaining);
validBits[ n >> 5 ] |= 1 << n; // mark source-node valid
if ( nodeIdx != n ) // valid internal (forward-) link
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
validBits[ nodeIdx >> 5 ] |= 1 << nodeIdx; // mark target-node valid
reverseLinks.addDataElement(nodeIdx, n); // register reverse link
finaldatasize += 1 + aboffset - startPointer; // reserve place for reverse
validBits[nodeIdx >> 5] |= 1 << nodeIdx; // mark target-node valid
}
writeModeAndDesc( isReverse, wayTags == null ? null : wayTags.data );
writeModeAndDesc(isReverse, wayTags == null ? null : wayTags.data);
}
if ( !isReverse ) // write geometry for forward links only
if (!isReverse) // write geometry for forward links only
{
WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher;
int ilontarget = ilon + dlon_remaining;
int ilattarget = ilat + dlat_remaining;
if ( matcher != null )
{
if ( !matcher.start( ilon, ilat, ilontarget, ilattarget ) )
{
if (matcher != null) {
if (!matcher.start(ilon, ilat, ilontarget, ilattarget)) {
matcher = null;
}
}
int transcount = bc.decodeVarBits();
if ( debug ) System.out.println( "*** decoding geometry with count=" + transcount );
int count = transcount+1;
for( int i=0; i<transcount; i++ )
{
int dlon = bc.decodePredictedValue( dlon_remaining/count );
int dlat = bc.decodePredictedValue( dlat_remaining/count );
if (debug) System.out.println("*** decoding geometry with count=" + transcount);
int count = transcount + 1;
for (int i = 0; i < transcount; i++) {
int dlon = bc.decodePredictedValue(dlon_remaining / count);
int dlat = bc.decodePredictedValue(dlat_remaining / count);
dlon_remaining -= dlon;
dlat_remaining -= dlat;
count--;
int elediff = transEleDiff.decodeSignedValue();
if ( wayTags != null )
{
writeVarLengthSigned( dlon );
writeVarLengthSigned( dlat );
writeVarLengthSigned( elediff );
if (wayTags != null) {
writeVarLengthSigned(dlon);
writeVarLengthSigned(dlat);
writeVarLengthSigned(elediff);
}
if ( matcher != null ) matcher.transferNode( ilontarget - dlon_remaining, ilattarget - dlat_remaining );
if (matcher != null)
matcher.transferNode(ilontarget - dlon_remaining, ilattarget - dlat_remaining);
}
if ( matcher != null ) matcher.end();
if (matcher != null) matcher.end();
}
if ( linkValid )
{
injectSize( sizeoffset );
if (linkValid) {
injectSize(sizeoffset);
}
}
fapos[n] = aboffset;
}
// calculate final data size
int finalsize = 0;
int startpos = 0;
for( int i=0; i<size; i++ )
{
for (int i = 0; i < size; i++) {
int endpos = fapos[i];
if ( ( validBits[ i >> 5 ] & (1 << i ) ) != 0 )
{
finaldatasize += endpos-startpos;
finalsize++;
if ((validBits[i >> 5] & (1 << i)) != 0) {
finaldatasize += endpos - startpos;
finalsize++;
}
startpos = endpos;
}
@ -240,29 +222,26 @@ public final class MicroCache2 extends MicroCache
size = 0;
startpos = 0;
for ( int n = 0; n < sizeOld; n++ )
{
for (int n = 0; n < sizeOld; n++) {
int endpos = faposOld[n];
if ( ( validBits[ n >> 5 ] & (1 << n ) ) != 0 )
{
if ((validBits[n >> 5] & (1 << n)) != 0) {
int len = endpos - startpos;
System.arraycopy( abOld, startpos, ab, aboffset, len );
if ( debug )
System.out.println( "*** copied " + len + " bytes from " + aboffset + " for node " + n );
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 );
int cnt = reverseLinks.initList(n);
if (debug)
System.out.println("*** appending " + cnt + " reverse links for node " + n);
for ( int ri = 0; ri < cnt; ri++ )
{
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 );
writeVarLengthSigned(alon[nodeIdx] - alon[n]);
writeVarLengthSigned(alat[nodeIdx] - alat[n]);
writeModeAndDesc(true, null);
injectSize(sizeoffset);
}
faid[size] = faidOld[n];
fapos[size] = aboffset;
@ -270,65 +249,59 @@ public final class MicroCache2 extends MicroCache
}
startpos = endpos;
}
init( size );
init(size);
}
@Override
public long expandId( int id32 )
{
public long expandId(int id32) {
int dlon = 0;
int dlat = 0;
for( int bm = 1; bm < 0x8000; bm <<= 1 )
{
if ( (id32 & 1) != 0 ) dlon |= bm;
if ( (id32 & 2) != 0 ) dlat |= bm;
for (int bm = 1; bm < 0x8000; bm <<= 1) {
if ((id32 & 1) != 0) dlon |= bm;
if ((id32 & 2) != 0) dlat |= bm;
id32 >>= 2;
}
int lon32 = lonBase + dlon;
int lat32 = latBase + dlat;
return ((long)lon32)<<32 | lat32;
return ((long) lon32) << 32 | lat32;
}
@Override
public int shrinkId( long id64 )
{
int lon32 = (int)(id64 >> 32);
int lat32 = (int)(id64 & 0xffffffff);
public int shrinkId(long id64) {
int lon32 = (int) (id64 >> 32);
int lat32 = (int) (id64 & 0xffffffff);
int dlon = lon32 - lonBase;
int dlat = lat32 - latBase;
int id32 = 0;
for( int bm = 0x4000; bm > 0; bm >>= 1 )
{
for (int bm = 0x4000; bm > 0; bm >>= 1) {
id32 <<= 2;
if ( ( dlon & bm ) != 0 ) id32 |= 1;
if ( ( dlat & bm ) != 0 ) id32 |= 2;
if ((dlon & bm) != 0) id32 |= 1;
if ((dlat & bm) != 0) id32 |= 2;
}
return id32;
}
@Override
public boolean isInternal( int ilon, int ilat )
{
public boolean isInternal(int ilon, int ilat) {
return ilon >= lonBase && ilon < lonBase + cellsize
&& ilat >= latBase && ilat < latBase + cellsize;
&& ilat >= latBase && ilat < latBase + cellsize;
}
@Override
public int encodeMicroCache( byte[] buffer )
{
HashMap<Long,Integer> idMap = new HashMap<Long,Integer>();
for( int n=0; n<size; n++ ) // loop over nodes
public int encodeMicroCache(byte[] buffer) {
HashMap<Long, Integer> idMap = new HashMap<Long, Integer>();
for (int n = 0; n < size; n++) // loop over nodes
{
idMap.put( Long.valueOf( expandId( faid[n] ) ), Integer.valueOf( n ) );
idMap.put(Long.valueOf(expandId(faid[n])), Integer.valueOf(n));
}
IntegerFifo3Pass linkCounts = new IntegerFifo3Pass( 256 );
IntegerFifo3Pass transCounts = new IntegerFifo3Pass( 256 );
IntegerFifo3Pass restrictionBits = new IntegerFifo3Pass( 16 );
IntegerFifo3Pass linkCounts = new IntegerFifo3Pass(256);
IntegerFifo3Pass transCounts = new IntegerFifo3Pass(256);
IntegerFifo3Pass restrictionBits = new IntegerFifo3Pass(16);
TagValueCoder wayTagCoder = new TagValueCoder();
TagValueCoder nodeTagCoder = new TagValueCoder();
@ -337,182 +310,173 @@ public final class MicroCache2 extends MicroCache
NoisyDiffCoder extLonDiff = new NoisyDiffCoder();
NoisyDiffCoder extLatDiff = new NoisyDiffCoder();
NoisyDiffCoder transEleDiff = new NoisyDiffCoder();
int netdatasize = 0;
for(int pass=1;; pass++) // 3 passes: counters, stat-collection, encoding
for (int pass = 1; ; pass++) // 3 passes: counters, stat-collection, encoding
{
boolean dostats = pass == 3;
boolean dodebug = debug && pass == 3;
if ( pass < 3 ) netdatasize = fapos[size-1];
StatCoderContext bc = new StatCoderContext( buffer );
if (pass < 3) netdatasize = fapos[size - 1];
StatCoderContext bc = new StatCoderContext(buffer);
linkCounts.init();
transCounts.init();
restrictionBits.init();
wayTagCoder.encodeDictionary( bc );
if ( dostats ) bc.assignBits( "wayTagDictionary" );
nodeTagCoder.encodeDictionary( bc );
if ( dostats ) bc.assignBits( "nodeTagDictionary" );
nodeIdxDiff.encodeDictionary( bc );
nodeEleDiff.encodeDictionary( bc );
extLonDiff.encodeDictionary( bc );
extLatDiff.encodeDictionary( bc );
transEleDiff.encodeDictionary( bc );
if ( dostats ) bc.assignBits( "noisebits" );
bc.encodeNoisyNumber( size, 5 );
if ( dostats ) bc.assignBits( "nodecount" );
bc.encodeSortedArray( faid, 0, size, 0x20000000, 0 );
if ( dostats ) bc.assignBits( "node-positions" );
bc.encodeNoisyNumber( netdatasize, 10 ); // net-size
if ( dostats ) bc.assignBits( "netdatasize" );
if ( dodebug ) System.out.println( "*** encoding cache of size=" + size );
wayTagCoder.encodeDictionary(bc);
if (dostats) bc.assignBits("wayTagDictionary");
nodeTagCoder.encodeDictionary(bc);
if (dostats) bc.assignBits("nodeTagDictionary");
nodeIdxDiff.encodeDictionary(bc);
nodeEleDiff.encodeDictionary(bc);
extLonDiff.encodeDictionary(bc);
extLatDiff.encodeDictionary(bc);
transEleDiff.encodeDictionary(bc);
if (dostats) bc.assignBits("noisebits");
bc.encodeNoisyNumber(size, 5);
if (dostats) bc.assignBits("nodecount");
bc.encodeSortedArray(faid, 0, size, 0x20000000, 0);
if (dostats) bc.assignBits("node-positions");
bc.encodeNoisyNumber(netdatasize, 10); // net-size
if (dostats) bc.assignBits("netdatasize");
if (dodebug) System.out.println("*** encoding cache of size=" + size);
int lastSelev = 0;
for( int n=0; n<size; n++ ) // loop over nodes
for (int n = 0; n < size; n++) // loop over nodes
{
aboffset = startPos( n );
aboffset = startPos(n);
aboffsetEnd = fapos[n];
if ( dodebug ) System.out.println( "*** encoding node " + n + " from " + aboffset + " to " + aboffsetEnd );
if (dodebug)
System.out.println("*** encoding node " + n + " from " + aboffset + " to " + aboffsetEnd);
long id64 = expandId( faid[n] );
int ilon = (int)(id64 >> 32);
int ilat = (int)(id64 & 0xffffffff);
long id64 = expandId(faid[n]);
int ilon = (int) (id64 >> 32);
int ilat = (int) (id64 & 0xffffffff);
if ( aboffset == aboffsetEnd )
{
bc.encodeVarBits( 13 ); // empty node escape (delta files only)
if (aboffset == aboffsetEnd) {
bc.encodeVarBits(13); // empty node escape (delta files only)
continue;
}
// write turn restrictions
while( readBoolean() )
{
while (readBoolean()) {
short exceptions = readShort(); // except bikes, psv, ...
if ( exceptions != 0 )
{
bc.encodeVarBits( 2 ); // 2 = tr exceptions
bc.encodeNoisyNumber( 10 , 5 ); // bit-count
bc.encodeBounded( 1023 , exceptions & 1023 );
if (exceptions != 0) {
bc.encodeVarBits(2); // 2 = tr exceptions
bc.encodeNoisyNumber(10, 5); // bit-count
bc.encodeBounded(1023, exceptions & 1023);
}
bc.encodeVarBits( 1 ); // 1 = turn restriction
bc.encodeNoisyNumber( restrictionBits.getNext(), 5 ); // bit-count using look-ahead fifo
bc.encodeVarBits(1); // 1 = turn restriction
bc.encodeNoisyNumber(restrictionBits.getNext(), 5); // bit-count using look-ahead fifo
long b0 = bc.getWritingBitPosition();
bc.encodeBit( readBoolean() ); // isPositive
bc.encodeNoisyDiff( readInt() - ilon, 10 ); // fromLon
bc.encodeNoisyDiff( readInt() - ilat, 10 ); // fromLat
bc.encodeNoisyDiff( readInt() - ilon, 10 ); // toLon
bc.encodeNoisyDiff( readInt() - ilat, 10 ); // toLat
restrictionBits.add( (int)( bc.getWritingBitPosition() - b0 ) );
bc.encodeBit(readBoolean()); // isPositive
bc.encodeNoisyDiff(readInt() - ilon, 10); // fromLon
bc.encodeNoisyDiff(readInt() - ilat, 10); // fromLat
bc.encodeNoisyDiff(readInt() - ilon, 10); // toLon
bc.encodeNoisyDiff(readInt() - ilat, 10); // toLat
restrictionBits.add((int) (bc.getWritingBitPosition() - b0));
}
bc.encodeVarBits( 0 ); // end of extra data
bc.encodeVarBits(0); // end of extra data
if ( dostats ) bc.assignBits( "extradata" );
if (dostats) bc.assignBits("extradata");
int selev = readShort();
nodeEleDiff.encodeSignedValue( selev - lastSelev );
if ( dostats ) bc.assignBits( "nodeele" );
nodeEleDiff.encodeSignedValue(selev - lastSelev);
if (dostats) bc.assignBits("nodeele");
lastSelev = selev;
nodeTagCoder.encodeTagValueSet( readVarBytes() );
if ( dostats ) bc.assignBits( "nodeTagIdx" );
nodeTagCoder.encodeTagValueSet(readVarBytes());
if (dostats) bc.assignBits("nodeTagIdx");
int nlinks = linkCounts.getNext();
if ( dodebug ) System.out.println( "*** nlinks=" + nlinks );
bc.encodeNoisyNumber( nlinks, 1 );
if ( dostats ) bc.assignBits( "link-counts" );
if (dodebug) System.out.println("*** nlinks=" + nlinks);
bc.encodeNoisyNumber(nlinks, 1);
if (dostats) bc.assignBits("link-counts");
nlinks = 0;
while( hasMoreData() ) // loop over links
while (hasMoreData()) // loop over links
{
// read link data
int startPointer = aboffset;
int endPointer = getEndPointer();
int ilonlink = ilon + readVarLengthSigned();
int ilatlink = ilat + readVarLengthSigned();
int sizecode = readVarLengthUnsigned();
boolean isReverse = ( sizecode & 1 ) != 0;
boolean isReverse = (sizecode & 1) != 0;
int descSize = sizecode >> 1;
byte[] description = null;
if ( descSize > 0 )
{
if (descSize > 0) {
description = new byte[descSize];
readFully( description );
readFully(description);
}
long link64 = ((long)ilonlink)<<32 | ilatlink;
Integer idx = idMap.get( Long.valueOf( link64 ) );
long link64 = ((long) ilonlink) << 32 | ilatlink;
Integer idx = idMap.get(Long.valueOf(link64));
boolean isInternal = idx != null;
if ( isReverse && isInternal )
{
if ( dodebug ) System.out.println( "*** NOT encoding link reverse=" + isReverse + " internal=" + isInternal );
netdatasize -= aboffset-startPointer;
if (isReverse && isInternal) {
if (dodebug)
System.out.println("*** NOT encoding link reverse=" + isReverse + " internal=" + isInternal);
netdatasize -= aboffset - startPointer;
continue; // do not encode internal reverse links
}
if ( dodebug ) System.out.println( "*** encoding link reverse=" + isReverse + " internal=" + isInternal );
if (dodebug)
System.out.println("*** encoding link reverse=" + isReverse + " internal=" + isInternal);
nlinks++;
if ( isInternal )
{
if (isInternal) {
int nodeIdx = idx.intValue();
if ( dodebug ) System.out.println( "*** target nodeIdx=" + nodeIdx );
if ( nodeIdx == n ) throw new RuntimeException( "ups: self ref?" );
nodeIdxDiff.encodeSignedValue( nodeIdx - n );
if ( dostats ) bc.assignBits( "nodeIdx" );
if (dodebug) System.out.println("*** target nodeIdx=" + nodeIdx);
if (nodeIdx == n) throw new RuntimeException("ups: self ref?");
nodeIdxDiff.encodeSignedValue(nodeIdx - n);
if (dostats) bc.assignBits("nodeIdx");
} else {
nodeIdxDiff.encodeSignedValue(0);
bc.encodeBit(isReverse);
extLonDiff.encodeSignedValue(ilonlink - ilon);
extLatDiff.encodeSignedValue(ilatlink - ilat);
if (dostats) bc.assignBits("externalNode");
}
else
{
nodeIdxDiff.encodeSignedValue( 0 );
bc.encodeBit( isReverse );
extLonDiff.encodeSignedValue( ilonlink - ilon );
extLatDiff.encodeSignedValue( ilatlink - ilat );
if ( dostats ) bc.assignBits( "externalNode" );
}
wayTagCoder.encodeTagValueSet( description );
if ( dostats ) bc.assignBits( "wayDescIdx" );
if ( !isReverse )
{
byte[] geometry = readDataUntil( endPointer );
wayTagCoder.encodeTagValueSet(description);
if (dostats) bc.assignBits("wayDescIdx");
if (!isReverse) {
byte[] geometry = readDataUntil(endPointer);
// write transition nodes
int count = transCounts.getNext();
if ( dodebug ) System.out.println( "*** encoding geometry with count=" + count );
bc.encodeVarBits( count++ );
if ( dostats ) bc.assignBits( "transcount" );
if (dodebug) System.out.println("*** encoding geometry with count=" + count);
bc.encodeVarBits(count++);
if (dostats) bc.assignBits("transcount");
int transcount = 0;
if ( geometry != null )
{
if (geometry != null) {
int dlon_remaining = ilonlink - ilon;
int dlat_remaining = ilatlink - ilat;
ByteDataReader r = new ByteDataReader( geometry );
while ( r.hasMoreData() )
{
ByteDataReader r = new ByteDataReader(geometry);
while (r.hasMoreData()) {
transcount++;
int dlon = r.readVarLengthSigned();
int dlat = r.readVarLengthSigned();
bc.encodePredictedValue( dlon, dlon_remaining/count );
bc.encodePredictedValue( dlat, dlat_remaining/count );
bc.encodePredictedValue(dlon, dlon_remaining / count);
bc.encodePredictedValue(dlat, dlat_remaining / count);
dlon_remaining -= dlon;
dlat_remaining -= dlat;
if ( count > 1 ) count--;
if ( dostats ) bc.assignBits( "transpos" );
transEleDiff.encodeSignedValue( r.readVarLengthSigned() );
if ( dostats ) bc.assignBits( "transele" );
if (count > 1) count--;
if (dostats) bc.assignBits("transpos");
transEleDiff.encodeSignedValue(r.readVarLengthSigned());
if (dostats) bc.assignBits("transele");
}
}
transCounts.add( transcount );
transCounts.add(transcount);
}
}
linkCounts.add( nlinks );
linkCounts.add(nlinks);
}
if ( pass == 3 )
{
if (pass == 3) {
return bc.closeAndGetEncodedLength();
}
}

View file

@ -4,12 +4,11 @@ package btools.codec;
* Encoder/Decoder for signed integers that automatically detects the typical
* range of these numbers to determine a noisy-bit count as a very simple
* dictionary
*
* <p>
* Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding )
* but doesn't do anything at pass1
*/
public final class NoisyDiffCoder
{
public final class NoisyDiffCoder {
private int tot;
private int[] freqs;
private int noisybits;
@ -19,8 +18,7 @@ public final class NoisyDiffCoder
/**
* Create a decoder and read the noisy-bit count from the gibe context
*/
public NoisyDiffCoder( StatCoderContext bc )
{
public NoisyDiffCoder(StatCoderContext bc) {
noisybits = bc.decodeVarBits();
this.bc = bc;
}
@ -28,60 +26,49 @@ public final class NoisyDiffCoder
/**
* Create an encoder for 3-pass-encoding
*/
public NoisyDiffCoder()
{
public NoisyDiffCoder() {
}
/**
* encodes a signed int (pass3 only, stats collection in pass2)
*/
public void encodeSignedValue( int value )
{
if ( pass == 3 )
{
bc.encodeNoisyDiff( value, noisybits );
}
else if ( pass == 2 )
{
count( value < 0 ? -value : value );
public void encodeSignedValue(int value) {
if (pass == 3) {
bc.encodeNoisyDiff(value, noisybits);
} else if (pass == 2) {
count(value < 0 ? -value : value);
}
}
/**
* decodes a signed int
*/
public int decodeSignedValue()
{
return bc.decodeNoisyDiff( noisybits );
public int decodeSignedValue() {
return bc.decodeNoisyDiff(noisybits);
}
/**
* Starts a new encoding pass and (in pass3) calculates the noisy-bit count
* from the stats collected in pass2 and writes that to the given context
*/
public void encodeDictionary( StatCoderContext bc )
{
if ( ++pass == 3 )
{
public void encodeDictionary(StatCoderContext bc) {
if (++pass == 3) {
// how many noisy bits?
for ( noisybits = 0; noisybits < 14 && tot > 0; noisybits++ )
{
if ( freqs[noisybits] < ( tot >> 1 ) )
for (noisybits = 0; noisybits < 14 && tot > 0; noisybits++) {
if (freqs[noisybits] < (tot >> 1))
break;
}
bc.encodeVarBits( noisybits );
bc.encodeVarBits(noisybits);
}
this.bc = bc;
}
private void count( int value )
{
if ( freqs == null )
private void count(int value) {
if (freqs == null)
freqs = new int[14];
int bm = 1;
for ( int i = 0; i < 14; i++ )
{
if ( value < bm )
for (int i = 0; i < 14; i++) {
if (value < bm)
break;
else
freqs[i]++;

View file

@ -4,23 +4,19 @@ import java.util.TreeMap;
import btools.util.BitCoderContext;
public final class StatCoderContext extends BitCoderContext
{
public final class StatCoderContext extends BitCoderContext {
private static TreeMap<String, long[]> statsPerName;
private long lastbitpos = 0;
private static final int[] noisy_bits = new int[1024];
static
{
static {
// noisybits lookup
for( int i=0; i<1024; i++ )
{
for (int i = 0; i < 1024; i++) {
int p = i;
int noisybits = 0;
while (p > 2)
{
while (p > 2) {
noisybits++;
p >>= 1;
}
@ -29,29 +25,25 @@ public final class StatCoderContext extends BitCoderContext
}
public StatCoderContext( byte[] ab )
{
super( ab );
public StatCoderContext(byte[] ab) {
super(ab);
}
/**
* assign the de-/encoded bits since the last call assignBits to the given
* name. Used for encoding statistics
*
*
* @see #getBitReport
*/
public void assignBits( String name )
{
public void assignBits(String name) {
long bitpos = getWritingBitPosition();
if ( statsPerName == null )
{
if (statsPerName == null) {
statsPerName = new TreeMap<String, long[]>();
}
long[] stats = statsPerName.get( name );
if ( stats == null )
{
long[] stats = statsPerName.get(name);
if (stats == null) {
stats = new long[2];
statsPerName.put( name, stats );
statsPerName.put(name, stats);
}
stats[0] += bitpos - lastbitpos;
stats[1] += 1;
@ -60,20 +52,17 @@ public final class StatCoderContext extends BitCoderContext
/**
* Get a textual report on the bit-statistics
*
*
* @see #assignBits
*/
public static String getBitReport()
{
if ( statsPerName == null )
{
public static String getBitReport() {
if (statsPerName == null) {
return "<empty bit report>";
}
StringBuilder sb = new StringBuilder();
for ( String name : statsPerName.keySet() )
{
long[] stats = statsPerName.get( name );
sb.append( name + " count=" + stats[1] + " bits=" + stats[0] + "\n" );
for (String name : statsPerName.keySet()) {
long[] stats = statsPerName.get(name);
sb.append(name + " count=" + stats[1] + " bits=" + stats[0] + "\n");
}
statsPerName = null;
return sb.toString();
@ -82,76 +71,65 @@ public final class StatCoderContext extends BitCoderContext
/**
* encode an unsigned integer with some of of least significant bits
* considered noisy
*
*
* @see #decodeNoisyNumber
*/
public void encodeNoisyNumber( int value, int noisybits )
{
if ( value < 0 )
{
throw new IllegalArgumentException( "encodeVarBits expects positive value" );
public void encodeNoisyNumber(int value, int noisybits) {
if (value < 0) {
throw new IllegalArgumentException("encodeVarBits expects positive value");
}
if ( noisybits > 0 )
{
int mask = 0xffffffff >>> ( 32 - noisybits );
encodeBounded( mask, value & mask );
if (noisybits > 0) {
int mask = 0xffffffff >>> (32 - noisybits);
encodeBounded(mask, value & mask);
value >>= noisybits;
}
encodeVarBits( value );
encodeVarBits(value);
}
/**
* decode an unsigned integer with some of of least significant bits
* considered noisy
*
*
* @see #encodeNoisyNumber
*/
public int decodeNoisyNumber( int noisybits )
{
int value = decodeBits( noisybits );
return value | ( decodeVarBits() << noisybits );
public int decodeNoisyNumber(int noisybits) {
int value = decodeBits(noisybits);
return value | (decodeVarBits() << noisybits);
}
/**
* encode a signed integer with some of of least significant bits considered
* noisy
*
*
* @see #decodeNoisyDiff
*/
public void encodeNoisyDiff( int value, int noisybits )
{
if ( noisybits > 0 )
{
value += 1 << ( noisybits - 1 );
int mask = 0xffffffff >>> ( 32 - noisybits );
encodeBounded( mask, value & mask );
public void encodeNoisyDiff(int value, int noisybits) {
if (noisybits > 0) {
value += 1 << (noisybits - 1);
int mask = 0xffffffff >>> (32 - noisybits);
encodeBounded(mask, value & mask);
value >>= noisybits;
}
encodeVarBits( value < 0 ? -value : value );
if ( value != 0 )
{
encodeBit( value < 0 );
encodeVarBits(value < 0 ? -value : value);
if (value != 0) {
encodeBit(value < 0);
}
}
/**
* decode a signed integer with some of of least significant bits considered
* noisy
*
*
* @see #encodeNoisyDiff
*/
public int decodeNoisyDiff( int noisybits )
{
public int decodeNoisyDiff(int noisybits) {
int value = 0;
if ( noisybits > 0 )
{
value = decodeBits( noisybits ) - ( 1 << ( noisybits - 1 ) );
if (noisybits > 0) {
value = decodeBits(noisybits) - (1 << (noisybits - 1));
}
int val2 = decodeVarBits() << noisybits;
if ( val2 != 0 )
{
if ( decodeBit() )
{
if (val2 != 0) {
if (decodeBit()) {
val2 = -val2;
}
}
@ -161,38 +139,34 @@ public final class StatCoderContext extends BitCoderContext
/**
* encode a signed integer with the typical range and median taken from the
* predicted value
*
*
* @see #decodePredictedValue
*/
public void encodePredictedValue( int value, int predictor )
{
public void encodePredictedValue(int value, int predictor) {
int p = predictor < 0 ? -predictor : predictor;
int noisybits = 0;
while (p > 2)
{
while (p > 2) {
noisybits++;
p >>= 1;
}
encodeNoisyDiff( value - predictor, noisybits );
encodeNoisyDiff(value - predictor, noisybits);
}
/**
* decode a signed integer with the typical range and median taken from the
* predicted value
*
*
* @see #encodePredictedValue
*/
public int decodePredictedValue( int predictor )
{
public int decodePredictedValue(int predictor) {
int p = predictor < 0 ? -predictor : predictor;
int noisybits = 0;
while (p > 1023)
{
while (p > 1023) {
noisybits++;
p >>= 1;
}
return predictor + decodeNoisyDiff( noisybits + noisy_bits[p] );
return predictor + decodeNoisyDiff(noisybits + noisy_bits[p]);
}
/**
@ -201,30 +175,22 @@ public final class StatCoderContext extends BitCoderContext
* number of values with the current bit being 0. This yields an number of
* bits per value that only depends on the typical distance between subsequent
* values and also benefits
*
* @param values
* the array to encode
* @param offset
* position in this array where to start
* @param subsize
* number of values to encode
* @param nextbit
* bitmask with the most significant bit set to 1
* @param mask
* should be 0
*
* @param values the array to encode
* @param offset position in this array where to start
* @param subsize number of values to encode
* @param nextbit bitmask with the most significant bit set to 1
* @param mask should be 0
*/
public void encodeSortedArray( int[] values, int offset, int subsize, int nextbit, int mask )
{
if ( subsize == 1 ) // last-choice shortcut
public void encodeSortedArray(int[] values, int offset, int subsize, int nextbit, int mask) {
if (subsize == 1) // last-choice shortcut
{
while (nextbit != 0)
{
encodeBit( ( values[offset] & nextbit ) != 0 );
while (nextbit != 0) {
encodeBit((values[offset] & nextbit) != 0);
nextbit >>= 1;
}
}
if ( nextbit == 0 )
{
if (nextbit == 0) {
return;
}
@ -234,71 +200,55 @@ public final class StatCoderContext extends BitCoderContext
// count 0-bit-fraction
int i = offset;
int end = subsize + offset;
for ( ; i < end; i++ )
{
if ( ( values[i] & mask ) != data )
{
for (; i < end; i++) {
if ((values[i] & mask) != data) {
break;
}
}
int size1 = i - offset;
int size2 = subsize - size1;
encodeBounded( subsize, size1 );
if ( size1 > 0 )
{
encodeSortedArray( values, offset, size1, nextbit >> 1, mask );
encodeBounded(subsize, size1);
if (size1 > 0) {
encodeSortedArray(values, offset, size1, nextbit >> 1, mask);
}
if ( size2 > 0 )
{
encodeSortedArray( values, i, size2, nextbit >> 1, mask );
if (size2 > 0) {
encodeSortedArray(values, i, size2, nextbit >> 1, mask);
}
}
/**
* @param values the array to encode
* @param offset position in this array where to start
* @param subsize number of values to encode
* @param nextbit bitmask with the most significant bit set to 1
* @param value should be 0
* @see #encodeSortedArray
*
* @param values
* the array to encode
* @param offset
* position in this array where to start
* @param subsize
* number of values to encode
* @param nextbit
* bitmask with the most significant bit set to 1
* @param value
* should be 0
*/
public void decodeSortedArray( int[] values, int offset, int subsize, int nextbitpos, int value )
{
if ( subsize == 1 ) // last-choice shortcut
public void decodeSortedArray(int[] values, int offset, int subsize, int nextbitpos, int value) {
if (subsize == 1) // last-choice shortcut
{
if ( nextbitpos >= 0 )
{
value |= decodeBitsReverse( nextbitpos+1 );
if (nextbitpos >= 0) {
value |= decodeBitsReverse(nextbitpos + 1);
}
values[offset] = value;
return;
}
if ( nextbitpos < 0 )
{
while (subsize-- > 0)
{
if (nextbitpos < 0) {
while (subsize-- > 0) {
values[offset++] = value;
}
return;
}
int size1 = decodeBounded( subsize );
int size1 = decodeBounded(subsize);
int size2 = subsize - size1;
if ( size1 > 0 )
{
decodeSortedArray( values, offset, size1, nextbitpos-1, value );
if (size1 > 0) {
decodeSortedArray(values, offset, size1, nextbitpos - 1, value);
}
if ( size2 > 0 )
{
decodeSortedArray( values, offset + size1, size2, nextbitpos-1, value | (1 << nextbitpos) );
if (size2 > 0) {
decodeSortedArray(values, offset + size1, size2, nextbitpos - 1, value | (1 << nextbitpos));
}
}

View file

@ -8,51 +8,42 @@ import btools.util.BitCoderContext;
/**
* Encoder/Decoder for way-/node-descriptions
*
* <p>
* It detects identical descriptions and sorts them
* into a huffman-tree according to their frequencies
*
* <p>
* Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding )
* but doesn't do anything at pass1
*/
public final class TagValueCoder
{
public final class TagValueCoder {
private HashMap<TagValueSet, TagValueSet> identityMap;
private Object tree;
private BitCoderContext bc;
private int pass;
private int nextTagValueSetId;
public void encodeTagValueSet( byte[] data )
{
if ( pass == 1 )
{
public void encodeTagValueSet(byte[] data) {
if (pass == 1) {
return;
}
TagValueSet tvsProbe = new TagValueSet(nextTagValueSetId);
tvsProbe.data = data;
TagValueSet tvs = identityMap.get( tvsProbe );
if ( pass == 3 )
{
bc.encodeBounded( tvs.range - 1, tvs.code );
}
else if ( pass == 2 )
{
if ( tvs == null )
{
TagValueSet tvs = identityMap.get(tvsProbe);
if (pass == 3) {
bc.encodeBounded(tvs.range - 1, tvs.code);
} else if (pass == 2) {
if (tvs == null) {
tvs = tvsProbe;
nextTagValueSetId++;
identityMap.put( tvs, tvs );
identityMap.put(tvs, tvs);
}
tvs.frequency++;
}
}
public TagValueWrapper decodeTagValueSet()
{
public TagValueWrapper decodeTagValueSet() {
Object node = tree;
while (node instanceof TreeNode)
{
while (node instanceof TreeNode) {
TreeNode tn = (TreeNode) node;
boolean nextBit = bc.decodeBit();
node = nextBit ? tn.child2 : tn.child1;
@ -60,104 +51,87 @@ public final class TagValueCoder
return (TagValueWrapper) node;
}
public void encodeDictionary( BitCoderContext bc )
{
if ( ++pass == 3 )
{
if ( identityMap.size() == 0 )
{
public void encodeDictionary(BitCoderContext bc) {
if (++pass == 3) {
if (identityMap.size() == 0) {
TagValueSet dummy = new TagValueSet(nextTagValueSetId++);
identityMap.put( dummy, dummy );
identityMap.put(dummy, dummy);
}
PriorityQueue<TagValueSet> queue = new PriorityQueue<TagValueSet>(2*identityMap.size(), new TagValueSet.FrequencyComparator());
PriorityQueue<TagValueSet> queue = new PriorityQueue<TagValueSet>(2 * identityMap.size(), new TagValueSet.FrequencyComparator());
queue.addAll(identityMap.values());
while (queue.size() > 1)
{
while (queue.size() > 1) {
TagValueSet node = new TagValueSet(nextTagValueSetId++);
node.child1 = queue.poll();
node.child2 = queue.poll();
node.frequency = node.child1.frequency + node.child2.frequency;
queue.add( node );
queue.add(node);
}
TagValueSet root = queue.poll();
root.encode( bc, 1, 0 );
root.encode(bc, 1, 0);
}
this.bc = bc;
}
public TagValueCoder( BitCoderContext bc, DataBuffers buffers, TagValueValidator validator )
{
tree = decodeTree( bc, buffers, validator );
public TagValueCoder(BitCoderContext bc, DataBuffers buffers, TagValueValidator validator) {
tree = decodeTree(bc, buffers, validator);
this.bc = bc;
}
public TagValueCoder()
{
public TagValueCoder() {
identityMap = new HashMap<TagValueSet, TagValueSet>();
}
private Object decodeTree( BitCoderContext bc, DataBuffers buffers, TagValueValidator validator )
{
private Object decodeTree(BitCoderContext bc, DataBuffers buffers, TagValueValidator validator) {
boolean isNode = bc.decodeBit();
if ( isNode )
{
if (isNode) {
TreeNode node = new TreeNode();
node.child1 = decodeTree( bc, buffers, validator );
node.child2 = decodeTree( bc, buffers, validator );
node.child1 = decodeTree(bc, buffers, validator);
node.child2 = decodeTree(bc, buffers, validator);
return node;
}
byte[] buffer = buffers.tagbuf1;
BitCoderContext ctx = buffers.bctx1;
ctx.reset( buffer );
BitCoderContext ctx = buffers.bctx1;
ctx.reset(buffer);
int inum = 0;
int lastEncodedInum = 0;
boolean hasdata = false;
for ( ;; )
{
for (; ; ) {
int delta = bc.decodeVarBits();
if ( !hasdata )
{
if ( delta == 0 )
{
if (!hasdata) {
if (delta == 0) {
return null;
}
}
if ( delta == 0 )
{
ctx.encodeVarBits( 0 );
if (delta == 0) {
ctx.encodeVarBits(0);
break;
}
inum += delta;
int data = bc.decodeVarBits();
if ( validator == null || validator.isLookupIdxUsed( inum ) )
{
if (validator == null || validator.isLookupIdxUsed(inum)) {
hasdata = true;
ctx.encodeVarBits( inum - lastEncodedInum );
ctx.encodeVarBits( data );
ctx.encodeVarBits(inum - lastEncodedInum);
ctx.encodeVarBits(data);
lastEncodedInum = inum;
}
}
byte[] res;
int len = ctx.closeAndGetEncodedLength();
if ( validator == null )
{
if (validator == null) {
res = new byte[len];
System.arraycopy( buffer, 0, res, 0, len );
}
else
{
res = validator.unify( buffer, 0, len );
System.arraycopy(buffer, 0, res, 0, len);
} else {
res = validator.unify(buffer, 0, len);
}
int accessType = validator == null ? 2 : validator.accessType( res );
if ( accessType > 0 )
{
int accessType = validator == null ? 2 : validator.accessType(res);
if (accessType > 0) {
TagValueWrapper w = new TagValueWrapper();
w.data = res;
w.accessType = accessType;
@ -166,14 +140,12 @@ public final class TagValueCoder
return null;
}
public static final class TreeNode
{
public static final class TreeNode {
public Object child1;
public Object child2;
}
public static final class TagValueSet
{
public static final class TagValueSet {
public byte[] data;
public int frequency;
public int code;
@ -182,66 +154,51 @@ public final class TagValueCoder
public TagValueSet child2;
private int id; // serial number to make the comparator well defined in case of equal frequencies
public TagValueSet( int id )
{
public TagValueSet(int id) {
this.id = id;
}
public void encode( BitCoderContext bc, int range, int code )
{
public void encode(BitCoderContext bc, int range, int code) {
this.range = range;
this.code = code;
boolean isNode = child1 != null;
bc.encodeBit( isNode );
if ( isNode )
{
child1.encode( bc, range << 1, code );
child2.encode( bc, range << 1, code + range );
}
else
{
if ( data == null )
{
bc.encodeVarBits( 0 );
bc.encodeBit(isNode);
if (isNode) {
child1.encode(bc, range << 1, code);
child2.encode(bc, range << 1, code + range);
} else {
if (data == null) {
bc.encodeVarBits(0);
return;
}
BitCoderContext src = new BitCoderContext( data );
for ( ;; )
{
BitCoderContext src = new BitCoderContext(data);
for (; ; ) {
int delta = src.decodeVarBits();
bc.encodeVarBits( delta );
if ( delta == 0 )
{
bc.encodeVarBits(delta);
if (delta == 0) {
break;
}
int data = src.decodeVarBits();
bc.encodeVarBits( data );
bc.encodeVarBits(data);
}
}
}
@Override
public boolean equals( Object o )
{
if ( o instanceof TagValueSet )
{
public boolean equals(Object o) {
if (o instanceof TagValueSet) {
TagValueSet tvs = (TagValueSet) o;
if ( data == null )
{
if (data == null) {
return tvs.data == null;
}
if ( tvs.data == null )
{
if (tvs.data == null) {
return data == null;
}
if ( data.length != tvs.data.length )
{
if (data.length != tvs.data.length) {
return false;
}
for ( int i = 0; i < data.length; i++ )
{
if ( data[i] != tvs.data[i] )
{
for (int i = 0; i < data.length; i++) {
if (data[i] != tvs.data[i]) {
return false;
}
}
@ -251,39 +208,34 @@ public final class TagValueCoder
}
@Override
public int hashCode()
{
if ( data == null )
{
public int hashCode() {
if (data == null) {
return 0;
}
int h = 17;
for ( int i = 0; i < data.length; i++ )
{
h = ( h << 8 ) + data[i];
for (int i = 0; i < data.length; i++) {
h = (h << 8) + data[i];
}
return h;
}
public static class FrequencyComparator implements Comparator<TagValueSet>
{
public static class FrequencyComparator implements Comparator<TagValueSet> {
@Override
public int compare(TagValueSet tvs1, TagValueSet tvs2) {
if ( tvs1.frequency < tvs2.frequency )
if (tvs1.frequency < tvs2.frequency)
return -1;
if ( tvs1.frequency > tvs2.frequency )
if (tvs1.frequency > tvs2.frequency)
return 1;
// to avoid ordering instability, decide on the id if frequency is equal
if ( tvs1.id < tvs2.id )
if (tvs1.id < tvs2.id)
return -1;
if ( tvs1.id > tvs2.id )
if (tvs1.id > tvs2.id)
return 1;
if ( tvs1 != tvs2 )
{
throw new RuntimeException( "identity corruption!" );
if (tvs1 != tvs2) {
throw new RuntimeException("identity corruption!");
}
return 0;
}

View file

@ -1,17 +1,16 @@
package btools.codec;
public interface TagValueValidator
{
public interface TagValueValidator {
/**
* @param tagValueSet the way description to check
* @return 0 = nothing, 1=no matching, 2=normal
*/
public int accessType( byte[] tagValueSet );
public int accessType(byte[] tagValueSet);
public byte[] unify( byte[] tagValueSet, int offset, int len );
public byte[] unify(byte[] tagValueSet, int offset, int len);
public boolean isLookupIdxUsed( int idx );
public boolean isLookupIdxUsed(int idx);
public void setDecodeForbidden( boolean decodeForbidden );
public void setDecodeForbidden(boolean decodeForbidden);
}

View file

@ -5,8 +5,7 @@ package btools.codec;
* TagValueWrapper wrapps a description bitmap
* to add the access-type
*/
public final class TagValueWrapper
{
public final class TagValueWrapper {
public byte[] data;
public int accessType;
}

View file

@ -5,9 +5,10 @@ package btools.codec;
* from the decoder to find the closest
* matches to the waypoints
*/
public interface WaypointMatcher
{
boolean start( int ilonStart, int ilatStart, int ilonTarget, int ilatTarget );
void transferNode( int ilon, int ilat );
public interface WaypointMatcher {
boolean start(int ilonStart, int ilatStart, int ilonTarget, int ilatTarget);
void transferNode(int ilon, int ilat);
void end();
}

View file

@ -3,50 +3,39 @@ package btools.codec;
import org.junit.Assert;
import org.junit.Test;
public class LinkedListContainerTest
{
public class LinkedListContainerTest {
@Test
public void linkedListTest1()
{
public void linkedListTest1() {
int nlists = 553;
LinkedListContainer llc = new LinkedListContainer( nlists, null );
LinkedListContainer llc = new LinkedListContainer(nlists, null);
for ( int ln = 0; ln < nlists; ln++ )
{
for ( int i = 0; i < 10; i++ )
{
llc.addDataElement( ln, ln * i );
for (int ln = 0; ln < nlists; ln++) {
for (int i = 0; i < 10; i++) {
llc.addDataElement(ln, ln * i);
}
}
for ( int i = 0; i < 10; i++ )
{
for ( int ln = 0; ln < nlists; ln++ )
{
llc.addDataElement( ln, ln * i );
for (int i = 0; i < 10; i++) {
for (int ln = 0; ln < nlists; ln++) {
llc.addDataElement(ln, ln * i);
}
}
for ( int ln = 0; ln < nlists; ln++ )
{
int cnt = llc.initList( ln );
Assert.assertTrue( "list size test", cnt == 20 );
for (int ln = 0; ln < nlists; ln++) {
int cnt = llc.initList(ln);
Assert.assertTrue("list size test", cnt == 20);
for ( int i = 19; i >= 0; i-- )
{
for (int i = 19; i >= 0; i--) {
int data = llc.getDataElement();
Assert.assertTrue( "data value test", data == ln * ( i % 10 ) );
Assert.assertTrue("data value test", data == ln * (i % 10));
}
}
try
{
try {
llc.getDataElement();
Assert.fail( "no more elements expected" );
}
catch (IllegalArgumentException e)
{
Assert.fail("no more elements expected");
} catch (IllegalArgumentException e) {
}
}
}

View file

@ -6,100 +6,79 @@ import java.util.Random;
import org.junit.Assert;
import org.junit.Test;
public class StatCoderContextTest
{
public class StatCoderContextTest {
@Test
public void noisyVarBitsEncodeDecodeTest()
{
public void noisyVarBitsEncodeDecodeTest() {
byte[] ab = new byte[40000];
StatCoderContext ctx = new StatCoderContext( ab );
for ( int noisybits = 1; noisybits < 12; noisybits++ )
{
for ( int i = 0; i < 1000; i++ )
{
ctx.encodeNoisyNumber( i, noisybits );
StatCoderContext ctx = new StatCoderContext(ab);
for (int noisybits = 1; noisybits < 12; noisybits++) {
for (int i = 0; i < 1000; i++) {
ctx.encodeNoisyNumber(i, noisybits);
}
}
ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab );
ctx = new StatCoderContext(ab);
for ( int noisybits = 1; noisybits < 12; noisybits++ )
{
for ( int i = 0; i < 1000; i++ )
{
int value = ctx.decodeNoisyNumber( noisybits );
if ( value != i )
{
Assert.fail( "value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value );
for (int noisybits = 1; noisybits < 12; noisybits++) {
for (int i = 0; i < 1000; i++) {
int value = ctx.decodeNoisyNumber(noisybits);
if (value != i) {
Assert.fail("value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value);
}
}
}
}
@Test
public void noisySignedVarBitsEncodeDecodeTest()
{
public void noisySignedVarBitsEncodeDecodeTest() {
byte[] ab = new byte[80000];
StatCoderContext ctx = new StatCoderContext( ab );
for ( int noisybits = 0; noisybits < 12; noisybits++ )
{
for ( int i = -1000; i < 1000; i++ )
{
ctx.encodeNoisyDiff( i, noisybits );
StatCoderContext ctx = new StatCoderContext(ab);
for (int noisybits = 0; noisybits < 12; noisybits++) {
for (int i = -1000; i < 1000; i++) {
ctx.encodeNoisyDiff(i, noisybits);
}
}
ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab );
ctx = new StatCoderContext(ab);
for ( int noisybits = 0; noisybits < 12; noisybits++ )
{
for ( int i = -1000; i < 1000; i++ )
{
int value = ctx.decodeNoisyDiff( noisybits );
if ( value != i )
{
Assert.fail( "value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value );
for (int noisybits = 0; noisybits < 12; noisybits++) {
for (int i = -1000; i < 1000; i++) {
int value = ctx.decodeNoisyDiff(noisybits);
if (value != i) {
Assert.fail("value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value);
}
}
}
}
@Test
public void predictedValueEncodeDecodeTest()
{
public void predictedValueEncodeDecodeTest() {
byte[] ab = new byte[80000];
StatCoderContext ctx = new StatCoderContext( ab );
for ( int value = -100; value < 100; value += 5 )
{
for ( int predictor = -200; predictor < 200; predictor += 7 )
{
ctx.encodePredictedValue( value, predictor );
StatCoderContext ctx = new StatCoderContext(ab);
for (int value = -100; value < 100; value += 5) {
for (int predictor = -200; predictor < 200; predictor += 7) {
ctx.encodePredictedValue(value, predictor);
}
}
ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab );
ctx = new StatCoderContext(ab);
for ( int value = -100; value < 100; value += 5 )
{
for ( int predictor = -200; predictor < 200; predictor += 7 )
{
int decodedValue = ctx.decodePredictedValue( predictor );
if ( value != decodedValue )
{
Assert.fail( "value mismatch: value=" + value + " predictor=" + predictor + " decodedValue=" + decodedValue );
for (int value = -100; value < 100; value += 5) {
for (int predictor = -200; predictor < 200; predictor += 7) {
int decodedValue = ctx.decodePredictedValue(predictor);
if (value != decodedValue) {
Assert.fail("value mismatch: value=" + value + " predictor=" + predictor + " decodedValue=" + decodedValue);
}
}
}
}
@Test
public void sortedArrayEncodeDecodeTest()
{
public void sortedArrayEncodeDecodeTest() {
Random rand = new Random();
int size = 1000000;
int[] values = new int[size];
for ( int i = 0; i < size; i++ )
{
for (int i = 0; i < size; i++) {
values[i] = rand.nextInt() & 0x0fffffff;
}
values[5] = 175384; // force collision
@ -108,23 +87,21 @@ public class StatCoderContextTest
values[15] = 275384; // force neighbours
values[18] = 275385;
Arrays.sort( values );
Arrays.sort(values);
byte[] ab = new byte[3000000];
StatCoderContext ctx = new StatCoderContext( ab );
ctx.encodeSortedArray( values, 0, size, 0x08000000, 0 );
StatCoderContext ctx = new StatCoderContext(ab);
ctx.encodeSortedArray(values, 0, size, 0x08000000, 0);
ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab );
ctx = new StatCoderContext(ab);
int[] decodedValues = new int[size];
ctx.decodeSortedArray( decodedValues, 0, size, 27, 0 );
ctx.decodeSortedArray(decodedValues, 0, size, 27, 0);
for ( int i = 0; i < size; i++ )
{
if ( values[i] != decodedValues[i] )
{
Assert.fail( "mismatch at i=" + i + " " + values[i] + "<>" + decodedValues[i] );
for (int i = 0; i < size; i++) {
if (values[i] != decodedValues[i]) {
Assert.fail("mismatch at i=" + i + " " + values[i] + "<>" + decodedValues[i]);
}
}
}

View file

@ -11,15 +11,12 @@ import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
final class KinematicModel extends OsmPathModel
{
public OsmPrePath createPrePath()
{
final class KinematicModel extends OsmPathModel {
public OsmPrePath createPrePath() {
return new KinematicPrePath();
}
public OsmPath createPath()
{
public OsmPath createPath() {
return new KinematicPath();
}
@ -38,7 +35,7 @@ final class KinematicModel extends OsmPathModel
// derived values
public double pw; // balance power
public double cost0; // minimum possible cost per meter
private int wayIdxMaxspeed;
private int wayIdxMaxspeedExplicit;
private int wayIdxMinspeed;
@ -47,7 +44,7 @@ final class KinematicModel extends OsmPathModel
protected BExpressionContextWay ctxWay;
protected BExpressionContextNode ctxNode;
protected Map<String,String> params;
protected Map<String, String> params;
private boolean initDone = false;
@ -55,77 +52,67 @@ final class KinematicModel extends OsmPathModel
private double lastBreakingSpeed;
@Override
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> extraParams )
{
if ( !initDone )
{
public void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> extraParams) {
if (!initDone) {
ctxWay = expctxWay;
ctxNode = expctxNode;
wayIdxMaxspeed = ctxWay.getOutputVariableIndex( "maxspeed", false );
wayIdxMaxspeedExplicit = ctxWay.getOutputVariableIndex( "maxspeed_explicit", false );
wayIdxMinspeed = ctxWay.getOutputVariableIndex( "minspeed", false );
nodeIdxMaxspeed = ctxNode.getOutputVariableIndex( "maxspeed", false );
wayIdxMaxspeed = ctxWay.getOutputVariableIndex("maxspeed", false);
wayIdxMaxspeedExplicit = ctxWay.getOutputVariableIndex("maxspeed_explicit", false);
wayIdxMinspeed = ctxWay.getOutputVariableIndex("minspeed", false);
nodeIdxMaxspeed = ctxNode.getOutputVariableIndex("maxspeed", false);
initDone = true;
}
params = extraParams;
turnAngleDecayTime = getParam( "turnAngleDecayTime", 5.f );
f_roll = getParam( "f_roll", 232.f );
f_air = getParam( "f_air", 0.4f );
f_recup = getParam( "f_recup", 400.f );
p_standby = getParam( "p_standby", 250.f );
outside_temp = getParam( "outside_temp", 20.f );
recup_efficiency = getParam( "recup_efficiency", 0.7f );
totalweight = getParam( "totalweight", 1640.f );
vmax = getParam( "vmax", 80.f ) / 3.6;
leftWaySpeed = getParam( "leftWaySpeed", 12.f ) / 3.6;
rightWaySpeed = getParam( "rightWaySpeed", 12.f ) / 3.6;
turnAngleDecayTime = getParam("turnAngleDecayTime", 5.f);
f_roll = getParam("f_roll", 232.f);
f_air = getParam("f_air", 0.4f);
f_recup = getParam("f_recup", 400.f);
p_standby = getParam("p_standby", 250.f);
outside_temp = getParam("outside_temp", 20.f);
recup_efficiency = getParam("recup_efficiency", 0.7f);
totalweight = getParam("totalweight", 1640.f);
vmax = getParam("vmax", 80.f) / 3.6;
leftWaySpeed = getParam("leftWaySpeed", 12.f) / 3.6;
rightWaySpeed = getParam("rightWaySpeed", 12.f) / 3.6;
pw = 2. * f_air * vmax * vmax * vmax - p_standby;
cost0 = (pw+p_standby)/vmax + f_roll + f_air*vmax*vmax;
cost0 = (pw + p_standby) / vmax + f_roll + f_air * vmax * vmax;
}
protected float getParam( String name, float defaultValue )
{
String sval = params == null ? null : params.get( name );
if ( sval != null )
{
return Float.parseFloat( sval );
protected float getParam(String name, float defaultValue) {
String sval = params == null ? null : params.get(name);
if (sval != null) {
return Float.parseFloat(sval);
}
float v = ctxWay.getVariableValue( name, defaultValue );
if ( params != null )
{
params.put( name, "" + v );
float v = ctxWay.getVariableValue(name, defaultValue);
if (params != null) {
params.put(name, "" + v);
}
return v;
}
public float getWayMaxspeed()
{
return ctxWay.getBuildInVariable( wayIdxMaxspeed ) / 3.6f;
public float getWayMaxspeed() {
return ctxWay.getBuildInVariable(wayIdxMaxspeed) / 3.6f;
}
public float getWayMaxspeedExplicit()
{
return ctxWay.getBuildInVariable( wayIdxMaxspeedExplicit ) / 3.6f;
public float getWayMaxspeedExplicit() {
return ctxWay.getBuildInVariable(wayIdxMaxspeedExplicit) / 3.6f;
}
public float getWayMinspeed()
{
return ctxWay.getBuildInVariable( wayIdxMinspeed ) / 3.6f;
public float getWayMinspeed() {
return ctxWay.getBuildInVariable(wayIdxMinspeed) / 3.6f;
}
public float getNodeMaxspeed()
{
return ctxNode.getBuildInVariable( nodeIdxMaxspeed ) / 3.6f;
public float getNodeMaxspeed() {
return ctxNode.getBuildInVariable(nodeIdxMaxspeed) / 3.6f;
}
/**
* get the effective speed limit from the way-limit and vmax/vmin
*/
public double getEffectiveSpeedLimit( )
{
/**
* get the effective speed limit from the way-limit and vmax/vmin
*/
public double getEffectiveSpeedLimit() {
// performance related inline coding
double minspeed = getWayMinspeed();
double espeed = minspeed > vmax ? minspeed : vmax;
@ -133,30 +120,27 @@ final class KinematicModel extends OsmPathModel
return maxspeed < espeed ? maxspeed : espeed;
}
/**
* get the breaking speed for current balance-power (pw) and effective speed limit (vl)
*/
public double getBreakingSpeed( double vl )
{
if ( vl == lastEffectiveLimit )
{
/**
* get the breaking speed for current balance-power (pw) and effective speed limit (vl)
*/
public double getBreakingSpeed(double vl) {
if (vl == lastEffectiveLimit) {
return lastBreakingSpeed;
}
double v = vl*0.8;
double pw2 = pw+p_standby;
double v = vl * 0.8;
double pw2 = pw + p_standby;
double e = recup_efficiency;
double x0 = pw2/vl+f_air*e*vl*vl+(1.-e)*f_roll;
for(int i=0;i<5;i++)
{
double v2 = v*v;
double x = pw2/v+f_air*e*v2 - x0;
double dx = 2.*e*f_air*v - pw2/v2;
v -= x/dx;
double x0 = pw2 / vl + f_air * e * vl * vl + (1. - e) * f_roll;
for (int i = 0; i < 5; i++) {
double v2 = v * v;
double x = pw2 / v + f_air * e * v2 - x0;
double dx = 2. * e * f_air * v - pw2 / v2;
v -= x / dx;
}
lastEffectiveLimit = vl;
lastBreakingSpeed = v;
return v;
}

View file

@ -8,8 +8,7 @@ package btools.router;
import btools.util.FastMath;
final class KinematicPath extends OsmPath
{
final class KinematicPath extends OsmPath {
private double ekin; // kinetic energy (Joule)
private double totalTime; // travel time (seconds)
private double totalEnergy; // total route energy (Joule)
@ -17,9 +16,8 @@ final class KinematicPath extends OsmPath
private float floatingAngleRight; // sliding average right bend (degree)
@Override
protected void init( OsmPath orig )
{
KinematicPath origin = (KinematicPath)orig;
protected void init(OsmPath orig) {
KinematicPath origin = (KinematicPath) orig;
ekin = origin.ekin;
totalTime = origin.totalTime;
totalEnergy = origin.totalEnergy;
@ -29,8 +27,7 @@ final class KinematicPath extends OsmPath
}
@Override
protected void resetState()
{
protected void resetState() {
ekin = 0.;
totalTime = 0.;
totalEnergy = 0.;
@ -39,267 +36,237 @@ final class KinematicPath extends OsmPath
}
@Override
protected double processWaySection( RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier )
{
KinematicModel km = (KinematicModel)rc.pm;
protected double processWaySection(RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier) {
KinematicModel km = (KinematicModel) rc.pm;
double cost = 0.;
double extraTime = 0.;
if ( isStartpoint )
{
if (isStartpoint) {
// for forward direction, we start with target speed
if ( !rc.inverseDirection )
{
extraTime = 0.5 * (1. - cosangle ) * 40.; // 40 seconds turn penalty
if (!rc.inverseDirection) {
extraTime = 0.5 * (1. - cosangle) * 40.; // 40 seconds turn penalty
}
}
else
{
} else {
double turnspeed = 999.; // just high
if ( km.turnAngleDecayTime != 0. ) // process turn-angle slowdown
if (km.turnAngleDecayTime != 0.) // process turn-angle slowdown
{
if ( angle < 0 ) floatingAngleLeft -= (float)angle;
else floatingAngleRight += (float)angle;
float aa = Math.max( floatingAngleLeft, floatingAngleRight );
if (angle < 0) floatingAngleLeft -= (float) angle;
else floatingAngleRight += (float) angle;
float aa = Math.max(floatingAngleLeft, floatingAngleRight);
double curveSpeed = aa > 10. ? 200. / aa : 20.;
double curveSpeed = aa > 10. ? 200. / aa : 20.;
double distanceTime = dist / curveSpeed;
double decayFactor = FastMath.exp( - distanceTime / km.turnAngleDecayTime );
floatingAngleLeft = (float)( floatingAngleLeft * decayFactor );
floatingAngleRight = (float)( floatingAngleRight * decayFactor );
double decayFactor = FastMath.exp(-distanceTime / km.turnAngleDecayTime);
floatingAngleLeft = (float) (floatingAngleLeft * decayFactor);
floatingAngleRight = (float) (floatingAngleRight * decayFactor);
if ( curveSpeed < 20. )
{
if (curveSpeed < 20.) {
turnspeed = curveSpeed;
}
}
if ( nsection == 0 ) // process slowdown by crossing geometry
if (nsection == 0) // process slowdown by crossing geometry
{
double junctionspeed = 999.; // just high
int classifiermask = (int)rc.expctxWay.getClassifierMask();
int classifiermask = (int) rc.expctxWay.getClassifierMask();
// penalty for equal priority crossing
boolean hasLeftWay = false;
boolean hasRightWay = false;
boolean hasResidential = false;
for( OsmPrePath prePath = rc.firstPrePath; prePath != null; prePath = prePath.next )
{
KinematicPrePath pp = (KinematicPrePath)prePath;
for (OsmPrePath prePath = rc.firstPrePath; prePath != null; prePath = prePath.next) {
KinematicPrePath pp = (KinematicPrePath) prePath;
if ( ( (pp.classifiermask ^ classifiermask) & 8 ) != 0 ) // exactly one is linktype
if (((pp.classifiermask ^ classifiermask) & 8) != 0) // exactly one is linktype
{
continue;
}
if ( ( pp.classifiermask & 32 ) != 0 ) // touching a residential?
if ((pp.classifiermask & 32) != 0) // touching a residential?
{
hasResidential = true;
}
if ( pp.priorityclassifier > priorityclassifier || pp.priorityclassifier == priorityclassifier && priorityclassifier < 20 )
{
if (pp.priorityclassifier > priorityclassifier || pp.priorityclassifier == priorityclassifier && priorityclassifier < 20) {
double diff = pp.angle - angle;
if ( diff < -40. && diff > -140.) hasLeftWay = true;
if ( diff > 40. && diff < 140. ) hasRightWay = true;
if (diff < -40. && diff > -140.) hasLeftWay = true;
if (diff > 40. && diff < 140.) hasRightWay = true;
}
}
double residentialSpeed = 13.;
if ( hasLeftWay && junctionspeed > km.leftWaySpeed ) junctionspeed = km.leftWaySpeed;
if ( hasRightWay && junctionspeed > km.rightWaySpeed ) junctionspeed = km.rightWaySpeed;
if ( hasResidential && junctionspeed > residentialSpeed ) junctionspeed = residentialSpeed;
if (hasLeftWay && junctionspeed > km.leftWaySpeed) junctionspeed = km.leftWaySpeed;
if (hasRightWay && junctionspeed > km.rightWaySpeed) junctionspeed = km.rightWaySpeed;
if (hasResidential && junctionspeed > residentialSpeed) junctionspeed = residentialSpeed;
if ( (lastpriorityclassifier < 20) ^ (priorityclassifier < 20) )
{
if ((lastpriorityclassifier < 20) ^ (priorityclassifier < 20)) {
extraTime += 10.;
junctionspeed = 0; // full stop for entering or leaving road network
}
if ( lastpriorityclassifier != priorityclassifier && (classifiermask & 8) != 0 )
{
if (lastpriorityclassifier != priorityclassifier && (classifiermask & 8) != 0) {
extraTime += 2.; // two seconds for entering a link-type
}
turnspeed = turnspeed > junctionspeed ? junctionspeed : turnspeed;
if ( message != null )
{
message.vnode0 = (int) ( junctionspeed * 3.6 + 0.5 );
if (message != null) {
message.vnode0 = (int) (junctionspeed * 3.6 + 0.5);
}
}
cutEkin( km.totalweight, turnspeed ); // apply turnspeed
cutEkin(km.totalweight, turnspeed); // apply turnspeed
}
// linear temperature correction
double tcorr = (20.-km.outside_temp)*0.0035;
double tcorr = (20. - km.outside_temp) * 0.0035;
// air_pressure down 1mb/8m
double ecorr = 0.0001375 * (elevation - 100.);
double f_air = km.f_air * ( 1. + tcorr - ecorr );
double f_air = km.f_air * (1. + tcorr - ecorr);
double distanceCost = evolveDistance( km, dist, delta_h, f_air );
double distanceCost = evolveDistance(km, dist, delta_h, f_air);
if ( message != null )
{
message.costfactor = (float)(distanceCost/dist);
message.vmax = (int) ( km.getWayMaxspeed() * 3.6 + 0.5 );
message.vmaxExplicit = (int) ( km.getWayMaxspeedExplicit() * 3.6 + 0.5 );
message.vmin = (int) ( km.getWayMinspeed() * 3.6 + 0.5 );
message.extraTime = (int)(extraTime*1000);
if (message != null) {
message.costfactor = (float) (distanceCost / dist);
message.vmax = (int) (km.getWayMaxspeed() * 3.6 + 0.5);
message.vmaxExplicit = (int) (km.getWayMaxspeedExplicit() * 3.6 + 0.5);
message.vmin = (int) (km.getWayMinspeed() * 3.6 + 0.5);
message.extraTime = (int) (extraTime * 1000);
}
cost += extraTime * km.pw / km.cost0;
cost += extraTime * km.pw / km.cost0;
totalTime += extraTime;
return cost + distanceCost;
}
protected double evolveDistance( KinematicModel km, double dist, double delta_h, double f_air )
{
protected double evolveDistance(KinematicModel km, double dist, double delta_h, double f_air) {
// elevation force
double fh = delta_h * km.totalweight * 9.81 / dist;
double effectiveSpeedLimit = km.getEffectiveSpeedLimit();
double emax = 0.5*km.totalweight*effectiveSpeedLimit*effectiveSpeedLimit;
if ( emax <= 0. )
{
double emax = 0.5 * km.totalweight * effectiveSpeedLimit * effectiveSpeedLimit;
if (emax <= 0.) {
return -1.;
}
double vb = km.getBreakingSpeed( effectiveSpeedLimit );
double elow = 0.5*km.totalweight*vb*vb;
double vb = km.getBreakingSpeed(effectiveSpeedLimit);
double elow = 0.5 * km.totalweight * vb * vb;
double elapsedTime = 0.;
double dissipatedEnergy = 0.;
double v = Math.sqrt( 2. * ekin / km.totalweight );
double v = Math.sqrt(2. * ekin / km.totalweight);
double d = dist;
while( d > 0. )
{
while (d > 0.) {
boolean slow = ekin < elow;
boolean fast = ekin >= emax;
double etarget = slow ? elow : emax;
double f = km.f_roll + f_air*v*v + fh;
double f_recup = Math.max( 0., fast ? -f : (slow ? km.f_recup :0 ) -fh ); // additional recup for slow part
double f = km.f_roll + f_air * v * v + fh;
double f_recup = Math.max(0., fast ? -f : (slow ? km.f_recup : 0) - fh); // additional recup for slow part
f += f_recup;
double delta_ekin;
double timeStep;
double x;
if ( fast )
{
if (fast) {
x = d;
delta_ekin = x*f;
timeStep = x/v;
delta_ekin = x * f;
timeStep = x / v;
ekin = etarget;
}
else
{
delta_ekin = etarget-ekin;
double b = 2.*f_air / km.totalweight;
double x0 = delta_ekin/f;
double x0b = x0*b;
x = x0*(1. - x0b*(0.5 + x0b*(0.333333333-x0b*0.25 ) ) ); // = ln( delta_ekin*b/f + 1.) / b;
double maxstep = Math.min( 50., d );
if ( x >= maxstep )
{
} else {
delta_ekin = etarget - ekin;
double b = 2. * f_air / km.totalweight;
double x0 = delta_ekin / f;
double x0b = x0 * b;
x = x0 * (1. - x0b * (0.5 + x0b * (0.333333333 - x0b * 0.25))); // = ln( delta_ekin*b/f + 1.) / b;
double maxstep = Math.min(50., d);
if (x >= maxstep) {
x = maxstep;
double xb = x*b;
delta_ekin = x*f*(1.+xb*(0.5+xb*(0.166666667+xb*0.0416666667 ) ) ); // = f/b* exp(xb-1)
double xb = x * b;
delta_ekin = x * f * (1. + xb * (0.5 + xb * (0.166666667 + xb * 0.0416666667))); // = f/b* exp(xb-1)
ekin += delta_ekin;
}
else
{
} else {
ekin = etarget;
}
double v2 = Math.sqrt( 2. * ekin / km.totalweight );
double v2 = Math.sqrt(2. * ekin / km.totalweight);
double a = f / km.totalweight; // TODO: average force?
timeStep = (v2-v)/a;
timeStep = (v2 - v) / a;
v = v2;
}
d -= x;
elapsedTime += timeStep;
// dissipated energy does not contain elevation and efficient recup
dissipatedEnergy += delta_ekin - x*(fh + f_recup*km.recup_efficiency);
dissipatedEnergy += delta_ekin - x * (fh + f_recup * km.recup_efficiency);
// correction: inefficient recup going into heating is half efficient
double ieRecup = x*f_recup*(1.-km.recup_efficiency);
double eaux = timeStep*km.p_standby;
dissipatedEnergy -= Math.max( ieRecup, eaux ) * 0.5;
double ieRecup = x * f_recup * (1. - km.recup_efficiency);
double eaux = timeStep * km.p_standby;
dissipatedEnergy -= Math.max(ieRecup, eaux) * 0.5;
}
dissipatedEnergy += elapsedTime * km.p_standby;
totalTime += elapsedTime;
totalEnergy += dissipatedEnergy + dist*fh;
totalEnergy += dissipatedEnergy + dist * fh;
return (km.pw * elapsedTime + dissipatedEnergy)/km.cost0; // =cost
return (km.pw * elapsedTime + dissipatedEnergy) / km.cost0; // =cost
}
@Override
protected double processTargetNode( RoutingContext rc )
{
KinematicModel km = (KinematicModel)rc.pm;
protected double processTargetNode(RoutingContext rc) {
KinematicModel km = (KinematicModel) rc.pm;
// finally add node-costs for target node
if ( targetNode.nodeDescription != null )
{
rc.expctxNode.evaluate( false , targetNode.nodeDescription );
if (targetNode.nodeDescription != null) {
rc.expctxNode.evaluate(false, targetNode.nodeDescription);
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
if (initialcost >= 1000000.) {
return -1.;
}
cutEkin( km.totalweight, km.getNodeMaxspeed() ); // apply node maxspeed
cutEkin(km.totalweight, km.getNodeMaxspeed()); // apply node maxspeed
if ( message != null )
{
message.linknodecost += (int)initialcost;
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription( false, targetNode.nodeDescription );
if (message != null) {
message.linknodecost += (int) initialcost;
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription(false, targetNode.nodeDescription);
message.vnode1 = (int) ( km.getNodeMaxspeed() * 3.6 + 0.5 );
message.vnode1 = (int) (km.getNodeMaxspeed() * 3.6 + 0.5);
}
return initialcost;
}
return 0.;
}
private void cutEkin( double weight, double speed )
{
double e = 0.5*weight*speed*speed;
if ( ekin > e ) ekin = e;
private void cutEkin(double weight, double speed) {
double e = 0.5 * weight * speed * speed;
if (ekin > e) ekin = e;
}
@Override
public int elevationCorrection( RoutingContext rc )
{
public int elevationCorrection(RoutingContext rc) {
return 0;
}
@Override
public boolean definitlyWorseThan( OsmPath path, RoutingContext rc )
{
KinematicPath p = (KinematicPath)path;
public boolean definitlyWorseThan(OsmPath path, RoutingContext rc) {
KinematicPath p = (KinematicPath) path;
int c = p.cost;
return cost > c + 100;
int c = p.cost;
return cost > c + 100;
}
@Override
public double getTotalTime()
{
public double getTotalTime() {
return totalTime;
}
@Override
public double getTotalEnergy()
{
public double getTotalEnergy() {
return totalEnergy;
}
}

View file

@ -8,16 +8,14 @@ package btools.router;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
final class KinematicPrePath extends OsmPrePath
{
final class KinematicPrePath extends OsmPrePath {
public double angle;
public int priorityclassifier;
public int classifiermask;
protected void initPrePath(OsmPath origin, RoutingContext rc )
{
protected void initPrePath(OsmPath origin, RoutingContext rc) {
byte[] description = link.descriptionBitmap;
if ( description == null ) throw new IllegalArgumentException( "null description for: " + link );
if (description == null) throw new IllegalArgumentException("null description for: " + link);
// extract the 3 positions of the first section
int lon0 = origin.originLon;
@ -27,32 +25,29 @@ final class KinematicPrePath extends OsmPrePath
int lon1 = p1.getILon();
int lat1 = p1.getILat();
boolean isReverse = link.isReverse( sourceNode );
boolean isReverse = link.isReverse(sourceNode);
// evaluate the way tags
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
rc.expctxWay.evaluate(rc.inverseDirection ^ isReverse, description);
OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry( link.geometry, p1, targetNode, isReverse );
: rc.geometryDecoder.decodeGeometry(link.geometry, p1, targetNode, isReverse);
int lon2;
int lat2;
if ( transferNode == null )
{
if (transferNode == null) {
lon2 = targetNode.ilon;
lat2 = targetNode.ilat;
}
else
{
} else {
lon2 = transferNode.ilon;
lat2 = transferNode.ilat;
}
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
int dist = rc.calcDistance(lon1, lat1, lon2, lat2);
angle = rc.anglemeter.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
classifiermask = (int)rc.expctxWay.getClassifierMask();
angle = rc.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
priorityclassifier = (int) rc.expctxWay.getPriorityClassifier();
classifiermask = (int) rc.expctxWay.getClassifierMask();
}
}

View file

@ -6,15 +6,13 @@
package btools.router;
final class MessageData implements Cloneable
{
final class MessageData implements Cloneable {
int linkdist = 0;
int linkelevationcost = 0;
int linkturncost = 0;
int linknodecost = 0;
int linkinitcost = 0;
float costfactor;
int priorityclassifier;
int classifiermask;
@ -25,7 +23,7 @@ final class MessageData implements Cloneable
int lon;
int lat;
short ele;
float time;
float energy;
@ -37,84 +35,70 @@ final class MessageData implements Cloneable
int vnode1 = 999;
int extraTime = 0;
String toMessage()
{
if ( wayKeyValues == null )
{
String toMessage() {
if (wayKeyValues == null) {
return null;
}
int iCost = (int)(costfactor*1000 + 0.5f);
return (lon-180000000) + "\t"
+ (lat-90000000) + "\t"
+ ele/4 + "\t"
+ linkdist + "\t"
+ iCost + "\t"
+ linkelevationcost
+ "\t" + linkturncost
+ "\t" + linknodecost
+ "\t" + linkinitcost
+ "\t" + wayKeyValues
+ "\t" + ( nodeKeyValues == null ? "" : nodeKeyValues )
+ "\t" + ((int)time)
+ "\t" + ((int)energy);
int iCost = (int) (costfactor * 1000 + 0.5f);
return (lon - 180000000) + "\t"
+ (lat - 90000000) + "\t"
+ ele / 4 + "\t"
+ linkdist + "\t"
+ iCost + "\t"
+ linkelevationcost
+ "\t" + linkturncost
+ "\t" + linknodecost
+ "\t" + linkinitcost
+ "\t" + wayKeyValues
+ "\t" + (nodeKeyValues == null ? "" : nodeKeyValues)
+ "\t" + ((int) time)
+ "\t" + ((int) energy);
}
void add( MessageData d )
{
void add(MessageData d) {
linkdist += d.linkdist;
linkelevationcost += d.linkelevationcost;
linkturncost += d.linkturncost;
linknodecost += d.linknodecost;
linkinitcost+= d.linkinitcost;
linkinitcost += d.linkinitcost;
}
MessageData copy()
{
try
{
return (MessageData)clone();
}
catch( CloneNotSupportedException e )
{
throw new RuntimeException( e );
MessageData copy() {
try {
return (MessageData) clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString()
{
public String toString() {
return "dist=" + linkdist + " prio=" + priorityclassifier + " turn=" + turnangle;
}
public int getPrio()
{
public int getPrio() {
return priorityclassifier;
}
public boolean isBadOneway()
{
return ( classifiermask & 1 ) != 0;
public boolean isBadOneway() {
return (classifiermask & 1) != 0;
}
public boolean isGoodOneway()
{
return ( classifiermask & 2 ) != 0;
public boolean isGoodOneway() {
return (classifiermask & 2) != 0;
}
public boolean isRoundabout()
{
return ( classifiermask & 4 ) != 0;
public boolean isRoundabout() {
return (classifiermask & 4) != 0;
}
public boolean isLinktType()
{
return ( classifiermask & 8 ) != 0;
public boolean isLinktType() {
return (classifiermask & 8) != 0;
}
public boolean isGoodForCars()
{
return ( classifiermask & 16 ) != 0;
public boolean isGoodForCars() {
return (classifiermask & 16) != 0;
}
}

View file

@ -1,103 +1,98 @@
/**
* Container for an osm node
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
import btools.util.CheapRuler;
public class OsmNodeNamed extends OsmNode
{
public String name;
public double radius; // radius of nogopoint (in meters)
public double nogoWeight; // weight for nogopoint
public boolean isNogo = false;
public OsmNodeNamed()
{
}
public OsmNodeNamed( OsmNode n)
{
super( n.ilon, n.ilat );
}
@Override
public String toString()
{
if ( Double.isNaN(nogoWeight ) ) {
return ilon + "," + ilat + "," + name;
} else {
return ilon + "," + ilat + "," + name + "," + nogoWeight;
}
}
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lat1 + lat2) >> 1 );
boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius;
boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
// First point is within the circle
if (isFirstPointWithinCircle) {
// Last point is within the circle
if (isLastPointWithinCircle) {
return totalSegmentLength;
}
// Last point is not within the circle
// Just swap points and go on with first first point not within the
// circle now.
// Swap longitudes
int tmp = lon2;
lon2 = lon1;
lon1 = tmp;
// Swap latitudes
tmp = lat2;
lat2 = lat1;
lat1 = tmp;
// Fix boolean values
isLastPointWithinCircle = isFirstPointWithinCircle;
isFirstPointWithinCircle = false;
}
// Distance between the initial point and projection of center of
// the circle on the current segment.
double initialToProject = (
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
) / totalSegmentLength;
// Distance between the initial point and the center of the circle.
double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
// Half length of the segment within the circle
double halfDistanceWithin = Math.sqrt(
radius*radius - (
initialToCenter*initialToCenter -
initialToProject*initialToProject
)
);
// Last point is within the circle
if (isLastPointWithinCircle) {
return halfDistanceWithin + (totalSegmentLength - initialToProject);
}
return 2 * halfDistanceWithin;
}
public static OsmNodeNamed decodeNogo( String s )
{
OsmNodeNamed n = new OsmNodeNamed();
int idx1 = s.indexOf( ',' );
n.ilon = Integer.parseInt( s.substring( 0, idx1 ) );
int idx2 = s.indexOf( ',', idx1+1 );
n.ilat = Integer.parseInt( s.substring( idx1+1, idx2 ) );
int idx3 = s.indexOf( ',', idx2+1 );
if ( idx3 == -1) {
n.name = s.substring( idx2 + 1 );
n.nogoWeight = Double.NaN;
} else {
n.name = s.substring( idx2+1, idx3 );
n.nogoWeight = Double.parseDouble( s.substring( idx3 + 1 ) );
}
n.isNogo = true;
return n;
}
}
/**
* Container for an osm node
*
* @author ab
*/
package btools.router;
import btools.mapaccess.OsmNode;
import btools.util.CheapRuler;
public class OsmNodeNamed extends OsmNode {
public String name;
public double radius; // radius of nogopoint (in meters)
public double nogoWeight; // weight for nogopoint
public boolean isNogo = false;
public OsmNodeNamed() {
}
public OsmNodeNamed(OsmNode n) {
super(n.ilon, n.ilat);
}
@Override
public String toString() {
if (Double.isNaN(nogoWeight)) {
return ilon + "," + ilat + "," + name;
} else {
return ilon + "," + ilat + "," + name + "," + nogoWeight;
}
}
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lat1 + lat2) >> 1);
boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius;
boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
// First point is within the circle
if (isFirstPointWithinCircle) {
// Last point is within the circle
if (isLastPointWithinCircle) {
return totalSegmentLength;
}
// Last point is not within the circle
// Just swap points and go on with first first point not within the
// circle now.
// Swap longitudes
int tmp = lon2;
lon2 = lon1;
lon1 = tmp;
// Swap latitudes
tmp = lat2;
lat2 = lat1;
lat1 = tmp;
// Fix boolean values
isLastPointWithinCircle = isFirstPointWithinCircle;
isFirstPointWithinCircle = false;
}
// Distance between the initial point and projection of center of
// the circle on the current segment.
double initialToProject = (
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
) / totalSegmentLength;
// Distance between the initial point and the center of the circle.
double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
// Half length of the segment within the circle
double halfDistanceWithin = Math.sqrt(
radius * radius - (
initialToCenter * initialToCenter -
initialToProject * initialToProject
)
);
// Last point is within the circle
if (isLastPointWithinCircle) {
return halfDistanceWithin + (totalSegmentLength - initialToProject);
}
return 2 * halfDistanceWithin;
}
public static OsmNodeNamed decodeNogo(String s) {
OsmNodeNamed n = new OsmNodeNamed();
int idx1 = s.indexOf(',');
n.ilon = Integer.parseInt(s.substring(0, idx1));
int idx2 = s.indexOf(',', idx1 + 1);
n.ilat = Integer.parseInt(s.substring(idx1 + 1, idx2));
int idx3 = s.indexOf(',', idx2 + 1);
if (idx3 == -1) {
n.name = s.substring(idx2 + 1);
n.nogoWeight = Double.NaN;
} else {
n.name = s.substring(idx2 + 1, idx3);
n.nogoWeight = Double.parseDouble(s.substring(idx3 + 1));
}
n.isNogo = true;
return n;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,524 +1,444 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import java.io.IOException;
import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
import btools.mapaccess.TurnRestriction;
import btools.util.CheapRuler;
abstract class OsmPath implements OsmLinkHolder
{
/**
* The cost of that path (a modified distance)
*/
public int cost = 0;
// the elevation assumed for that path can have a value
// if the corresponding node has not
public short selev;
public int airdistance = 0; // distance to endpos
protected OsmNode sourceNode;
protected OsmNode targetNode;
protected OsmLink link;
public OsmPathElement originElement;
public OsmPathElement myElement;
protected float traffic;
private OsmLinkHolder nextForLink = null;
public int treedepth = 0;
// the position of the waypoint just before
// this path position (for angle calculation)
public int originLon;
public int originLat;
// the classifier of the segment just before this paths position
protected float lastClassifier;
protected float lastInitialCost;
protected int priorityclassifier;
private static final int PATH_START_BIT = 1;
private static final int CAN_LEAVE_DESTINATION_BIT = 2;
private static final int IS_ON_DESTINATION_BIT = 4;
private static final int HAD_DESTINATION_START_BIT = 8;
protected int bitfield = PATH_START_BIT;
private boolean getBit( int mask )
{
return (bitfield & mask ) != 0;
}
private void setBit( int mask, boolean bit )
{
if ( getBit( mask ) != bit )
{
bitfield ^= mask;
}
}
public boolean didEnterDestinationArea()
{
return !getBit( HAD_DESTINATION_START_BIT ) && getBit( IS_ON_DESTINATION_BIT );
}
public MessageData message;
public void unregisterUpTree( RoutingContext rc )
{
try
{
OsmPathElement pe = originElement;
while( pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic)pe).unregister(rc) )
{
pe = pe.origin;
}
}
catch( IOException ioe )
{
throw new RuntimeException( ioe );
}
}
public void registerUpTree()
{
if ( originElement instanceof OsmPathElementWithTraffic )
{
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)originElement;
ot.register();
ot.addTraffic( traffic );
}
}
public void init( OsmLink link )
{
this.link = link;
targetNode = link.getTarget( null );
selev = targetNode.getSElev();
originLon = -1;
originLat = -1;
}
public void init( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc )
{
if ( origin.myElement == null )
{
origin.myElement = OsmPathElement.create( origin, rc.countTraffic );
}
this.originElement = origin.myElement;
this.link = link;
this.sourceNode = origin.targetNode;
this.targetNode = link.getTarget( sourceNode );
this.cost = origin.cost;
this.lastClassifier = origin.lastClassifier;
this.lastInitialCost = origin.lastInitialCost;
this.bitfield = origin.bitfield;
init( origin );
addAddionalPenalty(refTrack, detailMode, origin, link, rc );
}
protected abstract void init( OsmPath orig );
protected abstract void resetState();
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc )
{
byte[] description = link.descriptionBitmap;
if ( description == null )
{
return; // could be a beeline path
}
boolean recordTransferNodes = detailMode || rc.countTraffic;
rc.nogoCost = 0.;
// extract the 3 positions of the first section
int lon0 = origin.originLon;
int lat0 = origin.originLat;
int lon1 = sourceNode.getILon();
int lat1 = sourceNode.getILat();
short ele1 = origin.selev;
int linkdisttotal = 0;
message = detailMode ? new MessageData() : null;
boolean isReverse = link.isReverse( sourceNode );
// evaluate the way tags
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description );
// calculate the costfactor inputs
float costfactor = rc.expctxWay.getCostfactor();
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
int lastpriorityclassifier = priorityclassifier;
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier();
// *** add initial cost if the classifier changed
float newClassifier = rc.expctxWay.getInitialClassifier();
float newInitialCost = rc.expctxWay.getInitialcost();
float classifierDiff = newClassifier - lastClassifier;
if ( newClassifier != 0. && lastClassifier != 0. && ( classifierDiff > 0.0005 || classifierDiff < -0.0005 ) )
{
float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost;
if ( initialcost >= 1000000. )
{
cost = -1;
return;
}
int iicost = (int)initialcost;
if ( message != null )
{
message.linkinitcost += iicost;
}
cost += iicost;
}
lastClassifier = newClassifier;
lastInitialCost = newInitialCost;
// *** destination logic: no destination access in between
int classifiermask = (int)rc.expctxWay.getClassifierMask();
boolean newDestination = (classifiermask & 64) != 0;
boolean oldDestination = getBit( IS_ON_DESTINATION_BIT );
if ( getBit( PATH_START_BIT ) )
{
setBit( PATH_START_BIT, false );
setBit( CAN_LEAVE_DESTINATION_BIT, newDestination );
setBit( HAD_DESTINATION_START_BIT, newDestination );
}
else
{
if ( oldDestination && !newDestination )
{
if ( getBit( CAN_LEAVE_DESTINATION_BIT ) )
{
setBit( CAN_LEAVE_DESTINATION_BIT, false );
}
else
{
cost = -1;
return;
}
}
}
setBit( IS_ON_DESTINATION_BIT, newDestination );
OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry( link.geometry, sourceNode, targetNode, isReverse );
for(int nsection=0; ;nsection++)
{
originLon = lon1;
originLat = lat1;
int lon2;
int lat2;
short ele2;
if ( transferNode == null )
{
lon2 = targetNode.ilon;
lat2 = targetNode.ilat;
ele2 = targetNode.selev;
}
else
{
lon2 = transferNode.ilon;
lat2 = transferNode.ilat;
ele2 = transferNode.selev;
}
boolean isStartpoint = lon0 == -1 && lat0 == -1;
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
if ( nsection == 0 && rc.considerTurnRestrictions && !detailMode&& !isStartpoint )
{
if ( rc.inverseDirection
? TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode )
: TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode ) )
{
cost = -1;
return;
}
}
// if recording, new MessageData for each section (needed for turn-instructions)
if ( message != null && message.wayKeyValues != null )
{
originElement.message = message;
message = new MessageData();
}
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 );
boolean stopAtEndpoint = false;
if ( rc.shortestmatch )
{
if ( rc.isEndpoint )
{
stopAtEndpoint = true;
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
}
else
{
// we just start here, reset everything
cost = 0;
resetState();
lon0 = -1; // reset turncost-pipe
lat0 = -1;
isStartpoint = true;
if ( recordTransferNodes )
{
if ( rc.wayfraction > 0. )
{
ele1 = interpolateEle( ele1, ele2, 1. - rc.wayfraction );
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic );
}
else
{
originElement = null; // prevent duplicate point
}
}
if ( rc.checkPendingEndpoint() )
{
dist = rc.calcDistance( rc.ilonshortest, rc.ilatshortest, lon2, lat2 );
if ( rc.shortestmatch )
{
stopAtEndpoint = true;
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
}
}
}
}
if ( message != null )
{
message.linkdist += dist;
}
linkdisttotal += dist;
// apply a start-direction if appropriate (by faking the origin position)
if ( isStartpoint )
{
if ( rc.startDirectionValid )
{
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lon0 + lat1) >> 1 );
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / lonlat2m[0] );
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) / lonlat2m[1] );
}
else
{
lon0 = lon1 - (lon2-lon1);
lat0 = lat1 - (lat2-lat1);
}
}
double angle = rc.anglemeter.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
double cosangle = rc.anglemeter.getCosAngle();
// *** elevation stuff
double delta_h = 0.;
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1;
if ( ele1 != Short.MIN_VALUE )
{
delta_h = (ele2 - ele1)/4.;
if ( rc.inverseDirection )
{
delta_h = -delta_h;
}
}
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.;
double sectionCost = processWaySection( rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier );
if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. )
{
cost = -1;
return;
}
if ( isTrafficBackbone )
{
sectionCost = 0.;
}
cost += (int)sectionCost;
// calculate traffic
if ( rc.countTraffic )
{
int minDist = (int)rc.trafficSourceMinDist;
int cost2 = cost < minDist ? minDist : cost;
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent);
}
// compute kinematic
computeKinematic( rc, dist, delta_h, detailMode );
if ( message != null )
{
message.turnangle = (float)angle;
message.time = (float)getTotalTime();
message.energy = (float)getTotalEnergy();
message.priorityclassifier = priorityclassifier;
message.classifiermask = classifiermask;
message.lon = lon2;
message.lat = lat2;
message.ele = ele2;
message.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description );
}
if ( stopAtEndpoint )
{
if ( recordTransferNodes )
{
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
originElement.cost = cost;
if ( message != null )
{
originElement.message = message;
}
}
if ( rc.nogoCost < 0)
{
cost = -1;
}
else
{
cost += rc.nogoCost;
}
return;
}
if ( transferNode == null )
{
// *** penalty for being part of the reference track
if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( sourceNode ) )
{
int reftrackcost = linkdisttotal;
cost += reftrackcost;
}
selev = ele2;
break;
}
transferNode = transferNode.next;
if ( recordTransferNodes )
{
originElement = OsmPathElement.create( lon2, lat2, ele2, originElement, rc.countTraffic );
originElement.cost = cost;
originElement.addTraffic( traffic );
traffic = 0;
}
lon0 = lon1;
lat0 = lat1;
lon1 = lon2;
lat1 = lat2;
ele1 = ele2;
}
// check for nogo-matches (after the *actual* start of segment)
if ( rc.nogoCost < 0)
{
cost = -1;
return;
}
else
{
cost += rc.nogoCost;
}
// add target-node costs
double targetCost = processTargetNode( rc );
if ( targetCost < 0. || targetCost + cost >= 2000000000. )
{
cost = -1;
return;
}
cost += (int)targetCost;
}
public short interpolateEle( short e1, short e2, double fraction )
{
if ( e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE )
{
return Short.MIN_VALUE;
}
return (short)( e1*(1.-fraction) + e2*fraction );
}
protected abstract double processWaySection( RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier );
protected abstract double processTargetNode( RoutingContext rc );
protected void computeKinematic( RoutingContext rc, double dist, double delta_h, boolean detailMode )
{
}
public abstract int elevationCorrection( RoutingContext rc );
public abstract boolean definitlyWorseThan( OsmPath p, RoutingContext rc );
public OsmNode getSourceNode()
{
return sourceNode;
}
public OsmNode getTargetNode()
{
return targetNode;
}
public OsmLink getLink()
{
return link;
}
public void setNextForLink( OsmLinkHolder holder )
{
nextForLink = holder;
}
public OsmLinkHolder getNextForLink()
{
return nextForLink;
}
public double getTotalTime()
{
return 0.;
}
public double getTotalEnergy()
{
return 0.;
}
}
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.router;
import java.io.IOException;
import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
import btools.mapaccess.TurnRestriction;
import btools.util.CheapRuler;
abstract class OsmPath implements OsmLinkHolder {
/**
* The cost of that path (a modified distance)
*/
public int cost = 0;
// the elevation assumed for that path can have a value
// if the corresponding node has not
public short selev;
public int airdistance = 0; // distance to endpos
protected OsmNode sourceNode;
protected OsmNode targetNode;
protected OsmLink link;
public OsmPathElement originElement;
public OsmPathElement myElement;
protected float traffic;
private OsmLinkHolder nextForLink = null;
public int treedepth = 0;
// the position of the waypoint just before
// this path position (for angle calculation)
public int originLon;
public int originLat;
// the classifier of the segment just before this paths position
protected float lastClassifier;
protected float lastInitialCost;
protected int priorityclassifier;
private static final int PATH_START_BIT = 1;
private static final int CAN_LEAVE_DESTINATION_BIT = 2;
private static final int IS_ON_DESTINATION_BIT = 4;
private static final int HAD_DESTINATION_START_BIT = 8;
protected int bitfield = PATH_START_BIT;
private boolean getBit(int mask) {
return (bitfield & mask) != 0;
}
private void setBit(int mask, boolean bit) {
if (getBit(mask) != bit) {
bitfield ^= mask;
}
}
public boolean didEnterDestinationArea() {
return !getBit(HAD_DESTINATION_START_BIT) && getBit(IS_ON_DESTINATION_BIT);
}
public MessageData message;
public void unregisterUpTree(RoutingContext rc) {
try {
OsmPathElement pe = originElement;
while (pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic) pe).unregister(rc)) {
pe = pe.origin;
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public void registerUpTree() {
if (originElement instanceof OsmPathElementWithTraffic) {
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) originElement;
ot.register();
ot.addTraffic(traffic);
}
}
public void init(OsmLink link) {
this.link = link;
targetNode = link.getTarget(null);
selev = targetNode.getSElev();
originLon = -1;
originLat = -1;
}
public void init(OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc) {
if (origin.myElement == null) {
origin.myElement = OsmPathElement.create(origin, rc.countTraffic);
}
this.originElement = origin.myElement;
this.link = link;
this.sourceNode = origin.targetNode;
this.targetNode = link.getTarget(sourceNode);
this.cost = origin.cost;
this.lastClassifier = origin.lastClassifier;
this.lastInitialCost = origin.lastInitialCost;
this.bitfield = origin.bitfield;
init(origin);
addAddionalPenalty(refTrack, detailMode, origin, link, rc);
}
protected abstract void init(OsmPath orig);
protected abstract void resetState();
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc) {
byte[] description = link.descriptionBitmap;
if (description == null) {
return; // could be a beeline path
}
boolean recordTransferNodes = detailMode || rc.countTraffic;
rc.nogoCost = 0.;
// extract the 3 positions of the first section
int lon0 = origin.originLon;
int lat0 = origin.originLat;
int lon1 = sourceNode.getILon();
int lat1 = sourceNode.getILat();
short ele1 = origin.selev;
int linkdisttotal = 0;
message = detailMode ? new MessageData() : null;
boolean isReverse = link.isReverse(sourceNode);
// evaluate the way tags
rc.expctxWay.evaluate(rc.inverseDirection ^ isReverse, description);
// calculate the costfactor inputs
float costfactor = rc.expctxWay.getCostfactor();
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
int lastpriorityclassifier = priorityclassifier;
priorityclassifier = (int) rc.expctxWay.getPriorityClassifier();
// *** add initial cost if the classifier changed
float newClassifier = rc.expctxWay.getInitialClassifier();
float newInitialCost = rc.expctxWay.getInitialcost();
float classifierDiff = newClassifier - lastClassifier;
if (newClassifier != 0. && lastClassifier != 0. && (classifierDiff > 0.0005 || classifierDiff < -0.0005)) {
float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost;
if (initialcost >= 1000000.) {
cost = -1;
return;
}
int iicost = (int) initialcost;
if (message != null) {
message.linkinitcost += iicost;
}
cost += iicost;
}
lastClassifier = newClassifier;
lastInitialCost = newInitialCost;
// *** destination logic: no destination access in between
int classifiermask = (int) rc.expctxWay.getClassifierMask();
boolean newDestination = (classifiermask & 64) != 0;
boolean oldDestination = getBit(IS_ON_DESTINATION_BIT);
if (getBit(PATH_START_BIT)) {
setBit(PATH_START_BIT, false);
setBit(CAN_LEAVE_DESTINATION_BIT, newDestination);
setBit(HAD_DESTINATION_START_BIT, newDestination);
} else {
if (oldDestination && !newDestination) {
if (getBit(CAN_LEAVE_DESTINATION_BIT)) {
setBit(CAN_LEAVE_DESTINATION_BIT, false);
} else {
cost = -1;
return;
}
}
}
setBit(IS_ON_DESTINATION_BIT, newDestination);
OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry(link.geometry, sourceNode, targetNode, isReverse);
for (int nsection = 0; ; nsection++) {
originLon = lon1;
originLat = lat1;
int lon2;
int lat2;
short ele2;
if (transferNode == null) {
lon2 = targetNode.ilon;
lat2 = targetNode.ilat;
ele2 = targetNode.selev;
} else {
lon2 = transferNode.ilon;
lat2 = transferNode.ilat;
ele2 = transferNode.selev;
}
boolean isStartpoint = lon0 == -1 && lat0 == -1;
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
if (nsection == 0 && rc.considerTurnRestrictions && !detailMode && !isStartpoint) {
if (rc.inverseDirection
? TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode)
: TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode)) {
cost = -1;
return;
}
}
// if recording, new MessageData for each section (needed for turn-instructions)
if (message != null && message.wayKeyValues != null) {
originElement.message = message;
message = new MessageData();
}
int dist = rc.calcDistance(lon1, lat1, lon2, lat2);
boolean stopAtEndpoint = false;
if (rc.shortestmatch) {
if (rc.isEndpoint) {
stopAtEndpoint = true;
ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
} else {
// we just start here, reset everything
cost = 0;
resetState();
lon0 = -1; // reset turncost-pipe
lat0 = -1;
isStartpoint = true;
if (recordTransferNodes) {
if (rc.wayfraction > 0.) {
ele1 = interpolateEle(ele1, ele2, 1. - rc.wayfraction);
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic);
} else {
originElement = null; // prevent duplicate point
}
}
if (rc.checkPendingEndpoint()) {
dist = rc.calcDistance(rc.ilonshortest, rc.ilatshortest, lon2, lat2);
if (rc.shortestmatch) {
stopAtEndpoint = true;
ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
}
}
}
}
if (message != null) {
message.linkdist += dist;
}
linkdisttotal += dist;
// apply a start-direction if appropriate (by faking the origin position)
if (isStartpoint) {
if (rc.startDirectionValid) {
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lon0 + lat1) >> 1);
lon0 = lon1 - (int) (1000. * Math.sin(dir) / lonlat2m[0]);
lat0 = lat1 - (int) (1000. * Math.cos(dir) / lonlat2m[1]);
} else {
lon0 = lon1 - (lon2 - lon1);
lat0 = lat1 - (lat2 - lat1);
}
}
double angle = rc.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
double cosangle = rc.anglemeter.getCosAngle();
// *** elevation stuff
double delta_h = 0.;
if (ele2 == Short.MIN_VALUE) ele2 = ele1;
if (ele1 != Short.MIN_VALUE) {
delta_h = (ele2 - ele1) / 4.;
if (rc.inverseDirection) {
delta_h = -delta_h;
}
}
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2 / 4.;
double sectionCost = processWaySection(rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier);
if ((sectionCost < 0. || costfactor > 9998. && !detailMode) || sectionCost + cost >= 2000000000.) {
cost = -1;
return;
}
if (isTrafficBackbone) {
sectionCost = 0.;
}
cost += (int) sectionCost;
// calculate traffic
if (rc.countTraffic) {
int minDist = (int) rc.trafficSourceMinDist;
int cost2 = cost < minDist ? minDist : cost;
traffic += dist * rc.expctxWay.getTrafficSourceDensity() * Math.pow(cost2 / 10000.f, rc.trafficSourceExponent);
}
// compute kinematic
computeKinematic(rc, dist, delta_h, detailMode);
if (message != null) {
message.turnangle = (float) angle;
message.time = (float) getTotalTime();
message.energy = (float) getTotalEnergy();
message.priorityclassifier = priorityclassifier;
message.classifiermask = classifiermask;
message.lon = lon2;
message.lat = lat2;
message.ele = ele2;
message.wayKeyValues = rc.expctxWay.getKeyValueDescription(isReverse, description);
}
if (stopAtEndpoint) {
if (recordTransferNodes) {
originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic);
originElement.cost = cost;
if (message != null) {
originElement.message = message;
}
}
if (rc.nogoCost < 0) {
cost = -1;
} else {
cost += rc.nogoCost;
}
return;
}
if (transferNode == null) {
// *** penalty for being part of the reference track
if (refTrack != null && refTrack.containsNode(targetNode) && refTrack.containsNode(sourceNode)) {
int reftrackcost = linkdisttotal;
cost += reftrackcost;
}
selev = ele2;
break;
}
transferNode = transferNode.next;
if (recordTransferNodes) {
originElement = OsmPathElement.create(lon2, lat2, ele2, originElement, rc.countTraffic);
originElement.cost = cost;
originElement.addTraffic(traffic);
traffic = 0;
}
lon0 = lon1;
lat0 = lat1;
lon1 = lon2;
lat1 = lat2;
ele1 = ele2;
}
// check for nogo-matches (after the *actual* start of segment)
if (rc.nogoCost < 0) {
cost = -1;
return;
} else {
cost += rc.nogoCost;
}
// add target-node costs
double targetCost = processTargetNode(rc);
if (targetCost < 0. || targetCost + cost >= 2000000000.) {
cost = -1;
return;
}
cost += (int) targetCost;
}
public short interpolateEle(short e1, short e2, double fraction) {
if (e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE) {
return Short.MIN_VALUE;
}
return (short) (e1 * (1. - fraction) + e2 * fraction);
}
protected abstract double processWaySection(RoutingContext rc, double dist, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier);
protected abstract double processTargetNode(RoutingContext rc);
protected void computeKinematic(RoutingContext rc, double dist, double delta_h, boolean detailMode) {
}
public abstract int elevationCorrection(RoutingContext rc);
public abstract boolean definitlyWorseThan(OsmPath p, RoutingContext rc);
public OsmNode getSourceNode() {
return sourceNode;
}
public OsmNode getTargetNode() {
return targetNode;
}
public OsmLink getLink() {
return link;
}
public void setNextForLink(OsmLinkHolder holder) {
nextForLink = holder;
}
public OsmLinkHolder getNextForLink() {
return nextForLink;
}
public double getTotalTime() {
return 0.;
}
public double getTotalEnergy() {
return 0.;
}
}

View file

@ -1,136 +1,116 @@
package btools.router;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmPos;
import btools.util.CheapRuler;
/**
* Container for link between two Osm nodes
*
* @author ab
*/
public class OsmPathElement implements OsmPos
{
private int ilat; // latitude
private int ilon; // longitude
private short selev; // longitude
public MessageData message = null; // description
public int cost;
// interface OsmPos
public final int getILat()
{
return ilat;
}
public final int getILon()
{
return ilon;
}
public final short getSElev()
{
return selev;
}
public final double getElev()
{
return selev / 4.;
}
public final float getTime()
{
return message == null ? 0.f : message.time;
}
public final void setTime( float t )
{
if ( message != null )
{
message.time = t;
}
}
public final float getEnergy()
{
return message == null ? 0.f : message.energy;
}
public final void setEnergy( float e )
{
if ( message != null )
{
message.energy = e;
}
}
public final long getIdFromPos()
{
return ((long)ilon)<<32 | ilat;
}
public final int calcDistance( OsmPos p )
{
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
}
public OsmPathElement origin;
// construct a path element from a path
public static final OsmPathElement create( OsmPath path, boolean countTraffic )
{
OsmNode n = path.getTargetNode();
OsmPathElement pe = create( n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic );
pe.cost = path.cost;
pe.message = path.message;
return pe;
}
public static final OsmPathElement create( int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic )
{
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
pe.ilon = ilon;
pe.ilat = ilat;
pe.selev = selev;
pe.origin = origin;
return pe;
}
protected OsmPathElement()
{
}
public void addTraffic( float traffic )
{
}
public String toString()
{
return ilon + "_" + ilat;
}
public void writeToStream( DataOutput dos ) throws IOException
{
dos.writeInt( ilat );
dos.writeInt( ilon );
dos.writeShort( selev );
dos.writeInt( cost );
}
public static OsmPathElement readFromStream( DataInput dis ) throws IOException
{
OsmPathElement pe = new OsmPathElement();
pe.ilat = dis.readInt();
pe.ilon = dis.readInt();
pe.selev = dis.readShort();
pe.cost = dis.readInt();
return pe;
}
}
package btools.router;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmPos;
import btools.util.CheapRuler;
/**
* Container for link between two Osm nodes
*
* @author ab
*/
public class OsmPathElement implements OsmPos {
private int ilat; // latitude
private int ilon; // longitude
private short selev; // longitude
public MessageData message = null; // description
public int cost;
// interface OsmPos
public final int getILat() {
return ilat;
}
public final int getILon() {
return ilon;
}
public final short getSElev() {
return selev;
}
public final double getElev() {
return selev / 4.;
}
public final float getTime() {
return message == null ? 0.f : message.time;
}
public final void setTime(float t) {
if (message != null) {
message.time = t;
}
}
public final float getEnergy() {
return message == null ? 0.f : message.energy;
}
public final void setEnergy(float e) {
if (message != null) {
message.energy = e;
}
}
public final long getIdFromPos() {
return ((long) ilon) << 32 | ilat;
}
public final int calcDistance(OsmPos p) {
return (int) (CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
}
public OsmPathElement origin;
// construct a path element from a path
public static final OsmPathElement create(OsmPath path, boolean countTraffic) {
OsmNode n = path.getTargetNode();
OsmPathElement pe = create(n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic);
pe.cost = path.cost;
pe.message = path.message;
return pe;
}
public static final OsmPathElement create(int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic) {
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
pe.ilon = ilon;
pe.ilat = ilat;
pe.selev = selev;
pe.origin = origin;
return pe;
}
protected OsmPathElement() {
}
public void addTraffic(float traffic) {
}
public String toString() {
return ilon + "_" + ilat;
}
public void writeToStream(DataOutput dos) throws IOException {
dos.writeInt(ilat);
dos.writeInt(ilon);
dos.writeShort(selev);
dos.writeInt(cost);
}
public static OsmPathElement readFromStream(DataInput dis) throws IOException {
OsmPathElement pe = new OsmPathElement();
pe.ilat = dis.readInt();
pe.ilon = dis.readInt();
pe.selev = dis.readShort();
pe.cost = dis.readInt();
return pe;
}
}

View file

@ -9,19 +9,15 @@ import java.io.IOException;
* @author ab
*/
public final class OsmPathElementWithTraffic extends OsmPathElement
{
public final class OsmPathElementWithTraffic extends OsmPathElement {
private int registerCount;
private float farTraffic;
private float nearTraffic;
public void register()
{
if ( registerCount++ == 0 )
{
if ( origin instanceof OsmPathElementWithTraffic )
{
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)origin;
public void register() {
if (registerCount++ == 0) {
if (origin instanceof OsmPathElementWithTraffic) {
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
ot.register();
ot.farTraffic += farTraffic;
ot.nearTraffic += nearTraffic;
@ -30,42 +26,36 @@ public final class OsmPathElementWithTraffic extends OsmPathElement
}
}
}
@Override
public void addTraffic( float traffic )
{
public void addTraffic(float traffic) {
this.farTraffic += traffic;
this.nearTraffic += traffic;
}
// unregister from origin if our registercount is 0, else do nothing
public static double maxtraffic = 0.;
public static double maxtraffic = 0.;
public boolean unregister( RoutingContext rc ) throws IOException
{
if ( --registerCount == 0 )
{
if ( origin instanceof OsmPathElementWithTraffic )
{
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)origin;
int costdelta = cost-ot.cost;
ot.farTraffic += farTraffic*Math.exp(-costdelta/rc.farTrafficDecayLength);
ot.nearTraffic += nearTraffic*Math.exp(-costdelta/rc.nearTrafficDecayLength);
public boolean unregister(RoutingContext rc) throws IOException {
if (--registerCount == 0) {
if (origin instanceof OsmPathElementWithTraffic) {
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
if ( costdelta > 0 && farTraffic > maxtraffic ) maxtraffic = farTraffic;
int t2 = cost == ot.cost ? -1 : (int)(rc.farTrafficWeight*farTraffic + rc.nearTrafficWeight*nearTraffic);
if ( t2 > 4000 || t2 == -1 )
{
int costdelta = cost - ot.cost;
ot.farTraffic += farTraffic * Math.exp(-costdelta / rc.farTrafficDecayLength);
ot.nearTraffic += nearTraffic * Math.exp(-costdelta / rc.nearTrafficDecayLength);
if (costdelta > 0 && farTraffic > maxtraffic) maxtraffic = farTraffic;
int t2 = cost == ot.cost ? -1 : (int) (rc.farTrafficWeight * farTraffic + rc.nearTrafficWeight * nearTraffic);
if (t2 > 4000 || t2 == -1) {
// System.out.println( "unregistered: " + this + " origin=" + ot + " farTraffic =" + farTraffic + " nearTraffic =" + nearTraffic + " cost=" + cost );
if ( rc.trafficOutputStream != null )
{
rc.trafficOutputStream.writeLong( getIdFromPos());
rc.trafficOutputStream.writeLong( ot.getIdFromPos());
rc.trafficOutputStream.writeInt( t2 );
if (rc.trafficOutputStream != null) {
rc.trafficOutputStream.writeLong(getIdFromPos());
rc.trafficOutputStream.writeLong(ot.getIdFromPos());
rc.trafficOutputStream.writeInt(t2);
}
}
farTraffic = 0;

View file

@ -11,11 +11,10 @@ import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
abstract class OsmPathModel
{
abstract class OsmPathModel {
public abstract OsmPrePath createPrePath();
public abstract OsmPath createPath();
public abstract void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> keyValues );
public abstract void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> keyValues);
}

View file

@ -9,21 +9,19 @@ import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode;
public abstract class OsmPrePath
{
public abstract class OsmPrePath {
protected OsmNode sourceNode;
protected OsmNode targetNode;
protected OsmLink link;
public OsmPrePath next;
public void init( OsmPath origin, OsmLink link, RoutingContext rc )
{
public void init(OsmPath origin, OsmLink link, RoutingContext rc) {
this.link = link;
this.sourceNode = origin.getTargetNode();
this.targetNode = link.getTarget( sourceNode );
initPrePath(origin, rc );
this.targetNode = link.getTarget(sourceNode);
initPrePath(origin, rc);
}
protected abstract void initPrePath(OsmPath origin, RoutingContext rc );
protected abstract void initPrePath(OsmPath origin, RoutingContext rc);
}

File diff suppressed because it is too large Load diff

View file

@ -11,146 +11,125 @@ import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
public final class ProfileCache
{
public final class ProfileCache {
private static File lastLookupFile;
private static long lastLookupTimestamp;
private BExpressionContextWay expctxWay;
private BExpressionContextNode expctxNode;
private File lastProfileFile;
private long lastProfileTimestamp;
private long lastProfileTimestamp;
private boolean profilesBusy;
private long lastUseTime;
private static ProfileCache[] apc = new ProfileCache[1];
private static boolean debug = Boolean.getBoolean( "debugProfileCache" );
public static synchronized void setSize( int size )
{
private static ProfileCache[] apc = new ProfileCache[1];
private static boolean debug = Boolean.getBoolean("debugProfileCache");
public static synchronized void setSize(int size) {
apc = new ProfileCache[size];
}
public static synchronized boolean parseProfile( RoutingContext rc )
{
String profileBaseDir = System.getProperty( "profileBaseDir" );
File profileDir;
File profileFile;
if ( profileBaseDir == null )
{
profileDir = new File( rc.localFunction ).getParentFile();
profileFile = new File( rc.localFunction ) ;
}
else
{
profileDir = new File( profileBaseDir );
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ;
}
public static synchronized boolean parseProfile(RoutingContext rc) {
String profileBaseDir = System.getProperty("profileBaseDir");
File profileDir;
File profileFile;
if (profileBaseDir == null) {
profileDir = new File(rc.localFunction).getParentFile();
profileFile = new File(rc.localFunction);
} else {
profileDir = new File(profileBaseDir);
profileFile = new File(profileDir, rc.localFunction + ".brf");
}
rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum()<<24;
File lookupFile = new File( profileDir, "lookups.dat" );
// invalidate cache at lookup-table update
if ( !(lookupFile.equals( lastLookupFile ) && lookupFile.lastModified() == lastLookupTimestamp ) )
{
if ( lastLookupFile != null )
{
System.out.println( "******** invalidating profile-cache after lookup-file update ******** " );
}
apc = new ProfileCache[apc.length];
lastLookupFile = lookupFile;
lastLookupTimestamp = lookupFile.lastModified();
}
ProfileCache lru = null;
int unusedSlot =-1;
rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum() << 24;
File lookupFile = new File(profileDir, "lookups.dat");
// check for re-use
for( int i=0; i<apc.length; i++)
{
ProfileCache pc = apc[i];
if ( pc != null )
{
if ( (!pc.profilesBusy) && profileFile.equals( pc.lastProfileFile ) )
{
if ( rc.profileTimestamp == pc.lastProfileTimestamp )
{
rc.expctxWay = pc.expctxWay;
rc.expctxNode = pc.expctxNode;
rc.readGlobalConfig();
pc.profilesBusy = true;
return true;
}
lru = pc; // name-match but timestamp-mismatch -> we overide this one
unusedSlot = -1;
break;
}
if ( lru == null || lru.lastUseTime > pc.lastUseTime )
{
lru = pc;
// invalidate cache at lookup-table update
if (!(lookupFile.equals(lastLookupFile) && lookupFile.lastModified() == lastLookupTimestamp)) {
if (lastLookupFile != null) {
System.out.println("******** invalidating profile-cache after lookup-file update ******** ");
}
apc = new ProfileCache[apc.length];
lastLookupFile = lookupFile;
lastLookupTimestamp = lookupFile.lastModified();
}
ProfileCache lru = null;
int unusedSlot = -1;
// check for re-use
for (int i = 0; i < apc.length; i++) {
ProfileCache pc = apc[i];
if (pc != null) {
if ((!pc.profilesBusy) && profileFile.equals(pc.lastProfileFile)) {
if (rc.profileTimestamp == pc.lastProfileTimestamp) {
rc.expctxWay = pc.expctxWay;
rc.expctxNode = pc.expctxNode;
rc.readGlobalConfig();
pc.profilesBusy = true;
return true;
}
lru = pc; // name-match but timestamp-mismatch -> we overide this one
unusedSlot = -1;
break;
}
else if ( unusedSlot < 0 )
{
unusedSlot = i;
if (lru == null || lru.lastUseTime > pc.lastUseTime) {
lru = pc;
}
} else if (unusedSlot < 0) {
unusedSlot = i;
}
BExpressionMetaData meta = new BExpressionMetaData();
rc.expctxWay = new BExpressionContextWay( rc.memoryclass * 512, meta );
rc.expctxNode = new BExpressionContextNode( 0, meta );
rc.expctxNode.setForeignContext( rc.expctxWay );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
}
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode.parseFile( profileFile, "global" );
BExpressionMetaData meta = new BExpressionMetaData();
rc.readGlobalConfig();
if ( rc.processUnusedTags )
{
rc.expctxWay.setAllTagsUsed();
rc.expctxWay = new BExpressionContextWay(rc.memoryclass * 512, meta);
rc.expctxNode = new BExpressionContextNode(0, meta);
rc.expctxNode.setForeignContext(rc.expctxWay);
meta.readMetaData(new File(profileDir, "lookups.dat"));
rc.expctxWay.parseFile(profileFile, "global");
rc.expctxNode.parseFile(profileFile, "global");
rc.readGlobalConfig();
if (rc.processUnusedTags) {
rc.expctxWay.setAllTagsUsed();
}
if (lru == null || unusedSlot >= 0) {
lru = new ProfileCache();
if (unusedSlot >= 0) {
apc[unusedSlot] = lru;
if (debug)
System.out.println("******* adding new profile at idx=" + unusedSlot + " for " + profileFile);
}
}
if ( lru == null || unusedSlot >= 0 )
{
lru = new ProfileCache();
if ( unusedSlot >= 0 )
{
apc[unusedSlot] = lru;
if ( debug ) System.out.println( "******* adding new profile at idx=" + unusedSlot + " for " + profileFile );
}
}
if (lru.lastProfileFile != null) {
if (debug)
System.out.println("******* replacing profile of age " + ((System.currentTimeMillis() - lru.lastUseTime) / 1000L) + " sec " + lru.lastProfileFile + "->" + profileFile);
}
if ( lru.lastProfileFile != null )
{
if ( debug ) System.out.println( "******* replacing profile of age " + ((System.currentTimeMillis()-lru.lastUseTime)/1000L) + " sec " + lru.lastProfileFile + "->" + profileFile );
}
lru.lastProfileTimestamp = rc.profileTimestamp;
lru.lastProfileFile = profileFile;
lru.expctxWay = rc.expctxWay;
lru.expctxNode = rc.expctxNode;
lru.profilesBusy = true;
lru.lastUseTime = System.currentTimeMillis();
return false;
lru.lastProfileTimestamp = rc.profileTimestamp;
lru.lastProfileFile = profileFile;
lru.expctxWay = rc.expctxWay;
lru.expctxNode = rc.expctxNode;
lru.profilesBusy = true;
lru.lastUseTime = System.currentTimeMillis();
return false;
}
public static synchronized void releaseProfile( RoutingContext rc )
{
for( int i=0; i<apc.length; i++)
{
public static synchronized void releaseProfile(RoutingContext rc) {
for (int i = 0; i < apc.length; i++) {
ProfileCache pc = apc[i];
if ( pc != null )
{
if (pc != null) {
// only the thread that holds the cached instance can release it
if ( rc.expctxWay == pc.expctxWay && rc.expctxNode == pc.expctxNode )
{
if (rc.expctxWay == pc.expctxWay && rc.expctxNode == pc.expctxNode) {
pc.profilesBusy = false;
break;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,41 +9,33 @@ import java.io.File;
import btools.mapaccess.StorageConfigHelper;
public final class RoutingHelper
{
public static File getAdditionalMaptoolDir( File segmentDir )
{
return StorageConfigHelper.getAdditionalMaptoolDir(segmentDir);
}
public final class RoutingHelper {
public static File getAdditionalMaptoolDir(File segmentDir) {
return StorageConfigHelper.getAdditionalMaptoolDir(segmentDir);
}
public static File getSecondarySegmentDir( File segmentDir )
{
return StorageConfigHelper.getSecondarySegmentDir(segmentDir);
}
public static boolean hasDirectoryAnyDatafiles( File segmentDir )
{
if ( hasAnyDatafiles( segmentDir ) )
{
return true;
}
// check secondary, too
File secondary = StorageConfigHelper.getSecondarySegmentDir( segmentDir );
if ( secondary != null )
{
return hasAnyDatafiles( secondary );
}
return false;
}
public static File getSecondarySegmentDir(File segmentDir) {
return StorageConfigHelper.getSecondarySegmentDir(segmentDir);
}
private static boolean hasAnyDatafiles( File dir )
{
String[] fileNames = dir.list();
for( String fileName : fileNames )
{
if ( fileName.endsWith( ".rd5" ) ) return true;
}
return false;
public static boolean hasDirectoryAnyDatafiles(File segmentDir) {
if (hasAnyDatafiles(segmentDir)) {
return true;
}
// check secondary, too
File secondary = StorageConfigHelper.getSecondarySegmentDir(segmentDir);
if (secondary != null) {
return hasAnyDatafiles(secondary);
}
return false;
}
private static boolean hasAnyDatafiles(File dir) {
String[] fileNames = dir.list();
for (String fileName : fileNames) {
if (fileName.endsWith(".rd5")) return true;
}
return false;
}
}

View file

@ -1,5 +1,4 @@
package btools.router;
public class RoutingIslandException extends RuntimeException
{
public class RoutingIslandException extends RuntimeException {
}

View file

@ -8,83 +8,80 @@ package btools.router;
import btools.mapaccess.OsmNode;
public final class SearchBoundary
{
public final class SearchBoundary {
private int minlon0;
private int minlat0;
private int maxlon0;
private int maxlat0;
private int minlon0;
private int minlat0;
private int maxlon0;
private int maxlat0;
private int minlon;
private int minlat;
private int maxlon;
private int maxlat;
private int radius;
private OsmNode p;
private int minlon;
private int minlat;
private int maxlon;
private int maxlat;
private int radius;
private OsmNode p;
int direction;
int direction;
/**
* @param radius Search radius in meters.
*/
public SearchBoundary( OsmNode n, int radius, int direction )
{
this.radius = radius;
this.direction = direction;
/**
* @param radius Search radius in meters.
*/
public SearchBoundary(OsmNode n, int radius, int direction) {
this.radius = radius;
this.direction = direction;
p = new OsmNode( n.ilon, n.ilat );
p = new OsmNode(n.ilon, n.ilat);
int lon = (n.ilon / 5000000 ) * 5000000;
int lat = (n.ilat / 5000000 ) * 5000000;
int lon = (n.ilon / 5000000) * 5000000;
int lat = (n.ilat / 5000000) * 5000000;
minlon0 = lon - 5000000;
minlat0 = lat - 5000000;
maxlon0 = lon + 10000000;
maxlat0 = lat + 10000000;
minlon0 = lon - 5000000;
minlat0 = lat - 5000000;
maxlon0 = lon + 10000000;
maxlat0 = lat + 10000000;
minlon = lon - 1000000;
minlat = lat - 1000000;
maxlon = lon + 6000000;
maxlat = lat + 6000000;
minlon = lon - 1000000;
minlat = lat - 1000000;
maxlon = lon + 6000000;
maxlat = lat + 6000000;
}
public static String getFileName(OsmNode n) {
int lon = (n.ilon / 5000000) * 5000000;
int lat = (n.ilat / 5000000) * 5000000;
int dlon = lon / 1000000 - 180;
int dlat = lat / 1000000 - 90;
String slon = dlon < 0 ? "W" + (-dlon) : "E" + dlon;
String slat = dlat < 0 ? "S" + (-dlat) : "N" + dlat;
return slon + "_" + slat + ".trf";
}
public boolean isInBoundary(OsmNode n, int cost) {
if (radius > 0) {
return n.calcDistance(p) < radius;
}
public static String getFileName( OsmNode n )
{
int lon = (n.ilon / 5000000 ) * 5000000;
int lat = (n.ilat / 5000000 ) * 5000000;
int dlon = lon / 1000000 -180;
int dlat = lat / 1000000 - 90;
String slon = dlon < 0 ? "W" + (-dlon) : "E" + dlon;
String slat = dlat < 0 ? "S" + (-dlat) : "N" + dlat;
return slon + "_" + slat + ".trf";
if (cost == 0) {
return n.ilon > minlon0 && n.ilon < maxlon0 && n.ilat > minlat0 && n.ilat < maxlat0;
}
return n.ilon > minlon && n.ilon < maxlon && n.ilat > minlat && n.ilat < maxlat;
}
public boolean isInBoundary( OsmNode n, int cost )
{
if ( radius > 0 )
{
return n.calcDistance( p ) < radius;
}
if ( cost == 0 )
{
return n.ilon > minlon0 && n.ilon < maxlon0 && n.ilat > minlat0 && n.ilat < maxlat0;
}
return n.ilon > minlon && n.ilon < maxlon && n.ilat > minlat && n.ilat < maxlat;
}
public int getBoundaryDistance( OsmNode n )
{
switch( direction )
{
case 0: return n.calcDistance( new OsmNode( n.ilon, minlat ) );
case 1: return n.calcDistance( new OsmNode( minlon, n.ilat ) );
case 2: return n.calcDistance( new OsmNode( n.ilon, maxlat ) );
case 3: return n.calcDistance( new OsmNode( maxlon, n.ilat ) );
default: throw new IllegalArgumentException( "undefined direction: "+ direction );
}
public int getBoundaryDistance(OsmNode n) {
switch (direction) {
case 0:
return n.calcDistance(new OsmNode(n.ilon, minlat));
case 1:
return n.calcDistance(new OsmNode(minlon, n.ilat));
case 2:
return n.calcDistance(new OsmNode(n.ilon, maxlat));
case 3:
return n.calcDistance(new OsmNode(maxlon, n.ilat));
default:
throw new IllegalArgumentException("undefined direction: " + direction);
}
}
}

View file

@ -12,15 +12,12 @@ import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
final class StdModel extends OsmPathModel
{
public OsmPrePath createPrePath()
{
final class StdModel extends OsmPathModel {
public OsmPrePath createPrePath() {
return null;
}
public OsmPath createPath()
{
public OsmPath createPath() {
return new StdPath();
}
@ -29,11 +26,10 @@ final class StdModel extends OsmPathModel
@Override
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> keyValues )
{
public void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> keyValues) {
ctxWay = expctxWay;
ctxNode = expctxNode;
BExpressionContext expctxGlobal = expctxWay; // just one of them...
}

View file

@ -7,8 +7,7 @@ package btools.router;
import btools.util.FastMath;
final class StdPath extends OsmPath
{
final class StdPath extends OsmPath {
/**
* The elevation-hysteresis-buffer (0-10 m)
*/
@ -23,9 +22,8 @@ final class StdPath extends OsmPath
private static final double GRAVITY = 9.81; // in meters per second^(-2)
@Override
public void init( OsmPath orig )
{
StdPath origin = (StdPath)orig;
public void init(OsmPath orig) {
StdPath origin = (StdPath) orig;
this.ehbd = origin.ehbd;
this.ehbu = origin.ehbu;
this.totalTime = origin.totalTime;
@ -34,8 +32,7 @@ final class StdPath extends OsmPath
}
@Override
protected void resetState()
{
protected void resetState() {
ehbd = 0;
ehbu = 0;
totalTime = 0.f;
@ -44,8 +41,7 @@ final class StdPath extends OsmPath
}
@Override
protected double processWaySection( RoutingContext rc, double distance, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier )
{
protected double processWaySection(RoutingContext rc, double distance, double delta_h, double elevation, double angle, double cosangle, boolean isStartpoint, int nsection, int lastpriorityclassifier) {
// calculate the costfactor inputs
float turncostbase = rc.expctxWay.getTurncost();
float cfup = rc.expctxWay.getUphillCostfactor();
@ -54,14 +50,13 @@ final class StdPath extends OsmPath
cfup = cfup == 0.f ? cf : cfup;
cfdown = cfdown == 0.f ? cf : cfdown;
int dist = (int)distance; // legacy arithmetics needs int
int dist = (int) distance; // legacy arithmetics needs int
// penalty for turning angle
int turncost = (int)((1.-cosangle) * turncostbase + 0.2 ); // e.g. turncost=90 -> 90 degree = 90m penalty
if ( message != null )
{
int turncost = (int) ((1. - cosangle) * turncostbase + 0.2); // e.g. turncost=90 -> 90 degree = 90m penalty
if (message != null) {
message.linkturncost += turncost;
message.turnangle = (float)angle;
message.turnangle = (float) angle;
}
double sectionCost = turncost;
@ -70,81 +65,66 @@ final class StdPath extends OsmPath
// only the part of the descend that does not fit into the elevation-hysteresis-buffers
// leads to an immediate penalty
int delta_h_micros = (int)(1000000. * delta_h);
int delta_h_micros = (int) (1000000. * delta_h);
ehbd += -delta_h_micros - dist * rc.downhillcutoff;
ehbu += delta_h_micros - dist * rc.uphillcutoff;
ehbu += delta_h_micros - dist * rc.uphillcutoff;
float downweight = 0.f;
if ( ehbd > rc.elevationpenaltybuffer )
{
if (ehbd > rc.elevationpenaltybuffer) {
downweight = 1.f;
int excess = ehbd - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
downweight = ((float)excess)/reduce;
if (reduce > excess) {
downweight = ((float) excess) / reduce;
reduce = excess;
}
excess = ehbd - rc.elevationmaxbuffer;
if ( reduce < excess )
{
if (reduce < excess) {
reduce = excess;
}
ehbd -= reduce;
if ( rc.downhillcostdiv > 0 )
{
int elevationCost = reduce/rc.downhillcostdiv;
if (rc.downhillcostdiv > 0) {
int elevationCost = reduce / rc.downhillcostdiv;
sectionCost += elevationCost;
if ( message != null )
{
if (message != null) {
message.linkelevationcost += elevationCost;
}
}
}
else if ( ehbd < 0 )
{
} else if (ehbd < 0) {
ehbd = 0;
}
float upweight = 0.f;
if ( ehbu > rc.elevationpenaltybuffer )
{
if (ehbu > rc.elevationpenaltybuffer) {
upweight = 1.f;
int excess = ehbu - rc.elevationpenaltybuffer;
int reduce = dist * rc.elevationbufferreduce;
if ( reduce > excess )
{
upweight = ((float)excess)/reduce;
if (reduce > excess) {
upweight = ((float) excess) / reduce;
reduce = excess;
}
excess = ehbu - rc.elevationmaxbuffer;
if ( reduce < excess )
{
if (reduce < excess) {
reduce = excess;
}
ehbu -= reduce;
if ( rc.uphillcostdiv > 0 )
{
int elevationCost = reduce/rc.uphillcostdiv;
if (rc.uphillcostdiv > 0) {
int elevationCost = reduce / rc.uphillcostdiv;
sectionCost += elevationCost;
if ( message != null )
{
if (message != null) {
message.linkelevationcost += elevationCost;
}
}
}
else if ( ehbu < 0 )
{
} else if (ehbu < 0) {
ehbu = 0;
}
// get the effective costfactor (slope dependent)
float costfactor = cfup*upweight + cf*(1.f - upweight - downweight) + cfdown*downweight;
float costfactor = cfup * upweight + cf * (1.f - upweight - downweight) + cfdown * downweight;
if ( message != null )
{
if (message != null) {
message.costfactor = costfactor;
}
@ -154,22 +134,18 @@ final class StdPath extends OsmPath
}
@Override
protected double processTargetNode( RoutingContext rc )
{
protected double processTargetNode(RoutingContext rc) {
// finally add node-costs for target node
if ( targetNode.nodeDescription != null )
{
if (targetNode.nodeDescription != null) {
boolean nodeAccessGranted = rc.expctxWay.getNodeAccessGranted() != 0.;
rc.expctxNode.evaluate( nodeAccessGranted , targetNode.nodeDescription );
rc.expctxNode.evaluate(nodeAccessGranted, targetNode.nodeDescription);
float initialcost = rc.expctxNode.getInitialcost();
if ( initialcost >= 1000000. )
{
if (initialcost >= 1000000.) {
return -1.;
}
if ( message != null )
{
message.linknodecost += (int)initialcost;
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription( nodeAccessGranted, targetNode.nodeDescription );
if (message != null) {
message.linknodecost += (int) initialcost;
message.nodeKeyValues = rc.expctxNode.getKeyValueDescription(nodeAccessGranted, targetNode.nodeDescription);
}
return initialcost;
}
@ -177,118 +153,96 @@ final class StdPath extends OsmPath
}
@Override
public int elevationCorrection( RoutingContext rc )
{
return ( rc.downhillcostdiv > 0 ? ehbd/rc.downhillcostdiv : 0 )
+ ( rc.uphillcostdiv > 0 ? ehbu/rc.uphillcostdiv : 0 );
public int elevationCorrection(RoutingContext rc) {
return (rc.downhillcostdiv > 0 ? ehbd / rc.downhillcostdiv : 0)
+ (rc.uphillcostdiv > 0 ? ehbu / rc.uphillcostdiv : 0);
}
@Override
public boolean definitlyWorseThan( OsmPath path, RoutingContext rc )
{
StdPath p = (StdPath)path;
public boolean definitlyWorseThan(OsmPath path, RoutingContext rc) {
StdPath p = (StdPath) path;
int c = p.cost;
if ( rc.downhillcostdiv > 0 )
{
int delta = p.ehbd - ehbd;
if ( delta > 0 ) c += delta/rc.downhillcostdiv;
}
if ( rc.uphillcostdiv > 0 )
{
int delta = p.ehbu - ehbu;
if ( delta > 0 ) c += delta/rc.uphillcostdiv;
}
int c = p.cost;
if (rc.downhillcostdiv > 0) {
int delta = p.ehbd - ehbd;
if (delta > 0) c += delta / rc.downhillcostdiv;
}
if (rc.uphillcostdiv > 0) {
int delta = p.ehbu - ehbu;
if (delta > 0) c += delta / rc.uphillcostdiv;
}
return cost > c;
return cost > c;
}
private double calcIncline( double dist )
{
private double calcIncline(double dist) {
double min_delta = 3.;
double shift;
if ( elevation_buffer > min_delta )
{
if (elevation_buffer > min_delta) {
shift = -min_delta;
}
else if ( elevation_buffer < min_delta )
{
} else if (elevation_buffer < min_delta) {
shift = -min_delta;
}
else
{
} else {
return 0.;
}
double decayFactor = FastMath.exp( - dist / 100. );
float new_elevation_buffer = (float)( (elevation_buffer+shift) * decayFactor - shift);
double incline = ( elevation_buffer - new_elevation_buffer ) / dist;
double decayFactor = FastMath.exp(-dist / 100.);
float new_elevation_buffer = (float) ((elevation_buffer + shift) * decayFactor - shift);
double incline = (elevation_buffer - new_elevation_buffer) / dist;
elevation_buffer = new_elevation_buffer;
return incline;
}
@Override
protected void computeKinematic( RoutingContext rc, double dist, double delta_h, boolean detailMode )
{
if ( !detailMode )
{
protected void computeKinematic(RoutingContext rc, double dist, double delta_h, boolean detailMode) {
if (!detailMode) {
return;
}
// compute incline
elevation_buffer += delta_h;
double incline = calcIncline( dist );
double incline = calcIncline(dist);
double wayMaxspeed;
wayMaxspeed = rc.expctxWay.getMaxspeed() / 3.6f;
if (wayMaxspeed == 0)
{
wayMaxspeed = rc.maxSpeed;
if (wayMaxspeed == 0) {
wayMaxspeed = rc.maxSpeed;
}
wayMaxspeed = Math.min(wayMaxspeed,rc.maxSpeed);
wayMaxspeed = Math.min(wayMaxspeed, rc.maxSpeed);
double speed; // Travel speed
double f_roll = rc.totalMass * GRAVITY * ( rc.defaultC_r + incline );
if (rc.footMode || rc.expctxWay.getCostfactor() > 4.9 )
{
double f_roll = rc.totalMass * GRAVITY * (rc.defaultC_r + incline);
if (rc.footMode || rc.expctxWay.getCostfactor() > 4.9) {
// Use Tobler's hiking function for walking sections
speed = rc.maxSpeed * 3.6;
speed = (speed * FastMath.exp(-3.5 * Math.abs( incline + 0.05))) / 3.6;
}
else if (rc.bikeMode)
{
speed = solveCubic( rc.S_C_x, f_roll, rc.bikerPower );
speed = (speed * FastMath.exp(-3.5 * Math.abs(incline + 0.05))) / 3.6;
} else if (rc.bikeMode) {
speed = solveCubic(rc.S_C_x, f_roll, rc.bikerPower);
speed = Math.min(speed, wayMaxspeed);
}
else // all other
} else // all other
{
speed = wayMaxspeed;
}
float dt = (float) ( dist / speed );
float dt = (float) (dist / speed);
totalTime += dt;
// Calc energy assuming biking (no good model yet for hiking)
// (Count only positive, negative would mean breaking to enforce maxspeed)
double energy = dist*(rc.S_C_x*speed*speed + f_roll);
if ( energy > 0. )
{
double energy = dist * (rc.S_C_x * speed * speed + f_roll);
if (energy > 0.) {
totalEnergy += energy;
}
}
private static double solveCubic( double a, double c, double d )
{
private static double solveCubic(double a, double c, double d) {
// Solves a * v^3 + c * v = d with a Newton method
// to get the speed v for the section.
double v = 8.;
boolean findingStartvalue = true;
for ( int i = 0; i < 10; i++ )
{
double y = ( a * v * v + c ) * v - d;
if ( y < .1 )
{
if ( findingStartvalue )
{
for (int i = 0; i < 10; i++) {
double y = (a * v * v + c) * v - d;
if (y < .1) {
if (findingStartvalue) {
v *= 2.;
continue;
}
@ -302,14 +256,12 @@ final class StdPath extends OsmPath
}
@Override
public double getTotalTime()
{
public double getTotalTime() {
return totalTime;
}
@Override
public double getTotalEnergy()
{
public double getTotalEnergy() {
return totalEnergy;
}
}

View file

@ -2,65 +2,58 @@ package btools.router;
import java.util.Map;
public class SuspectInfo
{
public static final int TRIGGER_DEAD_END = 1;
public static final int TRIGGER_DEAD_START = 2;
public static final int TRIGGER_NODE_BLOCK = 4;
public static final int TRIGGER_BAD_ACCESS = 8;
public static final int TRIGGER_UNK_ACCESS = 16;
public static final int TRIGGER_SHARP_EXIT = 32;
public class SuspectInfo {
public static final int TRIGGER_DEAD_END = 1;
public static final int TRIGGER_DEAD_START = 2;
public static final int TRIGGER_NODE_BLOCK = 4;
public static final int TRIGGER_BAD_ACCESS = 8;
public static final int TRIGGER_UNK_ACCESS = 16;
public static final int TRIGGER_SHARP_EXIT = 32;
public static final int TRIGGER_SHARP_ENTRY = 64;
public static final int TRIGGER_SHARP_LINK = 128;
public static final int TRIGGER_BAD_TR = 256;
public static final int TRIGGER_SHARP_LINK = 128;
public static final int TRIGGER_BAD_TR = 256;
public int prio;
public int triggers;
public static void addSuspect( Map<Long,SuspectInfo> map, long id, int prio, int trigger )
{
Long iD = Long.valueOf( id );
SuspectInfo info = map.get( iD );
if ( info == null )
{
public static void addSuspect(Map<Long, SuspectInfo> map, long id, int prio, int trigger) {
Long iD = Long.valueOf(id);
SuspectInfo info = map.get(iD);
if (info == null) {
info = new SuspectInfo();
map.put( iD, info );
map.put(iD, info);
}
info.prio = Math.max( info.prio, prio );
info.prio = Math.max(info.prio, prio);
info.triggers |= trigger;
}
public static SuspectInfo addTrigger( SuspectInfo old, int prio, int trigger )
{
if ( old == null )
{
public static SuspectInfo addTrigger(SuspectInfo old, int prio, int trigger) {
if (old == null) {
old = new SuspectInfo();
}
old.prio = Math.max( old.prio, prio );
old.prio = Math.max(old.prio, prio);
old.triggers |= trigger;
return old;
}
public static String getTriggerText( int triggers )
{
public static String getTriggerText(int triggers) {
StringBuilder sb = new StringBuilder();
addText( sb, "dead-end" , triggers, TRIGGER_DEAD_END );
addText( sb, "dead-start" , triggers, TRIGGER_DEAD_START );
addText( sb, "node-block" , triggers, TRIGGER_NODE_BLOCK );
addText( sb, "bad-access" , triggers, TRIGGER_BAD_ACCESS );
addText( sb, "unkown-access", triggers, TRIGGER_UNK_ACCESS );
addText( sb, "sharp-exit" , triggers, TRIGGER_SHARP_EXIT );
addText( sb, "sharp-entry" , triggers, TRIGGER_SHARP_ENTRY );
addText( sb, "sharp-link" , triggers, TRIGGER_SHARP_LINK );
addText( sb, "bad-tr" , triggers, TRIGGER_BAD_TR );
addText(sb, "dead-end", triggers, TRIGGER_DEAD_END);
addText(sb, "dead-start", triggers, TRIGGER_DEAD_START);
addText(sb, "node-block", triggers, TRIGGER_NODE_BLOCK);
addText(sb, "bad-access", triggers, TRIGGER_BAD_ACCESS);
addText(sb, "unkown-access", triggers, TRIGGER_UNK_ACCESS);
addText(sb, "sharp-exit", triggers, TRIGGER_SHARP_EXIT);
addText(sb, "sharp-entry", triggers, TRIGGER_SHARP_ENTRY);
addText(sb, "sharp-link", triggers, TRIGGER_SHARP_LINK);
addText(sb, "bad-tr", triggers, TRIGGER_BAD_TR);
return sb.toString();
}
private static void addText( StringBuilder sb, String text, int mask, int bit )
{
if ( ( bit & mask ) == 0 ) return;
if ( sb.length() > 0 ) sb.append( "," );
sb.append( text );
private static void addText(StringBuilder sb, String text, int mask, int bit) {
if ((bit & mask) == 0) return;
if (sb.length() > 0) sb.append(",");
sb.append(text);
}
}

View file

@ -9,8 +9,7 @@ package btools.router;
import java.util.ArrayList;
import java.util.List;
public class VoiceHint
{
public class VoiceHint {
static final int C = 1; // continue (go straight)
static final int TL = 2; // turn left
static final int TSLL = 3; // turn slightly left
@ -36,8 +35,7 @@ public class VoiceHint
double distanceToNext;
int indexInTrack;
public float getTime()
{
public float getTime() {
return oldWay == null ? 0.f : oldWay.time;
}
@ -47,269 +45,281 @@ public class VoiceHint
int roundaboutExit;
boolean isRoundabout()
{
boolean isRoundabout() {
return roundaboutExit != 0;
}
public void addBadWay( MessageData badWay )
{
if ( badWay == null )
{
public void addBadWay(MessageData badWay) {
if (badWay == null) {
return;
}
if ( badWays == null )
{
if (badWays == null) {
badWays = new ArrayList<MessageData>();
}
badWays.add( badWay );
badWays.add(badWay);
}
public int getCommand()
{
public int getCommand() {
return cmd;
}
public int getExitNumber()
{
public int getExitNumber() {
return roundaboutExit;
}
public String getCommandString()
{
switch ( cmd )
{
case TU : return "TU";
case TSHL : return "TSHL";
case TL : return "TL";
case TSLL : return "TSLL";
case KL : return "KL";
case C : return "C";
case KR : return "KR";
case TSLR : return "TSLR";
case TR : return "TR";
case TSHR : return "TSHR";
case TRU : return "TRU";
case RNDB : return "RNDB" + roundaboutExit;
case RNLB : return "RNLB" + (-roundaboutExit);
default : throw new IllegalArgumentException( "unknown command: " + cmd );
}
}
public String getSymbolString()
{
switch ( cmd )
{
case TU : return "TU";
case TSHL : return "TSHL";
case TL : return "Left";
case TSLL : return "TSLL";
case KL : return "TSLL"; // ?
case C : return "Straight";
case KR : return "TSLR"; // ?
case TSLR : return "TSLR";
case TR : return "Right";
case TSHR : return "TSHR";
case TRU : return "TU";
case RNDB : return "RNDB" + roundaboutExit;
case RNLB : return "RNLB" + (-roundaboutExit);
default : throw new IllegalArgumentException( "unknown command: " + cmd );
public String getCommandString() {
switch (cmd) {
case TU:
return "TU";
case TSHL:
return "TSHL";
case TL:
return "TL";
case TSLL:
return "TSLL";
case KL:
return "KL";
case C:
return "C";
case KR:
return "KR";
case TSLR:
return "TSLR";
case TR:
return "TR";
case TSHR:
return "TSHR";
case TRU:
return "TRU";
case RNDB:
return "RNDB" + roundaboutExit;
case RNLB:
return "RNLB" + (-roundaboutExit);
default:
throw new IllegalArgumentException("unknown command: " + cmd);
}
}
public String getMessageString()
{
switch ( cmd )
{
case TU : return "u-turn";
case TSHL : return "sharp left";
case TL : return "left";
case TSLL : return "slight left";
case KL : return "keep left";
case C : return "straight";
case KR : return "keep right";
case TSLR : return "slight right";
case TR : return "right";
case TSHR : return "sharp right";
case TRU : return "u-turn";
case RNDB : return "Take exit " + roundaboutExit;
case RNLB : return "Take exit " + (-roundaboutExit);
default : throw new IllegalArgumentException( "unknown command: " + cmd );
public String getSymbolString() {
switch (cmd) {
case TU:
return "TU";
case TSHL:
return "TSHL";
case TL:
return "Left";
case TSLL:
return "TSLL";
case KL:
return "TSLL"; // ?
case C:
return "Straight";
case KR:
return "TSLR"; // ?
case TSLR:
return "TSLR";
case TR:
return "Right";
case TSHR:
return "TSHR";
case TRU:
return "TU";
case RNDB:
return "RNDB" + roundaboutExit;
case RNLB:
return "RNLB" + (-roundaboutExit);
default:
throw new IllegalArgumentException("unknown command: " + cmd);
}
}
public int getLocusAction()
{
switch ( cmd )
{
case TU : return 13;
case TSHL : return 5;
case TL : return 4;
case TSLL : return 3;
case KL : return 9; // ?
case C : return 1;
case KR : return 10; // ?
case TSLR : return 6;
case TR : return 7;
case TSHR : return 8;
case TRU : return 14;
case RNDB : return 26 + roundaboutExit;
case RNLB : return 26 - roundaboutExit;
default : throw new IllegalArgumentException( "unknown command: " + cmd );
public String getMessageString() {
switch (cmd) {
case TU:
return "u-turn";
case TSHL:
return "sharp left";
case TL:
return "left";
case TSLL:
return "slight left";
case KL:
return "keep left";
case C:
return "straight";
case KR:
return "keep right";
case TSLR:
return "slight right";
case TR:
return "right";
case TSHR:
return "sharp right";
case TRU:
return "u-turn";
case RNDB:
return "Take exit " + roundaboutExit;
case RNLB:
return "Take exit " + (-roundaboutExit);
default:
throw new IllegalArgumentException("unknown command: " + cmd);
}
}
public int getOruxAction()
{
switch ( cmd )
{
case TU : return 1003;
case TSHL : return 1019;
case TL : return 1000;
case TSLL : return 1017;
case KL : return 1015; // ?
case C : return 1002;
case KR : return 1014; // ?
case TSLR : return 1016;
case TR : return 1001;
case TSHR : return 1018;
case TRU : return 1003;
case RNDB : return 1008 + roundaboutExit;
case RNLB : return 1008 + roundaboutExit;
default : throw new IllegalArgumentException( "unknown command: " + cmd );
}
public int getLocusAction() {
switch (cmd) {
case TU:
return 13;
case TSHL:
return 5;
case TL:
return 4;
case TSLL:
return 3;
case KL:
return 9; // ?
case C:
return 1;
case KR:
return 10; // ?
case TSLR:
return 6;
case TR:
return 7;
case TSHR:
return 8;
case TRU:
return 14;
case RNDB:
return 26 + roundaboutExit;
case RNLB:
return 26 - roundaboutExit;
default:
throw new IllegalArgumentException("unknown command: " + cmd);
}
}
public void calcCommand()
{
public int getOruxAction() {
switch (cmd) {
case TU:
return 1003;
case TSHL:
return 1019;
case TL:
return 1000;
case TSLL:
return 1017;
case KL:
return 1015; // ?
case C:
return 1002;
case KR:
return 1014; // ?
case TSLR:
return 1016;
case TR:
return 1001;
case TSHR:
return 1018;
case TRU:
return 1003;
case RNDB:
return 1008 + roundaboutExit;
case RNLB:
return 1008 + roundaboutExit;
default:
throw new IllegalArgumentException("unknown command: " + cmd);
}
}
public void calcCommand() {
float lowerBadWayAngle = -181;
float higherBadWayAngle = 181;
if ( badWays != null )
{
for ( MessageData badWay : badWays )
{
if ( badWay.isBadOneway() )
{
if (badWays != null) {
for (MessageData badWay : badWays) {
if (badWay.isBadOneway()) {
continue;
}
if ( lowerBadWayAngle < badWay.turnangle && badWay.turnangle < goodWay.turnangle )
{
if (lowerBadWayAngle < badWay.turnangle && badWay.turnangle < goodWay.turnangle) {
lowerBadWayAngle = badWay.turnangle;
}
if ( higherBadWayAngle > badWay.turnangle && badWay.turnangle > goodWay.turnangle )
{
if (higherBadWayAngle > badWay.turnangle && badWay.turnangle > goodWay.turnangle) {
higherBadWayAngle = badWay.turnangle;
}
}
}
float cmdAngle= angle;
float cmdAngle = angle;
// fall back to local angle if otherwise inconsistent
if ( lowerBadWayAngle > angle || higherBadWayAngle < angle )
{
if (lowerBadWayAngle > angle || higherBadWayAngle < angle) {
cmdAngle = goodWay.turnangle;
}
if (roundaboutExit > 0)
{
if (roundaboutExit > 0) {
cmd = RNDB;
}
else if (roundaboutExit < 0)
{
} else if (roundaboutExit < 0) {
cmd = RNLB;
}
else if ( cmdAngle < -159. )
{
} else if (cmdAngle < -159.) {
cmd = TU;
}
else if ( cmdAngle < -135. )
{
} else if (cmdAngle < -135.) {
cmd = TSHL;
}
else if ( cmdAngle < -45. )
{
} else if (cmdAngle < -45.) {
// a TL can be pushed in either direction by a close-by alternative
if ( higherBadWayAngle > -90. && higherBadWayAngle < -15. && lowerBadWayAngle < -180. )
{
if (higherBadWayAngle > -90. && higherBadWayAngle < -15. && lowerBadWayAngle < -180.) {
cmd = TSHL;
}
else if ( lowerBadWayAngle > -180. && lowerBadWayAngle < -90. && higherBadWayAngle > 0. )
{
} else if (lowerBadWayAngle > -180. && lowerBadWayAngle < -90. && higherBadWayAngle > 0.) {
cmd = TSLL;
}
else
{
} else {
cmd = TL;
}
}
else if ( cmdAngle < -21. )
{
if ( cmd != KR ) // don't overwrite KR with TSLL
} else if (cmdAngle < -21.) {
if (cmd != KR) // don't overwrite KR with TSLL
{
cmd = TSLL;
}
}
else if ( cmdAngle < 21. )
{
if ( cmd != KR && cmd != KL ) // don't overwrite KL/KR hints!
} else if (cmdAngle < 21.) {
if (cmd != KR && cmd != KL) // don't overwrite KL/KR hints!
{
cmd = C;
}
}
else if ( cmdAngle < 45. )
{
if ( cmd != KL ) // don't overwrite KL with TSLR
} else if (cmdAngle < 45.) {
if (cmd != KL) // don't overwrite KL with TSLR
{
cmd = TSLR;
}
}
else if ( cmdAngle < 135. )
{
} else if (cmdAngle < 135.) {
// a TR can be pushed in either direction by a close-by alternative
if ( higherBadWayAngle > 90. && higherBadWayAngle < 180. && lowerBadWayAngle < 0. )
{
if (higherBadWayAngle > 90. && higherBadWayAngle < 180. && lowerBadWayAngle < 0.) {
cmd = TSLR;
}
else if ( lowerBadWayAngle > 15. && lowerBadWayAngle < 90. && higherBadWayAngle > 180. )
{
} else if (lowerBadWayAngle > 15. && lowerBadWayAngle < 90. && higherBadWayAngle > 180.) {
cmd = TSHR;
}
else
{
} else {
cmd = TR;
}
}
else if ( cmdAngle < 159. )
{
} else if (cmdAngle < 159.) {
cmd = TSHR;
}
else
{
} else {
cmd = TRU;
}
}
public String formatGeometry()
{
public String formatGeometry() {
float oldPrio = oldWay == null ? 0.f : oldWay.priorityclassifier;
StringBuilder sb = new StringBuilder(30);
sb.append( ' ' ).append( (int)oldPrio );
appendTurnGeometry(sb,goodWay);
if ( badWays != null )
{
for ( MessageData badWay : badWays )
{
sb.append( " " );
appendTurnGeometry( sb, badWay );
sb.append(' ').append((int) oldPrio);
appendTurnGeometry(sb, goodWay);
if (badWays != null) {
for (MessageData badWay : badWays) {
sb.append(" ");
appendTurnGeometry(sb, badWay);
}
}
return sb.toString();
}
private void appendTurnGeometry( StringBuilder sb, MessageData msg )
{
sb.append( "(" ).append( (int)(msg.turnangle+0.5) ).append( ")" ).append( (int)(msg.priorityclassifier) );
private void appendTurnGeometry(StringBuilder sb, MessageData msg) {
sb.append("(").append((int) (msg.turnangle + 0.5)).append(")").append((int) (msg.priorityclassifier));
}
}

View file

@ -9,30 +9,24 @@ package btools.router;
import java.util.ArrayList;
import java.util.List;
public class VoiceHintList
{
public class VoiceHintList {
private String transportMode;
int turnInstructionMode;
ArrayList<VoiceHint> list = new ArrayList<VoiceHint>();
public void setTransportMode( boolean isCar, boolean isBike )
{
transportMode = isCar ? "car" : ( isBike ? "bike" : "foot" );
public void setTransportMode(boolean isCar, boolean isBike) {
transportMode = isCar ? "car" : (isBike ? "bike" : "foot");
}
public String getTransportMode()
{
public String getTransportMode() {
return transportMode;
}
public int getLocusRouteType()
{
if ( "car".equals( transportMode ) )
{
public int getLocusRouteType() {
if ("car".equals(transportMode)) {
return 0;
}
if ( "bike".equals( transportMode ) )
{
if ("bike".equals(transportMode)) {
return 5;
}
return 3; // foot

View file

@ -8,26 +8,21 @@ package btools.router;
import java.util.ArrayList;
import java.util.List;
public final class VoiceHintProcessor
{
public final class VoiceHintProcessor {
private double catchingRange; // range to catch angles and merge turns
private boolean explicitRoundabouts;
public VoiceHintProcessor( double catchingRange, boolean explicitRoundabouts )
{
public VoiceHintProcessor(double catchingRange, boolean explicitRoundabouts) {
this.catchingRange = catchingRange;
this.explicitRoundabouts = explicitRoundabouts;
}
private float sumNonConsumedWithinCatchingRange( List<VoiceHint> inputs, int offset )
{
private float sumNonConsumedWithinCatchingRange(List<VoiceHint> inputs, int offset) {
double distance = 0.;
float angle = 0.f;
while( offset >= 0 && distance < catchingRange )
{
VoiceHint input = inputs.get( offset-- );
if ( input.turnAngleConsumed )
{
while (offset >= 0 && distance < catchingRange) {
VoiceHint input = inputs.get(offset--);
if (input.turnAngleConsumed) {
break;
}
angle += input.goodWay.turnangle;
@ -44,10 +39,10 @@ public final class VoiceHintProcessor
* order (from target to start), but output is
* returned in travel-direction and only for
* those nodes that trigger a voice hint.
*
* <p>
* Input objects are expected for every segment
* of the track, also for those without a junction
*
* <p>
* VoiceHint objects in the output list are enriched
* by the voice-command, the total angle and the distance
* to the next hint
@ -55,54 +50,46 @@ public final class VoiceHintProcessor
* @param inputs tracknodes, un reverse order
* @return voice hints, in forward order
*/
public List<VoiceHint> process( List<VoiceHint> inputs )
{
public List<VoiceHint> process(List<VoiceHint> inputs) {
List<VoiceHint> results = new ArrayList<VoiceHint>();
double distance = 0.;
float roundAboutTurnAngle = 0.f; // sums up angles in roundabout
int roundaboutExit = 0;
for ( int hintIdx = 0; hintIdx < inputs.size(); hintIdx++ )
{
VoiceHint input = inputs.get( hintIdx );
for (int hintIdx = 0; hintIdx < inputs.size(); hintIdx++) {
VoiceHint input = inputs.get(hintIdx);
float turnAngle = input.goodWay.turnangle;
distance += input.goodWay.linkdist;
int currentPrio = input.goodWay.getPrio();
int oldPrio = input.oldWay.getPrio();
int minPrio = Math.min( oldPrio, currentPrio );
int minPrio = Math.min(oldPrio, currentPrio);
boolean isLink2Highway = input.oldWay.isLinktType() && !input.goodWay.isLinktType();
if ( input.oldWay.isRoundabout() )
{
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
if (input.oldWay.isRoundabout()) {
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
boolean isExit = roundaboutExit == 0; // exit point is always exit
if ( input.badWays != null )
{
for ( MessageData badWay : input.badWays )
{
if ( !badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs( badWay.turnangle ) < 120. )
{
if (input.badWays != null) {
for (MessageData badWay : input.badWays) {
if (!badWay.isBadOneway() && badWay.isGoodForCars() && Math.abs(badWay.turnangle) < 120.) {
isExit = true;
}
}
}
if ( isExit )
{
if (isExit) {
roundaboutExit++;
}
continue;
}
if ( roundaboutExit > 0 )
{
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
if (roundaboutExit > 0) {
roundAboutTurnAngle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
input.angle = roundAboutTurnAngle;
input.distanceToNext = distance;
input.roundaboutExit = turnAngle < 0 ? -roundaboutExit : roundaboutExit;
input.roundaboutExit = turnAngle < 0 ? -roundaboutExit : roundaboutExit;
distance = 0.;
results.add( input );
results.add(input);
roundAboutTurnAngle = 0.f;
roundaboutExit = 0;
continue;
@ -114,91 +101,77 @@ public final class VoiceHintProcessor
float minAngle = 180.f;
float minAbsAngeRaw = 180.f;
if ( input.badWays != null )
{
for ( MessageData badWay : input.badWays )
{
if (input.badWays != null) {
for (MessageData badWay : input.badWays) {
int badPrio = badWay.getPrio();
float badTurn = badWay.turnangle;
boolean isHighway2Link = !input.oldWay.isLinktType() && badWay.isLinktType();
if ( badPrio > maxPrioAll && !isHighway2Link )
{
if (badPrio > maxPrioAll && !isHighway2Link) {
maxPrioAll = badPrio;
}
if ( badWay.costfactor < 20.f && Math.abs( badTurn ) < minAbsAngeRaw )
{
minAbsAngeRaw = Math.abs( badTurn );
if (badWay.costfactor < 20.f && Math.abs(badTurn) < minAbsAngeRaw) {
minAbsAngeRaw = Math.abs(badTurn);
}
if ( badPrio < minPrio )
{
if (badPrio < minPrio) {
continue; // ignore low prio ways
}
if ( badWay.isBadOneway() )
{
if (badWay.isBadOneway()) {
continue; // ignore wrong oneways
}
if ( Math.abs( badTurn ) - Math.abs( turnAngle ) > 80.f )
{
if (Math.abs(badTurn) - Math.abs(turnAngle) > 80.f) {
continue; // ways from the back should not trigger a slight turn
}
if ( badPrio > maxPrioCandidates )
{
if (badPrio > maxPrioCandidates) {
maxPrioCandidates = badPrio;
}
if ( badTurn > maxAngle )
{
if (badTurn > maxAngle) {
maxAngle = badTurn;
}
if ( badTurn < minAngle )
{
if (badTurn < minAngle) {
minAngle = badTurn;
}
}
}
boolean hasSomethingMoreStraight = Math.abs( turnAngle ) - minAbsAngeRaw > 20.;
boolean hasSomethingMoreStraight = Math.abs(turnAngle) - minAbsAngeRaw > 20.;
// unconditional triggers are all junctions with
// - higher detour prios than the minimum route prio (except link->highway junctions)
// - or candidate detours with higher prio then the route exit leg
boolean unconditionalTrigger = hasSomethingMoreStraight || ( maxPrioAll > minPrio && !isLink2Highway ) || ( maxPrioCandidates > currentPrio );
boolean unconditionalTrigger = hasSomethingMoreStraight || (maxPrioAll > minPrio && !isLink2Highway) || (maxPrioCandidates > currentPrio);
// conditional triggers (=real turning angle required) are junctions
// with candidate detours equal in priority than the route exit leg
boolean conditionalTrigger = maxPrioCandidates >= minPrio;
if ( unconditionalTrigger || conditionalTrigger )
{
if (unconditionalTrigger || conditionalTrigger) {
input.angle = turnAngle;
input.calcCommand();
boolean isStraight = input.cmd == VoiceHint.C;
input.needsRealTurn = (!unconditionalTrigger) && isStraight;
// check for KR/KL
if ( maxAngle < turnAngle && maxAngle > turnAngle - 45.f - (turnAngle > 0.f ? turnAngle : 0.f ) )
{
if (maxAngle < turnAngle && maxAngle > turnAngle - 45.f - (turnAngle > 0.f ? turnAngle : 0.f)) {
input.cmd = VoiceHint.KR;
}
if ( minAngle > turnAngle && minAngle < turnAngle + 45.f - (turnAngle < 0.f ? turnAngle : 0.f ) )
{
if (minAngle > turnAngle && minAngle < turnAngle + 45.f - (turnAngle < 0.f ? turnAngle : 0.f)) {
input.cmd = VoiceHint.KL;
}
input.angle = sumNonConsumedWithinCatchingRange( inputs, hintIdx );
input.angle = sumNonConsumedWithinCatchingRange(inputs, hintIdx);
input.distanceToNext = distance;
distance = 0.;
results.add( input );
results.add(input);
}
if ( results.size() > 0 && distance < catchingRange )
{
results.get( results.size()-1 ).angle += sumNonConsumedWithinCatchingRange( inputs, hintIdx );
if (results.size() > 0 && distance < catchingRange) {
results.get(results.size() - 1).angle += sumNonConsumedWithinCatchingRange(inputs, hintIdx);
}
}
@ -207,25 +180,21 @@ public final class VoiceHintProcessor
List<VoiceHint> results2 = new ArrayList<VoiceHint>();
int i = results.size();
while( i > 0 )
{
while (i > 0) {
VoiceHint hint = results.get(--i);
if ( hint.cmd == 0 )
{
if (hint.cmd == 0) {
hint.calcCommand();
}
if ( ! ( hint.needsRealTurn && hint.cmd == VoiceHint.C ) )
{
if (!(hint.needsRealTurn && hint.cmd == VoiceHint.C)) {
double dist = hint.distanceToNext;
// sum up other hints within the catching range (e.g. 40m)
while( dist < catchingRange && i > 0 )
{
VoiceHint h2 = results.get(i-1);
while (dist < catchingRange && i > 0) {
VoiceHint h2 = results.get(i - 1);
dist = h2.distanceToNext;
hint.distanceToNext+= dist;
hint.distanceToNext += dist;
hint.angle += h2.angle;
i--;
if ( h2.isRoundabout() ) // if we hit a roundabout, use that as the trigger
if (h2.isRoundabout()) // if we hit a roundabout, use that as the trigger
{
h2.angle = hint.angle;
hint = h2;
@ -233,12 +202,11 @@ public final class VoiceHintProcessor
}
}
if ( !explicitRoundabouts )
{
if (!explicitRoundabouts) {
hint.roundaboutExit = 0; // use an angular hint instead
}
hint.calcCommand();
results2.add( hint );
results2.add(hint);
}
}
return results2;

View file

@ -12,11 +12,11 @@ import btools.util.CheapRuler;
public class OsmNodeNamedTest {
static int toOsmLon(double lon) {
return (int)( ( lon + 180. ) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
return (int) ((lon + 180.) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
}
static int toOsmLat(double lat) {
return (int)( ( lat + 90. ) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
return (int) ((lat + 90.) / CheapRuler.ILATLNG_TO_LATLNG + 0.5);
}
@Test

View file

@ -1,6 +1,6 @@
/**********************************************************************************************
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
**********************************************************************************************/
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
**********************************************************************************************/
package btools.router;
import static org.junit.Assert.assertEquals;
@ -22,26 +22,26 @@ public class OsmNogoPolygonTest {
static OsmNogoPolygon polygon;
static OsmNogoPolygon polyline;
static final double[] lons = { 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.1, -1.0 };
static final double[] lats = { -1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.1, -1.0 };
static final double[] lons = {1.0, 1.0, 0.5, 0.5, 1.0, 1.0, -1.1, -1.0};
static final double[] lats = {-1.0, -0.1, -0.1, 0.1, 0.1, 1.0, 1.1, -1.0};
static int toOsmLon(double lon, int offset_x) {
return (int)( ( lon + 180. ) *1000000. + 0.5)+offset_x; // see ServerHandler.readPosition()
return (int) ((lon + 180.) * 1000000. + 0.5) + offset_x; // see ServerHandler.readPosition()
}
static int toOsmLat(double lat, int offset_y) {
return (int)( ( lat + 90. ) *1000000. + 0.5)+offset_y;
return (int) ((lat + 90.) * 1000000. + 0.5) + offset_y;
}
@BeforeClass
public static void setUp() throws Exception {
polygon = new OsmNogoPolygon(true);
for (int i = 0; i<lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y));
for (int i = 0; i < lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], OFFSET_X), toOsmLat(lats[i], OFFSET_Y));
}
polyline = new OsmNogoPolygon(false);
for (int i = 0; i<lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y));
for (int i = 0; i < lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i], OFFSET_X), toOsmLat(lats[i], OFFSET_Y));
}
}
@ -51,162 +51,162 @@ public class OsmNogoPolygonTest {
@Test
public void testCalcBoundingCircle() {
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( polygon.ilat );
double[] lonlat2m = CheapRuler.getLonLatToMeterScales(polygon.ilat);
double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1];
polygon.calcBoundingCircle();
double r = polygon.radius;
for (int i=0; i<lons.length; i++) {
for (int i = 0; i < lons.length; i++) {
double dpx = (toOsmLon(lons[i], OFFSET_X) - polygon.ilon) * dlon2m;
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polygon.ilat) * dlat2m;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
double diff = r-r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
double diff = r - r1;
assertTrue("i: " + i + " r(" + r + ") >= r1(" + r1 + ")", diff >= 0);
}
polyline.calcBoundingCircle();
r = polyline.radius;
for (int i=0; i<lons.length; i++) {
for (int i = 0; i < lons.length; i++) {
double dpx = (toOsmLon(lons[i], OFFSET_X) - polyline.ilon) * dlon2m;
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polyline.ilat) * dlat2m;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
double diff = r-r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0);
double diff = r - r1;
assertTrue("i: " + i + " r(" + r + ") >= r1(" + r1 + ")", diff >= 0);
}
}
@Test
public void testIsWithin() {
double[] plons = { 0.0, 0.5, 1.0, -1.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, };
double[] plats = { 0.0, 1.5, 0.0, 0.5, -1.5, -1.0, -0.1, -0.1, 0.0, 0.1, };
boolean[] within = { true, false, false, false, false, true, true, true, true, true, };
double[] plons = {0.0, 0.5, 1.0, -1.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5,};
double[] plats = {0.0, 1.5, 0.0, 0.5, -1.5, -1.0, -0.1, -0.1, 0.0, 0.1,};
boolean[] within = {true, false, false, false, false, true, true, true, true, true,};
for (int i=0; i<plons.length; i++) {
assertEquals("("+plons[i]+","+plats[i]+")",within[i],polygon.isWithin(toOsmLon(plons[i], OFFSET_X), toOsmLat(plats[i], OFFSET_Y)));
for (int i = 0; i < plons.length; i++) {
assertEquals("(" + plons[i] + "," + plats[i] + ")", within[i], polygon.isWithin(toOsmLon(plons[i], OFFSET_X), toOsmLat(plats[i], OFFSET_Y)));
}
}
@Test
public void testIntersectsPolygon() {
double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0 };
double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0 };
double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5 };
double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5 };
boolean[] within = { false, false, false, true, true, true, false, true, true, true };
double[] p0lons = {0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0};
double[] p0lats = {0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0};
double[] p1lons = {0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5};
double[] p1lats = {0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5};
boolean[] within = {false, false, false, true, true, true, false, true, true, true};
for (int i=0; i<p0lons.length; i++) {
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polygon.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
for (int i = 0; i < p0lons.length; i++) {
assertEquals("(" + p0lons[i] + "," + p0lats[i] + ")-(" + p1lons[i] + "," + p1lats[i] + ")", within[i], polygon.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
}
}
@Test
public void testIntersectsPolyline() {
double[] p0lons = { 0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0 };
double[] p0lats = { 0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0 };
double[] p1lons = { 0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5 };
double[] p1lats = { 0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5 };
boolean[] within = { false, false, false, true, true, true, false, true, true, false };
double[] p0lons = {0.0, 1.0, -0.5, 0.5, 0.7, 0.7, 0.7, -1.5, -1.5, 0.0};
double[] p0lats = {0.0, 0.0, 0.5, 0.5, 0.5, 0.05, 0.05, -1.5, 0.2, 0.0};
double[] p1lons = {0.0, 1.0, 0.5, 1.0, 0.7, 0.7, 0.7, -0.5, -0.2, 0.5};
double[] p1lats = {0.0, 0.0, 0.5, 0.5, -0.5, -0.5, -0.05, -0.5, 1.5, -1.5};
boolean[] within = {false, false, false, true, true, true, false, true, true, false};
for (int i=0; i<p0lons.length; i++) {
assertEquals("("+p0lons[i]+","+p0lats[i]+")-("+p1lons[i]+","+p1lats[i]+")",within[i],polyline.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
for (int i = 0; i < p0lons.length; i++) {
assertEquals("(" + p0lons[i] + "," + p0lats[i] + ")-(" + p1lons[i] + "," + p1lats[i] + ")", within[i], polyline.intersects(toOsmLon(p0lons[i], OFFSET_X), toOsmLat(p0lats[i], OFFSET_Y), toOsmLon(p1lons[i], OFFSET_X), toOsmLat(p1lats[i], OFFSET_Y)));
}
}
@Test
public void testBelongsToLine() {
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 10,20));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 20,10, 10,10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,20, 10,10));
assertTrue(OsmNogoPolygon.isOnLine(10,15, 10,10, 10,20));
assertTrue(OsmNogoPolygon.isOnLine(15,10, 10,10, 20,10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,30));
assertTrue(OsmNogoPolygon.isOnLine(20,30, 10,10, 20,30));
assertTrue(OsmNogoPolygon.isOnLine(15,20, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 10,20));
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 20,10));
assertFalse(OsmNogoPolygon.isOnLine(15,21, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(15,19, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(0,-10, 10,10, 20,30));
assertFalse(OsmNogoPolygon.isOnLine(30,50, 10,10, 20,30));
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 10, 20));
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 20, 10));
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 20, 10, 10, 10));
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 20, 10, 10));
assertTrue(OsmNogoPolygon.isOnLine(10, 15, 10, 10, 10, 20));
assertTrue(OsmNogoPolygon.isOnLine(15, 10, 10, 10, 20, 10));
assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 20, 30));
assertTrue(OsmNogoPolygon.isOnLine(20, 30, 10, 10, 20, 30));
assertTrue(OsmNogoPolygon.isOnLine(15, 20, 10, 10, 20, 30));
assertFalse(OsmNogoPolygon.isOnLine(11, 11, 10, 10, 10, 20));
assertFalse(OsmNogoPolygon.isOnLine(11, 11, 10, 10, 20, 10));
assertFalse(OsmNogoPolygon.isOnLine(15, 21, 10, 10, 20, 30));
assertFalse(OsmNogoPolygon.isOnLine(15, 19, 10, 10, 20, 30));
assertFalse(OsmNogoPolygon.isOnLine(0, -10, 10, 10, 20, 30));
assertFalse(OsmNogoPolygon.isOnLine(30, 50, 10, 10, 20, 30));
}
@Test
public void testDistanceWithinPolygon() {
// Testing polygon
final double[] lons = { 2.333523, 2.333432, 2.333833, 2.333983, 2.334815, 2.334766 };
final double[] lats = { 48.823778, 48.824091, 48.82389, 48.824165, 48.824232, 48.82384 };
OsmNogoPolygon polygon = new OsmNogoPolygon(true);
for (int i = 0; i < lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
}
OsmNogoPolygon polyline = new OsmNogoPolygon(false);
for (int i = 0; i < lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
}
// Testing polygon
final double[] lons = {2.333523, 2.333432, 2.333833, 2.333983, 2.334815, 2.334766};
final double[] lats = {48.823778, 48.824091, 48.82389, 48.824165, 48.824232, 48.82384};
OsmNogoPolygon polygon = new OsmNogoPolygon(true);
for (int i = 0; i < lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
}
OsmNogoPolygon polyline = new OsmNogoPolygon(false);
for (int i = 0; i < lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
}
// Check with a segment with a single intersection with the polygon
int lon1 = toOsmLon(2.33308732509613, 0);
int lat1 = toOsmLat(48.8238790443901, 0);
int lon2 = toOsmLon(2.33378201723099, 0);
int lat2 = toOsmLat(48.8239585098974, 0);
assertEquals(
"Should give the correct length for a segment with a single intersection",
17.5,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 17.5
);
// Check with a segment with a single intersection with the polygon
int lon1 = toOsmLon(2.33308732509613, 0);
int lat1 = toOsmLat(48.8238790443901, 0);
int lon2 = toOsmLon(2.33378201723099, 0);
int lat2 = toOsmLat(48.8239585098974, 0);
assertEquals(
"Should give the correct length for a segment with a single intersection",
17.5,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 17.5
);
// Check with a segment crossing multiple times the polygon
lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0);
assertEquals(
"Should give the correct length for a segment with multiple intersections",
85,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 85
);
// Check with a segment crossing multiple times the polygon
lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0);
assertEquals(
"Should give the correct length for a segment with multiple intersections",
85,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 85
);
// Check that it works when a point is within the polygon
lon2 = toOsmLon(2.33433187007904, 0);
lat2 = toOsmLat(48.8240238480664, 0);
assertEquals(
"Should give the correct length when last point is within the polygon",
50,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 50
);
lon1 = toOsmLon(2.33433187007904, 0);
lat1 = toOsmLat(48.8240238480664, 0);
lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0);
assertEquals(
"Should give the correct length when first point is within the polygon",
35,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 35
);
// Check that it works when a point is within the polygon
lon2 = toOsmLon(2.33433187007904, 0);
lat2 = toOsmLat(48.8240238480664, 0);
assertEquals(
"Should give the correct length when last point is within the polygon",
50,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 50
);
lon1 = toOsmLon(2.33433187007904, 0);
lat1 = toOsmLat(48.8240238480664, 0);
lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0);
assertEquals(
"Should give the correct length when first point is within the polygon",
35,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 35
);
lon1 = toOsmLon(2.333523, 0);
lat1 = toOsmLat(48.823778, 0);
lon2 = toOsmLon(2.333432, 0);
lat2 = toOsmLat(48.824091, 0);
assertEquals(
"Should give the correct length if the segment overlaps with an edge of the polygon",
CheapRuler.distance(lon1, lat1, lon2, lat2),
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
);
lon1 = toOsmLon(2.333523, 0);
lat1 = toOsmLat(48.823778, 0);
lon2 = toOsmLon(2.333432, 0);
lat2 = toOsmLat(48.824091, 0);
assertEquals(
"Should give the correct length if the segment overlaps with an edge of the polygon",
CheapRuler.distance(lon1, lat1, lon2, lat2),
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
);
lon1 = toOsmLon(2.333523, 0);
lat1 = toOsmLat(48.823778, 0);
lon2 = toOsmLon(2.3334775, 0);
lat2 = toOsmLat(48.8239345, 0);
assertEquals(
"Should give the correct length if the segment overlaps with a polyline",
CheapRuler.distance(lon1, lat1, lon2, lat2),
polyline.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
);
lon1 = toOsmLon(2.333523, 0);
lat1 = toOsmLat(48.823778, 0);
lon2 = toOsmLon(2.3334775, 0);
lat2 = toOsmLat(48.8239345, 0);
assertEquals(
"Should give the correct length if the segment overlaps with a polyline",
CheapRuler.distance(lon1, lat1, lon2, lat2),
polyline.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
);
}
}

View file

@ -1,300 +1,255 @@
package btools.expressions;
import java.util.StringTokenizer;
final class BExpression
{
private static final int OR_EXP = 10;
private static final int AND_EXP = 11;
private static final int NOT_EXP = 12;
private static final int ADD_EXP = 20;
private static final int MULTIPLY_EXP = 21;
private static final int MAX_EXP = 22;
private static final int EQUAL_EXP = 23;
private static final int GREATER_EXP = 24;
private static final int MIN_EXP = 25;
private static final int SUB_EXP = 26;
private static final int LESSER_EXP = 27;
private static final int XOR_EXP = 28;
private static final int SWITCH_EXP = 30;
private static final int ASSIGN_EXP = 31;
private static final int LOOKUP_EXP = 32;
private static final int NUMBER_EXP = 33;
private static final int VARIABLE_EXP = 34;
private static final int FOREIGN_VARIABLE_EXP = 35;
private static final int VARIABLE_GET_EXP = 36;
private int typ;
private BExpression op1;
private BExpression op2;
private BExpression op3;
private float numberValue;
private int variableIdx;
private int lookupNameIdx;
private int[] lookupValueIdxArray;
// Parse the expression and all subexpression
public static BExpression parse( BExpressionContext ctx, int level ) throws Exception
{
return parse( ctx, level, null );
}
private static BExpression parse( BExpressionContext ctx, int level, String optionalToken ) throws Exception
{
boolean brackets = false;
String operator = ctx.parseToken();
if ( optionalToken != null && optionalToken.equals( operator ) )
{
operator = ctx.parseToken();
}
if ( "(".equals( operator ) )
{
brackets = true;
operator = ctx.parseToken();
}
if ( operator == null )
{
if ( level == 0 ) return null;
else throw new IllegalArgumentException( "unexpected end of file" );
}
if ( level == 0 )
{
if ( !"assign".equals( operator ) )
{
throw new IllegalArgumentException( "operator " + operator + " is invalid on toplevel (only 'assign' allowed)" );
}
}
BExpression exp = new BExpression();
int nops = 3;
boolean ifThenElse = false;
if ( "switch".equals( operator ) )
{
exp.typ = SWITCH_EXP;
}
else if ( "if".equals( operator ) )
{
exp.typ = SWITCH_EXP;
ifThenElse = true;
}
else
{
nops = 2; // check binary expressions
if ( "or".equals( operator ) )
{
exp.typ = OR_EXP;
}
else if ( "and".equals( operator ) )
{
exp.typ = AND_EXP;
}
else if ( "multiply".equals( operator ) )
{
exp.typ = MULTIPLY_EXP;
}
else if ( "add".equals( operator ) )
{
exp.typ = ADD_EXP;
}
else if ( "max".equals( operator ) )
{
exp.typ = MAX_EXP;
}
else if ( "min".equals( operator ) )
{
exp.typ = MIN_EXP;
}
else if ( "equal".equals( operator ) )
{
exp.typ = EQUAL_EXP;
}
else if ( "greater".equals( operator ) )
{
exp.typ = GREATER_EXP;
}
else if ( "sub".equals( operator ) )
{
exp.typ = SUB_EXP;
}
else if ( "lesser".equals( operator ) )
{
exp.typ = LESSER_EXP;
}
else if ( "xor".equals( operator ) )
{
exp.typ = XOR_EXP;
}
else
{
nops = 1; // check unary expressions
if ( "assign".equals( operator ) )
{
if ( level > 0 ) throw new IllegalArgumentException( "assign operator within expression" );
exp.typ = ASSIGN_EXP;
String variable = ctx.parseToken();
if ( variable == null ) throw new IllegalArgumentException( "unexpected end of file" );
if ( variable.indexOf( '=' ) >= 0 ) throw new IllegalArgumentException( "variable name cannot contain '=': " + variable );
if ( variable.indexOf( ':' ) >= 0 ) throw new IllegalArgumentException( "cannot assign context-prefixed variable: " + variable );
exp.variableIdx = ctx.getVariableIdx( variable, true );
if ( exp.variableIdx < ctx.getMinWriteIdx() ) throw new IllegalArgumentException( "cannot assign to readonly variable " + variable );
}
else if ( "not".equals( operator ) )
{
exp.typ = NOT_EXP;
}
else
{
nops = 0; // check elemantary expressions
int idx = operator.indexOf( '=' );
if ( idx >= 0 )
{
exp.typ = LOOKUP_EXP;
String name = operator.substring( 0, idx );
String values = operator.substring( idx+1 );
exp.lookupNameIdx = ctx.getLookupNameIdx( name );
if ( exp.lookupNameIdx < 0 )
{
throw new IllegalArgumentException( "unknown lookup name: " + name );
}
ctx.markLookupIdxUsed( exp.lookupNameIdx );
StringTokenizer tk = new StringTokenizer( values, "|" );
int nt = tk.countTokens();
int nt2 = nt == 0 ? 1 : nt;
exp.lookupValueIdxArray = new int[nt2];
for( int ti=0; ti<nt2; ti++ )
{
String value = ti < nt ? tk.nextToken() : "";
exp.lookupValueIdxArray[ti] = ctx.getLookupValueIdx( exp.lookupNameIdx, value );
if ( exp.lookupValueIdxArray[ti] < 0 )
{
throw new IllegalArgumentException( "unknown lookup value: " + value );
}
}
}
else if ( ( idx = operator.indexOf( ':' ) ) >= 0 )
{
/*
use of variable values
assign no_height
switch and not maxheight=
lesser v:maxheight my_height true
false
*/
if (operator.startsWith("v:")) {
String name = operator.substring(2);
exp.typ = VARIABLE_GET_EXP;
exp.lookupNameIdx = ctx.getLookupNameIdx( name );
} else {
String context = operator.substring( 0, idx );
String varname = operator.substring( idx+1 );
exp.typ = FOREIGN_VARIABLE_EXP;
exp.variableIdx = ctx.getForeignVariableIdx( context, varname );
}
}
else if ( (idx = ctx.getVariableIdx( operator, false )) >= 0 )
{
exp.typ = VARIABLE_EXP;
exp.variableIdx = idx;
}
else if ( "true".equals( operator ) )
{
exp.numberValue = 1.f;
exp.typ = NUMBER_EXP;
}
else if ( "false".equals( operator ) )
{
exp.numberValue = 0.f;
exp.typ = NUMBER_EXP;
}
else
{
try
{
exp.numberValue = Float.parseFloat( operator );
exp.typ = NUMBER_EXP;
}
catch( NumberFormatException nfe )
{
throw new IllegalArgumentException( "unknown expression: " + operator );
}
}
}
}
}
// parse operands
if ( nops > 0 )
{
exp.op1 = BExpression.parse( ctx, level+1, exp.typ == ASSIGN_EXP ? "=" : null );
}
if ( nops > 1 )
{
if ( ifThenElse ) checkExpectedToken( ctx, "then" );
exp.op2 = BExpression.parse( ctx, level+1, null );
}
if ( nops > 2 )
{
if ( ifThenElse ) checkExpectedToken( ctx, "else" );
exp.op3 = BExpression.parse( ctx, level+1, null );
}
if ( brackets )
{
checkExpectedToken( ctx, ")" );
}
return exp;
}
private static void checkExpectedToken( BExpressionContext ctx, String expected ) throws Exception
{
String token = ctx.parseToken();
if ( ! expected.equals( token ) )
{
throw new IllegalArgumentException( "unexpected token: " + token + ", expected: " + expected );
}
}
// Evaluate the expression
public float evaluate( BExpressionContext ctx )
{
switch( typ )
{
case OR_EXP: return op1.evaluate(ctx) != 0.f ? 1.f : ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f );
case XOR_EXP: return ( (op1.evaluate(ctx) != 0.f) ^ ( op2.evaluate(ctx) != 0.f ) ? 1.f : 0.f );
case AND_EXP: return op1.evaluate(ctx) != 0.f ? ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f ) : 0.f;
case ADD_EXP: return op1.evaluate(ctx) + op2.evaluate(ctx);
case SUB_EXP: return op1.evaluate(ctx) - op2.evaluate(ctx);
case MULTIPLY_EXP: return op1.evaluate(ctx) * op2.evaluate(ctx);
case MAX_EXP: return max( op1.evaluate(ctx), op2.evaluate(ctx) );
case MIN_EXP: return min( op1.evaluate(ctx), op2.evaluate(ctx) );
case EQUAL_EXP: return op1.evaluate(ctx) == op2.evaluate(ctx) ? 1.f : 0.f;
case GREATER_EXP: return op1.evaluate(ctx) > op2.evaluate(ctx) ? 1.f : 0.f;
case LESSER_EXP: return op1.evaluate(ctx) < op2.evaluate(ctx) ? 1.f : 0.f;
case SWITCH_EXP: return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx);
case ASSIGN_EXP: return ctx.assign( variableIdx, op1.evaluate(ctx) );
case LOOKUP_EXP: return ctx.getLookupMatch( lookupNameIdx, lookupValueIdxArray );
case NUMBER_EXP: return numberValue;
case VARIABLE_EXP: return ctx.getVariableValue( variableIdx );
case FOREIGN_VARIABLE_EXP: return ctx.getForeignVariableValue( variableIdx );
case VARIABLE_GET_EXP: return ctx.getLookupValue(lookupNameIdx);
case NOT_EXP: return op1.evaluate(ctx) == 0.f ? 1.f : 0.f;
default: throw new IllegalArgumentException( "unknown op-code: " + typ );
}
}
private float max( float v1, float v2 )
{
return v1 > v2 ? v1 : v2;
}
private float min( float v1, float v2 )
{
return v1 < v2 ? v1 : v2;
}
}
package btools.expressions;
import java.util.StringTokenizer;
final class BExpression {
private static final int OR_EXP = 10;
private static final int AND_EXP = 11;
private static final int NOT_EXP = 12;
private static final int ADD_EXP = 20;
private static final int MULTIPLY_EXP = 21;
private static final int MAX_EXP = 22;
private static final int EQUAL_EXP = 23;
private static final int GREATER_EXP = 24;
private static final int MIN_EXP = 25;
private static final int SUB_EXP = 26;
private static final int LESSER_EXP = 27;
private static final int XOR_EXP = 28;
private static final int SWITCH_EXP = 30;
private static final int ASSIGN_EXP = 31;
private static final int LOOKUP_EXP = 32;
private static final int NUMBER_EXP = 33;
private static final int VARIABLE_EXP = 34;
private static final int FOREIGN_VARIABLE_EXP = 35;
private static final int VARIABLE_GET_EXP = 36;
private int typ;
private BExpression op1;
private BExpression op2;
private BExpression op3;
private float numberValue;
private int variableIdx;
private int lookupNameIdx;
private int[] lookupValueIdxArray;
// Parse the expression and all subexpression
public static BExpression parse(BExpressionContext ctx, int level) throws Exception {
return parse(ctx, level, null);
}
private static BExpression parse(BExpressionContext ctx, int level, String optionalToken) throws Exception {
boolean brackets = false;
String operator = ctx.parseToken();
if (optionalToken != null && optionalToken.equals(operator)) {
operator = ctx.parseToken();
}
if ("(".equals(operator)) {
brackets = true;
operator = ctx.parseToken();
}
if (operator == null) {
if (level == 0) return null;
else throw new IllegalArgumentException("unexpected end of file");
}
if (level == 0) {
if (!"assign".equals(operator)) {
throw new IllegalArgumentException("operator " + operator + " is invalid on toplevel (only 'assign' allowed)");
}
}
BExpression exp = new BExpression();
int nops = 3;
boolean ifThenElse = false;
if ("switch".equals(operator)) {
exp.typ = SWITCH_EXP;
} else if ("if".equals(operator)) {
exp.typ = SWITCH_EXP;
ifThenElse = true;
} else {
nops = 2; // check binary expressions
if ("or".equals(operator)) {
exp.typ = OR_EXP;
} else if ("and".equals(operator)) {
exp.typ = AND_EXP;
} else if ("multiply".equals(operator)) {
exp.typ = MULTIPLY_EXP;
} else if ("add".equals(operator)) {
exp.typ = ADD_EXP;
} else if ("max".equals(operator)) {
exp.typ = MAX_EXP;
} else if ("min".equals(operator)) {
exp.typ = MIN_EXP;
} else if ("equal".equals(operator)) {
exp.typ = EQUAL_EXP;
} else if ("greater".equals(operator)) {
exp.typ = GREATER_EXP;
} else if ("sub".equals(operator)) {
exp.typ = SUB_EXP;
} else if ("lesser".equals(operator)) {
exp.typ = LESSER_EXP;
} else if ("xor".equals(operator)) {
exp.typ = XOR_EXP;
} else {
nops = 1; // check unary expressions
if ("assign".equals(operator)) {
if (level > 0) throw new IllegalArgumentException("assign operator within expression");
exp.typ = ASSIGN_EXP;
String variable = ctx.parseToken();
if (variable == null) throw new IllegalArgumentException("unexpected end of file");
if (variable.indexOf('=') >= 0)
throw new IllegalArgumentException("variable name cannot contain '=': " + variable);
if (variable.indexOf(':') >= 0)
throw new IllegalArgumentException("cannot assign context-prefixed variable: " + variable);
exp.variableIdx = ctx.getVariableIdx(variable, true);
if (exp.variableIdx < ctx.getMinWriteIdx())
throw new IllegalArgumentException("cannot assign to readonly variable " + variable);
} else if ("not".equals(operator)) {
exp.typ = NOT_EXP;
} else {
nops = 0; // check elemantary expressions
int idx = operator.indexOf('=');
if (idx >= 0) {
exp.typ = LOOKUP_EXP;
String name = operator.substring(0, idx);
String values = operator.substring(idx + 1);
exp.lookupNameIdx = ctx.getLookupNameIdx(name);
if (exp.lookupNameIdx < 0) {
throw new IllegalArgumentException("unknown lookup name: " + name);
}
ctx.markLookupIdxUsed(exp.lookupNameIdx);
StringTokenizer tk = new StringTokenizer(values, "|");
int nt = tk.countTokens();
int nt2 = nt == 0 ? 1 : nt;
exp.lookupValueIdxArray = new int[nt2];
for (int ti = 0; ti < nt2; ti++) {
String value = ti < nt ? tk.nextToken() : "";
exp.lookupValueIdxArray[ti] = ctx.getLookupValueIdx(exp.lookupNameIdx, value);
if (exp.lookupValueIdxArray[ti] < 0) {
throw new IllegalArgumentException("unknown lookup value: " + value);
}
}
} else if ((idx = operator.indexOf(':')) >= 0) {
/*
use of variable values
assign no_height
switch and not maxheight=
lesser v:maxheight my_height true
false
*/
if (operator.startsWith("v:")) {
String name = operator.substring(2);
exp.typ = VARIABLE_GET_EXP;
exp.lookupNameIdx = ctx.getLookupNameIdx(name);
} else {
String context = operator.substring(0, idx);
String varname = operator.substring(idx + 1);
exp.typ = FOREIGN_VARIABLE_EXP;
exp.variableIdx = ctx.getForeignVariableIdx(context, varname);
}
} else if ((idx = ctx.getVariableIdx(operator, false)) >= 0) {
exp.typ = VARIABLE_EXP;
exp.variableIdx = idx;
} else if ("true".equals(operator)) {
exp.numberValue = 1.f;
exp.typ = NUMBER_EXP;
} else if ("false".equals(operator)) {
exp.numberValue = 0.f;
exp.typ = NUMBER_EXP;
} else {
try {
exp.numberValue = Float.parseFloat(operator);
exp.typ = NUMBER_EXP;
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("unknown expression: " + operator);
}
}
}
}
}
// parse operands
if (nops > 0) {
exp.op1 = BExpression.parse(ctx, level + 1, exp.typ == ASSIGN_EXP ? "=" : null);
}
if (nops > 1) {
if (ifThenElse) checkExpectedToken(ctx, "then");
exp.op2 = BExpression.parse(ctx, level + 1, null);
}
if (nops > 2) {
if (ifThenElse) checkExpectedToken(ctx, "else");
exp.op3 = BExpression.parse(ctx, level + 1, null);
}
if (brackets) {
checkExpectedToken(ctx, ")");
}
return exp;
}
private static void checkExpectedToken(BExpressionContext ctx, String expected) throws Exception {
String token = ctx.parseToken();
if (!expected.equals(token)) {
throw new IllegalArgumentException("unexpected token: " + token + ", expected: " + expected);
}
}
// Evaluate the expression
public float evaluate(BExpressionContext ctx) {
switch (typ) {
case OR_EXP:
return op1.evaluate(ctx) != 0.f ? 1.f : (op2.evaluate(ctx) != 0.f ? 1.f : 0.f);
case XOR_EXP:
return ((op1.evaluate(ctx) != 0.f) ^ (op2.evaluate(ctx) != 0.f) ? 1.f : 0.f);
case AND_EXP:
return op1.evaluate(ctx) != 0.f ? (op2.evaluate(ctx) != 0.f ? 1.f : 0.f) : 0.f;
case ADD_EXP:
return op1.evaluate(ctx) + op2.evaluate(ctx);
case SUB_EXP:
return op1.evaluate(ctx) - op2.evaluate(ctx);
case MULTIPLY_EXP:
return op1.evaluate(ctx) * op2.evaluate(ctx);
case MAX_EXP:
return max(op1.evaluate(ctx), op2.evaluate(ctx));
case MIN_EXP:
return min(op1.evaluate(ctx), op2.evaluate(ctx));
case EQUAL_EXP:
return op1.evaluate(ctx) == op2.evaluate(ctx) ? 1.f : 0.f;
case GREATER_EXP:
return op1.evaluate(ctx) > op2.evaluate(ctx) ? 1.f : 0.f;
case LESSER_EXP:
return op1.evaluate(ctx) < op2.evaluate(ctx) ? 1.f : 0.f;
case SWITCH_EXP:
return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx);
case ASSIGN_EXP:
return ctx.assign(variableIdx, op1.evaluate(ctx));
case LOOKUP_EXP:
return ctx.getLookupMatch(lookupNameIdx, lookupValueIdxArray);
case NUMBER_EXP:
return numberValue;
case VARIABLE_EXP:
return ctx.getVariableValue(variableIdx);
case FOREIGN_VARIABLE_EXP:
return ctx.getForeignVariableValue(variableIdx);
case VARIABLE_GET_EXP:
return ctx.getLookupValue(lookupNameIdx);
case NOT_EXP:
return op1.evaluate(ctx) == 0.f ? 1.f : 0.f;
default:
throw new IllegalArgumentException("unknown op-code: " + typ);
}
}
private float max(float v1, float v2) {
return v1 > v2 ? v1 : v2;
}
private float min(float v1, float v2) {
return v1 < v2 ? v1 : v2;
}
}

View file

@ -7,32 +7,29 @@
package btools.expressions;
public final class BExpressionContextNode extends BExpressionContext
{
public final class BExpressionContextNode extends BExpressionContext {
private static String[] buildInVariables =
{ "initialcost" };
protected String[] getBuildInVariableNames()
{
{"initialcost"};
protected String[] getBuildInVariableNames() {
return buildInVariables;
}
public float getInitialcost() { return getBuildInVariable(0); }
public float getInitialcost() {
return getBuildInVariable(0);
}
public BExpressionContextNode( BExpressionMetaData meta )
{
super( "node", meta );
public BExpressionContextNode(BExpressionMetaData meta) {
super("node", meta);
}
/**
* Create an Expression-Context for way context
*
* @param hashSize size of hashmap for result caching
* @param hashSize size of hashmap for result caching
*/
public BExpressionContextNode( int hashSize, BExpressionMetaData meta )
{
super( "node", hashSize, meta );
public BExpressionContextNode(int hashSize, BExpressionMetaData meta) {
super("node", hashSize, meta);
}
}

View file

@ -8,66 +8,93 @@ package btools.expressions;
import btools.codec.TagValueValidator;
public final class BExpressionContextWay extends BExpressionContext implements 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", "maxspeed" };
protected String[] getBuildInVariableNames()
{
{"costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask", "maxspeed"};
protected String[] getBuildInVariableNames() {
return buildInVariables;
}
public float getCostfactor() { return getBuildInVariable(0); }
public float getTurncost() { return getBuildInVariable(1); }
public float getUphillCostfactor() { return getBuildInVariable(2); }
public float getDownhillCostfactor() { return getBuildInVariable(3); }
public float getInitialcost() { return getBuildInVariable(4); }
public float getNodeAccessGranted() { return getBuildInVariable(5); }
public float getInitialClassifier() { return getBuildInVariable(6); }
public float getTrafficSourceDensity() { return getBuildInVariable(7); }
public float getIsTrafficBackbone() { return getBuildInVariable(8); }
public float getPriorityClassifier() { return getBuildInVariable(9); }
public float getClassifierMask() { return getBuildInVariable(10); }
public float getMaxspeed() { return getBuildInVariable(11); }
public float getCostfactor() {
return getBuildInVariable(0);
}
public BExpressionContextWay( BExpressionMetaData meta )
{
super( "way", meta );
public float getTurncost() {
return getBuildInVariable(1);
}
public float getUphillCostfactor() {
return getBuildInVariable(2);
}
public float getDownhillCostfactor() {
return getBuildInVariable(3);
}
public float getInitialcost() {
return getBuildInVariable(4);
}
public float getNodeAccessGranted() {
return getBuildInVariable(5);
}
public float getInitialClassifier() {
return getBuildInVariable(6);
}
public float getTrafficSourceDensity() {
return getBuildInVariable(7);
}
public float getIsTrafficBackbone() {
return getBuildInVariable(8);
}
public float getPriorityClassifier() {
return getBuildInVariable(9);
}
public float getClassifierMask() {
return getBuildInVariable(10);
}
public float getMaxspeed() {
return getBuildInVariable(11);
}
public BExpressionContextWay(BExpressionMetaData meta) {
super("way", meta);
}
/**
* Create an Expression-Context for way context
*
* @param hashSize size of hashmap for result caching
* @param hashSize size of hashmap for result caching
*/
public BExpressionContextWay( int hashSize, BExpressionMetaData meta )
{
super( "way", hashSize, meta );
public BExpressionContextWay(int hashSize, BExpressionMetaData meta) {
super("way", hashSize, meta);
}
@Override
public int accessType( byte[] description )
{
evaluate( false, description );
public int accessType(byte[] description) {
evaluate(false, description);
float minCostFactor = getCostfactor();
if ( minCostFactor >= 9999.f )
{
if (minCostFactor >= 9999.f) {
setInverseVars();
float reverseCostFactor = getCostfactor();
if ( reverseCostFactor < minCostFactor )
{
if (reverseCostFactor < minCostFactor) {
minCostFactor = reverseCostFactor;
}
}
return minCostFactor < 9999.f ? 2 : decodeForbidden ? (minCostFactor < 10000.f ? 1 : 0) : 0;
}
@Override
public void setDecodeForbidden( boolean decodeForbidden )
{
this.decodeForbidden= decodeForbidden;
public void setDecodeForbidden(boolean decodeForbidden) {
this.decodeForbidden = decodeForbidden;
}
}

View file

@ -1,66 +1,56 @@
/**
* A lookup value with optional aliases
*
* toString just gives the primary value,
* equals just compares against primary value
* matches() also compares aliases
*
* @author ab
*/
package btools.expressions;
import java.util.ArrayList;
final class BExpressionLookupValue
{
String value;
ArrayList<String> aliases;
@Override
public String toString()
{
return value;
}
public BExpressionLookupValue( String value )
{
this.value = value;
}
public void addAlias( String alias )
{
if ( aliases == null ) aliases = new ArrayList<String>();
aliases.add( alias );
}
@Override
public boolean equals( Object o )
{
if ( o instanceof String )
{
String v = (String)o;
return value.equals( v );
}
if ( o instanceof BExpressionLookupValue )
{
BExpressionLookupValue v = (BExpressionLookupValue)o;
return value.equals( v.value );
}
return false;
}
public boolean matches( String s )
{
if ( value.equals( s ) ) return true;
if ( aliases != null )
{
for( String alias : aliases )
{
if ( alias.equals( s ) ) return true;
}
}
return false;
}
}
/**
* A lookup value with optional aliases
* <p>
* toString just gives the primary value,
* equals just compares against primary value
* matches() also compares aliases
*
* @author ab
*/
package btools.expressions;
import java.util.ArrayList;
final class BExpressionLookupValue {
String value;
ArrayList<String> aliases;
@Override
public String toString() {
return value;
}
public BExpressionLookupValue(String value) {
this.value = value;
}
public void addAlias(String alias) {
if (aliases == null) aliases = new ArrayList<String>();
aliases.add(alias);
}
@Override
public boolean equals(Object o) {
if (o instanceof String) {
String v = (String) o;
return value.equals(v);
}
if (o instanceof BExpressionLookupValue) {
BExpressionLookupValue v = (BExpressionLookupValue) o;
return value.equals(v.value);
}
return false;
}
public boolean matches(String s) {
if (value.equals(s)) return true;
if (aliases != null) {
for (String alias : aliases) {
if (alias.equals(s)) return true;
}
}
return false;
}
}

View file

@ -21,9 +21,8 @@ import btools.util.BitCoderContext;
import btools.util.Crc32;
public final class BExpressionMetaData
{
private static final String CONTEXT_TAG = "---context:";
public final class BExpressionMetaData {
private static final String CONTEXT_TAG = "---context:";
private static final String VERSION_TAG = "---lookupversion:";
private static final String MINOR_VERSION_TAG = "---minorversion:";
private static final String VARLENGTH_TAG = "---readvarlength";
@ -31,59 +30,49 @@ public final class BExpressionMetaData
public short lookupVersion = -1;
public short lookupMinorVersion = -1;
private HashMap<String,BExpressionContext> listeners = new HashMap<String,BExpressionContext>();
public void registerListener( String context, BExpressionContext ctx )
{
listeners.put( context, ctx );
private HashMap<String, BExpressionContext> listeners = new HashMap<String, BExpressionContext>();
public void registerListener(String context, BExpressionContext ctx) {
listeners.put(context, ctx);
}
public void readMetaData( File lookupsFile )
{
try
{
BufferedReader br = new BufferedReader( new FileReader( lookupsFile ) );
BExpressionContext ctx = null;
for(;;)
{
String line = br.readLine();
if ( line == null ) break;
line = line.trim();
if ( line.length() == 0 || line.startsWith( "#" ) ) continue;
if ( line.startsWith( CONTEXT_TAG ) )
{
ctx = listeners.get( line.substring( CONTEXT_TAG.length() ) );
continue;
public void readMetaData(File lookupsFile) {
try {
BufferedReader br = new BufferedReader(new FileReader(lookupsFile));
BExpressionContext ctx = null;
for (; ; ) {
String line = br.readLine();
if (line == null) break;
line = line.trim();
if (line.length() == 0 || line.startsWith("#")) continue;
if (line.startsWith(CONTEXT_TAG)) {
ctx = listeners.get(line.substring(CONTEXT_TAG.length()));
continue;
}
if (line.startsWith(VERSION_TAG)) {
lookupVersion = Short.parseShort(line.substring(VERSION_TAG.length()));
continue;
}
if (line.startsWith(MINOR_VERSION_TAG)) {
lookupMinorVersion = Short.parseShort(line.substring(MINOR_VERSION_TAG.length()));
continue;
}
if (line.startsWith(VARLENGTH_TAG)) // tag removed...
{
continue;
}
if (ctx != null) ctx.parseMetaLine(line);
}
if ( line.startsWith( VERSION_TAG ) )
{
lookupVersion = Short.parseShort( line.substring( VERSION_TAG.length() ) );
continue;
br.close();
for (BExpressionContext c : listeners.values()) {
c.finishMetaParsing();
}
if ( line.startsWith( MINOR_VERSION_TAG ) )
{
lookupMinorVersion = Short.parseShort( line.substring( MINOR_VERSION_TAG.length() ) );
continue;
}
if ( line.startsWith( VARLENGTH_TAG ) ) // tag removed...
{
continue;
}
if ( ctx != null ) ctx.parseMetaLine( line );
} catch (Exception e) {
throw new RuntimeException(e);
}
br.close();
for( BExpressionContext c : listeners.values() )
{
c.finishMetaParsing();
}
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
}

View file

@ -4,29 +4,24 @@ import java.util.Arrays;
import btools.util.LruMapNode;
public final class CacheNode extends LruMapNode
{
public final class CacheNode extends LruMapNode {
byte[] ab;
float[] vars;
@Override
public int hashCode()
{
public int hashCode() {
return hash;
}
@Override
public boolean equals( Object o )
{
public boolean equals(Object o) {
CacheNode n = (CacheNode) o;
if ( hash != n.hash )
{
if (hash != n.hash) {
return false;
}
if ( ab == null )
{
if (ab == null) {
return true; // hack: null = crc match only
}
return Arrays.equals( ab, n.ab );
return Arrays.equals(ab, n.ab);
}
}

View file

@ -3,45 +3,40 @@ package btools.expressions;
import java.io.File;
import java.util.Random;
public final class ProfileComparator
{
public static void main( String[] args )
{
if ( args.length != 4 )
{
System.out.println( "usage: java ProfileComparator <lookup-file> <profile1> <profile2> <nsamples>" );
public final class ProfileComparator {
public static void main(String[] args) {
if (args.length != 4) {
System.out.println("usage: java ProfileComparator <lookup-file> <profile1> <profile2> <nsamples>");
return;
}
File lookupFile = new File( args[0] );
File profile1File = new File( args[1] );
File profile2File = new File( args[2] );
int nsamples = Integer.parseInt( args[3] );
testContext( lookupFile, profile1File, profile2File, nsamples, false );
testContext( lookupFile, profile1File, profile2File, nsamples, true );
File lookupFile = new File(args[0]);
File profile1File = new File(args[1]);
File profile2File = new File(args[2]);
int nsamples = Integer.parseInt(args[3]);
testContext(lookupFile, profile1File, profile2File, nsamples, false);
testContext(lookupFile, profile1File, profile2File, nsamples, true);
}
private static void testContext( File lookupFile, File profile1File, File profile2File, int nsamples, boolean nodeContext )
{
private static void testContext(File lookupFile, File profile1File, File profile2File, int nsamples, boolean nodeContext) {
// read lookup.dat + profiles
BExpressionMetaData meta1 = new BExpressionMetaData();
BExpressionMetaData meta2 = new BExpressionMetaData();
BExpressionContext expctx1 = nodeContext ? new BExpressionContextNode( meta1 ) : new BExpressionContextWay( meta1 );
BExpressionContext expctx2 = nodeContext ? new BExpressionContextNode( meta2 ) : new BExpressionContextWay( meta2 );
meta1.readMetaData( lookupFile );
meta2.readMetaData( lookupFile );
expctx1.parseFile( profile1File, "global" );
expctx2.parseFile( profile2File, "global" );
BExpressionContext expctx1 = nodeContext ? new BExpressionContextNode(meta1) : new BExpressionContextWay(meta1);
BExpressionContext expctx2 = nodeContext ? new BExpressionContextNode(meta2) : new BExpressionContextWay(meta2);
meta1.readMetaData(lookupFile);
meta2.readMetaData(lookupFile);
expctx1.parseFile(profile1File, "global");
expctx2.parseFile(profile2File, "global");
Random rnd = new Random();
for( int i=0; i<nsamples; i++ )
{
int[] data = expctx1.generateRandomValues( rnd );
expctx1.evaluate( data );
expctx2.evaluate( data );
expctx1.assertAllVariablesEqual( expctx2 );
for (int i = 0; i < nsamples; i++) {
int[] data = expctx1.generateRandomValues(rnd);
expctx1.evaluate(data);
expctx2.evaluate(data);
expctx1.assertAllVariablesEqual(expctx2);
}
}
}
}

View file

@ -4,24 +4,20 @@ import java.util.Arrays;
import btools.util.LruMapNode;
public final class VarWrapper extends LruMapNode
{
public final class VarWrapper extends LruMapNode {
float[] vars;
@Override
public int hashCode()
{
public int hashCode() {
return hash;
}
@Override
public boolean equals( Object o )
{
public boolean equals(Object o) {
VarWrapper n = (VarWrapper) o;
if ( hash != n.hash )
{
if (hash != n.hash) {
return false;
}
return Arrays.equals( vars, n.vars );
return Arrays.equals(vars, n.vars);
}
}

View file

@ -7,54 +7,52 @@ import java.net.URL;
import org.junit.Assert;
import org.junit.Test;
public class EncodeDecodeTest
{
public class EncodeDecodeTest {
@Test
public void encodeDecodeTest()
{
URL testpurl = this.getClass().getResource( "/dummy.txt" );
public void encodeDecodeTest() {
URL testpurl = this.getClass().getResource("/dummy.txt");
File workingDir = new File(testpurl.getFile()).getParentFile();
File profileDir = new File( workingDir, "/../../../../misc/profiles2" );
File profileDir = new File(workingDir, "/../../../../misc/profiles2");
//File lookupFile = new File( profileDir, "lookups.dat" );
// add a test lookup
URL testlookup = this.getClass().getResource( "/lookups_test.dat" );
File lookupFile = new File( testlookup.getPath() );
// add a test lookup
URL testlookup = this.getClass().getResource("/lookups_test.dat");
File lookupFile = new File(testlookup.getPath());
// read lookup.dat + trekking.brf
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextWay expctxWay = new BExpressionContextWay( meta );
meta.readMetaData( lookupFile );
expctxWay.parseFile( new File( profileDir, "trekking.brf" ), "global" );
BExpressionContextWay expctxWay = new BExpressionContextWay(meta);
meta.readMetaData(lookupFile);
expctxWay.parseFile(new File(profileDir, "trekking.brf"), "global");
String[] tags = {
"highway=residential",
"oneway=yes",
"depth=1'6\"",
// "depth=6 feet",
"maxheight=5.1m",
"maxdraft=~3 mt",
"reversedirection=yes"
"highway=residential",
"oneway=yes",
"depth=1'6\"",
// "depth=6 feet",
"maxheight=5.1m",
"maxdraft=~3 mt",
"reversedirection=yes"
};
// encode the tags into 64 bit description word
int[] lookupData = expctxWay.createNewLookupData();
for( String arg: tags )
{
int idx = arg.indexOf( '=' );
if ( idx < 0 ) throw new IllegalArgumentException( "bad argument (should be <tag>=<value>): " + arg );
String key = arg.substring( 0, idx );
String value = arg.substring( idx+1 );
expctxWay.addLookupValue( key, value, lookupData );
for (String arg : tags) {
int idx = arg.indexOf('=');
if (idx < 0)
throw new IllegalArgumentException("bad argument (should be <tag>=<value>): " + arg);
String key = arg.substring(0, idx);
String value = arg.substring(idx + 1);
expctxWay.addLookupValue(key, value, lookupData);
}
byte[] description = expctxWay.encode(lookupData);
// calculate the cost factor from that description
expctxWay.evaluate( true, description ); // true = "reversedirection=yes" (not encoded in description anymore)
expctxWay.evaluate(true, description); // true = "reversedirection=yes" (not encoded in description anymore)
System.out.println( "description: " + expctxWay.getKeyValueDescription(true, description) );
System.out.println("description: " + expctxWay.getKeyValueDescription(true, description));
float costfactor = expctxWay.getCostfactor();
Assert.assertTrue( "costfactor mismatch", Math.abs( costfactor - 5.15 ) < 0.00001 );
Assert.assertTrue("costfactor mismatch", Math.abs(costfactor - 5.15) < 0.00001);
}
}

View file

@ -11,8 +11,7 @@ import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ConvertLidarTile
{
public class ConvertLidarTile {
public static int NROWS;
public static int NCOLS;
@ -21,78 +20,63 @@ public class ConvertLidarTile
static short[] imagePixels;
private static void readHgtZip( String filename, int rowOffset, int colOffset ) throws Exception
{
ZipInputStream zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( filename ) ) );
try
{
for ( ;; )
{
private static void readHgtZip(String filename, int rowOffset, int colOffset) throws Exception {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(filename)));
try {
for (; ; ) {
ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".hgt" ) )
{
readHgtFromStream( zis, rowOffset, colOffset );
if (ze.getName().endsWith(".hgt")) {
readHgtFromStream(zis, rowOffset, colOffset);
return;
}
}
}
finally
{
} finally {
zis.close();
}
}
private static void readHgtFromStream( InputStream is, int rowOffset, int colOffset )
throws Exception
{
DataInputStream dis = new DataInputStream( new BufferedInputStream( is ) );
for ( int ir = 0; ir < 1201; ir++ )
{
private static void readHgtFromStream(InputStream is, int rowOffset, int colOffset)
throws Exception {
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
for (int ir = 0; ir < 1201; ir++) {
int row = rowOffset + ir;
for ( int ic = 0; ic < 1201; ic++ )
{
for (int ic = 0; ic < 1201; ic++) {
int col = colOffset + ic;
int i1 = dis.read(); // msb first!
int i0 = dis.read();
if ( i0 == -1 || i1 == -1 )
throw new RuntimeException( "unexcepted end of file reading hgt entry!" );
if (i0 == -1 || i1 == -1)
throw new RuntimeException("unexcepted end of file reading hgt entry!");
short val = (short) ( ( i1 << 8 ) | i0 );
short val = (short) ((i1 << 8) | i0);
if ( val == NODATA2 )
{
if (val == NODATA2) {
val = NODATA;
}
setPixel( row, col, val );
setPixel(row, col, val);
}
}
}
private static void setPixel( int row, int col, short val )
{
if ( row >= 0 && row < NROWS && col >= 0 && col < NCOLS )
{
private static void setPixel(int row, int col, short val) {
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
imagePixels[row * NCOLS + col] = val;
}
}
private static short getPixel( int row, int col )
{
if ( row >= 0 && row < NROWS && col >= 0 && col < NCOLS )
{
private static short getPixel(int row, int col) {
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
return imagePixels[row * NCOLS + col];
}
return NODATA;
}
public static void doConvert( String inputDir, int lonDegreeStart, int latDegreeStart, String outputFile ) throws Exception
{
public static void doConvert(String inputDir, int lonDegreeStart, int latDegreeStart, String outputFile) throws Exception {
int extraBorder = 0;
NROWS = 5 * 1200 + 1 + 2 * extraBorder;
@ -101,34 +85,27 @@ public class ConvertLidarTile
imagePixels = new short[NROWS * NCOLS]; // 650 MB !
// prefill as NODATA
for ( int row = 0; row < NROWS; row++ )
{
for ( int col = 0; col < NCOLS; col++ )
{
for (int row = 0; row < NROWS; row++) {
for (int col = 0; col < NCOLS; col++) {
imagePixels[row * NCOLS + col] = NODATA;
}
}
for ( int latIdx = -1; latIdx <= 5; latIdx++ )
{
for (int latIdx = -1; latIdx <= 5; latIdx++) {
int latDegree = latDegreeStart + latIdx;
int rowOffset = extraBorder + ( 4 - latIdx ) * 1200;
int rowOffset = extraBorder + (4 - latIdx) * 1200;
for ( int lonIdx = -1; lonIdx <= 5; lonIdx++ )
{
for (int lonIdx = -1; lonIdx <= 5; lonIdx++) {
int lonDegree = lonDegreeStart + lonIdx;
int colOffset = extraBorder + lonIdx * 1200;
String filename = inputDir + "/" + formatLat( latDegree ) + formatLon( lonDegree ) + ".zip";
File f = new File( filename );
if ( f.exists() && f.length() > 0 )
{
System.out.println( "exist: " + filename );
readHgtZip( filename, rowOffset, colOffset );
}
else
{
System.out.println( "none : " + filename );
String filename = inputDir + "/" + formatLat(latDegree) + formatLon(lonDegree) + ".zip";
File f = new File(filename);
if (f.exists() && f.length() > 0) {
System.out.println("exist: " + filename);
readHgtZip(filename, rowOffset, colOffset);
} else {
System.out.println("none : " + filename);
}
}
}
@ -142,79 +119,71 @@ public class ConvertLidarTile
raster.halfcol = halfCol5;
raster.noDataValue = NODATA;
raster.cellsize = 1 / 1200.;
raster.xllcorner = lonDegreeStart - ( 0.5 + extraBorder ) * raster.cellsize;
raster.yllcorner = latDegreeStart - ( 0.5 + extraBorder ) * raster.cellsize;
raster.xllcorner = lonDegreeStart - (0.5 + extraBorder) * raster.cellsize;
raster.yllcorner = latDegreeStart - (0.5 + extraBorder) * raster.cellsize;
raster.eval_array = imagePixels;
// encode the raster
OutputStream os = new BufferedOutputStream( new FileOutputStream( outputFile ) );
new RasterCoder().encodeRaster( raster, os );
OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile));
new RasterCoder().encodeRaster(raster, os);
os.close();
// decode the raster
InputStream is = new BufferedInputStream( new FileInputStream( outputFile ) );
SrtmRaster raster2 = new RasterCoder().decodeRaster( is );
InputStream is = new BufferedInputStream(new FileInputStream(outputFile));
SrtmRaster raster2 = new RasterCoder().decodeRaster(is);
is.close();
short[] pix2 = raster2.eval_array;
if ( pix2.length != imagePixels.length )
throw new RuntimeException( "length mismatch!" );
if (pix2.length != imagePixels.length)
throw new RuntimeException("length mismatch!");
// compare decoding result
for ( int row = 0; row < NROWS; row++ )
{
for (int row = 0; row < NROWS; row++) {
int colstep = halfCol5 ? 2 : 1;
for ( int col = 0; col < NCOLS; col += colstep )
{
for (int col = 0; col < NCOLS; col += colstep) {
int idx = row * NCOLS + col;
short p2 = pix2[idx];
if ( p2 != imagePixels[idx] )
{
throw new RuntimeException( "content mismatch: p2=" + p2 + " p1=" + imagePixels[idx] );
if (p2 != imagePixels[idx]) {
throw new RuntimeException("content mismatch: p2=" + p2 + " p1=" + imagePixels[idx]);
}
}
}
}
private static String formatLon( int lon )
{
if ( lon >= 180 )
private static String formatLon(int lon) {
if (lon >= 180)
lon -= 180; // TODO: w180 oder E180 ?
String s = "E";
if ( lon < 0 )
{
if (lon < 0) {
lon = -lon;
s = "E";
}
String n = "000" + lon;
return s + n.substring( n.length() - 3 );
return s + n.substring(n.length() - 3);
}
private static String formatLat( int lat )
{
private static String formatLat(int lat) {
String s = "N";
if ( lat < 0 )
{
if (lat < 0) {
lat = -lat;
s = "S";
}
String n = "00" + lat;
return s + n.substring( n.length() - 2 );
return s + n.substring(n.length() - 2);
}
public static void main( String[] args ) throws Exception
{
String filename90 = args[0];
String filename30 = filename90.substring( 0, filename90.length() - 3 ) + "bef";
public static void main(String[] args) throws Exception {
String filename90 = args[0];
String filename30 = filename90.substring(0, filename90.length() - 3) + "bef";
int srtmLonIdx = Integer.parseInt( filename90.substring( 5, 7 ).toLowerCase() );
int srtmLatIdx = Integer.parseInt( filename90.substring( 8, 10 ).toLowerCase() );
int srtmLonIdx = Integer.parseInt(filename90.substring(5, 7).toLowerCase());
int srtmLatIdx = Integer.parseInt(filename90.substring(8, 10).toLowerCase());
int ilon_base = ( srtmLonIdx - 1 ) * 5 - 180;
int ilat_base = 150 - srtmLatIdx * 5 - 90;
doConvert( args[1], ilon_base, ilat_base, filename30 );
int ilon_base = (srtmLonIdx - 1) * 5 - 180;
int ilat_base = 150 - srtmLatIdx * 5 - 90;
doConvert(args[1], ilon_base, ilat_base, filename30);
}
}

View file

@ -3,8 +3,7 @@ package btools.mapcreator;
import java.io.*;
import java.util.zip.*;
public class ConvertSrtmTile
{
public class ConvertSrtmTile {
public static int NROWS;
public static int NCOLS;
@ -16,44 +15,33 @@ public class ConvertSrtmTile
public static int[] diffs = new int[100];
private static void readBilZip( String filename, int rowOffset, int colOffset, boolean halfCols ) throws Exception
{
ZipInputStream zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( filename ) ) );
try
{
for ( ;; )
{
private static void readBilZip(String filename, int rowOffset, int colOffset, boolean halfCols) throws Exception {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(filename)));
try {
for (; ; ) {
ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".bil" ) )
{
readBilFromStream( zis, rowOffset, colOffset, halfCols );
if (ze.getName().endsWith(".bil")) {
readBilFromStream(zis, rowOffset, colOffset, halfCols);
return;
}
}
}
finally
{
} finally {
zis.close();
}
}
private static void readBilFromStream( InputStream is, int rowOffset, int colOffset, boolean halfCols )
throws Exception
{
DataInputStream dis = new DataInputStream( new BufferedInputStream( is ) );
for ( int ir = 0; ir < 3601; ir++ )
{
private static void readBilFromStream(InputStream is, int rowOffset, int colOffset, boolean halfCols)
throws Exception {
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
for (int ir = 0; ir < 3601; ir++) {
int row = rowOffset + ir;
for ( int ic = 0; ic < 3601; ic++ )
{
for (int ic = 0; ic < 3601; ic++) {
int col = colOffset + ic;
if ( ( ic % 2 ) == 1 && halfCols )
{
if ( getPixel( row, col ) == NODATA )
{
setPixel( row, col, SKIPDATA );
if ((ic % 2) == 1 && halfCols) {
if (getPixel(row, col) == NODATA) {
setPixel(row, col, SKIPDATA);
}
continue;
}
@ -61,42 +49,36 @@ public class ConvertSrtmTile
int i0 = dis.read();
int i1 = dis.read();
if ( i0 == -1 || i1 == -1 )
throw new RuntimeException( "unexcepted end of file reading bil entry!" );
if (i0 == -1 || i1 == -1)
throw new RuntimeException("unexcepted end of file reading bil entry!");
short val = (short) ( ( i1 << 8 ) | i0 );
short val = (short) ((i1 << 8) | i0);
if ( val == NODATA2 )
{
if (val == NODATA2) {
val = NODATA;
}
setPixel( row, col, val );
setPixel(row, col, val);
}
}
}
private static void setPixel( int row, int col, short val )
{
if ( row >= 0 && row < NROWS && col >= 0 && col < NCOLS )
{
private static void setPixel(int row, int col, short val) {
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
imagePixels[row * NCOLS + col] = val;
}
}
private static short getPixel( int row, int col )
{
if ( row >= 0 && row < NROWS && col >= 0 && col < NCOLS )
{
private static short getPixel(int row, int col) {
if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
return imagePixels[row * NCOLS + col];
}
return NODATA;
}
public static void doConvert( String inputDir, String v1Dir, int lonDegreeStart, int latDegreeStart, String outputFile, SrtmRaster raster90 ) throws Exception
{
public static void doConvert(String inputDir, String v1Dir, int lonDegreeStart, int latDegreeStart, String outputFile, SrtmRaster raster90) throws Exception {
int extraBorder = 10;
int datacells = 0;
int mismatches = 0;
@ -107,95 +89,74 @@ public class ConvertSrtmTile
imagePixels = new short[NROWS * NCOLS]; // 650 MB !
// prefill as NODATA
for ( int row = 0; row < NROWS; row++ )
{
for ( int col = 0; col < NCOLS; col++ )
{
for (int row = 0; row < NROWS; row++) {
for (int col = 0; col < NCOLS; col++) {
imagePixels[row * NCOLS + col] = NODATA;
}
}
for ( int latIdx = -1; latIdx <= 5; latIdx++ )
{
for (int latIdx = -1; latIdx <= 5; latIdx++) {
int latDegree = latDegreeStart + latIdx;
int rowOffset = extraBorder + ( 4 - latIdx ) * 3600;
int rowOffset = extraBorder + (4 - latIdx) * 3600;
for ( int lonIdx = -1; lonIdx <= 5; lonIdx++ )
{
for (int lonIdx = -1; lonIdx <= 5; lonIdx++) {
int lonDegree = lonDegreeStart + lonIdx;
int colOffset = extraBorder + lonIdx * 3600;
String filename = inputDir + "/" + formatLat( latDegree ) + "_" + formatLon( lonDegree ) + "_1arc_v3_bil.zip";
File f = new File( filename );
if ( f.exists() && f.length() > 0 )
{
System.out.println( "exist: " + filename );
String filename = inputDir + "/" + formatLat(latDegree) + "_" + formatLon(lonDegree) + "_1arc_v3_bil.zip";
File f = new File(filename);
if (f.exists() && f.length() > 0) {
System.out.println("exist: " + filename);
boolean halfCol = latDegree >= 50 || latDegree < -50;
readBilZip( filename, rowOffset, colOffset, halfCol );
}
else
{
System.out.println( "none : " + filename );
readBilZip(filename, rowOffset, colOffset, halfCol);
} else {
System.out.println("none : " + filename);
}
}
}
boolean halfCol5 = latDegreeStart >= 50 || latDegreeStart < -50;
for ( int row90 = 0; row90 < 6001; row90++ )
{
for (int row90 = 0; row90 < 6001; row90++) {
int crow = 3 * row90 + extraBorder; // center row of 3x3
for ( int col90 = 0; col90 < 6001; col90++ )
{
for (int col90 = 0; col90 < 6001; col90++) {
int ccol = 3 * col90 + extraBorder; // center col of 3x3
// evaluate 3x3 area
if ( raster90 != null && (!halfCol5 || (col90 % 2) == 0 ) )
{
if (raster90 != null && (!halfCol5 || (col90 % 2) == 0)) {
short v90 = raster90.eval_array[row90 * 6001 + col90];
int sum = 0;
int nodatas = 0;
int datas = 0;
int colstep = halfCol5 ? 2 : 1;
for ( int row = crow - 1; row <= crow + 1; row++ )
{
for ( int col = ccol - colstep; col <= ccol + colstep; col += colstep )
{
for (int row = crow - 1; row <= crow + 1; row++) {
for (int col = ccol - colstep; col <= ccol + colstep; col += colstep) {
short v30 = imagePixels[row * NCOLS + col];
if ( v30 == NODATA )
{
if (v30 == NODATA) {
nodatas++;
}
else if ( v30 != SKIPDATA )
{
} else if (v30 != SKIPDATA) {
sum += v30;
datas++;
}
}
}
boolean doReplace = nodatas > 0 || v90 == NODATA || datas < 7;
if ( !doReplace )
{
if (!doReplace) {
datacells++;
int diff = sum - datas * v90;
if ( diff < -4 || diff > 4 )
{
if (diff < -4 || diff > 4) {
doReplace = true;
mismatches++;
}
if ( diff > -50 && diff < 50 && ( row90 % 1200 ) != 0 && ( col90 % 1200 ) != 0 )
{
if (diff > -50 && diff < 50 && (row90 % 1200) != 0 && (col90 % 1200) != 0) {
diffs[diff + 50]++;
}
}
if ( doReplace )
{
for ( int row = crow - 1; row <= crow + 1; row++ )
{
for ( int col = ccol - colstep; col <= ccol + colstep; col += colstep )
{
if (doReplace) {
for (int row = crow - 1; row <= crow + 1; row++) {
for (int col = ccol - colstep; col <= ccol + colstep; col += colstep) {
imagePixels[row * NCOLS + col] = v90;
}
}
@ -210,102 +171,90 @@ public class ConvertSrtmTile
raster.halfcol = halfCol5;
raster.noDataValue = NODATA;
raster.cellsize = 1 / 3600.;
raster.xllcorner = lonDegreeStart - ( 0.5 + extraBorder ) * raster.cellsize;
raster.yllcorner = latDegreeStart - ( 0.5 + extraBorder ) * raster.cellsize;
raster.xllcorner = lonDegreeStart - (0.5 + extraBorder) * raster.cellsize;
raster.yllcorner = latDegreeStart - (0.5 + extraBorder) * raster.cellsize;
raster.eval_array = imagePixels;
// encode the raster
OutputStream os = new BufferedOutputStream( new FileOutputStream( outputFile ) );
new RasterCoder().encodeRaster( raster, os );
OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile));
new RasterCoder().encodeRaster(raster, os);
os.close();
// decode the raster
InputStream is = new BufferedInputStream( new FileInputStream( outputFile ) );
SrtmRaster raster2 = new RasterCoder().decodeRaster( is );
InputStream is = new BufferedInputStream(new FileInputStream(outputFile));
SrtmRaster raster2 = new RasterCoder().decodeRaster(is);
is.close();
short[] pix2 = raster2.eval_array;
if ( pix2.length != imagePixels.length )
throw new RuntimeException( "length mismatch!" );
if (pix2.length != imagePixels.length)
throw new RuntimeException("length mismatch!");
// compare decoding result
for ( int row = 0; row < NROWS; row++ )
{
for (int row = 0; row < NROWS; row++) {
int colstep = halfCol5 ? 2 : 1;
for ( int col = 0; col < NCOLS; col += colstep )
{
for (int col = 0; col < NCOLS; col += colstep) {
int idx = row * NCOLS + col;
if ( imagePixels[idx] == SKIPDATA )
{
if (imagePixels[idx] == SKIPDATA) {
continue;
}
short p2 = pix2[idx];
if ( p2 > SKIPDATA )
{
if (p2 > SKIPDATA) {
p2 /= 2;
}
if ( p2 != imagePixels[idx] )
{
throw new RuntimeException( "content mismatch!" );
if (p2 != imagePixels[idx]) {
throw new RuntimeException("content mismatch!");
}
}
}
for(int i=1; i<100;i++) System.out.println( "diff[" + (i-50) + "] = " + diffs[i] );
System.out.println( "datacells=" + datacells + " mismatch%=" + (100.*mismatches)/datacells );
btools.util.MixCoderDataOutputStream.stats();
for (int i = 1; i < 100; i++) System.out.println("diff[" + (i - 50) + "] = " + diffs[i]);
System.out.println("datacells=" + datacells + " mismatch%=" + (100. * mismatches) / datacells);
btools.util.MixCoderDataOutputStream.stats();
// test( raster );
// raster.calcWeights( 50. );
// test( raster );
// 39828330 &lon=3115280&layer=OpenStreetMap
}
private static void test( SrtmRaster raster )
{
private static void test(SrtmRaster raster) {
int lat0 = 39828330;
int lon0 = 3115280;
for ( int iy = -9; iy <= 9; iy++ )
{
for (int iy = -9; iy <= 9; iy++) {
StringBuilder sb = new StringBuilder();
for ( int ix = -9; ix <= 9; ix++ )
{
for (int ix = -9; ix <= 9; ix++) {
int lat = lat0 + 90000000 - 100 * iy;
int lon = lon0 + 180000000 + 100 * ix;
int ival = (int) ( raster.getElevation( lon, lat ) / 4. );
int ival = (int) (raster.getElevation(lon, lat) / 4.);
String sval = " " + ival;
sb.append( sval.substring( sval.length() - 4 ) );
sb.append(sval.substring(sval.length() - 4));
}
System.out.println( sb );
System.out.println(sb);
System.out.println();
}
}
private static String formatLon( int lon )
{
if ( lon >= 180 )
private static String formatLon(int lon) {
if (lon >= 180)
lon -= 180; // TODO: w180 oder E180 ?
String s = "e";
if ( lon < 0 )
{
if (lon < 0) {
lon = -lon;
s = "w";
}
String n = "000" + lon;
return s + n.substring( n.length() - 3 );
return s + n.substring(n.length() - 3);
}
private static String formatLat( int lat )
{
private static String formatLat(int lat) {
String s = "n";
if ( lat < 0 )
{
if (lat < 0) {
lat = -lat;
s = "s";
}
String n = "00" + lat;
return s + n.substring( n.length() - 2 );
return s + n.substring(n.length() - 2);
}
}

View file

@ -4,57 +4,50 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class ConvertUrlList
{
public class ConvertUrlList {
public static final short NODATA = -32767;
public static void main( String[] args ) throws Exception
{
BufferedReader br = new BufferedReader( new FileReader( args[0] ) );
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
for ( ;; )
{
for (; ; ) {
String line = br.readLine();
if ( line == null )
{
if (line == null) {
break;
}
int idx1 = line.indexOf( "srtm_" );
if ( idx1 < 0 )
{
int idx1 = line.indexOf("srtm_");
if (idx1 < 0) {
continue;
}
String filename90 = line.substring( idx1 );
String filename30 = filename90.substring( 0, filename90.length() - 3 ) + "bef";
String filename90 = line.substring(idx1);
String filename30 = filename90.substring(0, filename90.length() - 3) + "bef";
if ( new File( filename30 ).exists() )
{
if (new File(filename30).exists()) {
continue;
}
// int srtmLonIdx = (ilon+5000000)/5000000; -> ilon = (srtmLonIdx-1)*5
// int srtmLatIdx = (154999999-ilat)/5000000; -> ilat = 155 - srtmLatIdx*5
int srtmLonIdx = Integer.parseInt( filename90.substring( 5, 7 ).toLowerCase() );
int srtmLatIdx = Integer.parseInt( filename90.substring( 8, 10 ).toLowerCase() );
int srtmLonIdx = Integer.parseInt(filename90.substring(5, 7).toLowerCase());
int srtmLatIdx = Integer.parseInt(filename90.substring(8, 10).toLowerCase());
int ilon_base = ( srtmLonIdx - 1 ) * 5 - 180;
int ilon_base = (srtmLonIdx - 1) * 5 - 180;
int ilat_base = 150 - srtmLatIdx * 5 - 90;
SrtmRaster raster90 = null;
File file90 = new File( new File( args[1] ), filename90 );
if ( file90.exists() )
{
System.out.println( "reading " + file90 );
raster90 = new SrtmData( file90 ).getRaster();
File file90 = new File(new File(args[1]), filename90);
if (file90.exists()) {
System.out.println("reading " + file90);
raster90 = new SrtmData(file90).getRaster();
}
ConvertSrtmTile.doConvert( args[2], args[3], ilon_base, ilat_base, filename30, raster90 );
ConvertSrtmTile.doConvert(args[2], args[3], ilon_base, ilat_base, filename30, raster90);
}
br.close();
}
}

View file

@ -9,76 +9,63 @@ import java.util.ArrayList;
import btools.util.CheapRuler;
public class DPFilter
{
public class DPFilter {
private static double dp_sql_threshold = 0.4 * 0.4;
/*
* for each node (except first+last), eventually set the DP_SURVIVOR_BIT
*/
public static void doDPFilter( ArrayList<OsmNodeP> nodes )
{
public static void doDPFilter(ArrayList<OsmNodeP> nodes) {
int first = 0;
int last = nodes.size()-1;
while( first < last && (nodes.get(first+1).bits & OsmNodeP.DP_SURVIVOR_BIT) != 0 )
{
int last = nodes.size() - 1;
while (first < last && (nodes.get(first + 1).bits & OsmNodeP.DP_SURVIVOR_BIT) != 0) {
first++;
}
while( first < last && (nodes.get(last-1).bits & OsmNodeP.DP_SURVIVOR_BIT) != 0 )
{
while (first < last && (nodes.get(last - 1).bits & OsmNodeP.DP_SURVIVOR_BIT) != 0) {
last--;
}
if ( last - first > 1 )
{
doDPFilter( nodes, first, last );
if (last - first > 1) {
doDPFilter(nodes, first, last);
}
}
public static void doDPFilter( ArrayList<OsmNodeP> nodes, int first, int last )
{
public static void doDPFilter(ArrayList<OsmNodeP> nodes, int first, int last) {
double maxSqDist = -1.;
int index = -1;
OsmNodeP p1 = nodes.get( first );
OsmNodeP p2 = nodes.get( last );
OsmNodeP p1 = nodes.get(first);
OsmNodeP p2 = nodes.get(last);
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (p1.ilat+p2.ilat) >> 1 );
double[] lonlat2m = CheapRuler.getLonLatToMeterScales((p1.ilat + p2.ilat) >> 1);
double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1];
double dx = (p2.ilon - p1.ilon) * dlon2m;
double dy = (p2.ilat - p1.ilat) * dlat2m;
double d2 = dx * dx + dy * dy;
for ( int i = first + 1; i < last; i++ )
{
OsmNodeP p = nodes.get( i );
for (int i = first + 1; i < last; i++) {
OsmNodeP p = nodes.get(i);
double t = 0.;
if ( d2 != 0f )
{
t = ( ( p.ilon - p1.ilon ) * dlon2m * dx + ( p.ilat - p1.ilat ) * dlat2m * dy ) / d2;
t = t > 1. ? 1. : ( t < 0. ? 0. : t );
if (d2 != 0f) {
t = ((p.ilon - p1.ilon) * dlon2m * dx + (p.ilat - p1.ilat) * dlat2m * dy) / d2;
t = t > 1. ? 1. : (t < 0. ? 0. : t);
}
double dx2 = (p.ilon - ( p1.ilon + t*( p2.ilon - p1.ilon ) ) ) * dlon2m;
double dy2 = (p.ilat - ( p1.ilat + t*( p2.ilat - p1.ilat ) ) ) * dlat2m;
double dx2 = (p.ilon - (p1.ilon + t * (p2.ilon - p1.ilon))) * dlon2m;
double dy2 = (p.ilat - (p1.ilat + t * (p2.ilat - p1.ilat))) * dlat2m;
double sqDist = dx2 * dx2 + dy2 * dy2;
if ( sqDist > maxSqDist )
{
if (sqDist > maxSqDist) {
index = i;
maxSqDist = sqDist;
}
}
if ( index >= 0 )
{
if ( index - first > 1 )
{
doDPFilter( nodes, first, index );
if (index >= 0) {
if (index - first > 1) {
doDPFilter(nodes, first, index);
}
if ( maxSqDist >= dp_sql_threshold )
{
nodes.get( index ).bits |= OsmNodeP.DP_SURVIVOR_BIT;
if (maxSqDist >= dp_sql_threshold) {
nodes.get(index).bits |= OsmNodeP.DP_SURVIVOR_BIT;
}
if ( last - index > 1 )
{
doDPFilter( nodes, index, last );
if (last - index > 1) {
doDPFilter(nodes, index, last);
}
}
}

View file

@ -1,171 +1,158 @@
/**
* common base class for the map-filters
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import btools.util.DiffCoderDataOutputStream;
public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener
{
private DiffCoderDataOutputStream[] 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 DiffCoderDataOutputStream createOutStream( File outFile ) throws IOException
{
return new DiffCoderDataOutputStream( new BufferedOutputStream( new FileOutputStream( outFile ) ) );
}
protected DiffCoderDataOutputStream getOutStreamForTile( int tileIndex ) throws Exception
{
if ( tileOutStreams == null )
{
tileOutStreams = new DiffCoderDataOutputStream[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 boolean wayFileStart( File wayfile ) throws Exception { return true; }
@Override
public void nextWay( WayData data ) throws Exception {}
@Override
public void wayFileEnd( File wayfile ) throws Exception {}
@Override
public void nextRelation( RelationData data ) throws Exception {}
@Override
public void nextRestriction( RelationData data, long fromWid, long toWid, long viaNid ) throws Exception {}
}
/**
* common base class for the map-filters
*
* @author ab
*/
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import btools.util.DiffCoderDataOutputStream;
public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener {
private DiffCoderDataOutputStream[] 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 DiffCoderDataOutputStream createOutStream(File outFile) throws IOException {
return new DiffCoderDataOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
}
protected DiffCoderDataOutputStream getOutStreamForTile(int tileIndex) throws Exception {
if (tileOutStreams == null) {
tileOutStreams = new DiffCoderDataOutputStream[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 boolean wayFileStart(File wayfile) throws Exception {
return true;
}
@Override
public void nextWay(WayData data) throws Exception {
}
@Override
public void wayFileEnd(File wayfile) throws Exception {
}
@Override
public void nextRelation(RelationData data) throws Exception {
}
@Override
public void nextRestriction(RelationData data, long fromWid, long toWid, long viaNid) throws Exception {
}
}

View file

@ -1,84 +1,75 @@
package btools.mapcreator;
import java.io.File;
/**
* 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 init( File nodeTilesOut )
{
this.outTileDir = nodeTilesOut;
}
public void process( File nodeTilesIn, File nodeTilesOut ) throws Exception
{
init( 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";
}
}
package btools.mapcreator;
import java.io.File;
/**
* NodeCutter does 1 step in map-processing:
* <p>
* - 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 init(File nodeTilesOut) {
this.outTileDir = nodeTilesOut;
}
public void process(File nodeTilesIn, File nodeTilesOut) throws Exception {
init(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

@ -1,46 +1,49 @@
package btools.mapcreator;
import btools.util.DiffCoderDataInputStream;
import btools.util.DiffCoderDataOutputStream;
/**
* 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 byte[] 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( DiffCoderDataInputStream dis ) throws Exception
{
nid = dis.readDiffed( 0 );
ilon = (int)dis.readDiffed( 1 );
ilat = (int)dis.readDiffed( 2 );
int mode = dis.readByte();
if ( ( mode & 1 ) != 0 ) { int dlen = dis.readShort(); description = new byte[dlen]; dis.readFully( description ); }
if ( ( mode & 2 ) != 0 ) selev = dis.readShort();
}
public void writeTo( DiffCoderDataOutputStream dos ) throws Exception
{
dos.writeDiffed( nid, 0 );
dos.writeDiffed( ilon, 1 );
dos.writeDiffed( ilat, 2 );
int mode = (description == null ? 0 : 1 ) | ( selev == Short.MIN_VALUE ? 0 : 2 );
dos.writeByte( (byte) mode);
if ( ( mode & 1 ) != 0 ) { dos.writeShort( description.length ); dos.write( description ); }
if ( ( mode & 2 ) != 0 ) dos.writeShort( selev );
}
}
package btools.mapcreator;
import btools.util.DiffCoderDataInputStream;
import btools.util.DiffCoderDataOutputStream;
/**
* 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 byte[] 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(DiffCoderDataInputStream dis) throws Exception {
nid = dis.readDiffed(0);
ilon = (int) dis.readDiffed(1);
ilat = (int) dis.readDiffed(2);
int mode = dis.readByte();
if ((mode & 1) != 0) {
int dlen = dis.readShort();
description = new byte[dlen];
dis.readFully(description);
}
if ((mode & 2) != 0) selev = dis.readShort();
}
public void writeTo(DiffCoderDataOutputStream dos) throws Exception {
dos.writeDiffed(nid, 0);
dos.writeDiffed(ilon, 1);
dos.writeDiffed(ilat, 2);
int mode = (description == null ? 0 : 1) | (selev == Short.MIN_VALUE ? 0 : 2);
dos.writeByte((byte) mode);
if ((mode & 1) != 0) {
dos.writeShort(description.length);
dos.write(description);
}
if ((mode & 2) != 0) dos.writeShort(selev);
}
}

View file

@ -1,92 +1,80 @@
package btools.mapcreator;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import btools.util.DenseLongMap;
import btools.util.DiffCoderDataOutputStream;
import btools.util.TinyDenseLongMap;
/**
* NodeFilter does 1 step in map-processing:
*
* - filters out unused nodes according to the way file
*
* @author ab
*/
public class NodeFilter extends MapCreatorBase
{
private DiffCoderDataOutputStream 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 init() throws Exception
{
nodebitmap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 512 ) : new TinyDenseLongMap();
}
public void process( File nodeTilesIn, File wayFileIn, File nodeTilesOut ) throws Exception
{
init();
this.nodeTilesOut = nodeTilesOut;
// read the wayfile into a bitmap of used nodes
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();
File outfile = new File( nodeTilesOut, filename );
nodesOutStream = new DiffCoderDataOutputStream( new BufferedOutputStream ( new FileOutputStream( outfile ) ) );
}
@Override
public void nextNode( NodeData n ) throws Exception
{
if ( isRelevant( n ) )
{
n.writeTo( nodesOutStream );
}
}
public boolean isRelevant( NodeData n )
{
// check if node passes bitmap
return nodebitmap.getInt( n.nid ) == 0; // 0 -> bit set, -1 -> unset
}
@Override
public void nodeFileEnd( File nodeFile ) throws Exception
{
nodesOutStream.close();
}
}
package btools.mapcreator;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import btools.util.DenseLongMap;
import btools.util.DiffCoderDataOutputStream;
import btools.util.TinyDenseLongMap;
/**
* NodeFilter does 1 step in map-processing:
* <p>
* - filters out unused nodes according to the way file
*
* @author ab
*/
public class NodeFilter extends MapCreatorBase {
private DiffCoderDataOutputStream 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 init() throws Exception {
nodebitmap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap(512) : new TinyDenseLongMap();
}
public void process(File nodeTilesIn, File wayFileIn, File nodeTilesOut) throws Exception {
init();
this.nodeTilesOut = nodeTilesOut;
// read the wayfile into a bitmap of used nodes
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();
File outfile = new File(nodeTilesOut, filename);
nodesOutStream = new DiffCoderDataOutputStream(new BufferedOutputStream(new FileOutputStream(outfile)));
}
@Override
public void nextNode(NodeData n) throws Exception {
if (isRelevant(n)) {
n.writeTo(nodesOutStream);
}
}
public boolean isRelevant(NodeData n) {
// check if node passes bitmap
return nodebitmap.getInt(n.nid) == 0; // 0 -> bit set, -1 -> unset
}
@Override
public void nodeFileEnd(File nodeFile) throws Exception {
nodesOutStream.close();
}
}

View file

@ -1,71 +1,59 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import btools.util.DiffCoderDataInputStream;
/**
* 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 );
DiffCoderDataInputStream di = new DiffCoderDataInputStream( 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();
}
}
}
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import btools.util.DiffCoderDataInputStream;
/**
* 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);
DiffCoderDataInputStream di = new DiffCoderDataInputStream(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

@ -1,17 +1,16 @@
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;
}
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

@ -1,332 +1,293 @@
/**
* 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.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
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;
private DataOutputStream restrictionsDos;
public WayCutter wayCutter;
public RestrictionCutter restrictionCutter;
public NodeFilter nodeFilter;
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 != 6 && args.length != 7)
{
System.out.println("usage: bzip2 -dc <map> | java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile>");
System.out.println("or : java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile> <inputfile> ");
return;
}
new OsmCutter().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.length > 6 ? new File( args[6] ) : null
);
}
private BExpressionContextWay _expctxWay;
private BExpressionContextNode _expctxNode;
// private BExpressionContextWay _expctxWayStat;
// private BExpressionContextNode _expctxNodeStat;
public void process (File lookupFile, File outTileDir, File wayFile, File relFile, File resFile, File profileFile, File mapFile ) throws Exception
{
if ( !lookupFile.exists() )
{
throw new IllegalArgumentException( "lookup-file: " + lookupFile + " does not exist" );
}
BExpressionMetaData meta = new BExpressionMetaData();
_expctxWay = new BExpressionContextWay( meta );
_expctxNode = new BExpressionContextNode( meta );
meta.readMetaData( lookupFile );
_expctxWay.parseFile( profileFile, "global" );
// _expctxWayStat = new BExpressionContextWay( null );
// _expctxNodeStat = new BExpressionContextNode( null );
this.outTileDir = outTileDir;
if ( !outTileDir.isDirectory() ) throw new RuntimeException( "out tile directory " + outTileDir + " does not exist" );
wayDos = wayFile == null ? null : new DataOutputStream( new BufferedOutputStream( new FileOutputStream( wayFile ) ) );
cyclewayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( relFile ) ) );
if ( resFile != null )
{
restrictionsDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( resFile ) ) );
}
// 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();
if ( wayDos != null )
{
wayDos.close();
}
cyclewayDos.close();
if ( restrictionsDos != null )
{
restrictionsDos.close();
}
// System.out.println( "-------- way-statistics -------- " );
// _expctxWayStat.dumpStatistics();
// System.out.println( "-------- node-statistics -------- " );
// _expctxNodeStat.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( Map.Entry<String,String> e : n.getTagsOrNull().entrySet() )
{
_expctxNode.addLookupValue( e.getKey(), e.getValue(), lookupData );
// _expctxNodeStat.addLookupValue( key, value, null );
}
n.description = _expctxNode.encode(lookupData);
}
// write node to file
int tileIndex = getTileIndex( n.ilon, n.ilat );
if ( tileIndex >= 0 )
{
n.writeTo( getOutStreamForTile( tileIndex ) );
if ( wayCutter != null )
{
wayCutter.nextNode( n );
}
}
}
private void generatePseudoTags( HashMap<String,String> map )
{
// add pseudo.tags for concrete:lanes and concrete:plates
String concrete = null;
for( Map.Entry<String,String> e : map.entrySet() )
{
String key = e.getKey();
if ( "concrete".equals( key ) )
{
return;
}
if ( "surface".equals( key ) )
{
String value = e.getValue();
if ( value.startsWith( "concrete:" ) )
{
concrete = value.substring( "concrete:".length() );
}
}
}
if ( concrete != null )
{
map.put( "concrete", concrete );
}
}
@Override
public void nextWay( WayData w ) throws Exception
{
waysParsed++;
checkStats();
// encode tags
if ( w.getTagsOrNull() == null ) return;
generatePseudoTags( w.getTagsOrNull() );
int[] lookupData = _expctxWay.createNewLookupData();
for( String key : w.getTagsOrNull().keySet() )
{
String value = w.getTag( key );
_expctxWay.addLookupValue( key, value.replace( ' ', '_' ), lookupData );
// _expctxWayStat.addLookupValue( key, value, null );
}
w.description = _expctxWay.encode(lookupData);
if ( w.description == null ) return;
// filter according to profile
_expctxWay.evaluate( false, w.description );
boolean ok = _expctxWay.getCostfactor() < 10000.;
_expctxWay.evaluate( true, w.description );
ok |= _expctxWay.getCostfactor() < 10000.;
if ( !ok ) return;
if ( wayDos != null )
{
w.writeTo( wayDos );
}
if ( wayCutter != null )
{
wayCutter.nextWay( w );
}
if ( nodeFilter != null )
{
nodeFilter.nextWay( w );
}
}
@Override
public void nextRelation( RelationData r ) throws Exception
{
relsParsed++;
checkStats();
String route = r.getTag( "route" );
// filter out non-cycle relations
if ( route == null )
{
return;
}
String network = r.getTag( "network" );
if ( network == null ) network = "";
String state = r.getTag( "state" );
if ( state == null ) state = "";
writeId( cyclewayDos, r.rid );
cyclewayDos.writeUTF( route );
cyclewayDos.writeUTF( network );
cyclewayDos.writeUTF( state );
for ( int i=0; i<r.ways.size();i++ )
{
long wid = r.ways.get(i);
writeId( cyclewayDos, wid );
}
writeId( cyclewayDos, -1 );
}
@Override
public void nextRestriction( RelationData r, long fromWid, long toWid, long viaNid ) throws Exception
{
String type = r.getTag( "type" );
if ( type == null || !"restriction".equals( type ) )
{
return;
}
short exceptions = 0;
String except = r.getTag( "except" );
if ( except != null )
{
exceptions |= toBit( "bicycle" , 0, except );
exceptions |= toBit( "motorcar" , 1, except );
exceptions |= toBit( "agricultural" , 2, except );
exceptions |= toBit( "forestry" , 2, except );
exceptions |= toBit( "psv" , 3, except );
exceptions |= toBit( "hgv" , 4, except );
}
for( String restrictionKey : r.getTagsOrNull().keySet() )
{
if ( !( restrictionKey.equals( "restriction" ) || restrictionKey.startsWith( "restriction:" ) ) )
{
continue;
}
String restriction = r.getTag( restrictionKey );
RestrictionData res = new RestrictionData();
res.restrictionKey = restrictionKey;
res.restriction = restriction;
res.exceptions = exceptions;
res.fromWid = fromWid;
res.toWid = toWid;
res.viaNid = viaNid;
if ( restrictionsDos != null )
{
res.writeTo( restrictionsDos );
}
if ( restrictionCutter != null )
{
restrictionCutter.nextRestriction( res );
}
}
}
private static short toBit( String tag, int bitpos, String s )
{
return (short) ( s.indexOf( tag ) < 0 ? 0 : 1 << bitpos );
}
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 + ".ntl";
}
}
/**
* 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.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
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;
private DataOutputStream restrictionsDos;
public WayCutter wayCutter;
public RestrictionCutter restrictionCutter;
public NodeFilter nodeFilter;
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 != 6 && args.length != 7) {
System.out.println("usage: bzip2 -dc <map> | java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile>");
System.out.println("or : java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile> <inputfile> ");
return;
}
new OsmCutter().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.length > 6 ? new File(args[6]) : null
);
}
private BExpressionContextWay _expctxWay;
private BExpressionContextNode _expctxNode;
// private BExpressionContextWay _expctxWayStat;
// private BExpressionContextNode _expctxNodeStat;
public void process(File lookupFile, File outTileDir, File wayFile, File relFile, File resFile, File profileFile, File mapFile) throws Exception {
if (!lookupFile.exists()) {
throw new IllegalArgumentException("lookup-file: " + lookupFile + " does not exist");
}
BExpressionMetaData meta = new BExpressionMetaData();
_expctxWay = new BExpressionContextWay(meta);
_expctxNode = new BExpressionContextNode(meta);
meta.readMetaData(lookupFile);
_expctxWay.parseFile(profileFile, "global");
// _expctxWayStat = new BExpressionContextWay( null );
// _expctxNodeStat = new BExpressionContextNode( null );
this.outTileDir = outTileDir;
if (!outTileDir.isDirectory())
throw new RuntimeException("out tile directory " + outTileDir + " does not exist");
wayDos = wayFile == null ? null : new DataOutputStream(new BufferedOutputStream(new FileOutputStream(wayFile)));
cyclewayDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(relFile)));
if (resFile != null) {
restrictionsDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(resFile)));
}
// 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();
if (wayDos != null) {
wayDos.close();
}
cyclewayDos.close();
if (restrictionsDos != null) {
restrictionsDos.close();
}
// System.out.println( "-------- way-statistics -------- " );
// _expctxWayStat.dumpStatistics();
// System.out.println( "-------- node-statistics -------- " );
// _expctxNodeStat.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 (Map.Entry<String, String> e : n.getTagsOrNull().entrySet()) {
_expctxNode.addLookupValue(e.getKey(), e.getValue(), lookupData);
// _expctxNodeStat.addLookupValue( key, value, null );
}
n.description = _expctxNode.encode(lookupData);
}
// write node to file
int tileIndex = getTileIndex(n.ilon, n.ilat);
if (tileIndex >= 0) {
n.writeTo(getOutStreamForTile(tileIndex));
if (wayCutter != null) {
wayCutter.nextNode(n);
}
}
}
private void generatePseudoTags(HashMap<String, String> map) {
// add pseudo.tags for concrete:lanes and concrete:plates
String concrete = null;
for (Map.Entry<String, String> e : map.entrySet()) {
String key = e.getKey();
if ("concrete".equals(key)) {
return;
}
if ("surface".equals(key)) {
String value = e.getValue();
if (value.startsWith("concrete:")) {
concrete = value.substring("concrete:".length());
}
}
}
if (concrete != null) {
map.put("concrete", concrete);
}
}
@Override
public void nextWay(WayData w) throws Exception {
waysParsed++;
checkStats();
// encode tags
if (w.getTagsOrNull() == null) return;
generatePseudoTags(w.getTagsOrNull());
int[] lookupData = _expctxWay.createNewLookupData();
for (String key : w.getTagsOrNull().keySet()) {
String value = w.getTag(key);
_expctxWay.addLookupValue(key, value.replace(' ', '_'), lookupData);
// _expctxWayStat.addLookupValue( key, value, null );
}
w.description = _expctxWay.encode(lookupData);
if (w.description == null) return;
// filter according to profile
_expctxWay.evaluate(false, w.description);
boolean ok = _expctxWay.getCostfactor() < 10000.;
_expctxWay.evaluate(true, w.description);
ok |= _expctxWay.getCostfactor() < 10000.;
if (!ok) return;
if (wayDos != null) {
w.writeTo(wayDos);
}
if (wayCutter != null) {
wayCutter.nextWay(w);
}
if (nodeFilter != null) {
nodeFilter.nextWay(w);
}
}
@Override
public void nextRelation(RelationData r) throws Exception {
relsParsed++;
checkStats();
String route = r.getTag("route");
// filter out non-cycle relations
if (route == null) {
return;
}
String network = r.getTag("network");
if (network == null) network = "";
String state = r.getTag("state");
if (state == null) state = "";
writeId(cyclewayDos, r.rid);
cyclewayDos.writeUTF(route);
cyclewayDos.writeUTF(network);
cyclewayDos.writeUTF(state);
for (int i = 0; i < r.ways.size(); i++) {
long wid = r.ways.get(i);
writeId(cyclewayDos, wid);
}
writeId(cyclewayDos, -1);
}
@Override
public void nextRestriction(RelationData r, long fromWid, long toWid, long viaNid) throws Exception {
String type = r.getTag("type");
if (type == null || !"restriction".equals(type)) {
return;
}
short exceptions = 0;
String except = r.getTag("except");
if (except != null) {
exceptions |= toBit("bicycle", 0, except);
exceptions |= toBit("motorcar", 1, except);
exceptions |= toBit("agricultural", 2, except);
exceptions |= toBit("forestry", 2, except);
exceptions |= toBit("psv", 3, except);
exceptions |= toBit("hgv", 4, except);
}
for (String restrictionKey : r.getTagsOrNull().keySet()) {
if (!(restrictionKey.equals("restriction") || restrictionKey.startsWith("restriction:"))) {
continue;
}
String restriction = r.getTag(restrictionKey);
RestrictionData res = new RestrictionData();
res.restrictionKey = restrictionKey;
res.restriction = restriction;
res.exceptions = exceptions;
res.fromWid = fromWid;
res.toWid = toWid;
res.viaNid = viaNid;
if (restrictionsDos != null) {
res.writeTo(restrictionsDos);
}
if (restrictionCutter != null) {
restrictionCutter.nextRestriction(res);
}
}
}
private static short toBit(String tag, int bitpos, String s) {
return (short) (s.indexOf(tag) < 0 ? 0 : 1 << bitpos);
}
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 + ".ntl";
}
}

View file

@ -9,55 +9,51 @@ package btools.mapcreator;
import java.io.File;
public class OsmFastCutter extends MapCreatorBase
{
public static void main(String[] args) throws Exception
{
public class OsmFastCutter extends MapCreatorBase {
public static void main(String[] args) throws Exception {
System.out.println("*** OsmFastCutter: cut an osm map in node-tiles + way-tiles");
if (args.length != 11 && args.length != 12)
{
if (args.length != 11 && args.length != 12) {
String common = "java OsmFastCutter <lookup-file> <node-dir> <way-dir> <node55-dir> <way55-dir> <border-file> <out-rel-file> <out-res-file> <filter-profile> <report-profile> <check-profile>";
System.out.println("usage: bzip2 -dc <map> | " + common );
System.out.println("or : " + common + " <inputfile> " );
System.out.println("usage: bzip2 -dc <map> | " + common);
System.out.println("or : " + common + " <inputfile> ");
return;
}
doCut(
new File( args[0] )
, new File( args[1] )
, new File( args[2] )
, new File( args[3] )
, new File( args[4] )
, new File( args[5] )
, new File( args[6] )
, new File( args[7] )
, new File( args[8] )
, new File( args[9] )
, new File( args[10] )
, args.length > 11 ? new File( args[11] ) : null
);
new File(args[0])
, new File(args[1])
, new File(args[2])
, new File(args[3])
, new File(args[4])
, new File(args[5])
, new File(args[6])
, new File(args[7])
, new File(args[8])
, new File(args[9])
, new File(args[10])
, args.length > 11 ? new File(args[11]) : null
);
}
public static void doCut (File lookupFile, File nodeDir, File wayDir, File node55Dir, File way55Dir, File borderFile, File relFile, File resFile, File profileAll, File profileReport, File profileCheck, File mapFile ) throws Exception
{
public static void doCut(File lookupFile, File nodeDir, File wayDir, File node55Dir, File way55Dir, File borderFile, File relFile, File resFile, File profileAll, File profileReport, File profileCheck, File mapFile) throws Exception {
// **** run OsmCutter ****
OsmCutter cutter = new OsmCutter();
// ... inject WayCutter
cutter.wayCutter = new WayCutter();
cutter.wayCutter.init( wayDir );
cutter.wayCutter.init(wayDir);
// ... inject RestrictionCutter
cutter.restrictionCutter = new RestrictionCutter();
cutter.restrictionCutter.init( new File( nodeDir.getParentFile(), "restrictions" ), cutter.wayCutter );
cutter.restrictionCutter.init(new File(nodeDir.getParentFile(), "restrictions"), cutter.wayCutter);
// ... inject NodeFilter
NodeFilter nodeFilter = new NodeFilter();
nodeFilter.init();
cutter.nodeFilter = nodeFilter;
cutter.process( lookupFile, nodeDir, null, relFile, null, profileAll, mapFile );
cutter.process(lookupFile, nodeDir, null, relFile, null, profileAll, mapFile);
cutter.wayCutter.finish();
cutter.restrictionCutter.finish();
cutter = null;
@ -67,20 +63,20 @@ public class OsmFastCutter extends MapCreatorBase
//... inject RelationMerger
wayCut5.relMerger = new RelationMerger();
wayCut5.relMerger.init( relFile, lookupFile, profileReport, profileCheck );
wayCut5.relMerger.init(relFile, lookupFile, profileReport, profileCheck);
// ... inject RestrictionCutter5
wayCut5.restrictionCutter5 = new RestrictionCutter5();
wayCut5.restrictionCutter5.init( new File( nodeDir.getParentFile(), "restrictions55" ), wayCut5 );
wayCut5.restrictionCutter5.init(new File(nodeDir.getParentFile(), "restrictions55"), wayCut5);
//... inject NodeFilter
wayCut5.nodeFilter = nodeFilter;
// ... inject NodeCutter
wayCut5.nodeCutter = new NodeCutter();
wayCut5.nodeCutter.init( node55Dir );
wayCut5.nodeCutter.init(node55Dir);
wayCut5.process( nodeDir, wayDir, way55Dir, borderFile );
wayCut5.process(nodeDir, wayDir, way55Dir, borderFile);
}
}

View file

@ -1,118 +1,90 @@
/**
* Container for link between two Osm nodes (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
public class OsmLinkP
{
/**
* The description bitmap is mainly the way description
* used to calculate the costfactor
*/
public byte[] descriptionBitmap;
/**
* The target is either the next link or the target node
*/
protected OsmNodeP sourceNode;
protected OsmNodeP targetNode;
protected OsmLinkP previous;
protected OsmLinkP next;
public OsmLinkP( OsmNodeP source, OsmNodeP target )
{
sourceNode = source;
targetNode = target;
}
protected OsmLinkP()
{
}
public final boolean counterLinkWritten( )
{
return descriptionBitmap == null;
}
/**
* Set the relevant next-pointer for the given source
*/
public void setNext( OsmLinkP link, OsmNodeP source )
{
if ( sourceNode == source )
{
next = link;
}
else if ( targetNode == source )
{
previous = link;
}
else
{
throw new IllegalArgumentException( "internal error: setNext: unknown source" );
}
}
/**
* Get the relevant next-pointer for the given source
*/
public OsmLinkP getNext( OsmNodeP source )
{
if ( sourceNode == source )
{
return next;
}
else if ( targetNode == source )
{
return previous;
}
else
{
throw new IllegalArgumentException( "internal error: gextNext: unknown source" );
}
}
/**
* Get the relevant target-node for the given source
*/
public OsmNodeP getTarget( OsmNodeP source )
{
if ( sourceNode == source )
{
return targetNode;
}
else if ( targetNode == source )
{
return sourceNode;
}
else
{
throw new IllegalArgumentException( "internal error: getTarget: unknown source" );
}
}
/**
* Check if reverse link for the given source
*/
public boolean isReverse( OsmNodeP source )
{
if ( sourceNode == source )
{
return false;
}
else if ( targetNode == source )
{
return true;
}
else
{
throw new IllegalArgumentException( "internal error: isReverse: unknown source" );
}
}
}
/**
* Container for link between two Osm nodes (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
public class OsmLinkP {
/**
* The description bitmap is mainly the way description
* used to calculate the costfactor
*/
public byte[] descriptionBitmap;
/**
* The target is either the next link or the target node
*/
protected OsmNodeP sourceNode;
protected OsmNodeP targetNode;
protected OsmLinkP previous;
protected OsmLinkP next;
public OsmLinkP(OsmNodeP source, OsmNodeP target) {
sourceNode = source;
targetNode = target;
}
protected OsmLinkP() {
}
public final boolean counterLinkWritten() {
return descriptionBitmap == null;
}
/**
* Set the relevant next-pointer for the given source
*/
public void setNext(OsmLinkP link, OsmNodeP source) {
if (sourceNode == source) {
next = link;
} else if (targetNode == source) {
previous = link;
} else {
throw new IllegalArgumentException("internal error: setNext: unknown source");
}
}
/**
* Get the relevant next-pointer for the given source
*/
public OsmLinkP getNext(OsmNodeP source) {
if (sourceNode == source) {
return next;
} else if (targetNode == source) {
return previous;
} else {
throw new IllegalArgumentException("internal error: gextNext: unknown source");
}
}
/**
* Get the relevant target-node for the given source
*/
public OsmNodeP getTarget(OsmNodeP source) {
if (sourceNode == source) {
return targetNode;
} else if (targetNode == source) {
return sourceNode;
} else {
throw new IllegalArgumentException("internal error: getTarget: unknown source");
}
}
/**
* Check if reverse link for the given source
*/
public boolean isReverse(OsmNodeP source) {
if (sourceNode == source) {
return false;
} else if (targetNode == source) {
return true;
} else {
throw new IllegalArgumentException("internal error: isReverse: unknown source");
}
}
}

View file

@ -12,8 +12,7 @@ import java.util.HashMap;
import btools.codec.MicroCache;
import btools.codec.MicroCache2;
public class OsmNodeP extends OsmLinkP
{
public class OsmNodeP extends OsmLinkP {
/**
* The latitude
*/
@ -40,311 +39,261 @@ public class OsmNodeP extends OsmLinkP
public byte bits = 0;
// interface OsmPos
public int getILat()
{
public int getILat() {
return ilat;
}
public int getILon()
{
public int getILon() {
return ilon;
}
public short getSElev()
{
public short getSElev() {
// if all bridge or all tunnel, elevation=no-data
return ( bits & NO_BRIDGE_BIT ) == 0 || ( bits & NO_TUNNEL_BIT ) == 0 ? Short.MIN_VALUE : selev;
return (bits & NO_BRIDGE_BIT) == 0 || (bits & NO_TUNNEL_BIT) == 0 ? Short.MIN_VALUE : selev;
}
public double getElev()
{
public double getElev() {
return selev / 4.;
}
// populate and return the inherited link, if available,
// else create a new one
public OsmLinkP createLink( OsmNodeP source )
{
if ( sourceNode == null && targetNode == null )
{
public OsmLinkP createLink(OsmNodeP source) {
if (sourceNode == null && targetNode == null) {
// inherited instance is available, use this
sourceNode = source;
targetNode = this;
source.addLink( this );
source.addLink(this);
return this;
}
OsmLinkP link = new OsmLinkP( source, this );
addLink( link );
source.addLink( link );
OsmLinkP link = new OsmLinkP(source, this);
addLink(link);
source.addLink(link);
return link;
}
// memory-squeezing-hack: OsmLinkP's "previous" also used as firstlink..
public void addLink( OsmLinkP link )
{
link.setNext( previous, this );
public void addLink(OsmLinkP link) {
link.setNext(previous, this);
previous = link;
}
public OsmLinkP getFirstLink()
{
public OsmLinkP getFirstLink() {
return sourceNode == null && targetNode == null ? previous : this;
}
public byte[] getNodeDecsription()
{
public byte[] getNodeDecsription() {
return null;
}
public RestrictionData getFirstRestriction()
{
public RestrictionData getFirstRestriction() {
return null;
}
public void writeNodeData( MicroCache mc, OsmTrafficMap trafficMap ) throws IOException
{
public void writeNodeData(MicroCache mc, OsmTrafficMap trafficMap) throws IOException {
boolean valid = true;
if ( mc instanceof MicroCache2 )
{
valid = writeNodeData2( (MicroCache2) mc, trafficMap );
}
else
throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() );
if ( valid )
{
mc.finishNode( getIdFromPos() );
}
else
{
if (mc instanceof MicroCache2) {
valid = writeNodeData2((MicroCache2) mc, trafficMap);
} else
throw new IllegalArgumentException("unknown cache version: " + mc.getClass());
if (valid) {
mc.finishNode(getIdFromPos());
} else {
mc.discardNode();
}
}
public void checkDuplicateTargets()
{
HashMap<OsmNodeP,OsmLinkP> targets = new HashMap<OsmNodeP,OsmLinkP>();
public void checkDuplicateTargets() {
HashMap<OsmNodeP, OsmLinkP> targets = new HashMap<OsmNodeP, OsmLinkP>();
for ( OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext( this ) )
{
for (OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext(this)) {
OsmLinkP link = link0;
OsmNodeP origin = this;
OsmNodeP target = null;
// first pass just to see if that link is consistent
while (link != null)
{
target = link.getTarget( origin );
if ( !target.isTransferNode() )
{
while (link != null) {
target = link.getTarget(origin);
if (!target.isTransferNode()) {
break;
}
// next link is the one (of two), does does'nt point back
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
{
if ( link.getTarget( target ) != origin )
for (link = target.getFirstLink(); link != null; link = link.getNext(target)) {
if (link.getTarget(target) != origin)
break;
}
origin = target;
}
if ( link == null ) continue;
OsmLinkP oldLink = targets.put( target, link0 );
if ( oldLink != null )
{
unifyLink( oldLink );
unifyLink( link0 );
if (link == null) continue;
OsmLinkP oldLink = targets.put(target, link0);
if (oldLink != null) {
unifyLink(oldLink);
unifyLink(link0);
}
}
}
private void unifyLink( OsmLinkP link )
{
if ( link.isReverse( this ) ) return;
OsmNodeP target = link.getTarget( this );
if ( target.isTransferNode() )
{
private void unifyLink(OsmLinkP link) {
if (link.isReverse(this)) return;
OsmNodeP target = link.getTarget(this);
if (target.isTransferNode()) {
target.incWayCount();
}
}
public boolean writeNodeData2( MicroCache2 mc, OsmTrafficMap trafficMap ) throws IOException
{
public boolean writeNodeData2(MicroCache2 mc, OsmTrafficMap trafficMap) throws IOException {
boolean hasLinks = false;
// write turn restrictions
RestrictionData r = getFirstRestriction();
while( r != null )
{
if ( r.isValid() && r.fromLon != 0 && r.toLon != 0 )
{
mc.writeBoolean( true ); // restriction follows
mc.writeShort( r.exceptions );
mc.writeBoolean( r.isPositive() );
mc.writeInt( r.fromLon );
mc.writeInt( r.fromLat );
mc.writeInt( r.toLon );
mc.writeInt( r.toLat );
while (r != null) {
if (r.isValid() && r.fromLon != 0 && r.toLon != 0) {
mc.writeBoolean(true); // restriction follows
mc.writeShort(r.exceptions);
mc.writeBoolean(r.isPositive());
mc.writeInt(r.fromLon);
mc.writeInt(r.fromLat);
mc.writeInt(r.toLon);
mc.writeInt(r.toLat);
}
r = r.next;
}
mc.writeBoolean( false ); // end restritions
mc.writeBoolean(false); // end restritions
mc.writeShort( getSElev() );
mc.writeVarBytes( getNodeDecsription() );
mc.writeShort(getSElev());
mc.writeVarBytes(getNodeDecsription());
// buffer internal reverse links
ArrayList<OsmNodeP> internalReverse = new ArrayList<OsmNodeP>();
for ( OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext( this ) )
{
for (OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext(this)) {
OsmLinkP link = link0;
OsmNodeP origin = this;
OsmNodeP target = null;
ArrayList<OsmNodeP> linkNodes = new ArrayList<OsmNodeP>();
linkNodes.add( this );
linkNodes.add(this);
// first pass just to see if that link is consistent
while (link != null)
{
target = link.getTarget( origin );
linkNodes.add( target );
while (link != null) {
target = link.getTarget(origin);
linkNodes.add(target);
if ( !target.isTransferNode() )
{
if (!target.isTransferNode()) {
break;
}
// next link is the one (of two), does does'nt point back
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) )
{
if ( link.getTarget( target ) != origin )
for (link = target.getFirstLink(); link != null; link = link.getNext(target)) {
if (link.getTarget(target) != origin)
break;
}
if ( link != null && link.descriptionBitmap != link0.descriptionBitmap )
{
throw new IllegalArgumentException( "assertion failed: description change along transfer nodes" );
if (link != null && link.descriptionBitmap != link0.descriptionBitmap) {
throw new IllegalArgumentException("assertion failed: description change along transfer nodes");
}
origin = target;
}
if ( link == null )
if (link == null)
continue; // dead end
if ( target == this )
if (target == this)
continue; // self-ref
hasLinks = true;
// internal reverse links later
boolean isReverse = link0.isReverse( this );
if ( isReverse )
{
if ( mc.isInternal( target.ilon, target.ilat ) )
{
internalReverse.add( target );
boolean isReverse = link0.isReverse(this);
if (isReverse) {
if (mc.isInternal(target.ilon, target.ilat)) {
internalReverse.add(target);
continue;
}
}
// add traffic simulation, if present
byte[] description = link0.descriptionBitmap;
if ( trafficMap != null )
{
description = trafficMap.addTrafficClass( linkNodes, description );
if (trafficMap != null) {
description = trafficMap.addTrafficClass(linkNodes, description);
}
// write link data
int sizeoffset = mc.writeSizePlaceHolder();
mc.writeVarLengthSigned( target.ilon - ilon );
mc.writeVarLengthSigned( target.ilat - ilat );
mc.writeModeAndDesc( isReverse, description );
if ( !isReverse && linkNodes.size() > 2 ) // write geometry for forward links only
mc.writeVarLengthSigned(target.ilon - ilon);
mc.writeVarLengthSigned(target.ilat - ilat);
mc.writeModeAndDesc(isReverse, description);
if (!isReverse && linkNodes.size() > 2) // write geometry for forward links only
{
DPFilter.doDPFilter( linkNodes );
DPFilter.doDPFilter(linkNodes);
origin = this;
for( int i=1; i<linkNodes.size()-1; i++ )
{
for (int i = 1; i < linkNodes.size() - 1; i++) {
OsmNodeP tranferNode = linkNodes.get(i);
if ( ( tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT ) != 0 )
{
mc.writeVarLengthSigned( tranferNode.ilon - origin.ilon );
mc.writeVarLengthSigned( tranferNode.ilat - origin.ilat );
mc.writeVarLengthSigned( tranferNode.getSElev() - origin.getSElev() );
if ((tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT) != 0) {
mc.writeVarLengthSigned(tranferNode.ilon - origin.ilon);
mc.writeVarLengthSigned(tranferNode.ilat - origin.ilat);
mc.writeVarLengthSigned(tranferNode.getSElev() - origin.getSElev());
origin = tranferNode;
}
}
}
mc.injectSize( sizeoffset );
mc.injectSize(sizeoffset);
}
while (internalReverse.size() > 0)
{
while (internalReverse.size() > 0) {
int nextIdx = 0;
if ( internalReverse.size() > 1 )
{
if (internalReverse.size() > 1) {
int max32 = Integer.MIN_VALUE;
for ( int i = 0; i < internalReverse.size(); i++ )
{
int id32 = mc.shrinkId( internalReverse.get( i ).getIdFromPos() );
if ( id32 > max32 )
{
for (int i = 0; i < internalReverse.size(); i++) {
int id32 = mc.shrinkId(internalReverse.get(i).getIdFromPos());
if (id32 > max32) {
max32 = id32;
nextIdx = i;
}
}
}
OsmNodeP target = internalReverse.remove( nextIdx );
OsmNodeP target = internalReverse.remove(nextIdx);
int sizeoffset = mc.writeSizePlaceHolder();
mc.writeVarLengthSigned( target.ilon - ilon );
mc.writeVarLengthSigned( target.ilat - ilat );
mc.writeModeAndDesc( true, null );
mc.injectSize( sizeoffset );
mc.writeVarLengthSigned(target.ilon - ilon);
mc.writeVarLengthSigned(target.ilat - ilat);
mc.writeModeAndDesc(true, null);
mc.injectSize(sizeoffset);
}
return hasLinks;
}
public String toString2()
{
return ( ilon - 180000000 ) + "_" + ( ilat - 90000000 ) + "_" + ( selev / 4 );
public String toString2() {
return (ilon - 180000000) + "_" + (ilat - 90000000) + "_" + (selev / 4);
}
public long getIdFromPos()
{
return ( (long) ilon ) << 32 | ilat;
public long getIdFromPos() {
return ((long) ilon) << 32 | ilat;
}
public boolean isBorderNode()
{
return ( bits & BORDER_BIT ) != 0;
public boolean isBorderNode() {
return (bits & BORDER_BIT) != 0;
}
public boolean hasTraffic()
{
return ( bits & TRAFFIC_BIT ) != 0;
public boolean hasTraffic() {
return (bits & TRAFFIC_BIT) != 0;
}
/**
* Not really count the ways, just detect if more than one
*/
public void incWayCount()
{
if ( ( bits & ANY_WAY_BIT ) != 0 )
{
public void incWayCount() {
if ((bits & ANY_WAY_BIT) != 0) {
bits |= MULTI_WAY_BIT;
}
bits |= ANY_WAY_BIT;
}
public boolean isTransferNode()
{
return ( bits & BORDER_BIT ) == 0 && ( bits & MULTI_WAY_BIT ) == 0 && _linkCnt() == 2;
public boolean isTransferNode() {
return (bits & BORDER_BIT) == 0 && (bits & MULTI_WAY_BIT) == 0 && _linkCnt() == 2;
}
private int _linkCnt()
{
private int _linkCnt() {
int cnt = 0;
for ( OsmLinkP link = getFirstLink(); link != null; link = link.getNext( this ) )
{
for (OsmLinkP link = getFirstLink(); link != null; link = link.getNext(this)) {
cnt++;
}
return cnt;

View file

@ -1,50 +1,43 @@
/**
* Container for an osm node with tags or restrictions (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
public class OsmNodePT extends OsmNodeP
{
public byte[] descriptionBits;
public RestrictionData firstRestriction;
public OsmNodePT()
{
}
public OsmNodePT( OsmNodeP n )
{
ilat = n.ilat;
ilon = n.ilon;
selev = n.selev;
bits = n.bits;
}
public OsmNodePT( byte[] descriptionBits )
{
this.descriptionBits = descriptionBits;
}
@Override
public final byte[] getNodeDecsription()
{
return descriptionBits;
}
@Override
public final RestrictionData getFirstRestriction()
{
return firstRestriction;
}
@Override
public boolean isTransferNode()
{
return false; // always have descriptionBits so never transfernode
}
}
/**
* Container for an osm node with tags or restrictions (pre-pocessor version)
*
* @author ab
*/
package btools.mapcreator;
public class OsmNodePT extends OsmNodeP {
public byte[] descriptionBits;
public RestrictionData firstRestriction;
public OsmNodePT() {
}
public OsmNodePT(OsmNodeP n) {
ilat = n.ilat;
ilon = n.ilon;
selev = n.selev;
bits = n.bits;
}
public OsmNodePT(byte[] descriptionBits) {
this.descriptionBits = descriptionBits;
}
@Override
public final byte[] getNodeDecsription() {
return descriptionBits;
}
@Override
public final RestrictionData getFirstRestriction() {
return firstRestriction;
}
@Override
public boolean isTransferNode() {
return false; // always have descriptionBits so never transfernode
}
}

View file

@ -1,236 +1,200 @@
package btools.mapcreator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
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;
}
}
package btools.mapcreator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
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

@ -22,8 +22,7 @@ import btools.util.CompactLongMap;
import btools.util.FrozenLongMap;
public class OsmTrafficMap
{
public class OsmTrafficMap {
int minLon;
int minLat;
int maxLon;
@ -38,243 +37,206 @@ public class OsmTrafficMap
private int totalChanges = 0;
private int supressedChanges = 0;
private boolean doNotAdd = false;
private boolean debug = false;
public OsmTrafficMap( BExpressionContextWay expctxWay )
{
public OsmTrafficMap(BExpressionContextWay expctxWay) {
this.expctxWay = expctxWay;
debug = Boolean.getBoolean( "debugTrafficMap" );
debug = Boolean.getBoolean("debugTrafficMap");
}
public static class OsmTrafficElement
{
public static class OsmTrafficElement {
public long node2;
public int traffic;
public OsmTrafficElement next;
}
private CompactLongMap<OsmTrafficElement> map = new CompactLongMap<OsmTrafficElement>();
public void loadAll( File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways ) throws Exception
{
load( file, minLon, minLat, maxLon, maxLat, includeMotorways );
public void loadAll(File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways) throws Exception {
load(file, minLon, minLat, maxLon, maxLat, includeMotorways);
// check for old traffic data
oldTrafficFile = new File( file.getParentFile(), file.getName() + "_old" );
if ( oldTrafficFile.exists() )
{
oldTrafficClasses = new OsmTrafficMap( null );
oldTrafficFile = new File(file.getParentFile(), file.getName() + "_old");
if (oldTrafficFile.exists()) {
oldTrafficClasses = new OsmTrafficMap(null);
oldTrafficClasses.doNotAdd = true;
oldTrafficClasses.load( oldTrafficFile, minLon, minLat, maxLon, maxLat, false );
oldTrafficClasses.load(oldTrafficFile, minLon, minLat, maxLon, maxLat, false);
}
// check for old traffic data
newTrafficFile = new File( file.getParentFile(), file.getName() + "_new" );
newTrafficDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( newTrafficFile ) ) );
newTrafficFile = new File(file.getParentFile(), file.getName() + "_new");
newTrafficDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newTrafficFile)));
}
public void finish() throws Exception
{
if ( newTrafficDos != null )
{
public void finish() throws Exception {
if (newTrafficDos != null) {
newTrafficDos.close();
newTrafficDos = null;
oldTrafficFile.delete();
newTrafficFile.renameTo( oldTrafficFile );
System.out.println( "TrafficMap: changes total=" + totalChanges + " supressed=" + supressedChanges );
newTrafficFile.renameTo(oldTrafficFile);
System.out.println("TrafficMap: changes total=" + totalChanges + " supressed=" + supressedChanges);
}
}
public void load( File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways ) throws Exception
{
public void load(File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways) throws Exception {
this.minLon = minLon;
this.minLat = minLat;
this.maxLon = maxLon;
this.maxLat = maxLat;
int trafficElements = 0;
DataInputStream is = new DataInputStream( new BufferedInputStream( new FileInputStream( file ) ) );
try
{
for(;;)
{
long n1 = is.readLong();
long n2 = is.readLong();
int traffic = is.readInt();
if ( traffic == -1 && !includeMotorways )
{
continue;
}
if ( isInsideBounds( n1 ) || isInsideBounds( n2 ) )
{
if ( addElement( n1, n2, traffic ) )
{
trafficElements++;
}
int trafficElements = 0;
DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
try {
for (; ; ) {
long n1 = is.readLong();
long n2 = is.readLong();
int traffic = is.readInt();
if (traffic == -1 && !includeMotorways) {
continue;
}
if (isInsideBounds(n1) || isInsideBounds(n2)) {
if (addElement(n1, n2, traffic)) {
trafficElements++;
}
}
}
catch( EOFException eof ) {}
finally{ is.close(); }
map = new FrozenLongMap<OsmTrafficElement>( map );
System.out.println( "read traffic-elements: " + trafficElements );
} catch (EOFException eof) {
} finally {
is.close();
}
map = new FrozenLongMap<OsmTrafficElement>(map);
System.out.println("read traffic-elements: " + trafficElements);
}
public boolean addElement( long n1, long n2, int traffic )
{
OsmTrafficElement e = getElement( n1, n2 );
if ( e == null )
{
public boolean addElement(long n1, long n2, int traffic) {
OsmTrafficElement e = getElement(n1, n2);
if (e == null) {
e = new OsmTrafficElement();
e.node2 = n2;
e.traffic = traffic;
OsmTrafficElement e0 = map.get( n1 );
if ( e0 != null )
{
while( e0.next != null )
{
OsmTrafficElement e0 = map.get(n1);
if (e0 != null) {
while (e0.next != null) {
e0 = e0.next;
}
e0.next = e;
}
else
{
map.fastPut( n1, e );
} else {
map.fastPut(n1, e);
}
return true;
}
if ( doNotAdd )
{
e.traffic = Math.max( e.traffic, traffic );
}
else
{
if (doNotAdd) {
e.traffic = Math.max(e.traffic, traffic);
} else {
e.traffic = e.traffic == -1 || traffic == -1 ? -1 : e.traffic + traffic;
}
return false;
}
private boolean isInsideBounds( long id )
{
int ilon = (int)(id >> 32);
int ilat = (int)(id & 0xffffffff);
private boolean isInsideBounds(long id) {
int ilon = (int) (id >> 32);
int ilat = (int) (id & 0xffffffff);
return ilon >= minLon && ilon < maxLon && ilat >= minLat && ilat < maxLat;
}
public int getTrafficClass( long n1, long n2 )
{
public int getTrafficClass(long n1, long n2) {
// used for the old data, where we stpre traffic-classes, not volumes
OsmTrafficElement e = getElement( n1, n2 );
OsmTrafficElement e = getElement(n1, n2);
return e == null ? 0 : e.traffic;
}
public int getTrafficClassForTraffic( int traffic )
{
if ( traffic < 0 ) return -1;
if ( traffic < 40000 ) return 0;
if ( traffic < 80000 ) return 2;
if ( traffic < 160000 ) return 3;
if ( traffic < 320000 ) return 4;
if ( traffic < 640000 ) return 5;
if ( traffic <1280000 ) return 6;
public int getTrafficClassForTraffic(int traffic) {
if (traffic < 0) return -1;
if (traffic < 40000) return 0;
if (traffic < 80000) return 2;
if (traffic < 160000) return 3;
if (traffic < 320000) return 4;
if (traffic < 640000) return 5;
if (traffic < 1280000) return 6;
return 7;
}
private int getTraffic( long n1, long n2 )
{
OsmTrafficElement e1 = getElement( n1, n2 );
private int getTraffic(long n1, long n2) {
OsmTrafficElement e1 = getElement(n1, n2);
int traffic1 = e1 == null ? 0 : e1.traffic;
OsmTrafficElement e2 = getElement( n2, n1 );
OsmTrafficElement e2 = getElement(n2, n1);
int traffic2 = e2 == null ? 0 : e2.traffic;
return traffic1 == -1 || traffic2 == -1 ? -1 : traffic1 > traffic2 ? traffic1 : traffic2;
}
public void freeze()
{
public void freeze() {
}
private OsmTrafficElement getElement( long n1, long n2 )
{
OsmTrafficElement e = map.get( n1 );
while( e != null )
{
if ( e.node2 == n2 )
{
private OsmTrafficElement getElement(long n1, long n2) {
OsmTrafficElement e = map.get(n1);
while (e != null) {
if (e.node2 == n2) {
return e;
}
e = e.next;
}
e = e.next;
}
return null;
}
public OsmTrafficElement getElement( long n )
{
return map.get( n );
public OsmTrafficElement getElement(long n) {
return map.get(n);
}
public byte[] addTrafficClass( ArrayList<OsmNodeP> linkNodes, byte[] description ) throws IOException
{
public byte[] addTrafficClass(ArrayList<OsmNodeP> linkNodes, byte[] description) throws IOException {
double distance = 0.;
double sum = 0.;
for( int i=0; i<linkNodes.size()-1; i++ )
{
for (int i = 0; i < linkNodes.size() - 1; i++) {
OsmNodeP n1 = linkNodes.get(i);
OsmNodeP n2 = linkNodes.get(i+1);
int traffic = getTraffic( n1.getIdFromPos(), n2.getIdFromPos() );
double dist = CheapRuler.distance( n1.ilon, n1.ilat, n2.ilon, n2.ilat );
OsmNodeP n2 = linkNodes.get(i + 1);
int traffic = getTraffic(n1.getIdFromPos(), n2.getIdFromPos());
double dist = CheapRuler.distance(n1.ilon, n1.ilat, n2.ilon, n2.ilat);
distance += dist;
sum += dist*traffic;
sum += dist * traffic;
}
if ( distance == 0. )
{
if (distance == 0.) {
return description;
}
int traffic = (int)(sum/distance + 0.5);
int traffic = (int) (sum / distance + 0.5);
long id0 = linkNodes.get(0).getIdFromPos();
long id1 = linkNodes.get(linkNodes.size()-1).getIdFromPos();
int trafficClass = getTrafficClassForTraffic( traffic );
long id1 = linkNodes.get(linkNodes.size() - 1).getIdFromPos();
int trafficClass = getTrafficClassForTraffic(traffic);
// delta suppression: keep old traffic classes within some buffer range
if ( oldTrafficClasses != null )
{
int oldTrafficClass = oldTrafficClasses.getTrafficClass( id0, id1 );
if ( oldTrafficClass != trafficClass )
{
if (oldTrafficClasses != null) {
int oldTrafficClass = oldTrafficClasses.getTrafficClass(id0, id1);
if (oldTrafficClass != trafficClass) {
totalChanges++;
boolean supressChange =
oldTrafficClass == getTrafficClassForTraffic( (int)(traffic*1.3) )
|| oldTrafficClass == getTrafficClassForTraffic( (int)(traffic*0.77) );
oldTrafficClass == getTrafficClassForTraffic((int) (traffic * 1.3))
|| oldTrafficClass == getTrafficClassForTraffic((int) (traffic * 0.77));
if ( debug )
{
System.out.println( "traffic class change " + oldTrafficClass + "->" + trafficClass + " supress=" + supressChange );
if (debug) {
System.out.println("traffic class change " + oldTrafficClass + "->" + trafficClass + " supress=" + supressChange);
}
if ( supressChange )
{
if (supressChange) {
trafficClass = oldTrafficClass;
supressedChanges++;
}
}
}
if ( trafficClass > 0 )
{
newTrafficDos.writeLong( id0 );
newTrafficDos.writeLong( id1 );
newTrafficDos.writeInt( trafficClass );
expctxWay.decode( description );
expctxWay.addLookupValue( "estimated_traffic_class", trafficClass + 1 );
if (trafficClass > 0) {
newTrafficDos.writeLong(id0);
newTrafficDos.writeLong(id1);
newTrafficDos.writeInt(trafficClass);
expctxWay.decode(description);
expctxWay.addLookupValue("estimated_traffic_class", trafficClass + 1);
return expctxWay.encode();
}
return description;

View file

@ -1,229 +1,194 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import btools.util.CompactLongSet;
import btools.util.DiffCoderDataOutputStream;
import btools.util.FrozenLongSet;
/**
* 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 DiffCoderDataOutputStream nodesOutStream;
private DiffCoderDataOutputStream borderNodesOut;
private File nodeTilesOut;
private CompactLongSet[] positionSets;
private HashMap<String, SrtmRaster> srtmmap;
private int lastSrtmLonIdx;
private int lastSrtmLatIdx;
private SrtmRaster lastSrtmRaster;
private String srtmdir;
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> <srtm-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" ) );
positionSets = new CompactLongSet[2500];
}
@Override
public void nextNode( NodeData n ) throws Exception
{
SrtmRaster 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 boolean checkAdd( int lon, int lat )
{
int slot = ((lon%5000000)/100000)*50 + ((lat%5000000)/100000);
long id = ( (long) lon ) << 32 | lat;
CompactLongSet set = positionSets[slot];
if ( set == null )
{
positionSets[slot] = set = new CompactLongSet();
}
if ( !set.contains( id ) )
{
set.fastAdd( id );
return true;
}
return false;
}
private void findUniquePos( NodeData n )
{
if ( !checkAdd( n.ilon, n.ilat ) )
{
_findUniquePos( n );
}
}
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;
if ( checkAdd( lon, lat ) )
{
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 SrtmRaster srtmForNode( int ilon, int ilat ) throws Exception
{
int srtmLonIdx = ( ilon + 5000000 ) / 5000000;
int srtmLatIdx = ( 654999999 - ilat ) / 5000000 - 100; // ugly negative rounding...
if ( srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx )
{
return lastSrtmRaster;
}
lastSrtmLonIdx = srtmLonIdx;
lastSrtmLatIdx = srtmLatIdx;
String slonidx = "0" + srtmLonIdx;
String slatidx = "0" + srtmLatIdx;
String filename = "srtm_" + slonidx.substring( slonidx.length()-2 ) + "_" + slatidx.substring( slatidx.length()-2 );
lastSrtmRaster = srtmmap.get( filename );
if ( lastSrtmRaster == null && !srtmmap.containsKey( filename ) )
{
File f = new File( new File( srtmdir ), filename + ".bef" );
System.out.println( "checking: " + f + " ilon=" + ilon + " ilat=" + ilat );
if ( f.exists() )
{
System.out.println( "*** reading: " + f );
try
{
InputStream isc = new BufferedInputStream( new FileInputStream( f ) );
lastSrtmRaster = new RasterCoder().decodeRaster( isc );
isc.close();
}
catch (Exception e)
{
System.out.println( "**** ERROR reading " + f + " ****" );
}
srtmmap.put( filename, lastSrtmRaster );
return lastSrtmRaster;
}
f = new File( new File( srtmdir ), filename + ".zip" );
System.out.println( "reading: " + f + " ilon=" + ilon + " ilat=" + ilat );
if ( f.exists() )
{
try
{
lastSrtmRaster = new SrtmData( f ).getRaster();
}
catch (Exception e)
{
System.out.println( "**** ERROR reading " + f + " ****" );
}
}
srtmmap.put( filename, lastSrtmRaster );
}
return lastSrtmRaster;
}
private void resetSrtm()
{
srtmmap = new HashMap<String, SrtmRaster>();
lastSrtmLonIdx = -1;
lastSrtmLatIdx = -1;
lastSrtmRaster = null;
}
}
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import btools.util.CompactLongSet;
import btools.util.DiffCoderDataOutputStream;
import btools.util.FrozenLongSet;
/**
* PosUnifier does 3 steps in map-processing:
* <p>
* - 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 DiffCoderDataOutputStream nodesOutStream;
private DiffCoderDataOutputStream borderNodesOut;
private File nodeTilesOut;
private CompactLongSet[] positionSets;
private HashMap<String, SrtmRaster> srtmmap;
private int lastSrtmLonIdx;
private int lastSrtmLatIdx;
private SrtmRaster lastSrtmRaster;
private String srtmdir;
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> <srtm-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"));
positionSets = new CompactLongSet[2500];
}
@Override
public void nextNode(NodeData n) throws Exception {
SrtmRaster 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 boolean checkAdd(int lon, int lat) {
int slot = ((lon % 5000000) / 100000) * 50 + ((lat % 5000000) / 100000);
long id = ((long) lon) << 32 | lat;
CompactLongSet set = positionSets[slot];
if (set == null) {
positionSets[slot] = set = new CompactLongSet();
}
if (!set.contains(id)) {
set.fastAdd(id);
return true;
}
return false;
}
private void findUniquePos(NodeData n) {
if (!checkAdd(n.ilon, n.ilat)) {
_findUniquePos(n);
}
}
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;
if (checkAdd(lon, lat)) {
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 SrtmRaster srtmForNode(int ilon, int ilat) throws Exception {
int srtmLonIdx = (ilon + 5000000) / 5000000;
int srtmLatIdx = (654999999 - ilat) / 5000000 - 100; // ugly negative rounding...
if (srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx) {
return lastSrtmRaster;
}
lastSrtmLonIdx = srtmLonIdx;
lastSrtmLatIdx = srtmLatIdx;
String slonidx = "0" + srtmLonIdx;
String slatidx = "0" + srtmLatIdx;
String filename = "srtm_" + slonidx.substring(slonidx.length() - 2) + "_" + slatidx.substring(slatidx.length() - 2);
lastSrtmRaster = srtmmap.get(filename);
if (lastSrtmRaster == null && !srtmmap.containsKey(filename)) {
File f = new File(new File(srtmdir), filename + ".bef");
System.out.println("checking: " + f + " ilon=" + ilon + " ilat=" + ilat);
if (f.exists()) {
System.out.println("*** reading: " + f);
try {
InputStream isc = new BufferedInputStream(new FileInputStream(f));
lastSrtmRaster = new RasterCoder().decodeRaster(isc);
isc.close();
} catch (Exception e) {
System.out.println("**** ERROR reading " + f + " ****");
}
srtmmap.put(filename, lastSrtmRaster);
return lastSrtmRaster;
}
f = new File(new File(srtmdir), filename + ".zip");
System.out.println("reading: " + f + " ilon=" + ilon + " ilat=" + ilat);
if (f.exists()) {
try {
lastSrtmRaster = new SrtmData(f).getRaster();
} catch (Exception e) {
System.out.println("**** ERROR reading " + f + " ****");
}
}
srtmmap.put(filename, lastSrtmRaster);
}
return lastSrtmRaster;
}
private void resetSrtm() {
srtmmap = new HashMap<String, SrtmRaster>();
lastSrtmLonIdx = -1;
lastSrtmLatIdx = -1;
lastSrtmRaster = null;
}
}

View file

@ -1,16 +1,15 @@
package btools.mapcreator;
import java.io.*;
import btools.util.*;
//
// Encode/decode a raster
//
public class RasterCoder
{
public void encodeRaster(SrtmRaster raster, OutputStream os) throws IOException
{
public class RasterCoder {
public void encodeRaster(SrtmRaster raster, OutputStream os) throws IOException {
DataOutputStream dos = new DataOutputStream(os);
long t0 = System.currentTimeMillis();
@ -29,8 +28,7 @@ public class RasterCoder
System.out.println("finished encoding in " + (t1 - t0) + " ms");
}
public SrtmRaster decodeRaster(InputStream is) throws IOException
{
public SrtmRaster decodeRaster(InputStream is) throws IOException {
DataInputStream dis = new DataInputStream(is);
long t0 = System.currentTimeMillis();
@ -46,78 +44,65 @@ public class RasterCoder
raster.eval_array = new short[raster.ncols * raster.nrows];
_decodeRaster(raster, is);
raster.usingWeights = raster.ncols > 6001;
long t1 = System.currentTimeMillis();
System.out.println("finished decoding in " + (t1 - t0) + " ms ncols=" + raster.ncols + " nrows=" + raster.nrows );
System.out.println("finished decoding in " + (t1 - t0) + " ms ncols=" + raster.ncols + " nrows=" + raster.nrows);
return raster;
}
private void _encodeRaster(SrtmRaster raster, OutputStream os) throws IOException
{
private void _encodeRaster(SrtmRaster raster, OutputStream os) throws IOException {
MixCoderDataOutputStream mco = new MixCoderDataOutputStream(os);
int nrows = raster.nrows;
int ncols = raster.ncols;
short[] pixels = raster.eval_array;
int colstep = raster.halfcol ? 2 : 1;
for (int row = 0; row < nrows; row++)
{
for (int row = 0; row < nrows; row++) {
short lastval = Short.MIN_VALUE; // nodata
for (int col = 0; col < ncols; col += colstep )
{
for (int col = 0; col < ncols; col += colstep) {
short val = pixels[row * ncols + col];
if ( val == -32766 )
{
if (val == -32766) {
val = lastval; // replace remaining (border) skips
}
else
{
} else {
lastval = val;
}
// remap nodata
int code = val == Short.MIN_VALUE ? -1 : ( val < 0 ? val-1 : val );
mco.writeMixed( code );
int code = val == Short.MIN_VALUE ? -1 : (val < 0 ? val - 1 : val);
mco.writeMixed(code);
}
}
mco.flush();
}
private void _decodeRaster(SrtmRaster raster, InputStream is) throws IOException
{
private void _decodeRaster(SrtmRaster raster, InputStream is) throws IOException {
MixCoderDataInputStream mci = new MixCoderDataInputStream(is);
int nrows = raster.nrows;
int ncols = raster.ncols;
short[] pixels = raster.eval_array;
int colstep = raster.halfcol ? 2 : 1;
for (int row = 0; row < nrows; row++)
{
for (int col = 0; col < ncols; col += colstep )
{
for (int row = 0; row < nrows; row++) {
for (int col = 0; col < ncols; col += colstep) {
int code = mci.readMixed();
// remap nodata
int v30 = code == -1 ? Short.MIN_VALUE : ( code < 0 ? code + 1 : code );
if ( raster.usingWeights && v30 > -32766 )
{
int v30 = code == -1 ? Short.MIN_VALUE : (code < 0 ? code + 1 : code);
if (raster.usingWeights && v30 > -32766) {
v30 *= 2;
}
pixels[row * ncols + col] = (short) ( v30 );
}
pixels[row * ncols + col] = (short) (v30);
}
if ( raster.halfcol )
{
for (int col = 1; col < ncols-1; col += colstep )
{
int l = (int)pixels[row * ncols + col - 1];
int r = (int)pixels[row * ncols + col + 1];
if (raster.halfcol) {
for (int col = 1; col < ncols - 1; col += colstep) {
int l = (int) pixels[row * ncols + col - 1];
int r = (int) pixels[row * ncols + col + 1];
short v30 = Short.MIN_VALUE; // nodata
if ( l > -32766 && r > -32766 )
{
v30 = (short)((l+r)/2);
if (l > -32766 && r > -32766) {
v30 = (short) ((l + r) / 2);
}
pixels[row * ncols + col] = v30;
}

View file

@ -1,27 +1,24 @@
package btools.mapcreator;
import btools.util.LongList;
/**
* 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;
}
}
package btools.mapcreator;
import btools.util.LongList;
/**
* 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

@ -1,14 +1,13 @@
package btools.mapcreator;
/**
* Callbacklistener for Relations
*
* @author ab
*/
public interface RelationListener
{
void nextRelation( RelationData data ) throws Exception;
void nextRestriction( RelationData data, long fromWid, long toWid, long viaNid ) throws Exception;
}
package btools.mapcreator;
/**
* Callbacklistener for Relations
*
* @author ab
*/
public interface RelationListener {
void nextRelation(RelationData data) throws Exception;
void nextRestriction(RelationData data, long fromWid, long toWid, long viaNid) throws Exception;
}

View file

@ -13,152 +13,131 @@ import btools.util.FrozenLongSet;
/**
* RelationMerger does 1 step in map processing:
*
* <p>
* - enrich ways with relation information
*
* @author ab
*/
public class RelationMerger extends MapCreatorBase
{
private HashMap<String,CompactLongSet> routesets;
public class RelationMerger extends MapCreatorBase {
private HashMap<String, CompactLongSet> routesets;
private CompactLongSet routesetall;
private BExpressionContextWay expctxReport;
private BExpressionContextWay expctxCheck;
// private BExpressionContext expctxStat;
// private BExpressionContext expctxStat;
private DataOutputStream wayOutStream;
public static void main(String[] args) throws Exception
{
System.out.println("*** RelationMerger: merge relations into ways" );
if (args.length != 6)
{
System.out.println("usage: java RelationMerger <way-file-in> <way-file-out> <relation-file> <lookup-file> <report-profile> <check-profile>" );
public static void main(String[] args) throws Exception {
System.out.println("*** RelationMerger: merge relations into ways");
if (args.length != 6) {
System.out.println("usage: java RelationMerger <way-file-in> <way-file-out> <relation-file> <lookup-file> <report-profile> <check-profile>");
return;
}
new RelationMerger().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] ) );
new RelationMerger().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]));
}
public void init( File relationFileIn, File lookupFile, File reportProfile, File checkProfile ) throws Exception
{
public void init(File relationFileIn, File lookupFile, File reportProfile, File checkProfile) throws Exception {
// read lookup + profile for relation access-check
BExpressionMetaData metaReport = new BExpressionMetaData();
expctxReport = new BExpressionContextWay( metaReport );
metaReport.readMetaData( lookupFile );
BExpressionMetaData metaReport = new BExpressionMetaData();
expctxReport = new BExpressionContextWay(metaReport);
metaReport.readMetaData(lookupFile);
BExpressionMetaData metaCheck = new BExpressionMetaData();
expctxCheck = new BExpressionContextWay( metaCheck );
metaCheck.readMetaData( lookupFile );
BExpressionMetaData metaCheck = new BExpressionMetaData();
expctxCheck = new BExpressionContextWay(metaCheck);
metaCheck.readMetaData(lookupFile);
expctxReport.parseFile( reportProfile, "global" );
expctxCheck.parseFile( checkProfile, "global" );
expctxReport.parseFile(reportProfile, "global");
expctxCheck.parseFile(checkProfile, "global");
// expctxStat = new BExpressionContext("way");
// *** read the relation file into sets for each processed tag
routesets = new HashMap<String,CompactLongSet>();
routesets = new HashMap<String, CompactLongSet>();
routesetall = new CompactLongSet();
DataInputStream dis = createInStream( relationFileIn );
try
{
for(;;)
{
long rid = readId( dis );
DataInputStream dis = createInStream(relationFileIn);
try {
for (; ; ) {
long rid = readId(dis);
String route = dis.readUTF();
String network = dis.readUTF();
String state = dis.readUTF();
int value = "proposed".equals( state ) ? 3 : 2; // 2=yes, 3=proposed
int value = "proposed".equals(state) ? 3 : 2; // 2=yes, 3=proposed
String tagname = "route_" + route + "_" + network;
CompactLongSet routeset = null;
if ( expctxCheck.getLookupNameIdx(tagname) >= 0 )
{
if (expctxCheck.getLookupNameIdx(tagname) >= 0) {
String key = tagname + "_" + value;
routeset = routesets.get( key );
if ( routeset == null )
{
routeset = routesets.get(key);
if (routeset == null) {
routeset = new CompactLongSet();
routesets.put( key, routeset );
routesets.put(key, routeset);
}
}
for(;;)
{
long wid = readId( dis );
if ( wid == -1 ) break;
for (; ; ) {
long wid = readId(dis);
if (wid == -1) break;
// expctxStat.addLookupValue( tagname, "yes", null );
if ( routeset != null && !routeset.contains( wid ) )
{
routeset.add( wid );
routesetall.add( wid );
if (routeset != null && !routeset.contains(wid)) {
routeset.add(wid);
routesetall.add(wid);
}
}
}
}
catch( EOFException eof )
{
} catch (EOFException eof) {
dis.close();
}
for( String key : routesets.keySet() )
{
CompactLongSet routeset = new FrozenLongSet( routesets.get( key ) );
routesets.put( key, routeset );
System.out.println( "marked " + routeset.size() + " routes for key: " + key );
for (String key : routesets.keySet()) {
CompactLongSet routeset = new FrozenLongSet(routesets.get(key));
routesets.put(key, routeset);
System.out.println("marked " + routeset.size() + " routes for key: " + key);
}
}
public void process( File wayFileIn, File wayFileOut, File relationFileIn, File lookupFile, File reportProfile, File checkProfile ) throws Exception
{
init( relationFileIn, lookupFile, reportProfile, checkProfile );
public void process(File wayFileIn, File wayFileOut, File relationFileIn, File lookupFile, File reportProfile, File checkProfile) throws Exception {
init(relationFileIn, lookupFile, reportProfile, checkProfile);
// *** finally process the way-file
wayOutStream = createOutStream( wayFileOut );
new WayIterator( this, true ).processFile( wayFileIn );
wayOutStream = createOutStream(wayFileOut);
new WayIterator(this, true).processFile(wayFileIn);
wayOutStream.close();
// System.out.println( "-------- route-statistics -------- " );
// expctxStat.dumpStatistics();
}
}
@Override
public void nextWay( WayData data ) throws Exception
{
public void nextWay(WayData data) throws Exception {
// propagate the route-bits
if ( routesetall.contains( data.wid ) )
{
if (routesetall.contains(data.wid)) {
boolean ok = true;
// check access and log a warning for conflicts
expctxReport.evaluate( false, data.description );
expctxReport.evaluate(false, data.description);
boolean warn = expctxReport.getCostfactor() >= 10000.;
if ( warn )
{
expctxCheck.evaluate( false, data.description );
if (warn) {
expctxCheck.evaluate(false, data.description);
ok = expctxCheck.getCostfactor() < 10000.;
System.out.println( "** relation access conflict for wid = " + data.wid + " tags:" + expctxReport.getKeyValueDescription( false, data.description ) + " (ok=" + ok + ")" );
System.out.println("** relation access conflict for wid = " + data.wid + " tags:" + expctxReport.getKeyValueDescription(false, data.description) + " (ok=" + ok + ")");
}
if ( ok )
{
expctxReport.decode( data.description );
for( String key : routesets.keySet() )
{
CompactLongSet routeset = routesets.get( key );
if ( routeset.contains( data.wid ) )
{
int sepIdx = key.lastIndexOf( '_' );
String tagname = key.substring( 0, sepIdx );
int val = Integer.valueOf( key.substring( sepIdx+1 ) );
expctxReport.addSmallestLookupValue( tagname, val );
if (ok) {
expctxReport.decode(data.description);
for (String key : routesets.keySet()) {
CompactLongSet routeset = routesets.get(key);
if (routeset.contains(data.wid)) {
int sepIdx = key.lastIndexOf('_');
String tagname = key.substring(0, sepIdx);
int val = Integer.valueOf(key.substring(sepIdx + 1));
expctxReport.addSmallestLookupValue(tagname, val);
}
}
data.description = expctxReport.encode();
data.description = expctxReport.encode();
}
}
if ( wayOutStream != null )
{
data.writeTo( wayOutStream );
if (wayOutStream != null) {
data.writeTo(wayOutStream);
}
}

View file

@ -10,63 +10,52 @@ import btools.util.TinyDenseLongMap;
/**
* WayCutter does 2 step in map-processing:
*
* <p>
* - cut the way file into 45*30 - pieces
* - enrich ways with relation information
*
* @author ab
*/
public class RelationStatistics extends MapCreatorBase
{
public static void main(String[] args) throws Exception
{
public class RelationStatistics extends MapCreatorBase {
public static void main(String[] args) throws Exception {
System.out.println("*** RelationStatistics: count relation networks");
if (args.length != 1)
{
System.out.println("usage: java WayCutter <relation-file>" );
if (args.length != 1) {
System.out.println("usage: java WayCutter <relation-file>");
return;
}
new RelationStatistics().process( new File( args[0] ) );
new RelationStatistics().process(new File(args[0]));
}
public void process( File relationFileIn ) throws Exception
{
HashMap<String,long[]> relstats = new HashMap<String,long[]>();
DataInputStream dis = createInStream( relationFileIn );
try
{
for(;;)
{
long rid = readId( dis );
public void process(File relationFileIn) throws Exception {
HashMap<String, long[]> relstats = new HashMap<String, long[]>();
DataInputStream dis = createInStream(relationFileIn);
try {
for (; ; ) {
long rid = readId(dis);
String network = dis.readUTF();
int waycount = 0;
for(;;)
{
long wid = readId( dis );
if ( wid == -1 ) break;
for (; ; ) {
long wid = readId(dis);
if (wid == -1) break;
waycount++;
}
long[] stat = relstats.get( network );
if ( stat == null )
{
long[] stat = relstats.get(network);
if (stat == null) {
stat = new long[2];
relstats.put( network, stat );
relstats.put(network, stat);
}
stat[0]++;
stat[1] += waycount;
}
}
catch( EOFException eof )
{
} catch (EOFException eof) {
dis.close();
}
for( String network : relstats.keySet() )
{
long[] stat = relstats.get( network );
System.out.println( "network: " + network + " has " + stat[0] + " relations with " + stat[1] + " ways" );
for (String network : relstats.keySet()) {
long[] stat = relstats.get(network);
System.out.println("network: " + network + " has " + stat[0] + " relations with " + stat[1] + " ways");
}
}

View file

@ -4,41 +4,35 @@ import java.io.File;
/**
* RestrictionCutter writes Restrictions to tiles
*
* <p>
* - cut the way file into 45*30 - pieces
* - enrich ways with relation information
*
* @author ab
*/
public class RestrictionCutter extends MapCreatorBase
{
public class RestrictionCutter extends MapCreatorBase {
private WayCutter wayCutter;
public void init( File outTileDir, WayCutter wayCutter ) throws Exception
{
public void init(File outTileDir, WayCutter wayCutter) throws Exception {
outTileDir.mkdir();
this.outTileDir = outTileDir;
this.wayCutter = wayCutter;
}
public void finish() throws Exception
{
public void finish() throws Exception {
closeTileOutStreams();
}
public void nextRestriction( RestrictionData data ) throws Exception
{
int tileIndex = wayCutter.getTileIndexForNid( data.viaNid );
if ( tileIndex != -1 )
{
data.writeTo( getOutStreamForTile( tileIndex ) );
public void nextRestriction(RestrictionData data) throws Exception {
int tileIndex = wayCutter.getTileIndexForNid(data.viaNid);
if (tileIndex != -1) {
data.writeTo(getOutStreamForTile(tileIndex));
}
}
protected String getNameForTile( int tileIndex )
{
String name = wayCutter.getNameForTile( tileIndex );
return name.substring( 0, name.length()-3 ) + "rtl";
protected String getNameForTile(int tileIndex) {
String name = wayCutter.getNameForTile(tileIndex);
return name.substring(0, name.length() - 3) + "rtl";
}
}

View file

@ -4,40 +4,34 @@ import java.io.File;
/**
* RestrictionCutter5 does 1 step in map-processing:
*
* <p>
* - cut the 45*30 restriction files into 5*5 pieces
*
* @author ab
*/
public class RestrictionCutter5 extends MapCreatorBase
{
public class RestrictionCutter5 extends MapCreatorBase {
private WayCutter5 wayCutter5;
public void init( File outTileDir, WayCutter5 wayCutter5 ) throws Exception
{
public void init(File outTileDir, WayCutter5 wayCutter5) throws Exception {
outTileDir.mkdir();
this.outTileDir = outTileDir;
this.wayCutter5 = wayCutter5;
}
public void finish() throws Exception
{
public void finish() throws Exception {
closeTileOutStreams();
}
public void nextRestriction( RestrictionData data ) throws Exception
{
int tileIndex = wayCutter5.getTileIndexForNid( data.viaNid );
if ( tileIndex != -1 )
{
data.writeTo( getOutStreamForTile( tileIndex ) );
public void nextRestriction(RestrictionData data) throws Exception {
int tileIndex = wayCutter5.getTileIndexForNid(data.viaNid);
if (tileIndex != -1) {
data.writeTo(getOutStreamForTile(tileIndex));
}
}
protected String getNameForTile( int tileIndex )
{
String name = wayCutter5.getNameForTile( tileIndex );
return name.substring( 0, name.length()-3 ) + "rt5";
protected String getNameForTile(int tileIndex) {
String name = wayCutter5.getNameForTile(tileIndex);
return name.substring(0, name.length() - 3) + "rt5";
}
}

View file

@ -15,8 +15,7 @@ import btools.util.CheapAngleMeter;
*
* @author ab
*/
public class RestrictionData extends MapCreatorBase
{
public class RestrictionData extends MapCreatorBase {
public String restrictionKey;
public String restriction;
public short exceptions;
@ -30,125 +29,99 @@ public class RestrictionData extends MapCreatorBase
public int fromLon;
public int fromLat;
public int toLon;
public int toLat;
public boolean badWayMatch;
private static HashMap<String,String> names = new HashMap<>();
private static HashMap<String, String> names = new HashMap<>();
private static TreeSet<Long> badTRs = new TreeSet<>();
public RestrictionData()
{
}
public boolean isPositive()
{
return restriction.startsWith( "only_" );
public RestrictionData() {
}
public boolean isValid()
{
boolean valid = fromLon != 0 && toLon != 0 && ( restriction.startsWith( "only_" ) || restriction.startsWith( "no_" ) );
if ( (!valid) || badWayMatch || !(checkGeometry()) )
{
synchronized( badTRs )
{
badTRs.add( ( (long) viaLon ) << 32 | viaLat );
public boolean isPositive() {
return restriction.startsWith("only_");
}
public boolean isValid() {
boolean valid = fromLon != 0 && toLon != 0 && (restriction.startsWith("only_") || restriction.startsWith("no_"));
if ((!valid) || badWayMatch || !(checkGeometry())) {
synchronized (badTRs) {
badTRs.add(((long) viaLon) << 32 | viaLat);
}
}
return valid && "restriction".equals( restrictionKey );
return valid && "restriction".equals(restrictionKey);
}
private boolean checkGeometry()
{
double a = (new CheapAngleMeter()).calcAngle( fromLon, fromLat, viaLon, viaLat, toLon, toLat );
private boolean checkGeometry() {
double a = (new CheapAngleMeter()).calcAngle(fromLon, fromLat, viaLon, viaLat, toLon, toLat);
String t;
if ( restriction.startsWith( "only_" ) )
{
t = restriction.substring( "only_".length() );
}
else if ( restriction.startsWith( "no_" ) )
{
t = restriction.substring( "no_".length() );
}
else throw new RuntimeException( "ups" );
if (restriction.startsWith("only_")) {
t = restriction.substring("only_".length());
} else if (restriction.startsWith("no_")) {
t = restriction.substring("no_".length());
} else throw new RuntimeException("ups");
if ( restrictionKey.endsWith( ":conditional" ) )
{
int idx = t.indexOf( '@' );
if ( idx >= 0 )
{
t = t.substring(0, idx ).trim();
if (restrictionKey.endsWith(":conditional")) {
int idx = t.indexOf('@');
if (idx >= 0) {
t = t.substring(0, idx).trim();
}
}
if ( "left_turn".equals( t ) )
{
if ("left_turn".equals(t)) {
return a < -5. && a > -175.;
}
if ( "right_turn".equals( t ) )
{
if ("right_turn".equals(t)) {
return a > 5. && a < 175.;
}
if ( "straight_on".equals( t ) )
{
if ("straight_on".equals(t)) {
return a > -85. && a < 85.;
}
if ( "u_turn".equals( t ) )
{
return a < - 95. || a > 95.;
if ("u_turn".equals(t)) {
return a < -95. || a > 95.;
}
return "entry".equals( t ) || "exit".equals( t );
return "entry".equals(t) || "exit".equals(t);
}
private static String unifyName( String name )
{
synchronized( names )
{
private static String unifyName(String name) {
synchronized (names) {
String n = names.get(name);
if ( n == null )
{
names.put( name, name );
if (n == null) {
names.put(name, name);
n = name;
}
return n;
}
}
public static void dumpBadTRs()
{
try( BufferedWriter bw = new BufferedWriter( new FileWriter( "badtrs.txt" ) ) )
{
for( Long id : badTRs )
{
bw.write( "" + id + " 26\n" );
public static void dumpBadTRs() {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("badtrs.txt"))) {
for (Long id : badTRs) {
bw.write("" + id + " 26\n");
}
}
catch( IOException ioe )
{
throw new RuntimeException( ioe );
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public RestrictionData( DataInputStream di ) throws Exception
{
restrictionKey = unifyName( di.readUTF() );
restriction = unifyName( di.readUTF() );
public RestrictionData(DataInputStream di) throws Exception {
restrictionKey = unifyName(di.readUTF());
restriction = unifyName(di.readUTF());
exceptions = di.readShort();
fromWid = readId( di );
toWid = readId( di );
viaNid = readId( di );
fromWid = readId(di);
toWid = readId(di);
viaNid = readId(di);
}
public void writeTo( DataOutputStream dos ) throws Exception
{
dos.writeUTF( restrictionKey );
dos.writeUTF( restriction );
dos.writeShort( exceptions );
writeId( dos, fromWid );
writeId( dos, toWid );
writeId( dos, viaNid );
public void writeTo(DataOutputStream dos) throws Exception {
dos.writeUTF(restrictionKey);
dos.writeUTF(restriction);
dos.writeShort(exceptions);
writeId(dos, fromWid);
writeId(dos, toWid);
writeId(dos, viaNid);
}
}

View file

@ -1,195 +1,166 @@
package btools.mapcreator;
/**
* 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
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class SrtmData
{
private SrtmRaster raster;
public SrtmData( File file ) throws Exception
{
raster = new SrtmRaster();
ZipInputStream zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( file ) ) );
try
{
for ( ;; )
{
ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".asc" ) )
{
readFromStream( zis );
return;
}
}
}
finally
{
zis.close();
}
}
public SrtmRaster getRaster()
{
return raster;
}
private String secondToken( String s )
{
StringTokenizer tk = new StringTokenizer( s, " " );
tk.nextToken();
return tk.nextToken();
}
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 )
raster.ncols = Integer.parseInt( secondToken( line ) );
else if ( linenr == 2 )
raster.nrows = Integer.parseInt( secondToken( line ) );
else if ( linenr == 3 )
raster.xllcorner = Double.parseDouble( secondToken( line ) );
else if ( linenr == 4 )
raster.yllcorner = Double.parseDouble( secondToken( line ) );
else if ( linenr == 5 )
raster.cellsize = Double.parseDouble( secondToken( line ) );
else if ( linenr == 6 )
{
// nodata ignored here ( < -250 assumed nodata... )
// raster.noDataValue = Short.parseShort( secondToken( line ) );
raster.eval_array = new short[raster.ncols * raster.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 < -250 ? Short.MIN_VALUE : (short) (n);
raster.eval_array[row * raster.ncols + col] = val;
if ( ++col == raster.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;
}
}
br.close();
}
public static void main( String[] args ) throws Exception
{
String fromDir = args[0];
String toDir = args[1];
File[] files = new File( fromDir ).listFiles();
for( File f : files )
{
if ( !f.getName().endsWith( ".zip" ) )
{
continue;
}
System.out.println( "*** reading: " + f );
long t0 = System.currentTimeMillis();
SrtmRaster raster = new SrtmData( f ).getRaster();
long t1 = System.currentTimeMillis();
String name = f.getName();
long zipTime = t1-t0;
File fbef = new File( new File( toDir ), name.substring( 0, name.length()-3 ) + "bef" );
System.out.println( "recoding: " + f + " to " + fbef );
OutputStream osbef = new BufferedOutputStream( new FileOutputStream( fbef ) );
new RasterCoder().encodeRaster( raster, osbef );
osbef.close();
System.out.println( "*** re-reading: " + fbef );
long t2 = System.currentTimeMillis();
InputStream isc = new BufferedInputStream( new FileInputStream( fbef ) );
SrtmRaster raster2 = new RasterCoder().decodeRaster( isc );
isc.close();
long t3 = System.currentTimeMillis();
long befTime = t3-t2;
System.out.println( "*** zip-time: " + zipTime + "*** bef-time: " + befTime );
String s1 = raster.toString();
String s2 = raster2.toString();
if ( !s1.equals( s2 ) )
{
throw new IllegalArgumentException( "missmatch: " + s1 + "<--->" + s2 );
}
int cols = raster.ncols;
int rows = raster.nrows;
for( int c = 0; c < cols; c++ )
{
for( int r = 0; r < rows; r++ )
{
int idx = r * cols + c;
if ( raster.eval_array[idx] != raster2.eval_array[idx] )
{
throw new IllegalArgumentException( "missmatch: at " + c + "," + r + ": " + raster.eval_array[idx] + "<--->" + raster2.eval_array[idx] );
}
}
}
}
}
}
package btools.mapcreator;
/**
* This is a wrapper for a 5*5 degree srtm file in ascii/zip-format
* <p>
* - filter out unused nodes according to the way file
* - enhance with SRTM elevation data
* - split further in smaller (5*5 degree) tiles
*
* @author ab
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class SrtmData {
private SrtmRaster raster;
public SrtmData(File file) throws Exception {
raster = new SrtmRaster();
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
try {
for (; ; ) {
ZipEntry ze = zis.getNextEntry();
if (ze.getName().endsWith(".asc")) {
readFromStream(zis);
return;
}
}
} finally {
zis.close();
}
}
public SrtmRaster getRaster() {
return raster;
}
private String secondToken(String s) {
StringTokenizer tk = new StringTokenizer(s, " ");
tk.nextToken();
return tk.nextToken();
}
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)
raster.ncols = Integer.parseInt(secondToken(line));
else if (linenr == 2)
raster.nrows = Integer.parseInt(secondToken(line));
else if (linenr == 3)
raster.xllcorner = Double.parseDouble(secondToken(line));
else if (linenr == 4)
raster.yllcorner = Double.parseDouble(secondToken(line));
else if (linenr == 5)
raster.cellsize = Double.parseDouble(secondToken(line));
else if (linenr == 6) {
// nodata ignored here ( < -250 assumed nodata... )
// raster.noDataValue = Short.parseShort( secondToken( line ) );
raster.eval_array = new short[raster.ncols * raster.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 < -250 ? Short.MIN_VALUE : (short) (n);
raster.eval_array[row * raster.ncols + col] = val;
if (++col == raster.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;
}
}
br.close();
}
public static void main(String[] args) throws Exception {
String fromDir = args[0];
String toDir = args[1];
File[] files = new File(fromDir).listFiles();
for (File f : files) {
if (!f.getName().endsWith(".zip")) {
continue;
}
System.out.println("*** reading: " + f);
long t0 = System.currentTimeMillis();
SrtmRaster raster = new SrtmData(f).getRaster();
long t1 = System.currentTimeMillis();
String name = f.getName();
long zipTime = t1 - t0;
File fbef = new File(new File(toDir), name.substring(0, name.length() - 3) + "bef");
System.out.println("recoding: " + f + " to " + fbef);
OutputStream osbef = new BufferedOutputStream(new FileOutputStream(fbef));
new RasterCoder().encodeRaster(raster, osbef);
osbef.close();
System.out.println("*** re-reading: " + fbef);
long t2 = System.currentTimeMillis();
InputStream isc = new BufferedInputStream(new FileInputStream(fbef));
SrtmRaster raster2 = new RasterCoder().decodeRaster(isc);
isc.close();
long t3 = System.currentTimeMillis();
long befTime = t3 - t2;
System.out.println("*** zip-time: " + zipTime + "*** bef-time: " + befTime);
String s1 = raster.toString();
String s2 = raster2.toString();
if (!s1.equals(s2)) {
throw new IllegalArgumentException("missmatch: " + s1 + "<--->" + s2);
}
int cols = raster.ncols;
int rows = raster.nrows;
for (int c = 0; c < cols; c++) {
for (int r = 0; r < rows; r++) {
int idx = r * cols + c;
if (raster.eval_array[idx] != raster2.eval_array[idx]) {
throw new IllegalArgumentException("missmatch: at " + c + "," + r + ": " + raster.eval_array[idx] + "<--->" + raster2.eval_array[idx]);
}
}
}
}
}
}

View file

@ -7,8 +7,7 @@ import btools.util.ReducedMedianFilter;
*
* @author ab
*/
public class SrtmRaster
{
public class SrtmRaster {
public int ncols;
public int nrows;
public boolean halfcol;
@ -22,99 +21,93 @@ public class SrtmRaster
private boolean missingData = false;
public short getElevation( int ilon, int ilat )
{
public short getElevation(int ilon, int ilat) {
double lon = ilon / 1000000. - 180.;
double lat = ilat / 1000000. - 90.;
if ( usingWeights )
{
return getElevationFromShiftWeights( lon, lat );
if (usingWeights) {
return getElevationFromShiftWeights(lon, lat);
}
// no weights calculated, use 2d linear interpolation
double dcol = (lon - xllcorner)/cellsize -0.5;
double drow = (lat - yllcorner)/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;
double dcol = (lon - xllcorner) / cellsize - 0.5;
double drow = (lat - yllcorner) / 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;
// System.out.println( "wrow=" + wrow + " wcol=" + wcol + " row=" + row + " col=" + col );
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);
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);
// System.out.println( "eval=" + eval );
return missingData ? Short.MIN_VALUE : (short)(eval*4);
return missingData ? Short.MIN_VALUE : (short) (eval * 4);
}
private short get( int r, int c )
{
short e = eval_array[ (nrows-1-r)*ncols + c ];
if ( e == Short.MIN_VALUE ) missingData = true;
private short get(int r, int c) {
short e = eval_array[(nrows - 1 - r) * ncols + c];
if (e == Short.MIN_VALUE) missingData = true;
return e;
}
private short getElevationFromShiftWeights( double lon, double lat )
{
private short getElevationFromShiftWeights(double lon, double lat) {
// calc lat-idx and -weight
double alat = lat < 0. ? - lat : lat;
double alat = lat < 0. ? -lat : lat;
alat /= 5.;
int latIdx = (int)alat;
int latIdx = (int) alat;
double wlat = alat - latIdx;
double dcol = (lon - xllcorner)/cellsize;
double drow = (lat - yllcorner)/cellsize;
int row = (int)drow;
int col = (int)dcol;
double dcol = (lon - xllcorner) / cellsize;
double drow = (lat - yllcorner) / cellsize;
int row = (int) drow;
int col = (int) dcol;
double dgx = (dcol-col)*gridSteps;
double dgy = (drow-row)*gridSteps;
double dgx = (dcol - col) * gridSteps;
double dgy = (drow - row) * gridSteps;
// System.out.println( "wrow=" + wrow + " wcol=" + wcol + " row=" + row + " col=" + col );
int gx = (int)(dgx);
int gy = (int)(dgy);
int gx = (int) (dgx);
int gy = (int) (dgy);
double wx = dgx-gx;
double wy = dgy-gy;
double wx = dgx - gx;
double wy = dgy - gy;
double w00 = (1.-wx)*(1.-wy);
double w01 = (1.-wx)*( wy);
double w10 = ( wx)*(1.-wy);
double w11 = ( wx)*( wy);
double w00 = (1. - wx) * (1. - wy);
double w01 = (1. - wx) * (wy);
double w10 = (wx) * (1. - wy);
double w11 = (wx) * (wy);
Weights[][] w0 = getWeights( latIdx );
Weights[][] w1 = getWeights( latIdx+1 );
Weights[][] w0 = getWeights(latIdx);
Weights[][] w1 = getWeights(latIdx + 1);
missingData = false;
double m0 = w00*getElevation( w0[gx ][gy ], row, col )
+ w01*getElevation( w0[gx ][gy+1], row, col )
+ w10*getElevation( w0[gx+1][gy ], row, col )
+ w11*getElevation( w0[gx+1][gy+1], row, col );
double m1 = w00*getElevation( w1[gx ][gy ], row, col )
+ w01*getElevation( w1[gx ][gy+1], row, col )
+ w10*getElevation( w1[gx+1][gy ], row, col )
+ w11*getElevation( w1[gx+1][gy+1], row, col );
double m0 = w00 * getElevation(w0[gx][gy], row, col)
+ w01 * getElevation(w0[gx][gy + 1], row, col)
+ w10 * getElevation(w0[gx + 1][gy], row, col)
+ w11 * getElevation(w0[gx + 1][gy + 1], row, col);
double m1 = w00 * getElevation(w1[gx][gy], row, col)
+ w01 * getElevation(w1[gx][gy + 1], row, col)
+ w10 * getElevation(w1[gx + 1][gy], row, col)
+ w11 * getElevation(w1[gx + 1][gy + 1], row, col);
if ( missingData ) return Short.MIN_VALUE;
double m = (1.-wlat) * m0 + wlat * m1;
return (short)(m * 2);
if (missingData) return Short.MIN_VALUE;
double m = (1. - wlat) * m0 + wlat * m1;
return (short) (m * 2);
}
private ReducedMedianFilter rmf = new ReducedMedianFilter( 256 );
private ReducedMedianFilter rmf = new ReducedMedianFilter(256);
private double getElevation( Weights w, int row, int col )
{
if ( missingData )
{
private double getElevation(Weights w, int row, int col) {
if (missingData) {
return 0.;
}
int nx = w.nx;
@ -126,64 +119,53 @@ public class SrtmRaster
rmf.reset();
for( int ix = 0; ix < nx; ix ++ )
{
for( int iy = 0; iy < ny; iy ++ )
{
short val = get( row + iy - my, col + ix - mx );
rmf.addSample( w.getWeight( ix, iy ), val );
for (int ix = 0; ix < nx; ix++) {
for (int iy = 0; iy < ny; iy++) {
short val = get(row + iy - my, col + ix - mx);
rmf.addSample(w.getWeight(ix, iy), val);
}
}
return missingData ? 0. : rmf.calcEdgeReducedMedian( filterCenterFraction );
return missingData ? 0. : rmf.calcEdgeReducedMedian(filterCenterFraction);
}
private static class Weights
{
private static class Weights {
int nx;
int ny;
double[] weights;
long total = 0;
Weights( int nx, int ny )
{
Weights(int nx, int ny) {
this.nx = nx;
this.ny = ny;
weights = new double[nx*ny];
weights = new double[nx * ny];
}
void inc( int ix, int iy )
{
weights[ iy*nx + ix ] += 1.;
void inc(int ix, int iy) {
weights[iy * nx + ix] += 1.;
total++;
}
void normalize( boolean verbose )
{
for( int iy =0; iy < ny; iy++ )
{
void normalize(boolean verbose) {
for (int iy = 0; iy < ny; iy++) {
StringBuilder sb = verbose ? new StringBuilder() : null;
for( int ix =0; ix < nx; ix++ )
{
weights[ iy*nx + ix ] /= total;
if ( sb != null )
{
int iweight = (int)(1000*weights[ iy*nx + ix ] + 0.5 );
for (int ix = 0; ix < nx; ix++) {
weights[iy * nx + ix] /= total;
if (sb != null) {
int iweight = (int) (1000 * weights[iy * nx + ix] + 0.5);
String sval = " " + iweight;
sb.append( sval.substring( sval.length() - 4 ) );
sb.append(sval.substring(sval.length() - 4));
}
}
if ( sb != null )
{
System.out.println( sb );
if (sb != null) {
System.out.println(sb);
System.out.println();
}
}
}
double getWeight( int ix, int iy )
{
return weights[ iy*nx + ix ];
double getWeight(int ix, int iy) {
return weights[iy * nx + ix];
}
}
@ -193,19 +175,16 @@ public class SrtmRaster
private static double filterCenterFraction = 0.2;
private static double filterDiscRadius = 4.999; // in pixels
static
{
String sRadius = System.getProperty( "filterDiscRadius" );
if ( sRadius != null && sRadius.length() > 0 )
{
filterDiscRadius = Integer.parseInt( sRadius );
System.out.println( "using filterDiscRadius = " + filterDiscRadius );
static {
String sRadius = System.getProperty("filterDiscRadius");
if (sRadius != null && sRadius.length() > 0) {
filterDiscRadius = Integer.parseInt(sRadius);
System.out.println("using filterDiscRadius = " + filterDiscRadius);
}
String sFraction = System.getProperty( "filterCenterFraction" );
if ( sFraction != null && sFraction.length() > 0 )
{
filterCenterFraction = Integer.parseInt( sFraction ) / 100.;
System.out.println( "using filterCenterFraction = " + filterCenterFraction );
String sFraction = System.getProperty("filterCenterFraction");
if (sFraction != null && sFraction.length() > 0) {
filterCenterFraction = Integer.parseInt(sFraction) / 100.;
System.out.println("using filterCenterFraction = " + filterCenterFraction);
}
}
@ -213,82 +192,73 @@ public class SrtmRaster
// calculate interpolation weights from the overlap of a probe disc of given radius at given latitude
// ( latIndex = 0 -> 0 deg, latIndex = 16 -> 80 degree)
private static Weights[][] getWeights( int latIndex )
{
private static Weights[][] getWeights(int latIndex) {
int idx = latIndex < 16 ? latIndex : 16;
Weights[][] res = allShiftWeights[idx];
if ( res == null )
{
res = calcWeights( idx );
if (res == null) {
res = calcWeights(idx);
allShiftWeights[idx] = res;
}
return res;
}
private static Weights[][] calcWeights( int latIndex )
{
double coslat = Math.cos( latIndex * 5. / 57.3 );
private static Weights[][] calcWeights(int latIndex) {
double coslat = Math.cos(latIndex * 5. / 57.3);
// radius in pixel units
double ry = filterDiscRadius;
double rx = ry / coslat;
// gridsize is 2*radius + 1 cell
int nx = ((int)rx) *2 + 3;
int ny = ((int)ry) *2 + 3;
int nx = ((int) rx) * 2 + 3;
int ny = ((int) ry) * 2 + 3;
System.out.println( "nx="+ nx + " ny=" + ny );
System.out.println("nx=" + nx + " ny=" + ny);
int mx = nx / 2; // mean pixels
int my = ny / 2;
// create a matrix for the relative intergrid-position
Weights[][] shiftWeights = new Weights[gridSteps+1][];
Weights[][] shiftWeights = new Weights[gridSteps + 1][];
// loop the intergrid-position
for( int gx=0; gx<=gridSteps; gx++ )
{
shiftWeights[gx] = new Weights[gridSteps+1];
double x0 = mx + ( (double)gx ) / gridSteps;
for (int gx = 0; gx <= gridSteps; gx++) {
shiftWeights[gx] = new Weights[gridSteps + 1];
double x0 = mx + ((double) gx) / gridSteps;
for( int gy=0; gy<=gridSteps; gy++ )
{
double y0 = my + ( (double)gy ) / gridSteps;
for (int gy = 0; gy <= gridSteps; gy++) {
double y0 = my + ((double) gy) / gridSteps;
// create the weight-matrix
Weights weights = new Weights( nx, ny );
Weights weights = new Weights(nx, ny);
shiftWeights[gx][gy] = weights;
double sampleStep = 0.001;
for( double x = -1. + sampleStep/2.; x < 1.; x += sampleStep )
{
double mx2 = 1. - x*x;
for (double x = -1. + sampleStep / 2.; x < 1.; x += sampleStep) {
double mx2 = 1. - x * x;
int x_idx = (int)(x0 + x*rx);
int x_idx = (int) (x0 + x * rx);
for( double y = -1. + sampleStep/2.; y < 1.; y += sampleStep )
{
if ( y*y > mx2 )
{
for (double y = -1. + sampleStep / 2.; y < 1.; y += sampleStep) {
if (y * y > mx2) {
continue;
}
// we are in the ellipse, see what pixel we are on
int y_idx = (int)(y0 + y*ry);
weights.inc( x_idx, y_idx );
int y_idx = (int) (y0 + y * ry);
weights.inc(x_idx, y_idx);
}
}
weights.normalize( true );
weights.normalize(true);
}
}
return shiftWeights;
}
@Override
public String toString()
{
public String toString() {
return ncols + "," + nrows + "," + halfcol + "," + xllcorner + "," + yllcorner + "," + cellsize + "," + noDataValue + "," + usingWeights;
}
}

View file

@ -1,112 +1,98 @@
package btools.mapcreator;
import java.io.File;
import btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap;
/**
* 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 DenseLongMap tileIndexMap;
public static void main(String[] args) throws Exception
{
System.out.println("*** WayCutter: Soft-Cut way-data into tiles");
if (args.length != 3)
{
System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out>" );
return;
}
new WayCutter().process( new File( args[0] ), new File( args[1] ), new File( args[2] ) );
}
public void process( File nodeTilesIn, File wayFileIn, File wayTilesOut ) throws Exception
{
init( wayTilesOut );
new NodeIterator( this, false ).processDir( nodeTilesIn, ".tlf" );
// *** finally process the way-file, cutting into pieces
new WayIterator( this, true ).processFile( wayFileIn );
finish();
}
public void init( File wayTilesOut ) throws Exception
{
this.outTileDir = wayTilesOut;
// *** read all nodes into tileIndexMap
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
}
public void finish() throws Exception
{
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
{
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 ) );
}
}
public int getTileIndexForNid( long nid )
{
return tileIndexMap.getInt( nid );
}
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;
}
public 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";
}
}
package btools.mapcreator;
import java.io.File;
import btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap;
/**
* WayCutter does 2 step in map-processing:
* <p>
* - cut the way file into 45*30 - pieces
* - enrich ways with relation information
*
* @author ab
*/
public class WayCutter extends MapCreatorBase {
private DenseLongMap tileIndexMap;
public static void main(String[] args) throws Exception {
System.out.println("*** WayCutter: Soft-Cut way-data into tiles");
if (args.length != 3) {
System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out>");
return;
}
new WayCutter().process(new File(args[0]), new File(args[1]), new File(args[2]));
}
public void process(File nodeTilesIn, File wayFileIn, File wayTilesOut) throws Exception {
init(wayTilesOut);
new NodeIterator(this, false).processDir(nodeTilesIn, ".tlf");
// *** finally process the way-file, cutting into pieces
new WayIterator(this, true).processFile(wayFileIn);
finish();
}
public void init(File wayTilesOut) throws Exception {
this.outTileDir = wayTilesOut;
// *** read all nodes into tileIndexMap
tileIndexMap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap() : new TinyDenseLongMap();
}
public void finish() throws Exception {
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 {
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));
}
}
public int getTileIndexForNid(long nid) {
return tileIndexMap.getInt(nid);
}
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;
}
public 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

@ -1,212 +1,182 @@
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 btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap;
/**
* 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 RelationMerger relMerger;
public NodeFilter nodeFilter;
public NodeCutter nodeCutter;
public RestrictionCutter5 restrictionCutter5;
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 boolean wayFileStart( File wayfile ) throws Exception
{
// read corresponding node-file into tileIndexMap
String name = wayfile.getName();
String nodefilename = name.substring( 0, name.length()-3 ) + "ntl";
File nodefile = new File( nodeTilesIn, nodefilename );
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap();
lonoffset = -1;
latoffset = -1;
if ( nodeCutter != null )
{
nodeCutter.nodeFileStart( null );
}
new NodeIterator( this, nodeCutter != null ).processFile( nodefile );
if ( restrictionCutter5 != null )
{
String resfilename = name.substring( 0, name.length()-3 ) + "rtl";
File resfile = new File( "restrictions", resfilename );
if ( resfile.exists() )
{
// read restrictions for nodes in nodesMap
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( resfile ) ) );
int ntr = 0;
try
{
for(;;)
{
RestrictionData res = new RestrictionData( di );
restrictionCutter5.nextRestriction( res );
ntr++;
}
}
catch( EOFException eof )
{
di.close();
}
System.out.println( "read " + ntr + " turn-restrictions" );
}
}
return true;
}
@Override
public void nextNode( NodeData n ) throws Exception
{
if ( nodeFilter != null )
{
if ( !nodeFilter.isRelevant( n ) )
{
return;
}
}
if ( nodeCutter != null )
{
nodeCutter.nextNode( n );
}
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;
}
if ( relMerger != null )
{
relMerger.nextWay( data );
}
// 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();
if ( nodeCutter != null )
{
nodeCutter.nodeFileEnd( null );
}
if ( restrictionCutter5 != null )
{
restrictionCutter5.finish();
}
}
public int getTileIndexForNid( long nid )
{
return tileIndexMap.getInt( nid );
}
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";
}
}
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 btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap;
/**
* WayCutter5 does 2 step in map-processing:
* <p>
* - 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 RelationMerger relMerger;
public NodeFilter nodeFilter;
public NodeCutter nodeCutter;
public RestrictionCutter5 restrictionCutter5;
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 boolean wayFileStart(File wayfile) throws Exception {
// read corresponding node-file into tileIndexMap
String name = wayfile.getName();
String nodefilename = name.substring(0, name.length() - 3) + "ntl";
File nodefile = new File(nodeTilesIn, nodefilename);
tileIndexMap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap() : new TinyDenseLongMap();
lonoffset = -1;
latoffset = -1;
if (nodeCutter != null) {
nodeCutter.nodeFileStart(null);
}
new NodeIterator(this, nodeCutter != null).processFile(nodefile);
if (restrictionCutter5 != null) {
String resfilename = name.substring(0, name.length() - 3) + "rtl";
File resfile = new File("restrictions", resfilename);
if (resfile.exists()) {
// read restrictions for nodes in nodesMap
DataInputStream di = new DataInputStream(new BufferedInputStream(new FileInputStream(resfile)));
int ntr = 0;
try {
for (; ; ) {
RestrictionData res = new RestrictionData(di);
restrictionCutter5.nextRestriction(res);
ntr++;
}
} catch (EOFException eof) {
di.close();
}
System.out.println("read " + ntr + " turn-restrictions");
}
}
return true;
}
@Override
public void nextNode(NodeData n) throws Exception {
if (nodeFilter != null) {
if (!nodeFilter.isRelevant(n)) {
return;
}
}
if (nodeCutter != null) {
nodeCutter.nextNode(n);
}
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;
}
if (relMerger != null) {
relMerger.nextWay(data);
}
// 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();
if (nodeCutter != null) {
nodeCutter.nodeFileEnd(null);
}
if (restrictionCutter5 != null) {
restrictionCutter5.finish();
}
}
public int getTileIndexForNid(long nid) {
return tileIndexMap.getInt(nid);
}
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

@ -1,55 +1,51 @@
package btools.mapcreator;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import btools.util.LongList;
/**
* Container for waydata on the preprocessor level
*
* @author ab
*/
public class WayData extends MapCreatorBase
{
public long wid;
public byte[] 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) ;
int dlen = di.readByte(); description = new byte[dlen]; di.readFully( description );
for (;;)
{
long nid = readId( di );
if ( nid == -1 ) break;
nodes.add( nid );
}
}
public void writeTo( DataOutputStream dos ) throws Exception
{
writeId( dos, wid );
dos.writeByte( description.length ); dos.write( description );
int size = nodes.size();
for( int i=0; i < size; i++ )
{
writeId( dos, nodes.get( i ) );
}
writeId( dos, -1 ); // stopbyte
}
}
package btools.mapcreator;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import btools.util.LongList;
/**
* Container for waydata on the preprocessor level
*
* @author ab
*/
public class WayData extends MapCreatorBase {
public long wid;
public byte[] 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);
int dlen = di.readByte();
description = new byte[dlen];
di.readFully(description);
for (; ; ) {
long nid = readId(di);
if (nid == -1) break;
nodes.add(nid);
}
}
public void writeTo(DataOutputStream dos) throws Exception {
writeId(dos, wid);
dos.writeByte(description.length);
dos.write(description);
int size = nodes.size();
for (int i = 0; i < size; i++) {
writeId(dos, nodes.get(i));
}
writeId(dos, -1); // stopbyte
}
}

View file

@ -1,80 +1,66 @@
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
/**
* 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;
private boolean descendingSize;
public WayIterator( WayListener wayListener, boolean deleteAfterReading )
{
listener = wayListener;
delete = deleteAfterReading;
}
public WayIterator( WayListener wayListener, boolean deleteAfterReading, boolean descendingSize )
{
this( wayListener, deleteAfterReading );
this.descendingSize = descendingSize;
}
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 = descendingSize ? af[af.length -1 - i] : af[i];
if ( wayfile.getName().endsWith( inSuffix ) )
{
processFile( wayfile );
}
}
}
public void processFile(File wayfile) throws Exception
{
System.out.println( "*** WayIterator reading: " + wayfile );
if ( !listener.wayFileStart( wayfile ) )
{
return;
}
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();
}
}
}
package btools.mapcreator;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
/**
* 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;
private boolean descendingSize;
public WayIterator(WayListener wayListener, boolean deleteAfterReading) {
listener = wayListener;
delete = deleteAfterReading;
}
public WayIterator(WayListener wayListener, boolean deleteAfterReading, boolean descendingSize) {
this(wayListener, deleteAfterReading);
this.descendingSize = descendingSize;
}
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 = descendingSize ? af[af.length - 1 - i] : af[i];
if (wayfile.getName().endsWith(inSuffix)) {
processFile(wayfile);
}
}
}
public void processFile(File wayfile) throws Exception {
System.out.println("*** WayIterator reading: " + wayfile);
if (!listener.wayFileStart(wayfile)) {
return;
}
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

@ -32,8 +32,7 @@ import btools.util.LazyArrayOfLists;
*
* @author ab
*/
public class WayLinker extends MapCreatorBase implements Runnable
{
public class WayLinker extends MapCreatorBase implements Runnable {
private File nodeTilesIn;
private File wayTilesIn;
private File trafficTilesIn;
@ -70,108 +69,92 @@ public class WayLinker extends MapCreatorBase implements Runnable
private boolean isSlave;
private ThreadController tc;
public static final class ThreadController
{
public static final class ThreadController {
long maxFileSize = 0L;
long currentSlaveSize;
long currentSlaveSize;
long currentMasterSize = 2000000000L;
synchronized boolean setCurrentMasterSize( long size )
{
try
{
if ( size <= currentSlaveSize )
{
synchronized boolean setCurrentMasterSize(long size) {
try {
if (size <= currentSlaveSize) {
maxFileSize = Long.MAX_VALUE;
return false;
}
currentMasterSize = size;
if ( maxFileSize == 0L )
{
if (maxFileSize == 0L) {
maxFileSize = size;
}
return true;
}
finally
{
} finally {
notify();
}
}
synchronized boolean setCurrentSlaveSize( long size ) throws Exception
{
if ( size >= currentMasterSize )
{
synchronized boolean setCurrentSlaveSize(long size) throws Exception {
if (size >= currentMasterSize) {
return false;
}
while ( size + currentMasterSize + 50000000L > maxFileSize )
{
System.out.println( "****** slave thread waiting for permission to process file of size " + size
+ " currentMaster=" + currentMasterSize + " maxFileSize=" + maxFileSize );
wait( 10000 );
while (size + currentMasterSize + 50000000L > maxFileSize) {
System.out.println("****** slave thread waiting for permission to process file of size " + size
+ " currentMaster=" + currentMasterSize + " maxFileSize=" + maxFileSize);
wait(10000);
}
currentSlaveSize = size;
return true;
}
}
private void reset()
{
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 region of an OSM map for routing" );
if ( args.length != 8 )
{
public static void main(String[] args) throws Exception {
System.out.println("*** WayLinker: Format a region of an OSM map for routing");
if (args.length != 8) {
System.out
.println( "usage: java WayLinker <node-tiles-in> <way-tiles-in> <bordernodes> <restrictions> <lookup-file> <profile-file> <data-tiles-out> <data-tiles-suffix> " );
.println("usage: java WayLinker <node-tiles-in> <way-tiles-in> <bordernodes> <restrictions> <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] ), new File(
args[6] ), args[7] );
System.out.println( "dumping bad TRs" );
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]), new File(
args[6]), args[7]);
System.out.println("dumping bad TRs");
RestrictionData.dumpBadTRs();
}
public void process( File nodeTilesIn, File wayTilesIn, File borderFileIn, File restrictionsFileIn, File lookupFile, File profileFile, File dataTilesOut,
String dataTilesSuffix ) throws Exception
{
public void process(File nodeTilesIn, File wayTilesIn, File borderFileIn, File restrictionsFileIn, File lookupFile, File profileFile, File dataTilesOut,
String dataTilesSuffix) throws Exception {
WayLinker master = new WayLinker();
WayLinker slave = new WayLinker();
slave.isSlave = true;
master.isSlave = false;
ThreadController tc = new ThreadController();
slave.tc = tc;
master.tc = tc;
master._process( nodeTilesIn, wayTilesIn, borderFileIn, restrictionsFileIn, lookupFile, profileFile, dataTilesOut, dataTilesSuffix );
slave._process( nodeTilesIn, wayTilesIn, borderFileIn, restrictionsFileIn, lookupFile, profileFile, dataTilesOut, dataTilesSuffix );
Thread m = new Thread( master );
Thread s = new Thread( slave );
master._process(nodeTilesIn, wayTilesIn, borderFileIn, restrictionsFileIn, lookupFile, profileFile, dataTilesOut, dataTilesSuffix);
slave._process(nodeTilesIn, wayTilesIn, borderFileIn, restrictionsFileIn, lookupFile, profileFile, dataTilesOut, dataTilesSuffix);
Thread m = new Thread(master);
Thread s = new Thread(slave);
m.start();
s.start();
m.join();
s.join();
}
private void _process( File nodeTilesIn, File wayTilesIn, File borderFileIn, File restrictionsFileIn, File lookupFile, File profileFile, File dataTilesOut,
String dataTilesSuffix ) throws Exception
{
private void _process(File nodeTilesIn, File wayTilesIn, File borderFileIn, File restrictionsFileIn, File lookupFile, File profileFile, File dataTilesOut,
String dataTilesSuffix) throws Exception {
this.nodeTilesIn = nodeTilesIn;
this.wayTilesIn = wayTilesIn;
this.trafficTilesIn = new File( "../traffic" );
this.trafficTilesIn = new File("../traffic");
this.dataTilesOut = dataTilesOut;
this.borderFileIn = borderFileIn;
this.restrictionsFileIn = restrictionsFileIn;
@ -180,114 +163,92 @@ public class WayLinker extends MapCreatorBase implements Runnable
BExpressionMetaData meta = new BExpressionMetaData();
// read lookup + profile for lookup-version + access-filter
expctxWay = new BExpressionContextWay( meta );
meta.readMetaData( lookupFile );
expctxWay = new BExpressionContextWay(meta);
meta.readMetaData(lookupFile);
lookupVersion = meta.lookupVersion;
lookupMinorVersion = meta.lookupMinorVersion;
expctxWay.parseFile( profileFile, "global" );
expctxWay.parseFile(profileFile, "global");
creationTimeStamp = System.currentTimeMillis();
abUnifier = new ByteArrayUnifier( 16384, false );
abUnifier = new ByteArrayUnifier(16384, false);
skipEncodingCheck = Boolean.getBoolean( "skipEncodingCheck" );
skipEncodingCheck = Boolean.getBoolean("skipEncodingCheck");
}
@Override
public void run()
{
try
{
public void run() {
try {
// then process all segments
new WayIterator( this, true, !isSlave ).processDir( wayTilesIn, ".wt5" );
}
catch( Exception e )
{
System.out.println( "******* thread (slave=" + isSlave + ") got Exception: " + e );
throw new RuntimeException( e );
}
finally
{
if (!isSlave)
{
tc.setCurrentMasterSize( 0L );
new WayIterator(this, true, !isSlave).processDir(wayTilesIn, ".wt5");
} catch (Exception e) {
System.out.println("******* thread (slave=" + isSlave + ") got Exception: " + e);
throw new RuntimeException(e);
} finally {
if (!isSlave) {
tc.setCurrentMasterSize(0L);
}
}
}
@Override
public boolean wayFileStart( File wayfile ) throws Exception
{
public boolean wayFileStart(File wayfile) throws Exception {
// master/slave logic:
// total memory size should stay below a maximum
// and no file should be processed twice
long filesize = wayfile.length();
long filesize = wayfile.length();
System.out.println( "**** wayFileStart() for isSlave=" + isSlave + " size=" + filesize );
System.out.println("**** wayFileStart() for isSlave=" + isSlave + " size=" + filesize);
if ( isSlave )
{
if ( !tc.setCurrentSlaveSize( filesize ) )
{
if (isSlave) {
if (!tc.setCurrentSlaveSize(filesize)) {
return false;
}
} else {
if (!tc.setCurrentMasterSize(filesize)) {
return false;
}
}
else
{
if ( !tc.setCurrentMasterSize( filesize ) )
{
return false;
}
}
File trafficFile = fileFromTemplate( wayfile, trafficTilesIn, "trf" );
File trafficFile = fileFromTemplate(wayfile, trafficTilesIn, "trf");
// process corresponding node-file, if any
File nodeFile = fileFromTemplate( wayfile, nodeTilesIn, "u5d" );
if ( nodeFile.exists() )
{
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 );
new NodeIterator(this, false).processFile(borderFileIn);
borderSet = new FrozenLongSet(borderSet);
// read this tile's nodes
readingBorder = false;
new NodeIterator( this, true ).processFile( nodeFile );
new NodeIterator(this, true).processFile(nodeFile);
// freeze the nodes-map
FrozenLongMap<OsmNodeP> nodesMapFrozen = new FrozenLongMap<OsmNodeP>( nodesMap );
FrozenLongMap<OsmNodeP> nodesMapFrozen = new FrozenLongMap<OsmNodeP>(nodesMap);
nodesMap = nodesMapFrozen;
File restrictionFile = fileFromTemplate( wayfile, new File( nodeTilesIn.getParentFile(), "restrictions55" ), "rt5" );
File restrictionFile = fileFromTemplate(wayfile, new File(nodeTilesIn.getParentFile(), "restrictions55"), "rt5");
// read restrictions for nodes in nodesMap
if ( restrictionFile.exists() )
{
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( restrictionFile ) ) );
if (restrictionFile.exists()) {
DataInputStream di = new DataInputStream(new BufferedInputStream(new FileInputStream(restrictionFile)));
int ntr = 0;
try
{
for(;;)
{
RestrictionData res = new RestrictionData( di );
OsmNodeP n = nodesMap.get( res.viaNid );
if ( n != null )
{
if ( ! ( n instanceof OsmNodePT ) )
{
n = new OsmNodePT( n );
nodesMap.put( res.viaNid, n );
try {
for (; ; ) {
RestrictionData res = new RestrictionData(di);
OsmNodeP n = nodesMap.get(res.viaNid);
if (n != null) {
if (!(n instanceof OsmNodePT)) {
n = new OsmNodePT(n);
nodesMap.put(res.viaNid, n);
}
OsmNodePT nt = (OsmNodePT) n;
res.viaLon = nt.ilon;
@ -297,55 +258,49 @@ public class WayLinker extends MapCreatorBase implements Runnable
ntr++;
}
}
}
catch( EOFException eof )
{
} catch (EOFException eof) {
di.close();
}
System.out.println( "read " + ntr + " turn-restrictions" );
System.out.println("read " + ntr + " turn-restrictions");
}
nodesList = nodesMapFrozen.getValueList();
}
// read a traffic-file, if any
if ( trafficFile.exists() )
{
trafficMap = new OsmTrafficMap( expctxWay );
trafficMap.loadAll( trafficFile, minLon, minLat, minLon + 5000000, minLat + 5000000, false );
if (trafficFile.exists()) {
trafficMap = new OsmTrafficMap(expctxWay);
trafficMap.loadAll(trafficFile, minLon, minLat, minLon + 5000000, minLat + 5000000, false);
}
return true;
}
@Override
public void nextNode( NodeData data ) throws Exception
{
OsmNodeP n = data.description == null ? new OsmNodeP() : new OsmNodePT( data.description );
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;
if ( readingBorder || ( !borderSet.contains( data.nid ) ) )
{
nodesMap.fastPut( data.nid, n );
if (readingBorder || (!borderSet.contains(data.nid))) {
nodesMap.fastPut(data.nid, n);
}
if ( readingBorder )
{
if (readingBorder) {
n.bits |= OsmNodeP.BORDER_BIT;
borderSet.fastAdd( data.nid );
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 )
int min_lon = (n.ilon / 5000000) * 5000000;
int min_lat = (n.ilat / 5000000) * 5000000;
if (minLon == -1)
minLon = min_lon;
if ( minLat == -1 )
if (minLat == -1)
minLat = min_lat;
if ( minLat != min_lat || minLon != min_lon )
throw new IllegalArgumentException( "inconsistent node: " + n.ilon + " " + n.ilat );
if (minLat != min_lat || minLon != min_lon)
throw new IllegalArgumentException("inconsistent node: " + n.ilon + " " + n.ilat);
}
// check if one of the nodes has a turn-restriction with
@ -354,39 +309,30 @@ public class WayLinker extends MapCreatorBase implements Runnable
// starts or ends at it's via node. However, we allow
// ways not ending at the via node, and in this case we take
// the leg according to the mapped direction
private void checkRestriction( OsmNodeP n1, OsmNodeP n2, WayData w )
{
checkRestriction( n1, n2, w, true );
checkRestriction( n2, n1, w, false );
private void checkRestriction(OsmNodeP n1, OsmNodeP n2, WayData w) {
checkRestriction(n1, n2, w, true);
checkRestriction(n2, n1, w, false);
}
private void checkRestriction( OsmNodeP n1, OsmNodeP n2, WayData w, boolean checkFrom )
{
private void checkRestriction(OsmNodeP n1, OsmNodeP n2, WayData w, boolean checkFrom) {
RestrictionData r = n2.getFirstRestriction();
while ( r != null )
{
if ( r.fromWid == w.wid )
{
if ( r.fromLon == 0 || checkFrom )
{
while (r != null) {
if (r.fromWid == w.wid) {
if (r.fromLon == 0 || checkFrom) {
r.fromLon = n1.ilon;
r.fromLat = n1.ilat;
n1.bits |= OsmNodeP.DP_SURVIVOR_BIT;
if ( !isEndNode( n2, w ) )
{
if (!isEndNode(n2, w)) {
r.badWayMatch = true;
}
}
}
if ( r.toWid == w.wid )
{
if ( r.toLon == 0 || !checkFrom )
{
if (r.toWid == w.wid) {
if (r.toLon == 0 || !checkFrom) {
r.toLon = n1.ilon;
r.toLat = n1.ilat;
n1.bits |= OsmNodeP.DP_SURVIVOR_BIT;
if ( !isEndNode( n2, w ) )
{
if (!isEndNode(n2, w)) {
r.badWayMatch = true;
}
}
@ -394,56 +340,50 @@ public class WayLinker extends MapCreatorBase implements Runnable
r = r.next;
}
}
private boolean isEndNode( OsmNodeP n, WayData w )
{
return n == nodesMap.get( w.nodes.get( 0 ) ) || n == nodesMap.get( w.nodes.get( w.nodes.size() - 1 ) );
private boolean isEndNode(OsmNodeP n, WayData w) {
return n == nodesMap.get(w.nodes.get(0)) || n == nodesMap.get(w.nodes.get(w.nodes.size() - 1));
}
@Override
public void nextWay( WayData way ) throws Exception
{
byte[] description = abUnifier.unify( way.description );
public void nextWay(WayData way) throws Exception {
byte[] description = abUnifier.unify(way.description);
// filter according to profile
expctxWay.evaluate( false, description );
expctxWay.evaluate(false, description);
boolean ok = expctxWay.getCostfactor() < 10000.;
expctxWay.evaluate( true, description );
expctxWay.evaluate(true, description);
ok |= expctxWay.getCostfactor() < 10000.;
if ( !ok )
if (!ok)
return;
byte wayBits = 0;
expctxWay.decode( description );
if ( !expctxWay.getBooleanLookupValue( "bridge" ) )
expctxWay.decode(description);
if (!expctxWay.getBooleanLookupValue("bridge"))
wayBits |= OsmNodeP.NO_BRIDGE_BIT;
if ( !expctxWay.getBooleanLookupValue( "tunnel" ) )
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 );
for (int i = 0; i < way.nodes.size(); i++) {
long nid = way.nodes.get(i);
n1 = n2;
n2 = nodesMap.get( nid );
n2 = nodesMap.get(nid);
if ( n1 != null && n2 != null && n1 != n2 )
{
checkRestriction( n1, n2, way );
OsmLinkP link = n2.createLink( n1 );
if (n1 != null && n2 != null && n1 != n2) {
checkRestriction(n1, n2, way);
OsmLinkP link = n2.createLink(n1);
link.descriptionBitmap = description;
if ( n1.ilon / cellsize != n2.ilon / cellsize || n1.ilat / cellsize != n2.ilat / cellsize )
{
if (n1.ilon / cellsize != n2.ilon / cellsize || n1.ilat / cellsize != n2.ilat / cellsize) {
n2.incWayCount(); // force first node after cell-change to be a
// network node
// network node
}
}
if ( n2 != null )
{
if (n2 != null) {
n2.bits |= wayBits;
n2.incWayCount();
}
@ -451,8 +391,7 @@ public class WayLinker extends MapCreatorBase implements Runnable
}
@Override
public void wayFileEnd( File wayfile ) throws Exception
{
public void wayFileEnd(File wayfile) throws Exception {
int ncaches = divisor * divisor;
int indexsize = ncaches * 4;
@ -466,126 +405,109 @@ public class WayLinker extends MapCreatorBase implements Runnable
int maxLat = minLat + 5000000;
// cleanup duplicate targets
for ( OsmNodeP n : nodesList )
{
if ( n == null || n.getFirstLink() == null || n.isTransferNode() )
for (OsmNodeP n : nodesList) {
if (n == null || n.getFirstLink() == null || n.isTransferNode())
continue;
n.checkDuplicateTargets();
}
// write segment data to individual files
{
int nLonSegs = ( maxLon - minLon ) / 1000000;
int nLatSegs = ( maxLat - minLat ) / 1000000;
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.getFirstLink() == null || n.isTransferNode() )
LazyArrayOfLists<OsmNodeP> seglists = new LazyArrayOfLists<OsmNodeP>(nLonSegs * nLatSegs);
for (OsmNodeP n : nodesList) {
if (n == null || n.getFirstLink() == null || n.isTransferNode())
continue;
if ( n.ilon < minLon || n.ilon >= maxLon || n.ilat < minLat || n.ilat >= maxLat )
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 lonIdx = (n.ilon - minLon) / 1000000;
int latIdx = (n.ilat - minLat) / 1000000;
int tileIndex = lonIdx * nLatSegs + latIdx;
seglists.getList( tileIndex ).add( n );
seglists.getList(tileIndex).add(n);
}
nodesList = null;
seglists.trimAll();
// open the output file
File outfile = fileFromTemplate( wayfile, dataTilesOut, dataTilesSuffix );
DataOutputStream os = createOutStream( outfile );
File outfile = fileFromTemplate(wayfile, dataTilesOut, dataTilesSuffix);
DataOutputStream os = createOutStream(outfile);
long[] fileIndex = new long[25];
int[] fileHeaderCrcs = new int[25];
// write 5*5 index dummy
for ( int i55 = 0; i55 < 25; i55++ )
{
os.writeLong( 0 );
for (int i55 = 0; i55 < 25; i55++) {
os.writeLong(0);
}
long filepos = 200L;
// sort further in 1/divisor-degree squares
for ( int lonIdx = 0; lonIdx < nLonSegs; lonIdx++ )
{
for ( int latIdx = 0; latIdx < nLatSegs; latIdx++ )
{
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 );
if (seglists.getSize(tileIndex) > 0) {
List<OsmNodeP> nlist = seglists.getList(tileIndex);
LazyArrayOfLists<OsmNodeP> subs = new LazyArrayOfLists<OsmNodeP>( ncaches );
LazyArrayOfLists<OsmNodeP> subs = new LazyArrayOfLists<OsmNodeP>(ncaches);
byte[][] subByteArrays = new byte[ncaches][];
for ( int ni = 0; ni < nlist.size(); ni++ )
{
OsmNodeP n = nlist.get( ni );
int subLonIdx = ( n.ilon - minLon ) / cellsize - divisor * lonIdx;
int subLatIdx = ( n.ilat - minLat ) / cellsize - divisor * latIdx;
for (int ni = 0; ni < nlist.size(); ni++) {
OsmNodeP n = nlist.get(ni);
int subLonIdx = (n.ilon - minLon) / cellsize - divisor * lonIdx;
int subLatIdx = (n.ilat - minLat) / cellsize - divisor * latIdx;
int si = subLatIdx * divisor + subLonIdx;
subs.getList( si ).add( n );
subs.getList(si).add(n);
}
subs.trimAll();
int[] posIdx = new int[ncaches];
int pos = indexsize;
for ( int si = 0; si < ncaches; si++ )
{
List<OsmNodeP> subList = subs.getList( si );
for (int si = 0; si < ncaches; si++) {
List<OsmNodeP> subList = subs.getList(si);
int size = subList.size();
if ( size > 0 )
{
OsmNodeP n0 = subList.get( 0 );
if (size > 0) {
OsmNodeP n0 = subList.get(0);
int lonIdxDiv = n0.ilon / cellsize;
int latIdxDiv = n0.ilat / cellsize;
MicroCache mc = new MicroCache2( size, abBuf2, lonIdxDiv, latIdxDiv, divisor );
MicroCache mc = new MicroCache2(size, abBuf2, lonIdxDiv, latIdxDiv, divisor);
// sort via treemap
TreeMap<Integer, OsmNodeP> sortedList = new TreeMap<Integer, OsmNodeP>();
for ( OsmNodeP n : subList )
{
for (OsmNodeP n : subList) {
long longId = n.getIdFromPos();
int shrinkid = mc.shrinkId( longId );
if ( mc.expandId( shrinkid ) != longId )
{
throw new IllegalArgumentException( "inconstistent shrinking: " + longId );
int shrinkid = mc.shrinkId(longId);
if (mc.expandId(shrinkid) != longId) {
throw new IllegalArgumentException("inconstistent shrinking: " + longId);
}
sortedList.put( Integer.valueOf( shrinkid ), n );
sortedList.put(Integer.valueOf(shrinkid), n);
}
for ( OsmNodeP n : sortedList.values() )
{
n.writeNodeData( mc, trafficMap );
for (OsmNodeP n : sortedList.values()) {
n.writeNodeData(mc, trafficMap);
}
if ( mc.getSize() > 0 )
{
if (mc.getSize() > 0) {
byte[] subBytes;
for ( ;; )
{
int len = mc.encodeMicroCache( abBuf1 );
for (; ; ) {
int len = mc.encodeMicroCache(abBuf1);
subBytes = new byte[len];
System.arraycopy( abBuf1, 0, subBytes, 0, len );
if ( skipEncodingCheck )
{
System.arraycopy(abBuf1, 0, subBytes, 0, len);
if (skipEncodingCheck) {
break;
}
// cross-check the encoding: re-instantiate the cache
MicroCache mc2 = new MicroCache2( new StatCoderContext( subBytes ), new DataBuffers( null ), lonIdxDiv, latIdxDiv, divisor, null, null );
MicroCache mc2 = new MicroCache2(new StatCoderContext(subBytes), new DataBuffers(null), lonIdxDiv, latIdxDiv, divisor, null, null);
// ..and check if still the same
String diffMessage = mc.compareWith( mc2 );
if ( diffMessage != null )
{
if ( MicroCache.debug )
throw new RuntimeException( "encoding crosscheck failed: " + diffMessage );
String diffMessage = mc.compareWith(mc2);
if (diffMessage != null) {
if (MicroCache.debug)
throw new RuntimeException("encoding crosscheck failed: " + diffMessage);
else
MicroCache.debug = true;
}
else
} else
break;
}
pos += subBytes.length + 4; // reserve 4 bytes for crc
@ -595,16 +517,14 @@ public class WayLinker extends MapCreatorBase implements Runnable
posIdx[si] = pos;
}
byte[] abSubIndex = compileSubFileIndex( posIdx );
fileHeaderCrcs[tileIndex] = Crc32.crc( abSubIndex, 0, abSubIndex.length );
os.write( abSubIndex, 0, abSubIndex.length );
for ( int si = 0; si < ncaches; si++ )
{
byte[] abSubIndex = compileSubFileIndex(posIdx);
fileHeaderCrcs[tileIndex] = Crc32.crc(abSubIndex, 0, abSubIndex.length);
os.write(abSubIndex, 0, abSubIndex.length);
for (int si = 0; si < ncaches; si++) {
byte[] ab = subByteArrays[si];
if ( ab != null )
{
os.write( ab );
os.writeInt( Crc32.crc( ab, 0, ab.length ) ^ microCacheEncoding );
if (ab != null) {
os.write(ab);
os.writeInt(Crc32.crc(ab, 0, ab.length) ^ microCacheEncoding);
}
}
filepos += pos;
@ -613,52 +533,46 @@ public class WayLinker extends MapCreatorBase implements Runnable
}
}
byte[] abFileIndex = compileFileIndex( fileIndex, lookupVersion, lookupMinorVersion );
byte[] abFileIndex = compileFileIndex(fileIndex, lookupVersion, lookupMinorVersion);
// write extra data: timestamp + index-checksums
os.writeLong( creationTimeStamp );
os.writeInt( Crc32.crc( abFileIndex, 0, abFileIndex.length ) ^ microCacheEncoding );
for ( int i55 = 0; i55 < 25; i55++ )
{
os.writeInt( fileHeaderCrcs[i55] );
os.writeLong(creationTimeStamp);
os.writeInt(Crc32.crc(abFileIndex, 0, abFileIndex.length) ^ microCacheEncoding);
for (int i55 = 0; i55 < 25; i55++) {
os.writeInt(fileHeaderCrcs[i55]);
}
os.close();
// re-open random-access to write file-index
RandomAccessFile ra = new RandomAccessFile( outfile, "rw" );
ra.write( abFileIndex, 0, abFileIndex.length );
RandomAccessFile ra = new RandomAccessFile(outfile, "rw");
ra.write(abFileIndex, 0, abFileIndex.length);
ra.close();
}
if ( trafficMap != null )
{
if (trafficMap != null) {
trafficMap.finish();
trafficMap = null;
}
System.out.println( "**** codec stats: *******\n" + StatCoderContext.getBitReport() );
System.out.println("**** codec stats: *******\n" + StatCoderContext.getBitReport());
}
private byte[] compileFileIndex( long[] fileIndex, short lookupVersion, short lookupMinorVersion ) throws Exception
{
private byte[] compileFileIndex(long[] fileIndex, short lookupVersion, short lookupMinorVersion) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream( bos );
for ( int i55 = 0; i55 < 25; i55++ )
{
DataOutputStream dos = new DataOutputStream(bos);
for (int i55 = 0; i55 < 25; i55++) {
long versionPrefix = i55 == 1 ? lookupMinorVersion : lookupVersion;
versionPrefix <<= 48;
dos.writeLong( fileIndex[i55] | versionPrefix );
dos.writeLong(fileIndex[i55] | versionPrefix);
}
dos.close();
return bos.toByteArray();
}
private byte[] compileSubFileIndex( int[] posIdx ) throws Exception
{
private byte[] compileSubFileIndex(int[] posIdx) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream( bos );
for ( int si = 0; si < posIdx.length; si++ )
{
dos.writeInt( posIdx[si] );
DataOutputStream dos = new DataOutputStream(bos);
for (int si = 0; si < posIdx.length; si++) {
dos.writeInt(posIdx[si]);
}
dos.close();
return bos.toByteArray();

View file

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

View file

@ -1,54 +1,53 @@
package btools.mapcreator;
import java.util.Random;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import java.net.URL;
import java.io.File;
public class MapcreatorTest
{
@Test
public void mapcreatorTest() throws Exception
{
URL mapurl = this.getClass().getResource( "/dreieich.osm.gz" );
Assert.assertTrue( "test-osm-map dreieich.osm not found", mapurl != null );
File mapFile = new File(mapurl.getFile());
File workingDir = mapFile.getParentFile();
File profileDir = new File( workingDir, "/../../../../misc/profiles2" );
File tmpdir = new File( workingDir, "tmp" );
tmpdir.mkdir();
File nodes = new File( tmpdir, "nodetiles" );
nodes.mkdir();
File ways = new File( tmpdir, "waytiles" );
ways.mkdir();
File nodes55 = new File( tmpdir, "nodes55" );
nodes55.mkdir();
File ways55 = new File( tmpdir, "waytiles55" );
ways55.mkdir();
File lookupFile = new File( profileDir, "lookups.dat" );
File relFile = new File( tmpdir, "cycleways.dat" );
File resFile = new File( tmpdir, "restrictions.dat" );
File profileAll = new File( profileDir, "all.brf" );
File profileReport = new File( profileDir, "trekking.brf" );
File profileCheck = new File( profileDir, "softaccess.brf" );
File borderFile = new File( tmpdir, "bordernids.dat" );
new OsmFastCutter().doCut( lookupFile, nodes, ways, nodes55, ways55, borderFile, relFile, resFile, profileAll, profileReport, profileCheck, mapFile );
// run PosUnifier
File unodes55 = new File( tmpdir, "unodes55" );
File bordernodes = new File( tmpdir, "bordernodes.dat" );
unodes55.mkdir();
new PosUnifier().process( nodes55, unodes55, borderFile, bordernodes, "/private-backup/srtm" );
// run WayLinker
File segments = new File( tmpdir, "segments" );
segments.mkdir();
new WayLinker().process( unodes55, ways55, bordernodes, resFile, lookupFile, profileAll, segments, "rd5" );
}
}
package btools.mapcreator;
import java.util.Random;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import java.net.URL;
import java.io.File;
public class MapcreatorTest {
@Test
public void mapcreatorTest() throws Exception {
URL mapurl = this.getClass().getResource("/dreieich.osm.gz");
Assert.assertTrue("test-osm-map dreieich.osm not found", mapurl != null);
File mapFile = new File(mapurl.getFile());
File workingDir = mapFile.getParentFile();
File profileDir = new File(workingDir, "/../../../../misc/profiles2");
File tmpdir = new File(workingDir, "tmp");
tmpdir.mkdir();
File nodes = new File(tmpdir, "nodetiles");
nodes.mkdir();
File ways = new File(tmpdir, "waytiles");
ways.mkdir();
File nodes55 = new File(tmpdir, "nodes55");
nodes55.mkdir();
File ways55 = new File(tmpdir, "waytiles55");
ways55.mkdir();
File lookupFile = new File(profileDir, "lookups.dat");
File relFile = new File(tmpdir, "cycleways.dat");
File resFile = new File(tmpdir, "restrictions.dat");
File profileAll = new File(profileDir, "all.brf");
File profileReport = new File(profileDir, "trekking.brf");
File profileCheck = new File(profileDir, "softaccess.brf");
File borderFile = new File(tmpdir, "bordernids.dat");
new OsmFastCutter().doCut(lookupFile, nodes, ways, nodes55, ways55, borderFile, relFile, resFile, profileAll, profileReport, profileCheck, mapFile);
// run PosUnifier
File unodes55 = new File(tmpdir, "unodes55");
File bordernodes = new File(tmpdir, "bordernodes.dat");
unodes55.mkdir();
new PosUnifier().process(nodes55, unodes55, borderFile, bordernodes, "/private-backup/srtm");
// run WayLinker
File segments = new File(tmpdir, "segments");
segments.mkdir();
new WayLinker().process(unodes55, ways55, bordernodes, resFile, lookupFile, profileAll, segments, "rd5");
}
}

View file

@ -14,113 +14,100 @@ import btools.util.IByteArrayUnifier;
* DirectWeaver does the same decoding as MicroCache2, but decodes directly
* into the instance-graph, not into the intermediate nodes-cache
*/
public final class DirectWeaver extends ByteDataWriter
{
public final class DirectWeaver extends ByteDataWriter {
private long id64Base;
private int size = 0;
public DirectWeaver( StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes )
{
super( null );
public DirectWeaver(StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes) {
super(null);
int cellsize = 1000000 / divisor;
id64Base = ((long)(lonIdx*cellsize))<<32 | (latIdx*cellsize);
id64Base = ((long) (lonIdx * cellsize)) << 32 | (latIdx * cellsize);
TagValueCoder wayTagCoder = new TagValueCoder( bc, dataBuffers, wayValidator );
TagValueCoder nodeTagCoder = new TagValueCoder( bc, dataBuffers, null );
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder( bc );
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder( bc );
TagValueCoder wayTagCoder = new TagValueCoder(bc, dataBuffers, wayValidator);
TagValueCoder nodeTagCoder = new TagValueCoder(bc, dataBuffers, null);
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLatDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder transEleDiff = new NoisyDiffCoder( bc );
NoisyDiffCoder transEleDiff = new NoisyDiffCoder(bc);
size = bc.decodeNoisyNumber( 5 );
size = bc.decodeNoisyNumber(5);
int[] faid = size > dataBuffers.ibuf2.length ? new int[size] : dataBuffers.ibuf2;
bc.decodeSortedArray( faid, 0, size, 29, 0 );
bc.decodeSortedArray(faid, 0, size, 29, 0);
OsmNode[] nodes = new OsmNode[size];
for( int n = 0; n<size; n++ )
{
long id = expandId( faid[n] );
int ilon = (int) ( id >> 32 );
int ilat = (int) ( id & 0xffffffff );
OsmNode node = hollowNodes.get( ilon, ilat );
if ( node == null )
{
node = new OsmNode( ilon, ilat );
}
else
{
for (int n = 0; n < size; n++) {
long id = expandId(faid[n]);
int ilon = (int) (id >> 32);
int ilat = (int) (id & 0xffffffff);
OsmNode node = hollowNodes.get(ilon, ilat);
if (node == null) {
node = new OsmNode(ilon, ilat);
} else {
node.visitID = 1;
hollowNodes.remove( node );
hollowNodes.remove(node);
}
nodes[n] = node;
}
int netdatasize = bc.decodeNoisyNumber( 10 ); // (not needed for direct weaving)
int netdatasize = bc.decodeNoisyNumber(10); // (not needed for direct weaving)
ab = dataBuffers.bbuf1;
aboffset = 0;
int selev = 0;
for( int n=0; n<size; n++ ) // loop over nodes
{
for (int n = 0; n < size; n++) // loop over nodes
{
OsmNode node = nodes[n];
int ilon = node.ilon;
int ilat = node.ilat;
// future escapes (turn restrictions?)
short trExceptions = 0;
for(;;)
{
for (; ; ) {
int featureId = bc.decodeVarBits();
if ( featureId == 0 ) break;
int bitsize = bc.decodeNoisyNumber( 5 );
if (featureId == 0) break;
int bitsize = bc.decodeNoisyNumber(5);
if ( featureId == 2 ) // exceptions to turn-restriction
if (featureId == 2) // exceptions to turn-restriction
{
trExceptions = (short)bc.decodeBounded( 1023 );
}
else if ( featureId == 1 ) // turn-restriction
trExceptions = (short) bc.decodeBounded(1023);
} else if (featureId == 1) // turn-restriction
{
TurnRestriction tr = new TurnRestriction();
tr.exceptions = trExceptions;
tr.exceptions = trExceptions;
trExceptions = 0;
tr.isPositive = bc.decodeBit();
tr.fromLon = ilon + bc.decodeNoisyDiff( 10 );
tr.fromLat = ilat + bc.decodeNoisyDiff( 10 );
tr.toLon = ilon + bc.decodeNoisyDiff( 10 );
tr.toLat = ilat + bc.decodeNoisyDiff( 10 );
node.addTurnRestriction( tr );
}
else
{
for( int i=0; i< bitsize; i++ ) bc.decodeBit(); // unknown feature, just skip
tr.isPositive = bc.decodeBit();
tr.fromLon = ilon + bc.decodeNoisyDiff(10);
tr.fromLat = ilat + bc.decodeNoisyDiff(10);
tr.toLon = ilon + bc.decodeNoisyDiff(10);
tr.toLat = ilat + bc.decodeNoisyDiff(10);
node.addTurnRestriction(tr);
} else {
for (int i = 0; i < bitsize; i++) bc.decodeBit(); // unknown feature, just skip
}
}
selev += nodeEleDiff.decodeSignedValue();
node.selev = (short)selev;
node.selev = (short) selev;
TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet();
node.nodeDescription = nodeTags == null ? null : nodeTags.data; // TODO: unified?
int links = bc.decodeNoisyNumber( 1 );
for( int li=0; li<links; li++ )
{
int links = bc.decodeNoisyNumber(1);
for (int li = 0; li < links; li++) {
int nodeIdx = n + nodeIdxDiff.decodeSignedValue();
int dlon_remaining;
int dlat_remaining;
boolean isReverse = false;
if ( nodeIdx != n ) // internal (forward-) link
if (nodeIdx != n) // internal (forward-) link
{
dlon_remaining = nodes[nodeIdx].ilon - ilon;
dlat_remaining = nodes[nodeIdx].ilat - ilat;
}
else
{
} else {
isReverse = bc.decodeBit();
dlon_remaining = extLonDiff.decodeSignedValue();
dlat_remaining = extLatDiff.decodeSignedValue();
@ -131,104 +118,92 @@ public final class DirectWeaver extends ByteDataWriter
int linklon = ilon + dlon_remaining;
int linklat = ilat + dlat_remaining;
aboffset = 0;
if ( !isReverse ) // write geometry for forward links only
if (!isReverse) // write geometry for forward links only
{
WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher;
int ilontarget = ilon + dlon_remaining;
int ilattarget = ilat + dlat_remaining;
if ( matcher != null )
{
if ( !matcher.start( ilon, ilat, ilontarget, ilattarget ) )
{
if (matcher != null) {
if (!matcher.start(ilon, ilat, ilontarget, ilattarget)) {
matcher = null;
}
}
int transcount = bc.decodeVarBits();
int count = transcount+1;
for( int i=0; i<transcount; i++ )
{
int dlon = bc.decodePredictedValue( dlon_remaining/count );
int dlat = bc.decodePredictedValue( dlat_remaining/count );
int count = transcount + 1;
for (int i = 0; i < transcount; i++) {
int dlon = bc.decodePredictedValue(dlon_remaining / count);
int dlat = bc.decodePredictedValue(dlat_remaining / count);
dlon_remaining -= dlon;
dlat_remaining -= dlat;
count--;
int elediff = transEleDiff.decodeSignedValue();
if ( wayTags != null )
{
writeVarLengthSigned( dlon );
writeVarLengthSigned( dlat );
writeVarLengthSigned( elediff );
if (wayTags != null) {
writeVarLengthSigned(dlon);
writeVarLengthSigned(dlat);
writeVarLengthSigned(elediff);
}
if ( matcher != null ) matcher.transferNode( ilontarget - dlon_remaining, ilattarget - dlat_remaining );
if (matcher != null)
matcher.transferNode(ilontarget - dlon_remaining, ilattarget - dlat_remaining);
}
if ( matcher != null ) matcher.end();
if (matcher != null) matcher.end();
}
if ( wayTags != null )
{
if (wayTags != null) {
byte[] geometry = null;
if ( aboffset > 0 )
{
if (aboffset > 0) {
geometry = new byte[aboffset];
System.arraycopy( ab, 0, geometry, 0, aboffset );
System.arraycopy(ab, 0, geometry, 0, aboffset);
}
if ( nodeIdx != n ) // valid internal (forward-) link
if (nodeIdx != n) // valid internal (forward-) link
{
OsmNode node2 = nodes[nodeIdx];
OsmLink link = node.isLinkUnused() ? node : ( node2.isLinkUnused() ? node2 : null );
if ( link == null )
{
OsmLink link = node.isLinkUnused() ? node : (node2.isLinkUnused() ? node2 : null);
if (link == null) {
link = new OsmLink();
}
link.descriptionBitmap = wayTags.data;
link.geometry = geometry;
node.addLink( link, isReverse, node2 );
}
else // weave external link
node.addLink(link, isReverse, node2);
} else // weave external link
{
node.addLink( linklon, linklat, wayTags.data, geometry, hollowNodes, isReverse );
node.addLink(linklon, linklat, wayTags.data, geometry, hollowNodes, isReverse);
node.visitID = 1;
}
}
} // ... loop over links
} // ... loop over nodes
hollowNodes.cleanupAndCount( nodes );
hollowNodes.cleanupAndCount(nodes);
}
private static final long[] id32_00 = new long[1024];
private static final long[] id32_10 = new long[1024];
private static final long[] id32_20 = new long[1024];
static
{
for( int i=0; i<1024; i++ )
{
id32_00[i] = _expandId( i );
id32_10[i] = _expandId( i << 10 );
id32_20[i] = _expandId( i << 20 );
static {
for (int i = 0; i < 1024; i++) {
id32_00[i] = _expandId(i);
id32_10[i] = _expandId(i << 10);
id32_20[i] = _expandId(i << 20);
}
}
private static long _expandId( int id32 )
{
private static long _expandId(int id32) {
int dlon = 0;
int dlat = 0;
for( int bm = 1; bm < 0x8000; bm <<= 1 )
{
if ( (id32 & 1) != 0 ) dlon |= bm;
if ( (id32 & 2) != 0 ) dlat |= bm;
for (int bm = 1; bm < 0x8000; bm <<= 1) {
if ((id32 & 1) != 0) dlon |= bm;
if ((id32 & 2) != 0) dlat |= bm;
id32 >>= 2;
}
return ((long)dlon)<<32 | dlat;
return ((long) dlon) << 32 | dlat;
}
public long expandId( int id32 )
{
return id64Base + id32_00[ id32 & 1023 ] + id32_10[ (id32>>10) & 1023 ] + id32_20[ (id32>>20) & 1023 ];
public long expandId(int id32) {
return id64Base + id32_00[id32 & 1023] + id32_10[(id32 >> 10) & 1023] + id32_20[(id32 >> 20) & 1023];
}
}

View file

@ -8,9 +8,8 @@ package btools.mapaccess;
import btools.util.ByteDataReader;
public final class GeometryDecoder
{
private ByteDataReader r = new ByteDataReader( null );
public final class GeometryDecoder {
private ByteDataReader r = new ByteDataReader(null);
private OsmTransferNode[] cachedNodes;
private int nCachedNodes = 128;
@ -19,63 +18,53 @@ public final class GeometryDecoder
private boolean lastReverse;
private byte[] lastGeometry;
public GeometryDecoder()
{
public GeometryDecoder() {
// create some caches
cachedNodes = new OsmTransferNode[nCachedNodes];
for( int i=0; i<nCachedNodes; i++ )
{
for (int i = 0; i < nCachedNodes; i++) {
cachedNodes[i] = new OsmTransferNode();
}
}
public OsmTransferNode decodeGeometry( byte[] geometry, OsmNode sourceNode, OsmNode targetNode, boolean reverseLink )
{
if ( ( lastGeometry == geometry ) && ( lastReverse == reverseLink ) )
{
return firstTransferNode;
}
firstTransferNode = null;
OsmTransferNode lastTransferNode = null;
OsmNode startnode = reverseLink ? targetNode : sourceNode;
r.reset( geometry );
int olon = startnode.ilon;
int olat = startnode.ilat;
int oselev = startnode.selev;
int idx = 0;
while ( r.hasMoreData() )
{
OsmTransferNode trans = idx < nCachedNodes ? cachedNodes[idx++] : new OsmTransferNode();
trans.ilon = olon + r.readVarLengthSigned();
trans.ilat = olat + r.readVarLengthSigned();
trans.selev = (short)(oselev + r.readVarLengthSigned());
olon = trans.ilon;
olat = trans.ilat;
oselev = trans.selev;
if ( reverseLink ) // reverse chaining
{
trans.next = firstTransferNode;
firstTransferNode = trans;
}
else
{
trans.next = null;
if ( lastTransferNode == null )
{
firstTransferNode = trans;
}
else
{
lastTransferNode.next = trans;
}
lastTransferNode = trans;
}
}
lastReverse = reverseLink;
lastGeometry = geometry;
public OsmTransferNode decodeGeometry(byte[] geometry, OsmNode sourceNode, OsmNode targetNode, boolean reverseLink) {
if ((lastGeometry == geometry) && (lastReverse == reverseLink)) {
return firstTransferNode;
}
firstTransferNode = null;
OsmTransferNode lastTransferNode = null;
OsmNode startnode = reverseLink ? targetNode : sourceNode;
r.reset(geometry);
int olon = startnode.ilon;
int olat = startnode.ilat;
int oselev = startnode.selev;
int idx = 0;
while (r.hasMoreData()) {
OsmTransferNode trans = idx < nCachedNodes ? cachedNodes[idx++] : new OsmTransferNode();
trans.ilon = olon + r.readVarLengthSigned();
trans.ilat = olat + r.readVarLengthSigned();
trans.selev = (short) (oselev + r.readVarLengthSigned());
olon = trans.ilon;
olat = trans.ilat;
oselev = trans.selev;
if (reverseLink) // reverse chaining
{
trans.next = firstTransferNode;
firstTransferNode = trans;
} else {
trans.next = null;
if (lastTransferNode == null) {
firstTransferNode = trans;
} else {
lastTransferNode.next = trans;
}
lastTransferNode = trans;
}
}
lastReverse = reverseLink;
lastGeometry = geometry;
return firstTransferNode;
}
}

View file

@ -11,48 +11,45 @@ import java.io.IOException;
import btools.mapaccess.OsmNode;
public final class MatchedWaypoint
{
public final class MatchedWaypoint {
public OsmNode node1;
public OsmNode node2;
public OsmNode crosspoint;
public OsmNode waypoint;
public String name; // waypoint name used in error messages
public double radius; // distance in meter between waypoint and crosspoint
public boolean hasUpdate;
public void writeToStream( DataOutput dos ) throws IOException
{
dos.writeInt( node1.ilat );
dos.writeInt( node1.ilon );
dos.writeInt( node2.ilat );
dos.writeInt( node2.ilon );
dos.writeInt( crosspoint.ilat );
dos.writeInt( crosspoint.ilon );
dos.writeInt( waypoint.ilat );
dos.writeInt( waypoint.ilon );
dos.writeDouble( radius );
public void writeToStream(DataOutput dos) throws IOException {
dos.writeInt(node1.ilat);
dos.writeInt(node1.ilon);
dos.writeInt(node2.ilat);
dos.writeInt(node2.ilon);
dos.writeInt(crosspoint.ilat);
dos.writeInt(crosspoint.ilon);
dos.writeInt(waypoint.ilat);
dos.writeInt(waypoint.ilon);
dos.writeDouble(radius);
}
public static MatchedWaypoint readFromStream( DataInput dis ) throws IOException
{
MatchedWaypoint mwp = new MatchedWaypoint();
mwp.node1 = new OsmNode();
mwp.node2 = new OsmNode();
mwp.crosspoint = new OsmNode();
mwp.waypoint = new OsmNode();
public static MatchedWaypoint readFromStream(DataInput dis) throws IOException {
MatchedWaypoint mwp = new MatchedWaypoint();
mwp.node1 = new OsmNode();
mwp.node2 = new OsmNode();
mwp.crosspoint = new OsmNode();
mwp.waypoint = new OsmNode();
mwp.node1.ilat = dis.readInt();
mwp.node1.ilon = dis.readInt();
mwp.node2.ilat = dis.readInt();
mwp.node2.ilon = dis.readInt();
mwp.crosspoint.ilat = dis.readInt();
mwp.crosspoint.ilon = dis.readInt();
mwp.waypoint.ilat = dis.readInt();
mwp.waypoint.ilon = dis.readInt();
mwp.radius = dis.readDouble();
return mwp;
mwp.node1.ilat = dis.readInt();
mwp.node1.ilon = dis.readInt();
mwp.node2.ilat = dis.readInt();
mwp.node2.ilon = dis.readInt();
mwp.crosspoint.ilat = dis.readInt();
mwp.crosspoint.ilon = dis.readInt();
mwp.waypoint.ilat = dis.readInt();
mwp.waypoint.ilon = dis.readInt();
mwp.radius = dis.readDouble();
return mwp;
}
}

View file

@ -15,8 +15,7 @@ import btools.codec.MicroCache;
import btools.codec.WaypointMatcher;
import btools.expressions.BExpressionContextWay;
public final class NodesCache
{
public final class NodesCache {
private File segmentDir;
private File secondarySegmentsDir = null;
@ -40,7 +39,7 @@ public final class NodesCache
private long cacheSum = 0;
private long maxmemtiles;
private boolean detailed;
private boolean garbageCollectionEnabled = false;
private boolean ghostCleaningDone = false;
@ -48,155 +47,123 @@ public final class NodesCache
private long cacheSumClean = 0;
private long ghostSum = 0;
private long ghostWakeup = 0;
private boolean directWeaving = !Boolean.getBoolean( "disableDirectWeaving" );
public String formatStatus()
{
return "collecting=" + garbageCollectionEnabled + " noGhosts=" + ghostCleaningDone + " cacheSum=" + cacheSum + " cacheSumClean=" + cacheSumClean + " ghostSum=" + ghostSum + " ghostWakeup=" + ghostWakeup ;
private boolean directWeaving = !Boolean.getBoolean("disableDirectWeaving");
public String formatStatus() {
return "collecting=" + garbageCollectionEnabled + " noGhosts=" + ghostCleaningDone + " cacheSum=" + cacheSum + " cacheSumClean=" + cacheSumClean + " ghostSum=" + ghostSum + " ghostWakeup=" + ghostWakeup;
}
public NodesCache( File segmentDir, BExpressionContextWay ctxWay, boolean forceSecondaryData, long maxmem, NodesCache oldCache, boolean detailed )
{
public NodesCache(File segmentDir, BExpressionContextWay ctxWay, boolean forceSecondaryData, long maxmem, NodesCache oldCache, boolean detailed) {
this.maxmemtiles = maxmem / 8;
this.segmentDir = segmentDir;
this.nodesMap = new OsmNodesMap();
this.nodesMap.maxmem = (2L*maxmem) / 3L;
this.nodesMap.maxmem = (2L * maxmem) / 3L;
this.expCtxWay = ctxWay;
this.lookupVersion = ctxWay.meta.lookupVersion;
this.lookupMinorVersion = ctxWay.meta.lookupMinorVersion;
this.forceSecondaryData = forceSecondaryData;
this.detailed = detailed;
if ( ctxWay != null )
{
ctxWay.setDecodeForbidden( detailed );
if (ctxWay != null) {
ctxWay.setDecodeForbidden(detailed);
}
first_file_access_failed = false;
first_file_access_name = null;
if ( !this.segmentDir.isDirectory() )
throw new RuntimeException( "segment directory " + segmentDir.getAbsolutePath () + " does not exist" );
if (!this.segmentDir.isDirectory())
throw new RuntimeException("segment directory " + segmentDir.getAbsolutePath() + " does not exist");
if ( oldCache != null )
{
if (oldCache != null) {
fileCache = oldCache.fileCache;
dataBuffers = oldCache.dataBuffers;
secondarySegmentsDir = oldCache.secondarySegmentsDir;
// re-use old, virgin caches (if same detail-mode)
if ( oldCache.detailed == detailed)
{
if (oldCache.detailed == detailed) {
fileRows = oldCache.fileRows;
for ( OsmFile[] fileRow : fileRows )
{
if ( fileRow == null )
for (OsmFile[] fileRow : fileRows) {
if (fileRow == null)
continue;
for ( OsmFile osmf : fileRow )
{
for (OsmFile osmf : fileRow) {
cacheSum += osmf.setGhostState();
}
}
}
else
{
} else {
fileRows = new OsmFile[180][];
}
}
else
{
fileCache = new HashMap<String, PhysicalFile>( 4 );
} else {
fileCache = new HashMap<String, PhysicalFile>(4);
fileRows = new OsmFile[180][];
dataBuffers = new DataBuffers();
secondarySegmentsDir = StorageConfigHelper.getSecondarySegmentDir( segmentDir );
secondarySegmentsDir = StorageConfigHelper.getSecondarySegmentDir(segmentDir);
}
ghostSum = cacheSum;
}
public void clean( boolean all )
{
for ( OsmFile[] fileRow : fileRows )
{
if ( fileRow == null )
continue;
for ( OsmFile osmf : fileRow )
{
osmf.clean( all);
}
public void clean(boolean all) {
for (OsmFile[] fileRow : fileRows) {
if (fileRow == null)
continue;
for (OsmFile osmf : fileRow) {
osmf.clean(all);
}
}
}
// if the cache sum exceeded a threshold,
// clean all ghosts and enable garbage collection
private void checkEnableCacheCleaning()
{
if ( cacheSum < maxmemtiles )
{
private void checkEnableCacheCleaning() {
if (cacheSum < maxmemtiles) {
return;
}
for ( int i = 0; i < fileRows.length; i++ )
{
for (int i = 0; i < fileRows.length; i++) {
OsmFile[] fileRow = fileRows[i];
if ( fileRow == null )
{
if (fileRow == null) {
continue;
}
for ( OsmFile osmf : fileRow )
{
if ( garbageCollectionEnabled && !ghostCleaningDone )
{
for (OsmFile osmf : fileRow) {
if (garbageCollectionEnabled && !ghostCleaningDone) {
cacheSum -= osmf.cleanGhosts();
}
else
{
} else {
cacheSum -= osmf.collectAll();
}
}
}
if ( garbageCollectionEnabled )
{
if (garbageCollectionEnabled) {
ghostCleaningDone = true;
maxmemtiles *= 2;
}
else
{
} else {
cacheSumClean = cacheSum;
garbageCollectionEnabled = true;
}
}
public int loadSegmentFor( int ilon, int ilat )
{
MicroCache mc = getSegmentFor( ilon, ilat );
public int loadSegmentFor(int ilon, int ilat) {
MicroCache mc = getSegmentFor(ilon, ilat);
return mc == null ? 0 : mc.getSize();
}
public MicroCache getSegmentFor( int ilon, int ilat )
{
try
{
public MicroCache getSegmentFor(int ilon, int ilat) {
try {
int lonDegree = ilon / 1000000;
int latDegree = ilat / 1000000;
OsmFile osmf = null;
OsmFile[] fileRow = fileRows[latDegree];
int ndegrees = fileRow == null ? 0 : fileRow.length;
for ( int i = 0; i < ndegrees; i++ )
{
if ( fileRow[i].lonDegree == lonDegree )
{
for (int i = 0; i < ndegrees; i++) {
if (fileRow[i].lonDegree == lonDegree) {
osmf = fileRow[i];
break;
}
}
if ( osmf == null )
{
osmf = fileForSegment( lonDegree, latDegree );
if (osmf == null) {
osmf = fileForSegment(lonDegree, latDegree);
OsmFile[] newFileRow = new OsmFile[ndegrees + 1];
for ( int i = 0; i < ndegrees; i++ )
{
for (int i = 0; i < ndegrees; i++) {
newFileRow[i] = fileRow[i];
}
newFileRow[ndegrees] = osmf;
@ -204,33 +171,25 @@ public final class NodesCache
}
currentFileName = osmf.filename;
if ( !osmf.hasData() )
{
if (!osmf.hasData()) {
return null;
}
MicroCache segment = osmf.getMicroCache( ilon, ilat );
if ( segment == null )
{
MicroCache segment = osmf.getMicroCache(ilon, ilat);
if (segment == null) {
checkEnableCacheCleaning();
segment = osmf.createMicroCache( ilon, ilat, dataBuffers, expCtxWay, waypointMatcher, directWeaving ? nodesMap : null );
segment = osmf.createMicroCache(ilon, ilat, dataBuffers, expCtxWay, waypointMatcher, directWeaving ? nodesMap : null);
cacheSum += segment.getDataSize();
}
else if ( segment.ghost )
{
} else if (segment.ghost) {
segment.unGhost();
ghostWakeup += segment.getDataSize();
}
return segment;
}
catch (RuntimeException re)
{
} catch (RuntimeException re) {
throw re;
}
catch (Exception e)
{
throw new RuntimeException( "error reading datafile " + currentFileName + ": " + e, e );
} catch (Exception e) {
throw new RuntimeException("error reading datafile " + currentFileName + ": " + e, e);
}
}
@ -238,60 +197,50 @@ public final class NodesCache
* make sure the given node is non-hollow,
* which means it contains not just the id,
* but also the actual data
*
*
* @return true if successfull, false if node is still hollow
*/
public boolean obtainNonHollowNode( OsmNode node )
{
if ( !node.isHollow() )
public boolean obtainNonHollowNode(OsmNode node) {
if (!node.isHollow())
return true;
MicroCache segment = getSegmentFor( node.ilon, node.ilat );
if ( segment == null )
{
MicroCache segment = getSegmentFor(node.ilon, node.ilat);
if (segment == null) {
return false;
}
if ( !node.isHollow() )
{
if (!node.isHollow()) {
return true; // direct weaving...
}
long id = node.getIdFromPos();
if ( segment.getAndClear( id ) )
{
node.parseNodeBody( segment, nodesMap, expCtxWay );
if (segment.getAndClear(id)) {
node.parseNodeBody(segment, nodesMap, expCtxWay);
}
if ( garbageCollectionEnabled ) // garbage collection
if (garbageCollectionEnabled) // garbage collection
{
cacheSum -= segment.collect( segment.getSize() >> 1 ); // threshold = 1/2 of size is deleted
cacheSum -= segment.collect(segment.getSize() >> 1); // threshold = 1/2 of size is deleted
}
return !node.isHollow();
}
/**
* make sure all link targets of the given node are non-hollow
*/
public void expandHollowLinkTargets( OsmNode n )
{
for( OsmLink link = n.firstlink; link != null; link = link.getNext( n ) )
{
obtainNonHollowNode( link.getTarget( n ) );
public void expandHollowLinkTargets(OsmNode n) {
for (OsmLink link = n.firstlink; link != null; link = link.getNext(n)) {
obtainNonHollowNode(link.getTarget(n));
}
}
/**
* make sure all link targets of the given node are non-hollow
*/
public boolean hasHollowLinkTargets( OsmNode n )
{
for( OsmLink link = n.firstlink; link != null; link = link.getNext( n ) )
{
if ( link.getTarget( n ).isHollow() )
{
public boolean hasHollowLinkTargets(OsmNode n) {
for (OsmLink link = n.firstlink; link != null; link = link.getNext(n)) {
if (link.getTarget(n).isHollow()) {
return true;
}
}
@ -300,129 +249,107 @@ public final class NodesCache
/**
* get a node for the given id with all link-targets also non-hollow
*
* <p>
* It is required that an instance of the start-node does not yet
* exist, not even a hollow instance, so getStartNode should only
* be called once right after resetting the cache
*
*
* @param id the id of the node to load
*
* @return the fully expanded node for id, or null if it was not found
*/
public OsmNode getStartNode( long id )
{
public OsmNode getStartNode(long id) {
// initialize the start-node
OsmNode n = new OsmNode( id );
OsmNode n = new OsmNode(id);
n.setHollow();
nodesMap.put( n );
if ( !obtainNonHollowNode( n ) )
{
nodesMap.put(n);
if (!obtainNonHollowNode(n)) {
return null;
}
expandHollowLinkTargets( n );
expandHollowLinkTargets(n);
return n;
}
public OsmNode getGraphNode( OsmNode template )
{
OsmNode graphNode = new OsmNode( template.ilon, template.ilat );
public OsmNode getGraphNode(OsmNode template) {
OsmNode graphNode = new OsmNode(template.ilon, template.ilat);
graphNode.setHollow();
OsmNode existing = nodesMap.put( graphNode );
if ( existing == null )
{
OsmNode existing = nodesMap.put(graphNode);
if (existing == null) {
return graphNode;
}
nodesMap.put( existing );
nodesMap.put(existing);
return existing;
}
public void matchWaypointsToNodes( List<MatchedWaypoint> unmatchedWaypoints, double maxDistance, OsmNodePairSet islandNodePairs )
{
waypointMatcher = new WaypointMatcherImpl( unmatchedWaypoints, maxDistance, islandNodePairs );
for( MatchedWaypoint mwp : unmatchedWaypoints )
{
preloadPosition( mwp.waypoint );
public void matchWaypointsToNodes(List<MatchedWaypoint> unmatchedWaypoints, double maxDistance, OsmNodePairSet islandNodePairs) {
waypointMatcher = new WaypointMatcherImpl(unmatchedWaypoints, maxDistance, islandNodePairs);
for (MatchedWaypoint mwp : unmatchedWaypoints) {
preloadPosition(mwp.waypoint);
}
if ( first_file_access_failed )
{
throw new IllegalArgumentException( "datafile " + first_file_access_name + " not found" );
if (first_file_access_failed) {
throw new IllegalArgumentException("datafile " + first_file_access_name + " not found");
}
for( MatchedWaypoint mwp : unmatchedWaypoints )
{
if ( mwp.crosspoint == null )
{
throw new IllegalArgumentException( mwp.name + "-position not mapped in existing datafile" );
for (MatchedWaypoint mwp : unmatchedWaypoints) {
if (mwp.crosspoint == null) {
throw new IllegalArgumentException(mwp.name + "-position not mapped in existing datafile");
}
}
}
private void preloadPosition( OsmNode n )
{
private void preloadPosition(OsmNode n) {
int d = 12500;
first_file_access_failed = false;
first_file_access_name = null;
loadSegmentFor( n.ilon, n.ilat );
if ( first_file_access_failed )
{
throw new IllegalArgumentException( "datafile " + first_file_access_name + " not found" );
loadSegmentFor(n.ilon, n.ilat);
if (first_file_access_failed) {
throw new IllegalArgumentException("datafile " + first_file_access_name + " not found");
}
for( int idxLat=-1; idxLat<=1; idxLat++ )
for( int idxLon=-1; idxLon<=1; idxLon++ )
{
if ( idxLon != 0 || idxLat != 0 )
{
loadSegmentFor( n.ilon + d*idxLon , n.ilat +d*idxLat );
for (int idxLat = -1; idxLat <= 1; idxLat++)
for (int idxLon = -1; idxLon <= 1; idxLon++) {
if (idxLon != 0 || idxLat != 0) {
loadSegmentFor(n.ilon + d * idxLon, n.ilat + d * idxLat);
}
}
}
private OsmFile fileForSegment( int lonDegree, int latDegree ) throws Exception
{
private OsmFile fileForSegment(int lonDegree, int latDegree) throws Exception {
int lonMod5 = lonDegree % 5;
int latMod5 = latDegree % 5;
int lon = lonDegree - 180 - lonMod5;
String slon = lon < 0 ? "W" + ( -lon ) : "E" + lon;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
int lat = latDegree - 90 - latMod5;
String slat = lat < 0 ? "S" + ( -lat ) : "N" + lat;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
String filenameBase = slon + "_" + slat;
currentFileName = filenameBase + ".rd5";
PhysicalFile ra = null;
if ( !fileCache.containsKey( filenameBase ) )
{
if (!fileCache.containsKey(filenameBase)) {
File f = null;
if ( !forceSecondaryData )
{
File primary = new File( segmentDir, filenameBase + ".rd5" );
if ( primary .exists() )
{
if (!forceSecondaryData) {
File primary = new File(segmentDir, filenameBase + ".rd5");
if (primary.exists()) {
f = primary;
}
}
if ( f == null )
{
File secondary = new File( secondarySegmentsDir, filenameBase + ".rd5" );
if ( secondary.exists() )
{
if (f == null) {
File secondary = new File(secondarySegmentsDir, filenameBase + ".rd5");
if (secondary.exists()) {
f = secondary;
}
}
if ( f != null )
{
if (f != null) {
currentFileName = f.getName();
ra = new PhysicalFile( f, dataBuffers, lookupVersion, lookupMinorVersion );
ra = new PhysicalFile(f, dataBuffers, lookupVersion, lookupMinorVersion);
}
fileCache.put( filenameBase, ra );
fileCache.put(filenameBase, ra);
}
ra = fileCache.get( filenameBase );
OsmFile osmf = new OsmFile( ra, lonDegree, latDegree, dataBuffers );
ra = fileCache.get(filenameBase);
OsmFile osmf = new OsmFile(ra, lonDegree, latDegree, dataBuffers);
if ( first_file_access_name == null )
{
if (first_file_access_name == null) {
first_file_access_name = currentFileName;
first_file_access_failed = osmf.filename == null;
}
@ -430,17 +357,12 @@ public final class NodesCache
return osmf;
}
public void close()
{
for ( PhysicalFile f : fileCache.values() )
{
try
{
if ( f != null )
public void close() {
for (PhysicalFile f : fileCache.values()) {
try {
if (f != null)
f.ra.close();
}
catch (IOException ioe)
{
} catch (IOException ioe) {
// ignore
}
}

View file

@ -1,13 +1,12 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
final class NodesList
{
public OsmNode node;
public NodesList next;
}
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
final class NodesList {
public OsmNode node;
public NodesList next;
}

View file

@ -17,8 +17,7 @@ import btools.codec.WaypointMatcher;
import btools.util.ByteDataReader;
import btools.util.Crc32;
final class OsmFile
{
final class OsmFile {
private RandomAccessFile is = null;
private long fileOffset;
@ -35,16 +34,14 @@ final class OsmFile
private int ncaches;
private int indexsize;
public OsmFile( PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers ) throws IOException
{
public OsmFile(PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers) throws IOException {
this.lonDegree = lonDegree;
this.latDegree = latDegree;
int lonMod5 = lonDegree % 5;
int latMod5 = latDegree % 5;
int tileIndex = lonMod5 * 5 + latMod5;
if ( rafile != null )
{
if (rafile != null) {
divisor = rafile.divisor;
cellsize = 1000000 / divisor;
@ -56,197 +53,161 @@ final class OsmFile
long[] index = rafile.fileIndex;
fileOffset = tileIndex > 0 ? index[tileIndex - 1] : 200L;
if ( fileOffset == index[tileIndex] )
if (fileOffset == index[tileIndex])
return; // empty
is = rafile.ra;
posIdx = new int[ncaches];
microCaches = new MicroCache[ncaches];
is.seek( fileOffset );
is.readFully( iobuffer, 0, indexsize );
is.seek(fileOffset);
is.readFully(iobuffer, 0, indexsize);
if ( rafile.fileHeaderCrcs != null )
{
int headerCrc = Crc32.crc( iobuffer, 0, indexsize );
if ( rafile.fileHeaderCrcs[tileIndex] != headerCrc )
{
throw new IOException( "sub index checksum error" );
if (rafile.fileHeaderCrcs != null) {
int headerCrc = Crc32.crc(iobuffer, 0, indexsize);
if (rafile.fileHeaderCrcs[tileIndex] != headerCrc) {
throw new IOException("sub index checksum error");
}
}
ByteDataReader dis = new ByteDataReader( iobuffer );
for ( int i = 0; i < ncaches; i++ )
{
ByteDataReader dis = new ByteDataReader(iobuffer);
for (int i = 0; i < ncaches; i++) {
posIdx[i] = dis.readInt();
}
}
}
public boolean hasData()
{
public boolean hasData() {
return microCaches != null;
}
public MicroCache getMicroCache( int ilon, int ilat )
{
public MicroCache getMicroCache(int ilon, int ilat) {
int lonIdx = ilon / cellsize;
int latIdx = ilat / cellsize;
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
int subIdx = (latIdx - divisor * latDegree) * divisor + (lonIdx - divisor * lonDegree);
return microCaches[subIdx];
}
public MicroCache createMicroCache( int ilon, int ilat, DataBuffers dataBuffers, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes )
throws Exception
{
public MicroCache createMicroCache(int ilon, int ilat, DataBuffers dataBuffers, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes)
throws Exception {
int lonIdx = ilon / cellsize;
int latIdx = ilat / cellsize;
MicroCache segment = createMicroCache( lonIdx, latIdx, dataBuffers, wayValidator, waypointMatcher, true, hollowNodes );
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
MicroCache segment = createMicroCache(lonIdx, latIdx, dataBuffers, wayValidator, waypointMatcher, true, hollowNodes);
int subIdx = (latIdx - divisor * latDegree) * divisor + (lonIdx - divisor * lonDegree);
microCaches[subIdx] = segment;
return segment;
}
private int getPosIdx( int idx )
{
private int getPosIdx(int idx) {
return idx == -1 ? indexsize : posIdx[idx];
}
public int getDataInputForSubIdx( int subIdx, byte[] iobuffer ) throws IOException
{
int startPos = getPosIdx( subIdx - 1 );
int endPos = getPosIdx( subIdx );
public int getDataInputForSubIdx(int subIdx, byte[] iobuffer) throws IOException {
int startPos = getPosIdx(subIdx - 1);
int endPos = getPosIdx(subIdx);
int size = endPos - startPos;
if ( size > 0 )
{
is.seek( fileOffset + startPos );
if ( size <= iobuffer.length )
{
is.readFully( iobuffer, 0, size );
if (size > 0) {
is.seek(fileOffset + startPos);
if (size <= iobuffer.length) {
is.readFully(iobuffer, 0, size);
}
}
return size;
}
public MicroCache createMicroCache( int lonIdx, int latIdx, DataBuffers dataBuffers, TagValueValidator wayValidator,
WaypointMatcher waypointMatcher, boolean reallyDecode, OsmNodesMap hollowNodes ) throws IOException
{
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
public MicroCache createMicroCache(int lonIdx, int latIdx, DataBuffers dataBuffers, TagValueValidator wayValidator,
WaypointMatcher waypointMatcher, boolean reallyDecode, OsmNodesMap hollowNodes) throws IOException {
int subIdx = (latIdx - divisor * latDegree) * divisor + (lonIdx - divisor * lonDegree);
byte[] ab = dataBuffers.iobuffer;
int asize = getDataInputForSubIdx( subIdx, ab );
int asize = getDataInputForSubIdx(subIdx, ab);
if ( asize == 0 )
{
if (asize == 0) {
return MicroCache.emptyCache();
}
if ( asize > ab.length )
{
if (asize > ab.length) {
ab = new byte[asize];
asize = getDataInputForSubIdx( subIdx, ab );
asize = getDataInputForSubIdx(subIdx, ab);
}
StatCoderContext bc = new StatCoderContext( ab );
StatCoderContext bc = new StatCoderContext(ab);
try
{
if ( !reallyDecode )
{
try {
if (!reallyDecode) {
return null;
}
if ( hollowNodes == null )
{
return new MicroCache2( bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher );
if (hollowNodes == null) {
return new MicroCache2(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher);
}
new DirectWeaver( bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher, hollowNodes );
new DirectWeaver(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher, hollowNodes);
return MicroCache.emptyNonVirgin;
}
finally
{
} finally {
// crc check only if the buffer has not been fully read
int readBytes = (bc.getReadingBitPosition()+7)>>3;
if ( readBytes != asize-4 )
{
int crcData = Crc32.crc( ab, 0, asize - 4 );
int crcFooter = new ByteDataReader( ab, asize - 4 ).readInt();
if ( crcData == crcFooter )
{
throw new IOException( "old, unsupported data-format" );
}
else if ( ( crcData ^ 2 ) != crcFooter )
{
throw new IOException( "checkum error" );
int readBytes = (bc.getReadingBitPosition() + 7) >> 3;
if (readBytes != asize - 4) {
int crcData = Crc32.crc(ab, 0, asize - 4);
int crcFooter = new ByteDataReader(ab, asize - 4).readInt();
if (crcData == crcFooter) {
throw new IOException("old, unsupported data-format");
} else if ((crcData ^ 2) != crcFooter) {
throw new IOException("checkum error");
}
}
}
}
// set this OsmFile to ghost-state:
long setGhostState()
{
long setGhostState() {
long sum = 0;
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
for (int i = 0; i < nc; i++) {
MicroCache mc = microCaches[i];
if ( mc == null )
if (mc == null)
continue;
if ( mc.virgin )
{
if (mc.virgin) {
mc.ghost = true;
sum += mc.getDataSize();
}
else
{
} else {
microCaches[i] = null;
}
}
return sum;
}
long collectAll()
{
long collectAll() {
long deleted = 0;
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
for (int i = 0; i < nc; i++) {
MicroCache mc = microCaches[i];
if ( mc == null )
if (mc == null)
continue;
if ( !mc.ghost )
{
deleted += mc.collect( 0 );
if (!mc.ghost) {
deleted += mc.collect(0);
}
}
return deleted;
}
long cleanGhosts()
{
long cleanGhosts() {
long deleted = 0;
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
for (int i = 0; i < nc; i++) {
MicroCache mc = microCaches[i];
if ( mc == null )
if (mc == null)
continue;
if ( mc.ghost )
{
if (mc.ghost) {
microCaches[i] = null;
}
}
return deleted;
}
void clean( boolean all )
{
void clean(boolean all) {
int nc = microCaches == null ? 0 : microCaches.length;
for ( int i = 0; i < nc; i++ )
{
for (int i = 0; i < nc; i++) {
MicroCache mc = microCaches[i];
if ( mc == null )
if (mc == null)
continue;
if ( all || !mc.virgin )
{
if (all || !mc.virgin) {
microCaches[i] = null;
}
}

View file

@ -1,182 +1,155 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
public class OsmLink
{
/**
* The description bitmap contains the waytags (valid for both directions)
*/
public byte[] descriptionBitmap;
/**
* The geometry contains intermediate nodes, null for none (valid for both directions)
*/
public byte[] geometry;
// a link logically knows only its target, but for the reverse link, source and target are swapped
protected OsmNode n1;
protected OsmNode n2;
// same for the next-link-for-node pointer: previous applies to the reverse link
protected OsmLink previous;
protected OsmLink next;
private OsmLinkHolder reverselinkholder = null;
private OsmLinkHolder firstlinkholder = null;
protected OsmLink()
{
}
public OsmLink( OsmNode source, OsmNode target )
{
n1 = source;
n2 = target;
}
/**
* 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 true;
}
else
{
throw new IllegalArgumentException( "internal error: isReverse: unknown source" );
} */
}
public final boolean isBidirectional()
{
return n1 != null && n2 != null;
}
public final boolean isLinkUnused()
{
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 );
}
}
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
public class OsmLink {
/**
* The description bitmap contains the waytags (valid for both directions)
*/
public byte[] descriptionBitmap;
/**
* The geometry contains intermediate nodes, null for none (valid for both directions)
*/
public byte[] geometry;
// a link logically knows only its target, but for the reverse link, source and target are swapped
protected OsmNode n1;
protected OsmNode n2;
// same for the next-link-for-node pointer: previous applies to the reverse link
protected OsmLink previous;
protected OsmLink next;
private OsmLinkHolder reverselinkholder = null;
private OsmLinkHolder firstlinkholder = null;
protected OsmLink() {
}
public OsmLink(OsmNode source, OsmNode target) {
n1 = source;
n2 = target;
}
/**
* 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 true;
}
else
{
throw new IllegalArgumentException( "internal error: isReverse: unknown source" );
} */
}
public final boolean isBidirectional() {
return n1 != null && n2 != null;
}
public final boolean isLinkUnused() {
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);
}
}

View file

@ -1,13 +1,12 @@
/**
* Container for routig configs
*
* @author ab
*/
package btools.mapaccess;
public interface OsmLinkHolder
{
void setNextForLink( OsmLinkHolder holder );
OsmLinkHolder getNextForLink();
}
/**
* Container for routig configs
*
* @author ab
*/
package btools.mapaccess;
public interface OsmLinkHolder {
void setNextForLink(OsmLinkHolder holder);
OsmLinkHolder getNextForLink();
}

View file

@ -11,8 +11,7 @@ import btools.util.ByteArrayUnifier;
import btools.util.CheapRuler;
import btools.util.IByteArrayUnifier;
public class OsmNode extends OsmLink implements OsmPos
{
public class OsmNode extends OsmLink implements OsmPos {
/**
* The latitude
*/
@ -34,11 +33,10 @@ public class OsmNode extends OsmLink implements OsmPos
public byte[] nodeDescription;
public TurnRestriction firstRestriction;
public int visitID;
public void addTurnRestriction( TurnRestriction tr )
{
public void addTurnRestriction(TurnRestriction tr) {
tr.next = firstRestriction;
firstRestriction = tr;
}
@ -48,62 +46,50 @@ public class OsmNode extends OsmLink implements OsmPos
*/
public OsmLink firstlink;
public OsmNode()
{
public OsmNode() {
}
public OsmNode( int ilon, int ilat )
{
public OsmNode(int ilon, int ilat) {
this.ilon = ilon;
this.ilat = ilat;
}
public OsmNode( long id )
{
ilon = (int) ( id >> 32 );
ilat = (int) ( id & 0xffffffff );
public OsmNode(long id) {
ilon = (int) (id >> 32);
ilat = (int) (id & 0xffffffff);
}
// interface OsmPos
public final int getILat()
{
public final int getILat() {
return ilat;
}
public final int getILon()
{
public final int getILon() {
return ilon;
}
public final short getSElev()
{
public final short getSElev() {
return selev;
}
public final double getElev()
{
public final double getElev() {
return selev / 4.;
}
public final void addLink( OsmLink link, boolean isReverse, OsmNode tn )
{
if ( link == firstlink )
{
throw new IllegalArgumentException( "UUUUPS" );
public final void addLink(OsmLink link, boolean isReverse, OsmNode tn) {
if (link == firstlink) {
throw new IllegalArgumentException("UUUUPS");
}
if ( isReverse )
{
if (isReverse) {
link.n1 = tn;
link.n2 = this;
link.next = tn.firstlink;
link.previous = firstlink;
tn.firstlink = link;
firstlink = link;
}
else
{
} else {
link.n1 = this;
link.n2 = tn;
link.next = firstlink;
@ -113,202 +99,167 @@ public class OsmNode extends OsmLink implements OsmPos
}
}
public final int calcDistance( OsmPos p )
{
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
public final int calcDistance(OsmPos p) {
return (int) (CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
}
public String toString()
{
return "n_" + (ilon-180000000) + "_" + (ilat-90000000);
public String toString() {
return "n_" + (ilon - 180000000) + "_" + (ilat - 90000000);
}
public final void parseNodeBody( MicroCache mc, OsmNodesMap hollowNodes, IByteArrayUnifier expCtxWay )
{
if ( mc instanceof MicroCache2 )
{
parseNodeBody2( (MicroCache2) mc, hollowNodes, expCtxWay );
}
else
throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() );
public final void parseNodeBody(MicroCache mc, OsmNodesMap hollowNodes, IByteArrayUnifier expCtxWay) {
if (mc instanceof MicroCache2) {
parseNodeBody2((MicroCache2) mc, hollowNodes, expCtxWay);
} else
throw new IllegalArgumentException("unknown cache version: " + mc.getClass());
}
public final void parseNodeBody2( MicroCache2 mc, OsmNodesMap hollowNodes, IByteArrayUnifier expCtxWay )
{
public final void parseNodeBody2(MicroCache2 mc, OsmNodesMap hollowNodes, IByteArrayUnifier expCtxWay) {
ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier();
// read turn restrictions
while( mc.readBoolean() )
{
while (mc.readBoolean()) {
TurnRestriction tr = new TurnRestriction();
tr.exceptions = mc.readShort();
tr.isPositive = mc.readBoolean();
tr.exceptions = mc.readShort();
tr.isPositive = mc.readBoolean();
tr.fromLon = mc.readInt();
tr.fromLat = mc.readInt();
tr.toLon = mc.readInt();
tr.toLat = mc.readInt();
addTurnRestriction( tr );
addTurnRestriction(tr);
}
selev = mc.readShort();
int nodeDescSize = mc.readVarLengthUnsigned();
nodeDescription = nodeDescSize == 0 ? null : mc.readUnified( nodeDescSize, abUnifier );
nodeDescription = nodeDescSize == 0 ? null : mc.readUnified(nodeDescSize, abUnifier);
while (mc.hasMoreData())
{
while (mc.hasMoreData()) {
// read link data
int endPointer = mc.getEndPointer();
int linklon = ilon + mc.readVarLengthSigned();
int linklat = ilat + mc.readVarLengthSigned();
int sizecode = mc.readVarLengthUnsigned();
boolean isReverse = ( sizecode & 1 ) != 0;
boolean isReverse = (sizecode & 1) != 0;
byte[] description = null;
int descSize = sizecode >> 1;
if ( descSize > 0 )
{
description = mc.readUnified( descSize, expCtxWay );
if (descSize > 0) {
description = mc.readUnified(descSize, expCtxWay);
}
byte[] geometry = mc.readDataUntil( endPointer );
byte[] geometry = mc.readDataUntil(endPointer);
addLink( linklon, linklat, description, geometry, hollowNodes, isReverse );
addLink(linklon, linklat, description, geometry, hollowNodes, isReverse);
}
hollowNodes.remove( this );
hollowNodes.remove(this);
}
public void addLink( int linklon, int linklat, byte[] description, byte[] geometry, OsmNodesMap hollowNodes, boolean isReverse )
{
if ( linklon == ilon && linklat == ilat )
{
return; // skip self-ref
}
public void addLink(int linklon, int linklat, byte[] description, byte[] geometry, OsmNodesMap hollowNodes, boolean isReverse) {
if (linklon == ilon && linklat == ilat) {
return; // skip self-ref
}
OsmNode tn = null; // find the target node
OsmLink link = null;
OsmNode tn = null; // find the target node
OsmLink link = null;
// ...in our known links
for ( OsmLink l = firstlink; l != null; l = l.getNext( this ) )
{
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;
}
// ...in our known links
for (OsmLink l = firstlink; l != null; l = l.getNext(this)) {
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
}
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 = 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
}
}
if ( link == null )
{
addLink( link = new OsmLink(), isReverse, tn );
}
if ( !isReverse )
{
link.descriptionBitmap = description;
link.geometry = geometry;
tn = new OsmNode(linklon, linklat);
tn.setHollow();
hollowNodes.put(tn);
addLink(link = tn, isReverse, tn); // technical inheritance: link instance in node
}
}
if (link == null) {
addLink(link = new OsmLink(), isReverse, tn);
}
if (!isReverse) {
link.descriptionBitmap = description;
link.geometry = geometry;
}
}
public final boolean isHollow()
{
public final boolean isHollow() {
return selev == -12345;
}
public final void setHollow()
{
public final void setHollow() {
selev = -12345;
}
public final long getIdFromPos()
{
return ( (long) ilon ) << 32 | ilat;
public final long getIdFromPos() {
return ((long) ilon) << 32 | ilat;
}
public void vanish()
{
if ( !isHollow() )
{
public void vanish() {
if (!isHollow()) {
OsmLink l = firstlink;
while( l != null )
{
OsmNode target = l.getTarget( this );
OsmLink nextLink = l.getNext( this );
if ( !target.isHollow() )
{
unlinkLink( l );
if ( !l.isLinkUnused() )
{
target.unlinkLink( l );
}
while (l != null) {
OsmNode target = l.getTarget(this);
OsmLink nextLink = l.getNext(this);
if (!target.isHollow()) {
unlinkLink(l);
if (!l.isLinkUnused()) {
target.unlinkLink(l);
}
}
l = nextLink;
}
}
}
public final void unlinkLink( OsmLink link )
{
OsmLink n = link.clear( this );
public final void unlinkLink(OsmLink link) {
OsmLink n = link.clear(this);
if ( link == firstlink )
{
if (link == firstlink) {
firstlink = n;
return;
}
OsmLink l = firstlink;
while( l != null )
{
while (l != null) {
// if ( l.isReverse( this ) )
if ( l.n1 != this && l.n1 != null ) // isReverse inline
if (l.n1 != this && l.n1 != null) // isReverse inline
{
OsmLink nl = l.previous;
if ( nl == link )
{
if (nl == link) {
l.previous = n;
return;
}
l = nl;
}
else if ( l.n2 != this && l.n2 != null )
{
} else if (l.n2 != this && l.n2 != null) {
OsmLink nl = l.next;
if ( nl == link )
{
if (nl == link) {
l.next = n;
return;
}
l = nl;
}
else
{
throw new IllegalArgumentException( "unlinkLink: unknown source" );
} else {
throw new IllegalArgumentException("unlinkLink: unknown source");
}
}
}
@Override
public final boolean equals( Object o )
{
return ((OsmNode)o).ilon == ilon && ((OsmNode)o).ilat == ilat;
public final boolean equals(Object o) {
return ((OsmNode) o).ilon == ilon && ((OsmNode) o).ilat == ilat;
}
@Override
public final int hashCode()
{
public final int hashCode() {
return ilon + ilat;
}
}

View file

@ -7,8 +7,7 @@ package btools.mapaccess;
import btools.util.CompactLongMap;
public class OsmNodePairSet
{
public class OsmNodePairSet {
private long[] n1a;
private long[] n2a;
private int tempNodes = 0;
@ -16,108 +15,86 @@ public class OsmNodePairSet
private int npairs = 0;
private int freezecount = 0;
public OsmNodePairSet( int maxTempNodeCount )
{
public OsmNodePairSet(int maxTempNodeCount) {
maxTempNodes = maxTempNodeCount;
n1a = new long[maxTempNodes];
n2a = new long[maxTempNodes];
}
private static class OsmNodePair
{
private static class OsmNodePair {
public long node2;
public OsmNodePair next;
}
private CompactLongMap<OsmNodePair> map;
public void addTempPair( long n1, long n2 )
{
if ( tempNodes < maxTempNodes )
{
public void addTempPair(long n1, long n2) {
if (tempNodes < maxTempNodes) {
n1a[tempNodes] = n1;
n2a[tempNodes] = n2;
tempNodes++;
}
}
public void freezeTempPairs()
{
public void freezeTempPairs() {
freezecount++;
for( int i=0; i<tempNodes; i++ )
{
addPair( n1a[i], n2a[i] );
for (int i = 0; i < tempNodes; i++) {
addPair(n1a[i], n2a[i]);
}
tempNodes = 0;
}
public void clearTempPairs()
{
public void clearTempPairs() {
tempNodes = 0;
}
private void addPair( long n1, long n2 )
{
if ( map == null )
{
private void addPair(long n1, long n2) {
if (map == null) {
map = new CompactLongMap<OsmNodePair>();
}
npairs++;
OsmNodePair e = getElement( n1, n2 );
if ( e == null )
{
OsmNodePair e = getElement(n1, n2);
if (e == null) {
e = new OsmNodePair();
e.node2 = n2;
OsmNodePair e0 = map.get( n1 );
if ( e0 != null )
{
while( e0.next != null )
{
OsmNodePair e0 = map.get(n1);
if (e0 != null) {
while (e0.next != null) {
e0 = e0.next;
}
e0.next = e;
}
else
{
map.fastPut( n1, e );
} else {
map.fastPut(n1, e);
}
}
}
public int size()
{
public int size() {
return npairs;
}
public int tempSize()
{
public int tempSize() {
return tempNodes;
}
public int getMaxTmpNodes()
{
public int getMaxTmpNodes() {
return maxTempNodes;
}
public int getFreezeCount()
{
public int getFreezeCount() {
return freezecount;
}
public boolean hasPair( long n1, long n2 )
{
return map != null && ( getElement( n1, n2 ) != null || getElement( n2, n1 ) != null );
public boolean hasPair(long n1, long n2) {
return map != null && (getElement(n1, n2) != null || getElement(n2, n1) != null);
}
private OsmNodePair getElement( long n1, long n2 )
{
OsmNodePair e = map.get( n1 );
while (e != null)
{
if ( e.node2 == n2 )
{
private OsmNodePair getElement(long n1, long n2) {
OsmNodePair e = map.get(n1);
while (e != null) {
if (e.node2 == n2) {
return e;
}
e = e.next;

View file

@ -1,348 +1,293 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
import java.util.ArrayList;
import java.util.HashMap;
import btools.util.ByteArrayUnifier;
import btools.util.SortedHeap;
public final class OsmNodesMap
{
private HashMap<OsmNode,OsmNode> hmap = new HashMap<OsmNode,OsmNode>(4096);
private ByteArrayUnifier abUnifier = new ByteArrayUnifier( 16384, false );
private OsmNode testKey = new OsmNode();
public int nodesCreated;
public long maxmem;
private long currentmaxmem = 4000000; // start with 4 MB
public int lastVisitID = 1000;
public int baseID = 1000;
public OsmNode destination;
public int currentPathCost;
public int currentMaxCost = 1000000000;
public OsmNode endNode1;
public OsmNode endNode2;
public int cleanupMode = 0;
public void cleanupAndCount( OsmNode[] nodes )
{
if ( cleanupMode == 0 )
{
justCount( nodes );
}
else
{
cleanupPeninsulas( nodes );
}
}
private void justCount( OsmNode[] nodes )
{
for( int i=0; i<nodes.length; i++ )
{
OsmNode n = nodes[i];
if ( n.firstlink != null )
{
nodesCreated++;
}
}
}
private void cleanupPeninsulas( OsmNode[] nodes )
{
baseID = lastVisitID++;
for( int i=0; i<nodes.length; i++ ) // loop over nodes again just for housekeeping
{
OsmNode n = nodes[i];
if ( n.firstlink != null )
{
if ( n.visitID == 1 )
{
try
{
minVisitIdInSubtree( null, n );
}
catch( StackOverflowError soe )
{
// System.out.println( "+++++++++++++++ StackOverflowError ++++++++++++++++" );
}
}
}
}
}
private int minVisitIdInSubtree( OsmNode source, OsmNode n )
{
if ( n.visitID == 1 ) n.visitID = baseID; // border node
else n.visitID = lastVisitID++;
int minId = n.visitID;
nodesCreated++;
OsmLink nextLink = null;
for( OsmLink l = n.firstlink; l != null; l = nextLink )
{
nextLink = l.getNext( n );
OsmNode t = l.getTarget( n );
if ( t == source ) continue;
if ( t.isHollow() ) continue;
int minIdSub = t.visitID;
if ( minIdSub == 1 )
{
minIdSub = baseID;
}
else if ( minIdSub == 0 )
{
int nodesCreatedUntilHere = nodesCreated;
minIdSub = minVisitIdInSubtree( n, t);
if ( minIdSub > n.visitID ) // peninsula ?
{
nodesCreated = nodesCreatedUntilHere;
n.unlinkLink( l );
t.unlinkLink( l );
}
}
else if ( minIdSub < baseID )
{
continue;
}
else if ( cleanupMode == 2 )
{
minIdSub = baseID; // in tree-mode, hitting anything is like a gateway
}
if ( minIdSub < minId ) minId = minIdSub;
}
return minId;
}
public boolean isInMemoryBounds( int npaths, boolean extend )
{
// long total = nodesCreated * 76L + linksCreated * 48L;
long total = nodesCreated * 95L + npaths * 200L;
if ( extend )
{
total += 100000;
// when extending, try to have 1 MB space
long delta = total + 1900000 - currentmaxmem;
if ( delta > 0 )
{
currentmaxmem += delta;
if ( currentmaxmem > maxmem )
{
currentmaxmem = maxmem;
}
}
}
return total <= currentmaxmem;
}
private void addActiveNode( ArrayList<OsmNode> nodes2check, OsmNode n )
{
n.visitID = lastVisitID;
nodesCreated++;
nodes2check.add( n );
}
// is there an escape from this node
// to a hollow node (or destination node) ?
public boolean canEscape( OsmNode n0 )
{
boolean sawLowIDs = false;
lastVisitID++;
nodes2check.clear();
nodes2check.add( n0 );
while ( !nodes2check.isEmpty() )
{
OsmNode n = nodes2check.remove( nodes2check.size()-1 );
if ( n.visitID < baseID )
{
n.visitID = lastVisitID;
nodesCreated++;
for( OsmLink l = n.firstlink; l != null; l = l.getNext( n ) )
{
OsmNode t = l.getTarget( n );
nodes2check.add( t );
}
}
else if ( n.visitID < lastVisitID )
{
sawLowIDs = true;
}
}
if ( sawLowIDs )
{
return true;
}
nodes2check.add( n0 );
while ( !nodes2check.isEmpty() )
{
OsmNode n = nodes2check.remove( nodes2check.size()-1 );
if ( n.visitID == lastVisitID )
{
n.visitID = lastVisitID;
nodesCreated--;
for( OsmLink l = n.firstlink; l != null; l = l.getNext( n ) )
{
OsmNode t = l.getTarget( n );
nodes2check.add( t );
}
n.vanish();
}
}
return false;
}
private ArrayList<OsmNode> nodes2check;
public void clearTemp()
{
nodes2check = null;
}
public void collectOutreachers()
{
nodes2check = new ArrayList<OsmNode>(nodesCreated);
nodesCreated=0;
for( OsmNode n : hmap.values() )
{
addActiveNode( nodes2check, n );
}
lastVisitID++;
baseID = lastVisitID;
while ( !nodes2check.isEmpty() )
{
OsmNode n = nodes2check.remove( nodes2check.size()-1 );
n.visitID = lastVisitID;
for( OsmLink l = n.firstlink; l != null; l = l.getNext( n ) )
{
OsmNode t = l.getTarget( n );
if ( t.visitID != lastVisitID )
{
addActiveNode( nodes2check, t );
}
}
if ( destination != null && currentMaxCost < 1000000000 )
{
int distance = n.calcDistance( destination );
if ( distance > currentMaxCost - currentPathCost + 100 )
{
n.vanish();
}
}
if ( n.firstlink == null )
{
nodesCreated--;
}
}
}
public ByteArrayUnifier getByteArrayUnifier()
{
return abUnifier;
}
/**
* Get a node from the map
* @return the node for the given id if exist, else null
*/
public OsmNode get( int ilon, int ilat )
{
testKey.ilon = ilon;
testKey.ilat = ilat;
return hmap.get( testKey );
}
public void remove( OsmNode node )
{
if ( node != endNode1 && node != endNode2 ) // keep endnodes in hollow-map even when loaded
{ // (needed for escape analysis)
hmap.remove( node );
}
}
/**
* Put a node into the map
* @return the previous node if that id existed, else null
*/
public OsmNode put( OsmNode node )
{
return hmap.put( node, node );
}
// ********************** test cleanup **********************
private static void addLinks( OsmNode[] nodes, int idx, boolean isBorder, int[] links )
{
OsmNode n = nodes[idx];
n.visitID = isBorder ? 1 : 0;
n.selev = (short)idx;
for( int i : links )
{
OsmNode t = nodes[i];
OsmLink link = n.isLinkUnused() ? n : ( t.isLinkUnused() ? t : null );
if ( link == null )
{
link = new OsmLink();
}
n.addLink( link, false, t );
}
}
public static void main( String[] args )
{
OsmNode[] nodes = new OsmNode[12];
for( int i=0; i<nodes.length; i++ )
{
nodes[i]= new OsmNode( (i+1000)*1000,(i+1000)*1000 );
}
addLinks( nodes, 0, true , new int[]{1,5} ); // 0
addLinks( nodes, 1, true , new int[]{} ); // 1
addLinks( nodes, 2, false, new int[]{3,4} ); // 2
addLinks( nodes, 3, false, new int[]{4} ); // 3
addLinks( nodes, 4, false, new int[]{} ); // 4
addLinks( nodes, 5, true , new int[]{6,9} ); // 5
addLinks( nodes, 6, false, new int[]{7,8} ); // 6
addLinks( nodes, 7, false, new int[]{} ); // 7
addLinks( nodes, 8, false, new int[]{} ); // 8
addLinks( nodes, 9, false, new int[]{10,11} ); // 9
addLinks( nodes, 10, false, new int[]{11} ); // 10
addLinks( nodes, 11, false, new int[]{} ); // 11
OsmNodesMap nm = new OsmNodesMap();
nm.cleanupMode = 2;
nm.cleanupAndCount( nodes );
System.out.println( "nodesCreated=" + nm.nodesCreated );
nm.cleanupAndCount( nodes );
System.out.println( "nodesCreated=" + nm.nodesCreated );
}
}
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
import java.util.ArrayList;
import java.util.HashMap;
import btools.util.ByteArrayUnifier;
import btools.util.SortedHeap;
public final class OsmNodesMap {
private HashMap<OsmNode, OsmNode> hmap = new HashMap<OsmNode, OsmNode>(4096);
private ByteArrayUnifier abUnifier = new ByteArrayUnifier(16384, false);
private OsmNode testKey = new OsmNode();
public int nodesCreated;
public long maxmem;
private long currentmaxmem = 4000000; // start with 4 MB
public int lastVisitID = 1000;
public int baseID = 1000;
public OsmNode destination;
public int currentPathCost;
public int currentMaxCost = 1000000000;
public OsmNode endNode1;
public OsmNode endNode2;
public int cleanupMode = 0;
public void cleanupAndCount(OsmNode[] nodes) {
if (cleanupMode == 0) {
justCount(nodes);
} else {
cleanupPeninsulas(nodes);
}
}
private void justCount(OsmNode[] nodes) {
for (int i = 0; i < nodes.length; i++) {
OsmNode n = nodes[i];
if (n.firstlink != null) {
nodesCreated++;
}
}
}
private void cleanupPeninsulas(OsmNode[] nodes) {
baseID = lastVisitID++;
for (int i = 0; i < nodes.length; i++) // loop over nodes again just for housekeeping
{
OsmNode n = nodes[i];
if (n.firstlink != null) {
if (n.visitID == 1) {
try {
minVisitIdInSubtree(null, n);
} catch (StackOverflowError soe) {
// System.out.println( "+++++++++++++++ StackOverflowError ++++++++++++++++" );
}
}
}
}
}
private int minVisitIdInSubtree(OsmNode source, OsmNode n) {
if (n.visitID == 1) n.visitID = baseID; // border node
else n.visitID = lastVisitID++;
int minId = n.visitID;
nodesCreated++;
OsmLink nextLink = null;
for (OsmLink l = n.firstlink; l != null; l = nextLink) {
nextLink = l.getNext(n);
OsmNode t = l.getTarget(n);
if (t == source) continue;
if (t.isHollow()) continue;
int minIdSub = t.visitID;
if (minIdSub == 1) {
minIdSub = baseID;
} else if (minIdSub == 0) {
int nodesCreatedUntilHere = nodesCreated;
minIdSub = minVisitIdInSubtree(n, t);
if (minIdSub > n.visitID) // peninsula ?
{
nodesCreated = nodesCreatedUntilHere;
n.unlinkLink(l);
t.unlinkLink(l);
}
} else if (minIdSub < baseID) {
continue;
} else if (cleanupMode == 2) {
minIdSub = baseID; // in tree-mode, hitting anything is like a gateway
}
if (minIdSub < minId) minId = minIdSub;
}
return minId;
}
public boolean isInMemoryBounds(int npaths, boolean extend) {
// long total = nodesCreated * 76L + linksCreated * 48L;
long total = nodesCreated * 95L + npaths * 200L;
if (extend) {
total += 100000;
// when extending, try to have 1 MB space
long delta = total + 1900000 - currentmaxmem;
if (delta > 0) {
currentmaxmem += delta;
if (currentmaxmem > maxmem) {
currentmaxmem = maxmem;
}
}
}
return total <= currentmaxmem;
}
private void addActiveNode(ArrayList<OsmNode> nodes2check, OsmNode n) {
n.visitID = lastVisitID;
nodesCreated++;
nodes2check.add(n);
}
// is there an escape from this node
// to a hollow node (or destination node) ?
public boolean canEscape(OsmNode n0) {
boolean sawLowIDs = false;
lastVisitID++;
nodes2check.clear();
nodes2check.add(n0);
while (!nodes2check.isEmpty()) {
OsmNode n = nodes2check.remove(nodes2check.size() - 1);
if (n.visitID < baseID) {
n.visitID = lastVisitID;
nodesCreated++;
for (OsmLink l = n.firstlink; l != null; l = l.getNext(n)) {
OsmNode t = l.getTarget(n);
nodes2check.add(t);
}
} else if (n.visitID < lastVisitID) {
sawLowIDs = true;
}
}
if (sawLowIDs) {
return true;
}
nodes2check.add(n0);
while (!nodes2check.isEmpty()) {
OsmNode n = nodes2check.remove(nodes2check.size() - 1);
if (n.visitID == lastVisitID) {
n.visitID = lastVisitID;
nodesCreated--;
for (OsmLink l = n.firstlink; l != null; l = l.getNext(n)) {
OsmNode t = l.getTarget(n);
nodes2check.add(t);
}
n.vanish();
}
}
return false;
}
private ArrayList<OsmNode> nodes2check;
public void clearTemp() {
nodes2check = null;
}
public void collectOutreachers() {
nodes2check = new ArrayList<OsmNode>(nodesCreated);
nodesCreated = 0;
for (OsmNode n : hmap.values()) {
addActiveNode(nodes2check, n);
}
lastVisitID++;
baseID = lastVisitID;
while (!nodes2check.isEmpty()) {
OsmNode n = nodes2check.remove(nodes2check.size() - 1);
n.visitID = lastVisitID;
for (OsmLink l = n.firstlink; l != null; l = l.getNext(n)) {
OsmNode t = l.getTarget(n);
if (t.visitID != lastVisitID) {
addActiveNode(nodes2check, t);
}
}
if (destination != null && currentMaxCost < 1000000000) {
int distance = n.calcDistance(destination);
if (distance > currentMaxCost - currentPathCost + 100) {
n.vanish();
}
}
if (n.firstlink == null) {
nodesCreated--;
}
}
}
public ByteArrayUnifier getByteArrayUnifier() {
return abUnifier;
}
/**
* Get a node from the map
*
* @return the node for the given id if exist, else null
*/
public OsmNode get(int ilon, int ilat) {
testKey.ilon = ilon;
testKey.ilat = ilat;
return hmap.get(testKey);
}
public void remove(OsmNode node) {
if (node != endNode1 && node != endNode2) // keep endnodes in hollow-map even when loaded
{ // (needed for escape analysis)
hmap.remove(node);
}
}
/**
* Put a node into the map
*
* @return the previous node if that id existed, else null
*/
public OsmNode put(OsmNode node) {
return hmap.put(node, node);
}
// ********************** test cleanup **********************
private static void addLinks(OsmNode[] nodes, int idx, boolean isBorder, int[] links) {
OsmNode n = nodes[idx];
n.visitID = isBorder ? 1 : 0;
n.selev = (short) idx;
for (int i : links) {
OsmNode t = nodes[i];
OsmLink link = n.isLinkUnused() ? n : (t.isLinkUnused() ? t : null);
if (link == null) {
link = new OsmLink();
}
n.addLink(link, false, t);
}
}
public static void main(String[] args) {
OsmNode[] nodes = new OsmNode[12];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new OsmNode((i + 1000) * 1000, (i + 1000) * 1000);
}
addLinks(nodes, 0, true, new int[]{1, 5}); // 0
addLinks(nodes, 1, true, new int[]{}); // 1
addLinks(nodes, 2, false, new int[]{3, 4}); // 2
addLinks(nodes, 3, false, new int[]{4}); // 3
addLinks(nodes, 4, false, new int[]{}); // 4
addLinks(nodes, 5, true, new int[]{6, 9}); // 5
addLinks(nodes, 6, false, new int[]{7, 8}); // 6
addLinks(nodes, 7, false, new int[]{}); // 7
addLinks(nodes, 8, false, new int[]{}); // 8
addLinks(nodes, 9, false, new int[]{10, 11}); // 9
addLinks(nodes, 10, false, new int[]{11}); // 10
addLinks(nodes, 11, false, new int[]{}); // 11
OsmNodesMap nm = new OsmNodesMap();
nm.cleanupMode = 2;
nm.cleanupAndCount(nodes);
System.out.println("nodesCreated=" + nm.nodesCreated);
nm.cleanupAndCount(nodes);
System.out.println("nodesCreated=" + nm.nodesCreated);
}
}

View file

@ -1,23 +1,22 @@
/**
* Interface for a position (OsmNode or OsmPath)
*
* @author ab
*/
package btools.mapaccess;
public interface OsmPos
{
public int getILat();
public int getILon();
public short getSElev();
public double getElev();
public int calcDistance( OsmPos p );
public long getIdFromPos();
}
/**
* Interface for a position (OsmNode or OsmPath)
*
* @author ab
*/
package btools.mapaccess;
public interface OsmPos {
public int getILat();
public int getILon();
public short getSElev();
public double getElev();
public int calcDistance(OsmPos p);
public long getIdFromPos();
}

View file

@ -1,19 +1,16 @@
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
public final class OsmTransferNode
{
public OsmTransferNode next;
public int ilon;
public int ilat;
public short selev;
}
/**
* Container for link between two Osm nodes
*
* @author ab
*/
package btools.mapaccess;
public final class OsmTransferNode {
public OsmTransferNode next;
public int ilon;
public int ilat;
public short selev;
}

View file

@ -14,29 +14,27 @@ import btools.codec.MicroCache;
import btools.util.ByteDataReader;
import btools.util.Crc32;
final public class PhysicalFile
{
final public class PhysicalFile {
RandomAccessFile ra = null;
long[] fileIndex = new long[25];
int[] fileHeaderCrcs;
private int fileIndexCrc;
public long creationTime;
String fileName;
public int divisor = 80;
public static void main( String[] args )
{
public static void main(String[] args) {
MicroCache.debug = true;
try {
checkFileIntegrity( new File( args[0] ) );
checkFileIntegrity(new File(args[0]));
} catch (IOException e) {
System.err.println( "************************************" );
System.err.println("************************************");
e.printStackTrace();
System.err.println( "************************************" );
System.err.println("************************************");
}
}
@ -45,56 +43,46 @@ final public class PhysicalFile
*
* @return the error message if file corrupt, else null
*/
public static String checkFileIntegrity( File f ) throws IOException
{
public static String checkFileIntegrity(File f) throws IOException {
PhysicalFile pf = null;
try
{
try {
DataBuffers dataBuffers = new DataBuffers();
pf = new PhysicalFile( f, dataBuffers, -1, -1 );
pf = new PhysicalFile(f, dataBuffers, -1, -1);
int div = pf.divisor;
for ( int lonDegree = 0; lonDegree < 5; lonDegree++ ) // does'nt really matter..
for (int lonDegree = 0; lonDegree < 5; lonDegree++) // does'nt really matter..
{
for ( int latDegree = 0; latDegree < 5; latDegree++ ) // ..where on earth we are
for (int latDegree = 0; latDegree < 5; latDegree++) // ..where on earth we are
{
OsmFile osmf = new OsmFile( pf, lonDegree, latDegree, dataBuffers );
if ( osmf.hasData() )
for ( int lonIdx = 0; lonIdx < div; lonIdx++ )
for ( int latIdx = 0; latIdx < div; latIdx++ )
osmf.createMicroCache( lonDegree * div + lonIdx, latDegree * div + latIdx, dataBuffers, null, null, MicroCache.debug, null );
OsmFile osmf = new OsmFile(pf, lonDegree, latDegree, dataBuffers);
if (osmf.hasData())
for (int lonIdx = 0; lonIdx < div; lonIdx++)
for (int latIdx = 0; latIdx < div; latIdx++)
osmf.createMicroCache(lonDegree * div + lonIdx, latDegree * div + latIdx, dataBuffers, null, null, MicroCache.debug, null);
}
}
}
finally
{
if ( pf != null )
try
{
} finally {
if (pf != null)
try {
pf.ra.close();
}
catch (Exception ee)
{
} catch (Exception ee) {
}
}
return null;
}
public PhysicalFile( File f, DataBuffers dataBuffers, int lookupVersion, int lookupMinorVersion ) throws IOException
{
public PhysicalFile(File f, DataBuffers dataBuffers, int lookupVersion, int lookupMinorVersion) throws IOException {
fileName = f.getName();
byte[] iobuffer = dataBuffers.iobuffer;
ra = new RandomAccessFile( f, "r" );
ra.readFully( iobuffer, 0, 200 );
fileIndexCrc = Crc32.crc( iobuffer, 0, 200 );
ByteDataReader dis = new ByteDataReader( iobuffer );
for( int i=0; i<25; i++ )
{
ra = new RandomAccessFile(f, "r");
ra.readFully(iobuffer, 0, 200);
fileIndexCrc = Crc32.crc(iobuffer, 0, 200);
ByteDataReader dis = new ByteDataReader(iobuffer);
for (int i = 0; i < 25; i++) {
long lv = dis.readLong();
short readVersion = (short)(lv >> 48);
if ( i == 0 && lookupVersion != -1 && readVersion != lookupVersion )
{
throw new IOException( "lookup version mismatch (old rd5?) lookups.dat="
+ lookupVersion + " " + f. getAbsolutePath() + "=" + readVersion );
short readVersion = (short) (lv >> 48);
if (i == 0 && lookupVersion != -1 && readVersion != lookupVersion) {
throw new IOException("lookup version mismatch (old rd5?) lookups.dat="
+ lookupVersion + " " + f.getAbsolutePath() + "=" + readVersion);
}
fileIndex[i] = lv & 0xffffffffffffL;
}
@ -103,36 +91,30 @@ final public class PhysicalFile
long len = ra.length();
long pos = fileIndex[24];
int extraLen = 8 + 26*4;
int extraLen = 8 + 26 * 4;
if ( len == pos ) return; // old format o.k.
if (len == pos) return; // old format o.k.
if ( len < pos+extraLen ) // > is o.k. for future extensions!
if (len < pos + extraLen) // > is o.k. for future extensions!
{
throw new IOException( "file of size " + len + " too short, should be " + (pos+extraLen) );
throw new IOException("file of size " + len + " too short, should be " + (pos + extraLen));
}
ra.seek( pos );
ra.readFully( iobuffer, 0, extraLen );
dis = new ByteDataReader( iobuffer );
ra.seek(pos);
ra.readFully(iobuffer, 0, extraLen);
dis = new ByteDataReader(iobuffer);
creationTime = dis.readLong();
int crcData = dis.readInt();
if ( crcData == fileIndexCrc )
{
if (crcData == fileIndexCrc) {
divisor = 80; // old format
}
else if ( (crcData ^ 2) == fileIndexCrc )
{
} else if ((crcData ^ 2) == fileIndexCrc) {
divisor = 32; // new format
}
else
{
throw new IOException( "top index checksum error" );
} else {
throw new IOException("top index checksum error");
}
fileHeaderCrcs = new int[25];
for( int i=0; i<25; i++ )
{
for (int i = 0; i < 25; i++) {
fileHeaderCrcs[i] = dis.readInt();
}
}

View file

@ -13,90 +13,77 @@ import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
final public class Rd5DiffManager
{
public static void main( String[] args ) throws Exception
{
calcDiffs( new File( args[0] ),new File( args[1] ) );
final public class Rd5DiffManager {
public static void main(String[] args) throws Exception {
calcDiffs(new File(args[0]), new File(args[1]));
}
/**
* Compute diffs for all RD5 files
*/
public static void calcDiffs( File oldDir, File newDir ) throws Exception
{
File oldDiffDir = new File( oldDir, "diff" );
File newDiffDir = new File( newDir, "diff" );
public static void calcDiffs(File oldDir, File newDir) throws Exception {
File oldDiffDir = new File(oldDir, "diff");
File newDiffDir = new File(newDir, "diff");
File[] filesNew = newDir.listFiles();
for( File fn : filesNew )
{
for (File fn : filesNew) {
String name = fn.getName();
if ( !name.endsWith( ".rd5" ) )
{
if (!name.endsWith(".rd5")) {
continue;
}
if ( fn.length() < 1024*1024 )
{
if (fn.length() < 1024 * 1024) {
continue; // exclude very small files from diffing
}
String basename = name.substring( 0, name.length() - 4 );
File fo = new File( oldDir, name );
if ( !fo.isFile() )
{
String basename = name.substring(0, name.length() - 4);
File fo = new File(oldDir, name);
if (!fo.isFile()) {
continue;
}
// calculate MD5 of old file
String md5 = getMD5( fo );
String md5New = getMD5( fn );
System.out.println( "name=" + name + " md5=" + md5 );
File specificNewDiffs = new File( newDiffDir, basename );
// calculate MD5 of old file
String md5 = getMD5(fo);
String md5New = getMD5(fn);
System.out.println("name=" + name + " md5=" + md5);
File specificNewDiffs = new File(newDiffDir, basename);
specificNewDiffs.mkdirs();
String diffFileName = md5 + ".df5";
File diffFile = new File( specificNewDiffs, diffFileName );
File diffFile = new File(specificNewDiffs, diffFileName);
String dummyDiffFileName = md5New + ".df5";
File dummyDiffFile = new File( specificNewDiffs, dummyDiffFileName );
File dummyDiffFile = new File(specificNewDiffs, dummyDiffFileName);
dummyDiffFile.createNewFile();
// calc the new diff
Rd5DiffTool.diff2files( fo, fn, diffFile );
Rd5DiffTool.diff2files(fo, fn, diffFile);
// ... and add that to old diff files
File specificOldDiffs = new File( oldDiffDir, basename );
if ( specificOldDiffs.isDirectory() )
{
File specificOldDiffs = new File(oldDiffDir, basename);
if (specificOldDiffs.isDirectory()) {
File[] oldDiffs = specificOldDiffs.listFiles();
for( File od : oldDiffs )
{
if ( !od.getName().endsWith( ".df5" ) )
{
for (File od : oldDiffs) {
if (!od.getName().endsWith(".df5")) {
continue;
}
if ( System.currentTimeMillis() - od.lastModified() > 9*86400000L )
{
if (System.currentTimeMillis() - od.lastModified() > 9 * 86400000L) {
continue; // limit diff history to 9 days
}
File updatedDiff = new File( specificNewDiffs, od.getName() );
if ( !updatedDiff.exists() )
{
Rd5DiffTool.addDeltas( od, diffFile, updatedDiff );
updatedDiff.setLastModified( od.lastModified() );
File updatedDiff = new File(specificNewDiffs, od.getName());
if (!updatedDiff.exists()) {
Rd5DiffTool.addDeltas(od, diffFile, updatedDiff);
updatedDiff.setLastModified(od.lastModified());
}
}
}
}
}
public static String getMD5( File f ) throws IOException
{
public static String getMD5(File f) throws IOException {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
@ -121,9 +108,8 @@ final public class Rd5DiffManager
throw new IOException("MD5 algorithm not available", e);
}
}
private static char hexChar( int v )
{
return (char) ( v > 9 ? 'a' + (v-10) : '0' + v );
private static char hexChar(int v) {
return (char) (v > 9 ? 'a' + (v - 10) : '0' + v);
}
}

Some files were not shown because too many files have changed in this diff Show more