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 # Reformat brouter-routing-app using Android Studio
54d5c5e9439be2c3df4c95b6fc12d33fdcc9b389 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 * Container for some re-usable databuffers for the decoder
*/ */
public final class DataBuffers public final class DataBuffers {
{
public byte[] iobuffer; public byte[] iobuffer;
public byte[] tagbuf1 = new byte[256]; 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 byte[] bbuf1 = new byte[65636];
public int[] ibuf1 = new int[4096]; public int[] ibuf1 = new int[4096];
public int[] ibuf2 = new int[2048]; public int[] ibuf2 = new int[2048];
@ -17,17 +16,15 @@ public final class DataBuffers
public int[] alon = new int[2048]; public int[] alon = new int[2048];
public int[] alat = new int[2048]; public int[] alat = new int[2048];
public DataBuffers() public DataBuffers() {
{ this(new byte[65636]);
this( new byte[65636] );
} }
/** /**
* construct a set of databuffers except * construct a set of databuffers except
* for 'iobuffer', where the given array is used * for 'iobuffer', where the given array is used
*/ */
public DataBuffers( byte[] iobuffer ) public DataBuffers(byte[] iobuffer) {
{
this.iobuffer = iobuffer; this.iobuffer = iobuffer;
} }

View File

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

View File

@ -3,8 +3,7 @@ package btools.codec;
/** /**
* Simple container for a list of lists of integers * Simple container for a list of lists of integers
*/ */
public class LinkedListContainer public class LinkedListContainer {
{
private int[] ia; // prev, data, prev, data, ... private int[] ia; // prev, data, prev, data, ...
private int size; private int size;
private int[] startpointer; // 0=void, odd=head-data-cell 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 * Construct a container for the given number of lists
* * <p>
* If no default-buffer is given, an int[nlists*4] is constructed, * If no default-buffer is given, an int[nlists*4] is constructed,
* able to hold 2 entries per list on average * 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) * @param defaultbuffer an optional data array for re-use (gets replaced if too small)
*/ */
public LinkedListContainer( int nlists, int[] defaultbuffer ) public LinkedListContainer(int nlists, int[] defaultbuffer) {
{ ia = defaultbuffer == null ? new int[nlists * 4] : defaultbuffer;
ia = defaultbuffer == null ? new int[nlists*4] : defaultbuffer; startpointer = new int[nlists];
startpointer = new int[nlists];
} }
/** /**
* Add a data element to the given list * Add a data element to the given list
* *
* @param listNr the list to add the data to * @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 ) public void addDataElement(int listNr, int data) {
{ if (size + 2 > ia.length) {
if ( size + 2 > ia.length )
{
resize(); resize();
} }
ia[size++] = startpointer[ listNr ]; ia[size++] = startpointer[listNr];
startpointer[ listNr ] = size; startpointer[listNr] = size;
ia[size++] = data; ia[size++] = data;
} }
/** /**
* Initialize a list for reading * Initialize a list for reading
* *
* @param listNr the list to initialize * @param listNr the list to initialize
* @return the number of entries in that list * @return the number of entries in that list
*/ */
public int initList( int listNr ) public int initList(int listNr) {
{
int cnt = 0; int cnt = 0;
int lp = listpointer = startpointer[ listNr ]; int lp = listpointer = startpointer[listNr];
while( lp != 0 ) while (lp != 0) {
{ lp = ia[lp - 1];
lp = ia[ lp-1 ];
cnt++; cnt++;
} }
return cnt; return cnt;
@ -67,21 +61,18 @@ public class LinkedListContainer
* @return the data element * @return the data element
* @throws IllegalArgumentException if no more element * @throws IllegalArgumentException if no more element
*/ */
public int getDataElement() public int getDataElement() {
{ if (listpointer == 0) {
if ( listpointer == 0 ) throw new IllegalArgumentException("no more element!");
{
throw new IllegalArgumentException( "no more element!" );
} }
int data = ia[ listpointer ]; int data = ia[listpointer];
listpointer = ia[ listpointer-1 ]; listpointer = ia[listpointer - 1];
return data; return data;
} }
private void resize() private void resize() {
{ int[] ia2 = new int[2 * ia.length];
int[] ia2 = new int[2*ia.length]; System.arraycopy(ia, 0, ia2, 0, ia.length);
System.arraycopy( ia, 0, ia2, 0, ia.length );
ia = ia2; 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 * a micro-cache is a data cache for an area of some square kilometers or some
* hundreds or thousands nodes * hundreds or thousands nodes
* * <p>
* This is the basic io-unit: always a full microcache is loaded from the * 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 * data-file if a node is requested at a position not yet covered by the caches
* already loaded * already loaded
* * <p>
* The nodes are represented in a compact way (typical 20-50 bytes per node), * 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 * 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. * supported to remove the nodes already consumed from the cache.
* * <p>
* The cache-internal data representation is different from that in the * The cache-internal data representation is different from that in the
* data-files, where a cache is encoded as a whole, allowing more * data-files, where a cache is encoded as a whole, allowing more
* redundancy-removal for a more compact encoding * redundancy-removal for a more compact encoding
*/ */
public class MicroCache extends ByteDataWriter public class MicroCache extends ByteDataWriter {
{
protected int[] faid; protected int[] faid;
protected int[] fapos; protected int[] fapos;
protected int size = 0; protected int size = 0;
@ -35,25 +34,21 @@ public class MicroCache extends ByteDataWriter
public static boolean debug = false; public static boolean debug = false;
protected MicroCache( byte[] ab ) protected MicroCache(byte[] ab) {
{ super(ab);
super( ab );
} }
public final static MicroCache emptyNonVirgin = new MicroCache( null ); public final static MicroCache emptyNonVirgin = new MicroCache(null);
static static {
{
emptyNonVirgin.virgin = false; emptyNonVirgin.virgin = false;
} }
public static MicroCache emptyCache() public static MicroCache emptyCache() {
{ return new MicroCache(null); // TODO: singleton?
return new MicroCache( null ); // TODO: singleton?
} }
protected void init( int size ) protected void init(int size) {
{
this.size = size; this.size = size;
delcount = 0; delcount = 0;
delbytes = 0; delbytes = 0;
@ -62,35 +57,31 @@ public class MicroCache extends ByteDataWriter
p2size >>= 1; p2size >>= 1;
} }
public final void finishNode( long id ) public final void finishNode(long id) {
{
fapos[size] = aboffset; fapos[size] = aboffset;
faid[size] = shrinkId( id ); faid[size] = shrinkId(id);
size++; size++;
} }
public final void discardNode() public final void discardNode() {
{ aboffset = startPos(size);
aboffset = startPos( size );
} }
public final int getSize() public final int getSize() {
{
return size; return size;
} }
public final int getDataSize() public final int getDataSize() {
{
return ab == null ? 0 : ab.length; return ab == null ? 0 : ab.length;
} }
/** /**
* Set the internal reader (aboffset, aboffsetEnd) to the body data for the given id * 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 * 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), * (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. * 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 * Current implementation always returns false for not-found, however, for
* regression testing, at least for the case that is most likely a bug * regression testing, at least for the case that is most likely a bug
* (node found but marked as deleted = ready for garbage collection * (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 * @return true if id was found
*/ */
public final boolean getAndClear( long id64 ) public final boolean getAndClear(long id64) {
{ if (size == 0) {
if ( size == 0 )
{
return false; return false;
} }
int id = shrinkId( id64 ); int id = shrinkId(id64);
int[] a = faid; int[] a = faid;
int offset = p2size; int offset = p2size;
int n = 0; int n = 0;
while (offset > 0) while (offset > 0) {
{
int nn = n + offset; int nn = n + offset;
if ( nn < size && a[nn] <= id ) if (nn < size && a[nn] <= id) {
{
n = nn; n = nn;
} }
offset >>= 1; offset >>= 1;
} }
if ( a[n] == id ) if (a[n] == id) {
{ if ((fapos[n] & 0x80000000) == 0) {
if ( ( fapos[n] & 0x80000000 ) == 0 ) aboffset = startPos(n);
{
aboffset = startPos( n );
aboffsetEnd = fapos[n]; aboffsetEnd = fapos[n];
fapos[n] |= 0x80000000; // mark deleted fapos[n] |= 0x80000000; // mark deleted
delbytes += aboffsetEnd - aboffset; delbytes += aboffsetEnd - aboffset;
delcount++; delcount++;
return true; return true;
} } else // .. marked as deleted
else // .. marked as deleted
{ {
// throw new RuntimeException( "MicroCache: node already consumed: id=" + id ); // throw new RuntimeException( "MicroCache: node already consumed: id=" + id );
} }
@ -137,43 +121,35 @@ public class MicroCache extends ByteDataWriter
return false; return false;
} }
protected final int startPos( int n ) protected final int startPos(int n) {
{
return n > 0 ? fapos[n - 1] & 0x7fffffff : 0; return n > 0 ? fapos[n - 1] & 0x7fffffff : 0;
} }
public final int collect( int threshold ) public final int collect(int threshold) {
{ if (delcount <= threshold) {
if ( delcount <= threshold )
{
return 0; return 0;
} }
virgin = false; virgin = false;
int nsize = size - delcount; int nsize = size - delcount;
if ( nsize == 0 ) if (nsize == 0) {
{
faid = null; faid = null;
fapos = null; fapos = null;
} } else {
else
{
int[] nfaid = new int[nsize]; int[] nfaid = new int[nsize];
int[] nfapos = new int[nsize]; int[] nfapos = new int[nsize];
int idx = 0; int idx = 0;
byte[] nab = new byte[ab.length - delbytes]; byte[] nab = new byte[ab.length - delbytes];
int nab_off = 0; int nab_off = 0;
for ( int i = 0; i < size; i++ ) for (int i = 0; i < size; i++) {
{
int pos = fapos[i]; int pos = fapos[i];
if ( ( pos & 0x80000000 ) == 0 ) if ((pos & 0x80000000) == 0) {
{ int start = startPos(i);
int start = startPos( i );
int end = fapos[i]; int end = fapos[i];
int len = end - start; int len = end - start;
System.arraycopy( ab, start, nab, nab_off, len ); System.arraycopy(ab, start, nab, nab_off, len);
nfaid[idx] = faid[i]; nfaid[idx] = faid[i];
nab_off += len; nab_off += len;
nfapos[idx] = nab_off; nfapos[idx] = nab_off;
@ -185,17 +161,15 @@ public class MicroCache extends ByteDataWriter
ab = nab; ab = nab;
} }
int deleted = delbytes; int deleted = delbytes;
init( nsize ); init(nsize);
return deleted; return deleted;
} }
public final void unGhost() public final void unGhost() {
{
ghost = false; ghost = false;
delcount = 0; delcount = 0;
delbytes = 0; delbytes = 0;
for ( int i = 0; i < size; i++ ) for (int i = 0; i < size; i++) {
{
fapos[i] &= 0x7fffffff; // clear deleted flags 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 * @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]; 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 * expand a 32-bit micro-cache-internal id into a 64-bit (lon|lat) global-id
* *
* @see #shrinkId * @see #shrinkId
*/ */
public long expandId( int id32 ) public long expandId(int id32) {
{ throw new IllegalArgumentException("expandId for empty cache");
throw new IllegalArgumentException( "expandId for empty cache" );
} }
/** /**
* shrink a 64-bit (lon|lat) global-id into a a 32-bit micro-cache-internal id * shrink a 64-bit (lon|lat) global-id into a a 32-bit micro-cache-internal id
* *
* @see #expandId * @see #expandId
*/ */
public int shrinkId( long id64 ) public int shrinkId(long id64) {
{ throw new IllegalArgumentException("shrinkId for empty cache");
throw new IllegalArgumentException( "shrinkId for empty cache" );
} }
/** /**
* @return true if the given lon/lat position is internal for that micro-cache * @return true if the given lon/lat position is internal for that micro-cache
*/ */
public boolean isInternal( int ilon, int ilat ) public boolean isInternal(int ilon, int ilat) {
{ throw new IllegalArgumentException("isInternal for empty cache");
throw new IllegalArgumentException( "isInternal for empty cache" );
} }
/** /**
* (stasticially) encode the micro-cache into the format used in the datafiles * (stasticially) encode the micro-cache into the format used in the datafiles
* *
* @param buffer * @param buffer byte array to encode into (considered big enough)
* byte array to encode into (considered big enough)
* @return the size of the encoded data * @return the size of the encoded data
*/ */
public int encodeMicroCache( byte[] buffer ) public int encodeMicroCache(byte[] buffer) {
{ throw new IllegalArgumentException("encodeMicroCache for empty cache");
throw new IllegalArgumentException( "encodeMicroCache for empty cache" );
} }
/** /**
* Compare the content of this microcache to another * Compare the content of this microcache to another
* *
* @return null if equals, else a diff-report * @return null if equals, else a diff-report
*/ */
public String compareWith( MicroCache mc ) public String compareWith(MicroCache mc) {
{ String msg = _compareWith(mc);
String msg = _compareWith( mc ); if (msg != null) {
if ( msg != null ) StringBuilder sb = new StringBuilder(msg);
{ sb.append("\nencode cache:\n").append(summary());
StringBuilder sb = new StringBuilder( msg ); sb.append("\ndecode cache:\n").append(mc.summary());
sb.append( "\nencode cache:\n" ).append( summary() );
sb.append( "\ndecode cache:\n" ).append( mc.summary() );
return sb.toString(); return sb.toString();
} }
return null; return null;
} }
private String summary() private String summary() {
{ StringBuilder sb = new StringBuilder("size=" + size + " aboffset=" + aboffset);
StringBuilder sb = new StringBuilder( "size=" + size + " aboffset=" + aboffset ); for (int i = 0; i < size; i++) {
for ( int i = 0; i < size; i++ ) sb.append("\nidx=" + i + " faid=" + faid[i] + " fapos=" + fapos[i]);
{
sb.append( "\nidx=" + i + " faid=" + faid[i] + " fapos=" + fapos[i] );
} }
return sb.toString(); return sb.toString();
} }
private String _compareWith( MicroCache mc ) private String _compareWith(MicroCache mc) {
{ if (size != mc.size) {
if ( size != mc.size )
{
return "size missmatch: " + size + "->" + mc.size; return "size missmatch: " + size + "->" + mc.size;
} }
for ( int i = 0; i < size; i++ ) for (int i = 0; i < size; i++) {
{ if (faid[i] != mc.faid[i]) {
if ( faid[i] != mc.faid[i] )
{
return "faid missmatch at index " + i + ":" + 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 start = i > 0 ? fapos[i - 1] : 0;
int end = fapos[i] < mc.fapos[i] ? fapos[i] : mc.fapos[i]; int end = fapos[i] < mc.fapos[i] ? fapos[i] : mc.fapos[i];
int len = end - start; int len = end - start;
for ( int offset = 0; offset < len; offset++ ) for (int offset = 0; offset < len; offset++) {
{ if (mc.ab.length <= start + offset) {
if ( mc.ab.length <= start + offset )
{
return "data buffer too small"; 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; 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]; 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 "datasize missmatch: " + aboffset + "->" + mc.aboffset;
} }
return null; return null;
} }
public void calcDelta( MicroCache mc1, MicroCache mc2 ) public void calcDelta(MicroCache mc1, MicroCache mc2) {
{ int idx1 = 0;
int idx1 = 0; int idx2 = 0;
int idx2 = 0;
while( idx1 < mc1.size || idx2 < mc2.size ) while (idx1 < mc1.size || idx2 < mc2.size) {
{ int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE;
int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE; int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE;
int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE; int id;
int id; if (id1 >= id2) {
if ( id1 >= id2 ) id = id2;
{ int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
id = id2; int len2 = mc2.fapos[idx2++] - start2;
int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
int len2 = mc2.fapos[idx2++] - start2;
if ( id1 == id2 ) if (id1 == id2) {
{ // id exists in both caches, compare data
// id exists in both caches, compare data int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0;
int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0; int len1 = mc1.fapos[idx1++] - start1;
int len1 = mc1.fapos[idx1++] - start1; if (len1 == len2) {
if ( len1 == len2 ) int i = 0;
{ while (i < len1) {
int i = 0; if (mc1.ab[start1 + i] != mc2.ab[start2 + i]) {
while( i<len1 ) break;
{ }
if ( mc1.ab[start1+i] != mc2.ab[start2+i] ) i++;
{ }
break; if (i == len1) {
} continue; // same data -> do nothing
i++; }
} }
if ( i == len1 ) }
{ write(mc2.ab, start2, len2);
continue; // same data -> do nothing } else {
} idx1++;
} id = id1; // deleted node
} }
write( mc2.ab, start2, len2 ); fapos[size] = aboffset;
} faid[size] = id;
else size++;
{ }
idx1++;
id = id1; // deleted node
}
fapos[size] = aboffset;
faid[size] = id;
size++;
}
} }
public void addDelta( MicroCache mc1, MicroCache mc2, boolean keepEmptyNodes ) public void addDelta(MicroCache mc1, MicroCache mc2, boolean keepEmptyNodes) {
{ int idx1 = 0;
int idx1 = 0; int idx2 = 0;
int idx2 = 0;
while( idx1 < mc1.size || idx2 < mc2.size ) while (idx1 < mc1.size || idx2 < mc2.size) {
{ int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE;
int id1 = idx1 < mc1.size ? mc1.faid[idx1] : Integer.MAX_VALUE; int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE;
int id2 = idx2 < mc2.size ? mc2.faid[idx2] : Integer.MAX_VALUE; if (id1 >= id2) // data from diff file wins
if ( id1 >= id2 ) // data from diff file wins {
{ int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0;
int start2 = idx2 > 0 ? mc2.fapos[idx2 - 1] : 0; int len2 = mc2.fapos[idx2++] - start2;
int len2 = mc2.fapos[idx2++] - start2; if (keepEmptyNodes || len2 > 0) {
if ( keepEmptyNodes || len2 > 0 ) write(mc2.ab, start2, len2);
{ fapos[size] = aboffset;
write( mc2.ab, start2, len2 ); faid[size++] = id2;
fapos[size] = aboffset; }
faid[size++] = id2; if (id1 == id2) // // id exists in both caches
} {
if ( id1 == id2 ) // // id exists in both caches idx1++;
{ }
idx1++; } else // use data from base file
} {
} int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0;
else // use data from base file int len1 = mc1.fapos[idx1++] - start1;
{ write(mc1.ab, start1, len1);
int start1 = idx1 > 0 ? mc1.fapos[idx1 - 1] : 0; fapos[size] = aboffset;
int len1 = mc1.fapos[idx1++] - start1; faid[size++] = id1;
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 * MicroCache2 is the new format that uses statistical encoding and
* is able to do access filtering and waypoint matching during encoding * 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 lonBase;
private int latBase; private int latBase;
private int cellsize; private int cellsize;
public MicroCache2( int size, byte[] databuffer, int lonIdx, int latIdx, int divisor ) public MicroCache2(int size, byte[] databuffer, int lonIdx, int latIdx, int divisor) {
{ super(databuffer); // sets ab=databuffer, aboffset=0
super( databuffer ); // sets ab=databuffer, aboffset=0
faid = new int[size]; faid = new int[size];
fapos = new int[size]; fapos = new int[size];
this.size = 0; this.size = 0;
cellsize = 1000000 / divisor; cellsize = 1000000 / divisor;
lonBase = lonIdx*cellsize; lonBase = lonIdx * cellsize;
latBase = latIdx*cellsize; latBase = latIdx * cellsize;
}
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 ) public byte[] readUnified(int len, IByteArrayUnifier u) {
{ byte[] b = u.unify(ab, aboffset, len);
super( null ); 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; cellsize = 1000000 / divisor;
lonBase = lonIdx*cellsize; lonBase = lonIdx * cellsize;
latBase = latIdx*cellsize; latBase = latIdx * cellsize;
TagValueCoder wayTagCoder = new TagValueCoder( bc, dataBuffers, wayValidator ); TagValueCoder wayTagCoder = new TagValueCoder(bc, dataBuffers, wayValidator);
TagValueCoder nodeTagCoder = new TagValueCoder( bc, dataBuffers, null ); TagValueCoder nodeTagCoder = new TagValueCoder(bc, dataBuffers, null);
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder( bc ); NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder( bc ); NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc); NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLatDiff = 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; faid = size > dataBuffers.ibuf2.length ? new int[size] : dataBuffers.ibuf2;
fapos = size > dataBuffers.ibuf3.length ? new int[size] : dataBuffers.ibuf3; 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 ); int[] alon = size > dataBuffers.alon.length ? new int[size] : dataBuffers.alon;
int[] alat = size > dataBuffers.alat.length ? new int[size] : dataBuffers.alat;
for( int n = 0; n<size; n++ )
{ if (debug)
long id64 = expandId( faid[n] ); System.out.println("*** decoding cache of size=" + size + " for lonIdx=" + lonIdx + " latIdx=" + latIdx);
alon[n] = (int)(id64 >> 32);
alat[n] = (int)(id64 & 0xffffffff); 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; ab = netdatasize > dataBuffers.bbuf1.length ? new byte[netdatasize] : dataBuffers.bbuf1;
aboffset = 0; aboffset = 0;
int[] validBits = new int[(size+31)>>5]; int[] validBits = new int[(size + 31) >> 5];
int finaldatasize = 0; int finaldatasize = 0;
LinkedListContainer reverseLinks = new LinkedListContainer( size, dataBuffers.ibuf1 ); LinkedListContainer reverseLinks = new LinkedListContainer(size, dataBuffers.ibuf1);
int selev = 0; 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 ilon = alon[n];
int ilat = alat[n]; int ilat = alat[n];
// future escapes (turn restrictions?) // future escapes (turn restrictions?)
short trExceptions = 0; short trExceptions = 0;
int featureId = bc.decodeVarBits(); int featureId = bc.decodeVarBits();
if ( featureId == 13 ) if (featureId == 13) {
{
fapos[n] = aboffset; 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) continue; // empty node escape (delta files only)
} }
while( featureId != 0 ) while (featureId != 0) {
{ int bitsize = bc.decodeNoisyNumber(5);
int bitsize = bc.decodeNoisyNumber( 5 );
if ( featureId == 2 ) // exceptions to turn-restriction if (featureId == 2) // exceptions to turn-restriction
{ {
trExceptions = (short)bc.decodeBounded( 1023 ); trExceptions = (short) bc.decodeBounded(1023);
} } else if (featureId == 1) // turn-restriction
else if ( featureId == 1 ) // turn-restriction
{ {
writeBoolean( true ); writeBoolean(true);
writeShort( trExceptions ); // exceptions from previous feature writeShort(trExceptions); // exceptions from previous feature
trExceptions = 0; trExceptions = 0;
writeBoolean( bc.decodeBit() ); // isPositive writeBoolean(bc.decodeBit()); // isPositive
writeInt( ilon + bc.decodeNoisyDiff( 10 ) ); // fromLon writeInt(ilon + bc.decodeNoisyDiff(10)); // fromLon
writeInt( ilat + bc.decodeNoisyDiff( 10 ) ); // fromLat writeInt(ilat + bc.decodeNoisyDiff(10)); // fromLat
writeInt( ilon + bc.decodeNoisyDiff( 10 ) ); // toLon writeInt(ilon + bc.decodeNoisyDiff(10)); // toLon
writeInt( ilat + bc.decodeNoisyDiff( 10 ) ); // toLat writeInt(ilat + bc.decodeNoisyDiff(10)); // toLat
} } else {
else for (int i = 0; i < bitsize; i++) bc.decodeBit(); // unknown feature, just skip
{
for( int i=0; i< bitsize; i++ ) bc.decodeBit(); // unknown feature, just skip
} }
featureId = bc.decodeVarBits(); featureId = bc.decodeVarBits();
} }
writeBoolean( false ); writeBoolean(false);
selev += nodeEleDiff.decodeSignedValue(); selev += nodeEleDiff.decodeSignedValue();
writeShort( (short) selev ); writeShort((short) selev);
TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet(); TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet();
writeVarBytes( nodeTags == null ? null : nodeTags.data ); writeVarBytes(nodeTags == null ? null : nodeTags.data);
int links = bc.decodeNoisyNumber( 1 ); int links = bc.decodeNoisyNumber(1);
if ( debug ) System.out.println( "*** decoding node " + ilon + "/" + ilat + " with links=" + links ); if (debug)
for( int li=0; li<links; li++ ) System.out.println("*** decoding node " + ilon + "/" + ilat + " with links=" + links);
{ for (int li = 0; li < links; li++) {
int sizeoffset = 0; int sizeoffset = 0;
int nodeIdx = n + nodeIdxDiff.decodeSignedValue(); int nodeIdx = n + nodeIdxDiff.decodeSignedValue();
int dlon_remaining; int dlon_remaining;
int dlat_remaining; int dlat_remaining;
boolean isReverse = false; boolean isReverse = false;
if ( nodeIdx != n ) // internal (forward-) link if (nodeIdx != n) // internal (forward-) link
{ {
dlon_remaining = alon[nodeIdx] - ilon; dlon_remaining = alon[nodeIdx] - ilon;
dlat_remaining = alat[nodeIdx] - ilat; dlat_remaining = alat[nodeIdx] - ilat;
} } else {
else
{
isReverse = bc.decodeBit(); isReverse = bc.decodeBit();
dlon_remaining = extLonDiff.decodeSignedValue(); dlon_remaining = extLonDiff.decodeSignedValue();
dlat_remaining = extLatDiff.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(); TagValueWrapper wayTags = wayTagCoder.decodeTagValueSet();
boolean linkValid = wayTags != null || wayValidator == null; boolean linkValid = wayTags != null || wayValidator == null;
if ( linkValid ) if (linkValid) {
{
int startPointer = aboffset; int startPointer = aboffset;
sizeoffset = writeSizePlaceHolder(); sizeoffset = writeSizePlaceHolder();
writeVarLengthSigned( dlon_remaining ); writeVarLengthSigned(dlon_remaining);
writeVarLengthSigned( dlat_remaining ); writeVarLengthSigned(dlat_remaining);
validBits[ n >> 5 ] |= 1 << n; // mark source-node valid validBits[n >> 5] |= 1 << n; // mark source-node valid
if ( nodeIdx != n ) // valid internal (forward-) link if (nodeIdx != n) // valid internal (forward-) link
{ {
reverseLinks.addDataElement( nodeIdx, n ); // register reverse link reverseLinks.addDataElement(nodeIdx, n); // register reverse link
finaldatasize += 1 + aboffset-startPointer; // reserve place for reverse finaldatasize += 1 + aboffset - startPointer; // reserve place for reverse
validBits[ nodeIdx >> 5 ] |= 1 << nodeIdx; // mark target-node valid 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; WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher;
int ilontarget = ilon + dlon_remaining; int ilontarget = ilon + dlon_remaining;
int ilattarget = ilat + dlat_remaining; int ilattarget = ilat + dlat_remaining;
if ( matcher != null ) if (matcher != null) {
{ if (!matcher.start(ilon, ilat, ilontarget, ilattarget)) {
if ( !matcher.start( ilon, ilat, ilontarget, ilattarget ) )
{
matcher = null; matcher = null;
} }
} }
int transcount = bc.decodeVarBits(); int transcount = bc.decodeVarBits();
if ( debug ) System.out.println( "*** decoding geometry with count=" + transcount ); if (debug) System.out.println("*** decoding geometry with count=" + transcount);
int count = transcount+1; int count = transcount + 1;
for( int i=0; i<transcount; i++ ) for (int i = 0; i < transcount; i++) {
{ int dlon = bc.decodePredictedValue(dlon_remaining / count);
int dlon = bc.decodePredictedValue( dlon_remaining/count ); int dlat = bc.decodePredictedValue(dlat_remaining / count);
int dlat = bc.decodePredictedValue( dlat_remaining/count );
dlon_remaining -= dlon; dlon_remaining -= dlon;
dlat_remaining -= dlat; dlat_remaining -= dlat;
count--; count--;
int elediff = transEleDiff.decodeSignedValue(); int elediff = transEleDiff.decodeSignedValue();
if ( wayTags != null ) if (wayTags != null) {
{ writeVarLengthSigned(dlon);
writeVarLengthSigned( dlon ); writeVarLengthSigned(dlat);
writeVarLengthSigned( dlat ); writeVarLengthSigned(elediff);
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 ) if (linkValid) {
{ injectSize(sizeoffset);
injectSize( sizeoffset );
} }
} }
fapos[n] = aboffset; fapos[n] = aboffset;
} }
// calculate final data size // calculate final data size
int finalsize = 0; int finalsize = 0;
int startpos = 0; int startpos = 0;
for( int i=0; i<size; i++ ) for (int i = 0; i < size; i++) {
{
int endpos = fapos[i]; int endpos = fapos[i];
if ( ( validBits[ i >> 5 ] & (1 << i ) ) != 0 ) if ((validBits[i >> 5] & (1 << i)) != 0) {
{ finaldatasize += endpos - startpos;
finaldatasize += endpos-startpos; finalsize++;
finalsize++;
} }
startpos = endpos; startpos = endpos;
} }
@ -240,29 +222,26 @@ public final class MicroCache2 extends MicroCache
size = 0; size = 0;
startpos = 0; startpos = 0;
for ( int n = 0; n < sizeOld; n++ ) for (int n = 0; n < sizeOld; n++) {
{
int endpos = faposOld[n]; int endpos = faposOld[n];
if ( ( validBits[ n >> 5 ] & (1 << n ) ) != 0 ) if ((validBits[n >> 5] & (1 << n)) != 0) {
{
int len = endpos - startpos; int len = endpos - startpos;
System.arraycopy( abOld, startpos, ab, aboffset, len ); System.arraycopy(abOld, startpos, ab, aboffset, len);
if ( debug ) if (debug)
System.out.println( "*** copied " + len + " bytes from " + aboffset + " for node " + n ); System.out.println("*** copied " + len + " bytes from " + aboffset + " for node " + n);
aboffset += len; aboffset += len;
int cnt = reverseLinks.initList( n ); int cnt = reverseLinks.initList(n);
if ( debug ) if (debug)
System.out.println( "*** appending " + cnt + " reverse links for node " + n ); 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 nodeIdx = reverseLinks.getDataElement();
int sizeoffset = writeSizePlaceHolder(); int sizeoffset = writeSizePlaceHolder();
writeVarLengthSigned( alon[nodeIdx] - alon[n] ); writeVarLengthSigned(alon[nodeIdx] - alon[n]);
writeVarLengthSigned( alat[nodeIdx] - alat[n] ); writeVarLengthSigned(alat[nodeIdx] - alat[n]);
writeModeAndDesc( true, null ); writeModeAndDesc(true, null);
injectSize( sizeoffset ); injectSize(sizeoffset);
} }
faid[size] = faidOld[n]; faid[size] = faidOld[n];
fapos[size] = aboffset; fapos[size] = aboffset;
@ -270,65 +249,59 @@ public final class MicroCache2 extends MicroCache
} }
startpos = endpos; startpos = endpos;
} }
init( size ); init(size);
} }
@Override @Override
public long expandId( int id32 ) public long expandId(int id32) {
{
int dlon = 0; int dlon = 0;
int dlat = 0; int dlat = 0;
for( int bm = 1; bm < 0x8000; bm <<= 1 ) for (int bm = 1; bm < 0x8000; bm <<= 1) {
{ if ((id32 & 1) != 0) dlon |= bm;
if ( (id32 & 1) != 0 ) dlon |= bm; if ((id32 & 2) != 0) dlat |= bm;
if ( (id32 & 2) != 0 ) dlat |= bm;
id32 >>= 2; id32 >>= 2;
} }
int lon32 = lonBase + dlon; int lon32 = lonBase + dlon;
int lat32 = latBase + dlat; int lat32 = latBase + dlat;
return ((long)lon32)<<32 | lat32; return ((long) lon32) << 32 | lat32;
} }
@Override @Override
public int shrinkId( long id64 ) public int shrinkId(long id64) {
{ int lon32 = (int) (id64 >> 32);
int lon32 = (int)(id64 >> 32); int lat32 = (int) (id64 & 0xffffffff);
int lat32 = (int)(id64 & 0xffffffff);
int dlon = lon32 - lonBase; int dlon = lon32 - lonBase;
int dlat = lat32 - latBase; int dlat = lat32 - latBase;
int id32 = 0; int id32 = 0;
for( int bm = 0x4000; bm > 0; bm >>= 1 ) for (int bm = 0x4000; bm > 0; bm >>= 1) {
{
id32 <<= 2; id32 <<= 2;
if ( ( dlon & bm ) != 0 ) id32 |= 1; if ((dlon & bm) != 0) id32 |= 1;
if ( ( dlat & bm ) != 0 ) id32 |= 2; if ((dlat & bm) != 0) id32 |= 2;
} }
return id32; return id32;
} }
@Override @Override
public boolean isInternal( int ilon, int ilat ) public boolean isInternal(int ilon, int ilat) {
{
return ilon >= lonBase && ilon < lonBase + cellsize return ilon >= lonBase && ilon < lonBase + cellsize
&& ilat >= latBase && ilat < latBase + cellsize; && ilat >= latBase && ilat < latBase + cellsize;
} }
@Override @Override
public int encodeMicroCache( byte[] buffer ) public int encodeMicroCache(byte[] buffer) {
{ HashMap<Long, Integer> idMap = new HashMap<Long, Integer>();
HashMap<Long,Integer> idMap = new HashMap<Long,Integer>(); for (int n = 0; n < size; n++) // loop over nodes
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 linkCounts = new IntegerFifo3Pass(256);
IntegerFifo3Pass transCounts = new IntegerFifo3Pass( 256 ); IntegerFifo3Pass transCounts = new IntegerFifo3Pass(256);
IntegerFifo3Pass restrictionBits = new IntegerFifo3Pass( 16 ); IntegerFifo3Pass restrictionBits = new IntegerFifo3Pass(16);
TagValueCoder wayTagCoder = new TagValueCoder(); TagValueCoder wayTagCoder = new TagValueCoder();
TagValueCoder nodeTagCoder = new TagValueCoder(); TagValueCoder nodeTagCoder = new TagValueCoder();
@ -337,182 +310,173 @@ public final class MicroCache2 extends MicroCache
NoisyDiffCoder extLonDiff = new NoisyDiffCoder(); NoisyDiffCoder extLonDiff = new NoisyDiffCoder();
NoisyDiffCoder extLatDiff = new NoisyDiffCoder(); NoisyDiffCoder extLatDiff = new NoisyDiffCoder();
NoisyDiffCoder transEleDiff = new NoisyDiffCoder(); NoisyDiffCoder transEleDiff = new NoisyDiffCoder();
int netdatasize = 0; 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 dostats = pass == 3;
boolean dodebug = debug && pass == 3; boolean dodebug = debug && pass == 3;
if ( pass < 3 ) netdatasize = fapos[size-1]; if (pass < 3) netdatasize = fapos[size - 1];
StatCoderContext bc = new StatCoderContext( buffer ); StatCoderContext bc = new StatCoderContext(buffer);
linkCounts.init(); linkCounts.init();
transCounts.init(); transCounts.init();
restrictionBits.init(); restrictionBits.init();
wayTagCoder.encodeDictionary( bc ); wayTagCoder.encodeDictionary(bc);
if ( dostats ) bc.assignBits( "wayTagDictionary" ); if (dostats) bc.assignBits("wayTagDictionary");
nodeTagCoder.encodeDictionary( bc ); nodeTagCoder.encodeDictionary(bc);
if ( dostats ) bc.assignBits( "nodeTagDictionary" ); if (dostats) bc.assignBits("nodeTagDictionary");
nodeIdxDiff.encodeDictionary( bc ); nodeIdxDiff.encodeDictionary(bc);
nodeEleDiff.encodeDictionary( bc ); nodeEleDiff.encodeDictionary(bc);
extLonDiff.encodeDictionary( bc ); extLonDiff.encodeDictionary(bc);
extLatDiff.encodeDictionary( bc ); extLatDiff.encodeDictionary(bc);
transEleDiff.encodeDictionary( bc ); transEleDiff.encodeDictionary(bc);
if ( dostats ) bc.assignBits( "noisebits" ); if (dostats) bc.assignBits("noisebits");
bc.encodeNoisyNumber( size, 5 ); bc.encodeNoisyNumber(size, 5);
if ( dostats ) bc.assignBits( "nodecount" ); if (dostats) bc.assignBits("nodecount");
bc.encodeSortedArray( faid, 0, size, 0x20000000, 0 ); bc.encodeSortedArray(faid, 0, size, 0x20000000, 0);
if ( dostats ) bc.assignBits( "node-positions" ); if (dostats) bc.assignBits("node-positions");
bc.encodeNoisyNumber( netdatasize, 10 ); // net-size bc.encodeNoisyNumber(netdatasize, 10); // net-size
if ( dostats ) bc.assignBits( "netdatasize" ); if (dostats) bc.assignBits("netdatasize");
if ( dodebug ) System.out.println( "*** encoding cache of size=" + size ); if (dodebug) System.out.println("*** encoding cache of size=" + size);
int lastSelev = 0; 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]; 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] ); long id64 = expandId(faid[n]);
int ilon = (int)(id64 >> 32); int ilon = (int) (id64 >> 32);
int ilat = (int)(id64 & 0xffffffff); int ilat = (int) (id64 & 0xffffffff);
if ( aboffset == aboffsetEnd ) if (aboffset == aboffsetEnd) {
{ bc.encodeVarBits(13); // empty node escape (delta files only)
bc.encodeVarBits( 13 ); // empty node escape (delta files only)
continue; continue;
} }
// write turn restrictions // write turn restrictions
while( readBoolean() ) while (readBoolean()) {
{
short exceptions = readShort(); // except bikes, psv, ... short exceptions = readShort(); // except bikes, psv, ...
if ( exceptions != 0 ) if (exceptions != 0) {
{ bc.encodeVarBits(2); // 2 = tr exceptions
bc.encodeVarBits( 2 ); // 2 = tr exceptions bc.encodeNoisyNumber(10, 5); // bit-count
bc.encodeNoisyNumber( 10 , 5 ); // bit-count bc.encodeBounded(1023, exceptions & 1023);
bc.encodeBounded( 1023 , exceptions & 1023 );
} }
bc.encodeVarBits( 1 ); // 1 = turn restriction bc.encodeVarBits(1); // 1 = turn restriction
bc.encodeNoisyNumber( restrictionBits.getNext(), 5 ); // bit-count using look-ahead fifo bc.encodeNoisyNumber(restrictionBits.getNext(), 5); // bit-count using look-ahead fifo
long b0 = bc.getWritingBitPosition(); long b0 = bc.getWritingBitPosition();
bc.encodeBit( readBoolean() ); // isPositive bc.encodeBit(readBoolean()); // isPositive
bc.encodeNoisyDiff( readInt() - ilon, 10 ); // fromLon bc.encodeNoisyDiff(readInt() - ilon, 10); // fromLon
bc.encodeNoisyDiff( readInt() - ilat, 10 ); // fromLat bc.encodeNoisyDiff(readInt() - ilat, 10); // fromLat
bc.encodeNoisyDiff( readInt() - ilon, 10 ); // toLon bc.encodeNoisyDiff(readInt() - ilon, 10); // toLon
bc.encodeNoisyDiff( readInt() - ilat, 10 ); // toLat bc.encodeNoisyDiff(readInt() - ilat, 10); // toLat
restrictionBits.add( (int)( bc.getWritingBitPosition() - b0 ) ); 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(); int selev = readShort();
nodeEleDiff.encodeSignedValue( selev - lastSelev ); nodeEleDiff.encodeSignedValue(selev - lastSelev);
if ( dostats ) bc.assignBits( "nodeele" ); if (dostats) bc.assignBits("nodeele");
lastSelev = selev; lastSelev = selev;
nodeTagCoder.encodeTagValueSet( readVarBytes() ); nodeTagCoder.encodeTagValueSet(readVarBytes());
if ( dostats ) bc.assignBits( "nodeTagIdx" ); if (dostats) bc.assignBits("nodeTagIdx");
int nlinks = linkCounts.getNext(); int nlinks = linkCounts.getNext();
if ( dodebug ) System.out.println( "*** nlinks=" + nlinks ); if (dodebug) System.out.println("*** nlinks=" + nlinks);
bc.encodeNoisyNumber( nlinks, 1 ); bc.encodeNoisyNumber(nlinks, 1);
if ( dostats ) bc.assignBits( "link-counts" ); if (dostats) bc.assignBits("link-counts");
nlinks = 0; nlinks = 0;
while( hasMoreData() ) // loop over links while (hasMoreData()) // loop over links
{ {
// read link data // read link data
int startPointer = aboffset; int startPointer = aboffset;
int endPointer = getEndPointer(); int endPointer = getEndPointer();
int ilonlink = ilon + readVarLengthSigned(); int ilonlink = ilon + readVarLengthSigned();
int ilatlink = ilat + readVarLengthSigned(); int ilatlink = ilat + readVarLengthSigned();
int sizecode = readVarLengthUnsigned(); int sizecode = readVarLengthUnsigned();
boolean isReverse = ( sizecode & 1 ) != 0; boolean isReverse = (sizecode & 1) != 0;
int descSize = sizecode >> 1; int descSize = sizecode >> 1;
byte[] description = null; byte[] description = null;
if ( descSize > 0 ) if (descSize > 0) {
{
description = new byte[descSize]; description = new byte[descSize];
readFully( description ); readFully(description);
} }
long link64 = ((long)ilonlink)<<32 | ilatlink; long link64 = ((long) ilonlink) << 32 | ilatlink;
Integer idx = idMap.get( Long.valueOf( link64 ) ); Integer idx = idMap.get(Long.valueOf(link64));
boolean isInternal = idx != null; boolean isInternal = idx != null;
if ( isReverse && isInternal ) if (isReverse && isInternal) {
{ if (dodebug)
if ( dodebug ) System.out.println( "*** NOT encoding link reverse=" + isReverse + " internal=" + isInternal ); System.out.println("*** NOT encoding link reverse=" + isReverse + " internal=" + isInternal);
netdatasize -= aboffset-startPointer; netdatasize -= aboffset - startPointer;
continue; // do not encode internal reverse links 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++; nlinks++;
if ( isInternal ) if (isInternal) {
{
int nodeIdx = idx.intValue(); int nodeIdx = idx.intValue();
if ( dodebug ) System.out.println( "*** target nodeIdx=" + nodeIdx ); if (dodebug) System.out.println("*** target nodeIdx=" + nodeIdx);
if ( nodeIdx == n ) throw new RuntimeException( "ups: self ref?" ); if (nodeIdx == n) throw new RuntimeException("ups: self ref?");
nodeIdxDiff.encodeSignedValue( nodeIdx - n ); nodeIdxDiff.encodeSignedValue(nodeIdx - n);
if ( dostats ) bc.assignBits( "nodeIdx" ); 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 wayTagCoder.encodeTagValueSet(description);
{ if (dostats) bc.assignBits("wayDescIdx");
nodeIdxDiff.encodeSignedValue( 0 );
bc.encodeBit( isReverse ); if (!isReverse) {
extLonDiff.encodeSignedValue( ilonlink - ilon ); byte[] geometry = readDataUntil(endPointer);
extLatDiff.encodeSignedValue( ilatlink - ilat );
if ( dostats ) bc.assignBits( "externalNode" );
}
wayTagCoder.encodeTagValueSet( description );
if ( dostats ) bc.assignBits( "wayDescIdx" );
if ( !isReverse )
{
byte[] geometry = readDataUntil( endPointer );
// write transition nodes // write transition nodes
int count = transCounts.getNext(); int count = transCounts.getNext();
if ( dodebug ) System.out.println( "*** encoding geometry with count=" + count ); if (dodebug) System.out.println("*** encoding geometry with count=" + count);
bc.encodeVarBits( count++ ); bc.encodeVarBits(count++);
if ( dostats ) bc.assignBits( "transcount" ); if (dostats) bc.assignBits("transcount");
int transcount = 0; int transcount = 0;
if ( geometry != null ) if (geometry != null) {
{
int dlon_remaining = ilonlink - ilon; int dlon_remaining = ilonlink - ilon;
int dlat_remaining = ilatlink - ilat; int dlat_remaining = ilatlink - ilat;
ByteDataReader r = new ByteDataReader( geometry ); ByteDataReader r = new ByteDataReader(geometry);
while ( r.hasMoreData() ) while (r.hasMoreData()) {
{
transcount++; transcount++;
int dlon = r.readVarLengthSigned(); int dlon = r.readVarLengthSigned();
int dlat = r.readVarLengthSigned(); int dlat = r.readVarLengthSigned();
bc.encodePredictedValue( dlon, dlon_remaining/count ); bc.encodePredictedValue(dlon, dlon_remaining / count);
bc.encodePredictedValue( dlat, dlat_remaining/count ); bc.encodePredictedValue(dlat, dlat_remaining / count);
dlon_remaining -= dlon; dlon_remaining -= dlon;
dlat_remaining -= dlat; dlat_remaining -= dlat;
if ( count > 1 ) count--; if (count > 1) count--;
if ( dostats ) bc.assignBits( "transpos" ); if (dostats) bc.assignBits("transpos");
transEleDiff.encodeSignedValue( r.readVarLengthSigned() ); transEleDiff.encodeSignedValue(r.readVarLengthSigned());
if ( dostats ) bc.assignBits( "transele" ); 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(); return bc.closeAndGetEncodedLength();
} }
} }

View File

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

View File

@ -4,23 +4,19 @@ import java.util.TreeMap;
import btools.util.BitCoderContext; import btools.util.BitCoderContext;
public final class StatCoderContext extends BitCoderContext public final class StatCoderContext extends BitCoderContext {
{
private static TreeMap<String, long[]> statsPerName; private static TreeMap<String, long[]> statsPerName;
private long lastbitpos = 0; private long lastbitpos = 0;
private static final int[] noisy_bits = new int[1024]; private static final int[] noisy_bits = new int[1024];
static static {
{
// noisybits lookup // noisybits lookup
for( int i=0; i<1024; i++ ) for (int i = 0; i < 1024; i++) {
{
int p = i; int p = i;
int noisybits = 0; int noisybits = 0;
while (p > 2) while (p > 2) {
{
noisybits++; noisybits++;
p >>= 1; p >>= 1;
} }
@ -29,29 +25,25 @@ public final class StatCoderContext extends BitCoderContext
} }
public StatCoderContext( byte[] ab ) public StatCoderContext(byte[] ab) {
{ super(ab);
super( ab );
} }
/** /**
* assign the de-/encoded bits since the last call assignBits to the given * assign the de-/encoded bits since the last call assignBits to the given
* name. Used for encoding statistics * name. Used for encoding statistics
* *
* @see #getBitReport * @see #getBitReport
*/ */
public void assignBits( String name ) public void assignBits(String name) {
{
long bitpos = getWritingBitPosition(); long bitpos = getWritingBitPosition();
if ( statsPerName == null ) if (statsPerName == null) {
{
statsPerName = new TreeMap<String, long[]>(); statsPerName = new TreeMap<String, long[]>();
} }
long[] stats = statsPerName.get( name ); long[] stats = statsPerName.get(name);
if ( stats == null ) if (stats == null) {
{
stats = new long[2]; stats = new long[2];
statsPerName.put( name, stats ); statsPerName.put(name, stats);
} }
stats[0] += bitpos - lastbitpos; stats[0] += bitpos - lastbitpos;
stats[1] += 1; stats[1] += 1;
@ -60,20 +52,17 @@ public final class StatCoderContext extends BitCoderContext
/** /**
* Get a textual report on the bit-statistics * Get a textual report on the bit-statistics
* *
* @see #assignBits * @see #assignBits
*/ */
public static String getBitReport() public static String getBitReport() {
{ if (statsPerName == null) {
if ( statsPerName == null )
{
return "<empty bit report>"; return "<empty bit report>";
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for ( String name : statsPerName.keySet() ) for (String name : statsPerName.keySet()) {
{ long[] stats = statsPerName.get(name);
long[] stats = statsPerName.get( name ); sb.append(name + " count=" + stats[1] + " bits=" + stats[0] + "\n");
sb.append( name + " count=" + stats[1] + " bits=" + stats[0] + "\n" );
} }
statsPerName = null; statsPerName = null;
return sb.toString(); return sb.toString();
@ -82,76 +71,65 @@ public final class StatCoderContext extends BitCoderContext
/** /**
* encode an unsigned integer with some of of least significant bits * encode an unsigned integer with some of of least significant bits
* considered noisy * considered noisy
* *
* @see #decodeNoisyNumber * @see #decodeNoisyNumber
*/ */
public void encodeNoisyNumber( int value, int noisybits ) public void encodeNoisyNumber(int value, int noisybits) {
{ if (value < 0) {
if ( value < 0 ) throw new IllegalArgumentException("encodeVarBits expects positive value");
{
throw new IllegalArgumentException( "encodeVarBits expects positive value" );
} }
if ( noisybits > 0 ) if (noisybits > 0) {
{ int mask = 0xffffffff >>> (32 - noisybits);
int mask = 0xffffffff >>> ( 32 - noisybits ); encodeBounded(mask, value & mask);
encodeBounded( mask, value & mask );
value >>= noisybits; value >>= noisybits;
} }
encodeVarBits( value ); encodeVarBits(value);
} }
/** /**
* decode an unsigned integer with some of of least significant bits * decode an unsigned integer with some of of least significant bits
* considered noisy * considered noisy
* *
* @see #encodeNoisyNumber * @see #encodeNoisyNumber
*/ */
public int decodeNoisyNumber( int noisybits ) public int decodeNoisyNumber(int noisybits) {
{ int value = decodeBits(noisybits);
int value = decodeBits( noisybits ); return value | (decodeVarBits() << noisybits);
return value | ( decodeVarBits() << noisybits );
} }
/** /**
* encode a signed integer with some of of least significant bits considered * encode a signed integer with some of of least significant bits considered
* noisy * noisy
* *
* @see #decodeNoisyDiff * @see #decodeNoisyDiff
*/ */
public void encodeNoisyDiff( int value, int noisybits ) public void encodeNoisyDiff(int value, int noisybits) {
{ if (noisybits > 0) {
if ( noisybits > 0 ) value += 1 << (noisybits - 1);
{ int mask = 0xffffffff >>> (32 - noisybits);
value += 1 << ( noisybits - 1 ); encodeBounded(mask, value & mask);
int mask = 0xffffffff >>> ( 32 - noisybits );
encodeBounded( mask, value & mask );
value >>= noisybits; value >>= noisybits;
} }
encodeVarBits( value < 0 ? -value : value ); encodeVarBits(value < 0 ? -value : value);
if ( value != 0 ) if (value != 0) {
{ encodeBit(value < 0);
encodeBit( value < 0 );
} }
} }
/** /**
* decode a signed integer with some of of least significant bits considered * decode a signed integer with some of of least significant bits considered
* noisy * noisy
* *
* @see #encodeNoisyDiff * @see #encodeNoisyDiff
*/ */
public int decodeNoisyDiff( int noisybits ) public int decodeNoisyDiff(int noisybits) {
{
int value = 0; int value = 0;
if ( noisybits > 0 ) if (noisybits > 0) {
{ value = decodeBits(noisybits) - (1 << (noisybits - 1));
value = decodeBits( noisybits ) - ( 1 << ( noisybits - 1 ) );
} }
int val2 = decodeVarBits() << noisybits; int val2 = decodeVarBits() << noisybits;
if ( val2 != 0 ) if (val2 != 0) {
{ if (decodeBit()) {
if ( decodeBit() )
{
val2 = -val2; 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 * encode a signed integer with the typical range and median taken from the
* predicted value * predicted value
* *
* @see #decodePredictedValue * @see #decodePredictedValue
*/ */
public void encodePredictedValue( int value, int predictor ) public void encodePredictedValue(int value, int predictor) {
{
int p = predictor < 0 ? -predictor : predictor; int p = predictor < 0 ? -predictor : predictor;
int noisybits = 0; int noisybits = 0;
while (p > 2) while (p > 2) {
{
noisybits++; noisybits++;
p >>= 1; p >>= 1;
} }
encodeNoisyDiff( value - predictor, noisybits ); encodeNoisyDiff(value - predictor, noisybits);
} }
/** /**
* decode a signed integer with the typical range and median taken from the * decode a signed integer with the typical range and median taken from the
* predicted value * predicted value
* *
* @see #encodePredictedValue * @see #encodePredictedValue
*/ */
public int decodePredictedValue( int predictor ) public int decodePredictedValue(int predictor) {
{
int p = predictor < 0 ? -predictor : predictor; int p = predictor < 0 ? -predictor : predictor;
int noisybits = 0; int noisybits = 0;
while (p > 1023) while (p > 1023) {
{
noisybits++; noisybits++;
p >>= 1; 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 * 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 * bits per value that only depends on the typical distance between subsequent
* values and also benefits * values and also benefits
* *
* @param values * @param values the array to encode
* the array to encode * @param offset position in this array where to start
* @param offset * @param subsize number of values to encode
* position in this array where to start * @param nextbit bitmask with the most significant bit set to 1
* @param subsize * @param mask should be 0
* 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 ) public void encodeSortedArray(int[] values, int offset, int subsize, int nextbit, int mask) {
{ if (subsize == 1) // last-choice shortcut
if ( subsize == 1 ) // last-choice shortcut
{ {
while (nextbit != 0) while (nextbit != 0) {
{ encodeBit((values[offset] & nextbit) != 0);
encodeBit( ( values[offset] & nextbit ) != 0 );
nextbit >>= 1; nextbit >>= 1;
} }
} }
if ( nextbit == 0 ) if (nextbit == 0) {
{
return; return;
} }
@ -234,71 +200,55 @@ public final class StatCoderContext extends BitCoderContext
// count 0-bit-fraction // count 0-bit-fraction
int i = offset; int i = offset;
int end = subsize + offset; int end = subsize + offset;
for ( ; i < end; i++ ) for (; i < end; i++) {
{ if ((values[i] & mask) != data) {
if ( ( values[i] & mask ) != data )
{
break; break;
} }
} }
int size1 = i - offset; int size1 = i - offset;
int size2 = subsize - size1; int size2 = subsize - size1;
encodeBounded( subsize, size1 ); encodeBounded(subsize, size1);
if ( size1 > 0 ) if (size1 > 0) {
{ encodeSortedArray(values, offset, size1, nextbit >> 1, mask);
encodeSortedArray( values, offset, size1, nextbit >> 1, mask );
} }
if ( size2 > 0 ) if (size2 > 0) {
{ encodeSortedArray(values, i, size2, nextbit >> 1, mask);
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 * @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 ) public void decodeSortedArray(int[] values, int offset, int subsize, int nextbitpos, int value) {
{ if (subsize == 1) // last-choice shortcut
if ( subsize == 1 ) // last-choice shortcut
{ {
if ( nextbitpos >= 0 ) if (nextbitpos >= 0) {
{ value |= decodeBitsReverse(nextbitpos + 1);
value |= decodeBitsReverse( nextbitpos+1 );
} }
values[offset] = value; values[offset] = value;
return; return;
} }
if ( nextbitpos < 0 ) if (nextbitpos < 0) {
{ while (subsize-- > 0) {
while (subsize-- > 0)
{
values[offset++] = value; values[offset++] = value;
} }
return; return;
} }
int size1 = decodeBounded( subsize ); int size1 = decodeBounded(subsize);
int size2 = subsize - size1; int size2 = subsize - size1;
if ( size1 > 0 ) if (size1 > 0) {
{ decodeSortedArray(values, offset, size1, nextbitpos - 1, value);
decodeSortedArray( values, offset, size1, nextbitpos-1, value );
} }
if ( size2 > 0 ) if (size2 > 0) {
{ decodeSortedArray(values, offset + size1, size2, nextbitpos - 1, value | (1 << nextbitpos));
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 * Encoder/Decoder for way-/node-descriptions
* * <p>
* It detects identical descriptions and sorts them * It detects identical descriptions and sorts them
* into a huffman-tree according to their frequencies * into a huffman-tree according to their frequencies
* * <p>
* Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding ) * Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding )
* but doesn't do anything at pass1 * but doesn't do anything at pass1
*/ */
public final class TagValueCoder public final class TagValueCoder {
{
private HashMap<TagValueSet, TagValueSet> identityMap; private HashMap<TagValueSet, TagValueSet> identityMap;
private Object tree; private Object tree;
private BitCoderContext bc; private BitCoderContext bc;
private int pass; private int pass;
private int nextTagValueSetId; private int nextTagValueSetId;
public void encodeTagValueSet( byte[] data ) public void encodeTagValueSet(byte[] data) {
{ if (pass == 1) {
if ( pass == 1 )
{
return; return;
} }
TagValueSet tvsProbe = new TagValueSet(nextTagValueSetId); TagValueSet tvsProbe = new TagValueSet(nextTagValueSetId);
tvsProbe.data = data; tvsProbe.data = data;
TagValueSet tvs = identityMap.get( tvsProbe ); TagValueSet tvs = identityMap.get(tvsProbe);
if ( pass == 3 ) if (pass == 3) {
{ bc.encodeBounded(tvs.range - 1, tvs.code);
bc.encodeBounded( tvs.range - 1, tvs.code ); } else if (pass == 2) {
} if (tvs == null) {
else if ( pass == 2 )
{
if ( tvs == null )
{
tvs = tvsProbe; tvs = tvsProbe;
nextTagValueSetId++; nextTagValueSetId++;
identityMap.put( tvs, tvs ); identityMap.put(tvs, tvs);
} }
tvs.frequency++; tvs.frequency++;
} }
} }
public TagValueWrapper decodeTagValueSet() public TagValueWrapper decodeTagValueSet() {
{
Object node = tree; Object node = tree;
while (node instanceof TreeNode) while (node instanceof TreeNode) {
{
TreeNode tn = (TreeNode) node; TreeNode tn = (TreeNode) node;
boolean nextBit = bc.decodeBit(); boolean nextBit = bc.decodeBit();
node = nextBit ? tn.child2 : tn.child1; node = nextBit ? tn.child2 : tn.child1;
@ -60,104 +51,87 @@ public final class TagValueCoder
return (TagValueWrapper) node; return (TagValueWrapper) node;
} }
public void encodeDictionary( BitCoderContext bc ) public void encodeDictionary(BitCoderContext bc) {
{ if (++pass == 3) {
if ( ++pass == 3 ) if (identityMap.size() == 0) {
{
if ( identityMap.size() == 0 )
{
TagValueSet dummy = new TagValueSet(nextTagValueSetId++); 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()); queue.addAll(identityMap.values());
while (queue.size() > 1) while (queue.size() > 1) {
{
TagValueSet node = new TagValueSet(nextTagValueSetId++); TagValueSet node = new TagValueSet(nextTagValueSetId++);
node.child1 = queue.poll(); node.child1 = queue.poll();
node.child2 = queue.poll(); node.child2 = queue.poll();
node.frequency = node.child1.frequency + node.child2.frequency; node.frequency = node.child1.frequency + node.child2.frequency;
queue.add( node ); queue.add(node);
} }
TagValueSet root = queue.poll(); TagValueSet root = queue.poll();
root.encode( bc, 1, 0 ); root.encode(bc, 1, 0);
} }
this.bc = bc; this.bc = bc;
} }
public TagValueCoder( BitCoderContext bc, DataBuffers buffers, TagValueValidator validator ) public TagValueCoder(BitCoderContext bc, DataBuffers buffers, TagValueValidator validator) {
{ tree = decodeTree(bc, buffers, validator);
tree = decodeTree( bc, buffers, validator );
this.bc = bc; this.bc = bc;
} }
public TagValueCoder() public TagValueCoder() {
{
identityMap = new HashMap<TagValueSet, TagValueSet>(); 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(); boolean isNode = bc.decodeBit();
if ( isNode ) if (isNode) {
{
TreeNode node = new TreeNode(); TreeNode node = new TreeNode();
node.child1 = decodeTree( bc, buffers, validator ); node.child1 = decodeTree(bc, buffers, validator);
node.child2 = decodeTree( bc, buffers, validator ); node.child2 = decodeTree(bc, buffers, validator);
return node; return node;
} }
byte[] buffer = buffers.tagbuf1; byte[] buffer = buffers.tagbuf1;
BitCoderContext ctx = buffers.bctx1; BitCoderContext ctx = buffers.bctx1;
ctx.reset( buffer ); ctx.reset(buffer);
int inum = 0; int inum = 0;
int lastEncodedInum = 0; int lastEncodedInum = 0;
boolean hasdata = false; boolean hasdata = false;
for ( ;; ) for (; ; ) {
{
int delta = bc.decodeVarBits(); int delta = bc.decodeVarBits();
if ( !hasdata ) if (!hasdata) {
{ if (delta == 0) {
if ( delta == 0 )
{
return null; return null;
} }
} }
if ( delta == 0 ) if (delta == 0) {
{ ctx.encodeVarBits(0);
ctx.encodeVarBits( 0 );
break; break;
} }
inum += delta; inum += delta;
int data = bc.decodeVarBits(); int data = bc.decodeVarBits();
if ( validator == null || validator.isLookupIdxUsed( inum ) ) if (validator == null || validator.isLookupIdxUsed(inum)) {
{
hasdata = true; hasdata = true;
ctx.encodeVarBits( inum - lastEncodedInum ); ctx.encodeVarBits(inum - lastEncodedInum);
ctx.encodeVarBits( data ); ctx.encodeVarBits(data);
lastEncodedInum = inum; lastEncodedInum = inum;
} }
} }
byte[] res; byte[] res;
int len = ctx.closeAndGetEncodedLength(); int len = ctx.closeAndGetEncodedLength();
if ( validator == null ) if (validator == null) {
{
res = new byte[len]; res = new byte[len];
System.arraycopy( buffer, 0, res, 0, len ); System.arraycopy(buffer, 0, res, 0, len);
} } else {
else res = validator.unify(buffer, 0, len);
{
res = validator.unify( buffer, 0, len );
} }
int accessType = validator == null ? 2 : validator.accessType( res ); int accessType = validator == null ? 2 : validator.accessType(res);
if ( accessType > 0 ) if (accessType > 0) {
{
TagValueWrapper w = new TagValueWrapper(); TagValueWrapper w = new TagValueWrapper();
w.data = res; w.data = res;
w.accessType = accessType; w.accessType = accessType;
@ -166,14 +140,12 @@ public final class TagValueCoder
return null; return null;
} }
public static final class TreeNode public static final class TreeNode {
{
public Object child1; public Object child1;
public Object child2; public Object child2;
} }
public static final class TagValueSet public static final class TagValueSet {
{
public byte[] data; public byte[] data;
public int frequency; public int frequency;
public int code; public int code;
@ -182,66 +154,51 @@ public final class TagValueCoder
public TagValueSet child2; public TagValueSet child2;
private int id; // serial number to make the comparator well defined in case of equal frequencies 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; 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.range = range;
this.code = code; this.code = code;
boolean isNode = child1 != null; boolean isNode = child1 != null;
bc.encodeBit( isNode ); bc.encodeBit(isNode);
if ( isNode ) if (isNode) {
{ child1.encode(bc, range << 1, code);
child1.encode( bc, range << 1, code ); child2.encode(bc, range << 1, code + range);
child2.encode( bc, range << 1, code + range ); } else {
} if (data == null) {
else bc.encodeVarBits(0);
{
if ( data == null )
{
bc.encodeVarBits( 0 );
return; return;
} }
BitCoderContext src = new BitCoderContext( data ); BitCoderContext src = new BitCoderContext(data);
for ( ;; ) for (; ; ) {
{
int delta = src.decodeVarBits(); int delta = src.decodeVarBits();
bc.encodeVarBits( delta ); bc.encodeVarBits(delta);
if ( delta == 0 ) if (delta == 0) {
{
break; break;
} }
int data = src.decodeVarBits(); int data = src.decodeVarBits();
bc.encodeVarBits( data ); bc.encodeVarBits(data);
} }
} }
} }
@Override @Override
public boolean equals( Object o ) public boolean equals(Object o) {
{ if (o instanceof TagValueSet) {
if ( o instanceof TagValueSet )
{
TagValueSet tvs = (TagValueSet) o; TagValueSet tvs = (TagValueSet) o;
if ( data == null ) if (data == null) {
{
return tvs.data == null; return tvs.data == null;
} }
if ( tvs.data == null ) if (tvs.data == null) {
{
return data == null; return data == null;
} }
if ( data.length != tvs.data.length ) if (data.length != tvs.data.length) {
{
return false; return false;
} }
for ( int i = 0; i < data.length; i++ ) for (int i = 0; i < data.length; i++) {
{ if (data[i] != tvs.data[i]) {
if ( data[i] != tvs.data[i] )
{
return false; return false;
} }
} }
@ -251,39 +208,34 @@ public final class TagValueCoder
} }
@Override @Override
public int hashCode() public int hashCode() {
{ if (data == null) {
if ( data == null )
{
return 0; return 0;
} }
int h = 17; int h = 17;
for ( int i = 0; i < data.length; i++ ) for (int i = 0; i < data.length; i++) {
{ h = (h << 8) + data[i];
h = ( h << 8 ) + data[i];
} }
return h; return h;
} }
public static class FrequencyComparator implements Comparator<TagValueSet> public static class FrequencyComparator implements Comparator<TagValueSet> {
{
@Override @Override
public int compare(TagValueSet tvs1, TagValueSet tvs2) { public int compare(TagValueSet tvs1, TagValueSet tvs2) {
if ( tvs1.frequency < tvs2.frequency ) if (tvs1.frequency < tvs2.frequency)
return -1; return -1;
if ( tvs1.frequency > tvs2.frequency ) if (tvs1.frequency > tvs2.frequency)
return 1; return 1;
// to avoid ordering instability, decide on the id if frequency is equal // to avoid ordering instability, decide on the id if frequency is equal
if ( tvs1.id < tvs2.id ) if (tvs1.id < tvs2.id)
return -1; return -1;
if ( tvs1.id > tvs2.id ) if (tvs1.id > tvs2.id)
return 1; return 1;
if ( tvs1 != tvs2 ) if (tvs1 != tvs2) {
{ throw new RuntimeException("identity corruption!");
throw new RuntimeException( "identity corruption!" );
} }
return 0; return 0;
} }

View File

@ -1,17 +1,16 @@
package btools.codec; package btools.codec;
public interface TagValueValidator public interface TagValueValidator {
{
/** /**
* @param tagValueSet the way description to check * @param tagValueSet the way description to check
* @return 0 = nothing, 1=no matching, 2=normal * @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 * TagValueWrapper wrapps a description bitmap
* to add the access-type * to add the access-type
*/ */
public final class TagValueWrapper public final class TagValueWrapper {
{
public byte[] data; public byte[] data;
public int accessType; public int accessType;
} }

View File

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

View File

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

View File

@ -6,100 +6,79 @@ import java.util.Random;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class StatCoderContextTest public class StatCoderContextTest {
{
@Test @Test
public void noisyVarBitsEncodeDecodeTest() public void noisyVarBitsEncodeDecodeTest() {
{
byte[] ab = new byte[40000]; byte[] ab = new byte[40000];
StatCoderContext ctx = new StatCoderContext( ab ); StatCoderContext ctx = new StatCoderContext(ab);
for ( int noisybits = 1; noisybits < 12; noisybits++ ) for (int noisybits = 1; noisybits < 12; noisybits++) {
{ for (int i = 0; i < 1000; i++) {
for ( int i = 0; i < 1000; i++ ) ctx.encodeNoisyNumber(i, noisybits);
{
ctx.encodeNoisyNumber( i, noisybits );
} }
} }
ctx.closeAndGetEncodedLength(); ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab ); ctx = new StatCoderContext(ab);
for ( int noisybits = 1; noisybits < 12; noisybits++ ) for (int noisybits = 1; noisybits < 12; noisybits++) {
{ for (int i = 0; i < 1000; i++) {
for ( int i = 0; i < 1000; i++ ) int value = ctx.decodeNoisyNumber(noisybits);
{ if (value != i) {
int value = ctx.decodeNoisyNumber( noisybits ); Assert.fail("value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value);
if ( value != i )
{
Assert.fail( "value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value );
} }
} }
} }
} }
@Test @Test
public void noisySignedVarBitsEncodeDecodeTest() public void noisySignedVarBitsEncodeDecodeTest() {
{
byte[] ab = new byte[80000]; byte[] ab = new byte[80000];
StatCoderContext ctx = new StatCoderContext( ab ); StatCoderContext ctx = new StatCoderContext(ab);
for ( int noisybits = 0; noisybits < 12; noisybits++ ) for (int noisybits = 0; noisybits < 12; noisybits++) {
{ for (int i = -1000; i < 1000; i++) {
for ( int i = -1000; i < 1000; i++ ) ctx.encodeNoisyDiff(i, noisybits);
{
ctx.encodeNoisyDiff( i, noisybits );
} }
} }
ctx.closeAndGetEncodedLength(); ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab ); ctx = new StatCoderContext(ab);
for ( int noisybits = 0; noisybits < 12; noisybits++ ) for (int noisybits = 0; noisybits < 12; noisybits++) {
{ for (int i = -1000; i < 1000; i++) {
for ( int i = -1000; i < 1000; i++ ) int value = ctx.decodeNoisyDiff(noisybits);
{ if (value != i) {
int value = ctx.decodeNoisyDiff( noisybits ); Assert.fail("value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value);
if ( value != i )
{
Assert.fail( "value mismatch: noisybits=" + noisybits + " i=" + i + " value=" + value );
} }
} }
} }
} }
@Test @Test
public void predictedValueEncodeDecodeTest() public void predictedValueEncodeDecodeTest() {
{
byte[] ab = new byte[80000]; byte[] ab = new byte[80000];
StatCoderContext ctx = new StatCoderContext( ab ); StatCoderContext ctx = new StatCoderContext(ab);
for ( int value = -100; value < 100; value += 5 ) for (int value = -100; value < 100; value += 5) {
{ for (int predictor = -200; predictor < 200; predictor += 7) {
for ( int predictor = -200; predictor < 200; predictor += 7 ) ctx.encodePredictedValue(value, predictor);
{
ctx.encodePredictedValue( value, predictor );
} }
} }
ctx.closeAndGetEncodedLength(); ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab ); ctx = new StatCoderContext(ab);
for ( int value = -100; value < 100; value += 5 ) for (int value = -100; value < 100; value += 5) {
{ for (int predictor = -200; predictor < 200; predictor += 7) {
for ( int predictor = -200; predictor < 200; predictor += 7 ) int decodedValue = ctx.decodePredictedValue(predictor);
{ if (value != decodedValue) {
int decodedValue = ctx.decodePredictedValue( predictor ); Assert.fail("value mismatch: value=" + value + " predictor=" + predictor + " decodedValue=" + decodedValue);
if ( value != decodedValue )
{
Assert.fail( "value mismatch: value=" + value + " predictor=" + predictor + " decodedValue=" + decodedValue );
} }
} }
} }
} }
@Test @Test
public void sortedArrayEncodeDecodeTest() public void sortedArrayEncodeDecodeTest() {
{
Random rand = new Random(); Random rand = new Random();
int size = 1000000; int size = 1000000;
int[] values = new int[size]; 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[i] = rand.nextInt() & 0x0fffffff;
} }
values[5] = 175384; // force collision values[5] = 175384; // force collision
@ -108,23 +87,21 @@ public class StatCoderContextTest
values[15] = 275384; // force neighbours values[15] = 275384; // force neighbours
values[18] = 275385; values[18] = 275385;
Arrays.sort( values ); Arrays.sort(values);
byte[] ab = new byte[3000000]; byte[] ab = new byte[3000000];
StatCoderContext ctx = new StatCoderContext( ab ); StatCoderContext ctx = new StatCoderContext(ab);
ctx.encodeSortedArray( values, 0, size, 0x08000000, 0 ); ctx.encodeSortedArray(values, 0, size, 0x08000000, 0);
ctx.closeAndGetEncodedLength(); ctx.closeAndGetEncodedLength();
ctx = new StatCoderContext( ab ); ctx = new StatCoderContext(ab);
int[] decodedValues = new int[size]; 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++ ) for (int i = 0; i < size; i++) {
{ if (values[i] != decodedValues[i]) {
if ( values[i] != decodedValues[i] ) Assert.fail("mismatch at i=" + i + " " + 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; import btools.expressions.BExpressionContextWay;
final class KinematicModel extends OsmPathModel final class KinematicModel extends OsmPathModel {
{ public OsmPrePath createPrePath() {
public OsmPrePath createPrePath()
{
return new KinematicPrePath(); return new KinematicPrePath();
} }
public OsmPath createPath() public OsmPath createPath() {
{
return new KinematicPath(); return new KinematicPath();
} }
@ -38,7 +35,7 @@ final class KinematicModel extends OsmPathModel
// derived values // derived values
public double pw; // balance power public double pw; // balance power
public double cost0; // minimum possible cost per meter public double cost0; // minimum possible cost per meter
private int wayIdxMaxspeed; private int wayIdxMaxspeed;
private int wayIdxMaxspeedExplicit; private int wayIdxMaxspeedExplicit;
private int wayIdxMinspeed; private int wayIdxMinspeed;
@ -47,7 +44,7 @@ final class KinematicModel extends OsmPathModel
protected BExpressionContextWay ctxWay; protected BExpressionContextWay ctxWay;
protected BExpressionContextNode ctxNode; protected BExpressionContextNode ctxNode;
protected Map<String,String> params; protected Map<String, String> params;
private boolean initDone = false; private boolean initDone = false;
@ -55,77 +52,67 @@ final class KinematicModel extends OsmPathModel
private double lastBreakingSpeed; private double lastBreakingSpeed;
@Override @Override
public void init( BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String,String> extraParams ) public void init(BExpressionContextWay expctxWay, BExpressionContextNode expctxNode, Map<String, String> extraParams) {
{ if (!initDone) {
if ( !initDone )
{
ctxWay = expctxWay; ctxWay = expctxWay;
ctxNode = expctxNode; ctxNode = expctxNode;
wayIdxMaxspeed = ctxWay.getOutputVariableIndex( "maxspeed", false ); wayIdxMaxspeed = ctxWay.getOutputVariableIndex("maxspeed", false);
wayIdxMaxspeedExplicit = ctxWay.getOutputVariableIndex( "maxspeed_explicit", false ); wayIdxMaxspeedExplicit = ctxWay.getOutputVariableIndex("maxspeed_explicit", false);
wayIdxMinspeed = ctxWay.getOutputVariableIndex( "minspeed", false ); wayIdxMinspeed = ctxWay.getOutputVariableIndex("minspeed", false);
nodeIdxMaxspeed = ctxNode.getOutputVariableIndex( "maxspeed", false ); nodeIdxMaxspeed = ctxNode.getOutputVariableIndex("maxspeed", false);
initDone = true; initDone = true;
} }
params = extraParams; params = extraParams;
turnAngleDecayTime = getParam( "turnAngleDecayTime", 5.f ); turnAngleDecayTime = getParam("turnAngleDecayTime", 5.f);
f_roll = getParam( "f_roll", 232.f ); f_roll = getParam("f_roll", 232.f);
f_air = getParam( "f_air", 0.4f ); f_air = getParam("f_air", 0.4f);
f_recup = getParam( "f_recup", 400.f ); f_recup = getParam("f_recup", 400.f);
p_standby = getParam( "p_standby", 250.f ); p_standby = getParam("p_standby", 250.f);
outside_temp = getParam( "outside_temp", 20.f ); outside_temp = getParam("outside_temp", 20.f);
recup_efficiency = getParam( "recup_efficiency", 0.7f ); recup_efficiency = getParam("recup_efficiency", 0.7f);
totalweight = getParam( "totalweight", 1640.f ); totalweight = getParam("totalweight", 1640.f);
vmax = getParam( "vmax", 80.f ) / 3.6; vmax = getParam("vmax", 80.f) / 3.6;
leftWaySpeed = getParam( "leftWaySpeed", 12.f ) / 3.6; leftWaySpeed = getParam("leftWaySpeed", 12.f) / 3.6;
rightWaySpeed = getParam( "rightWaySpeed", 12.f ) / 3.6; rightWaySpeed = getParam("rightWaySpeed", 12.f) / 3.6;
pw = 2. * f_air * vmax * vmax * vmax - p_standby; 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 ) protected float getParam(String name, float defaultValue) {
{ String sval = params == null ? null : params.get(name);
String sval = params == null ? null : params.get( name ); if (sval != null) {
if ( sval != null ) return Float.parseFloat(sval);
{
return Float.parseFloat( sval );
} }
float v = ctxWay.getVariableValue( name, defaultValue ); float v = ctxWay.getVariableValue(name, defaultValue);
if ( params != null ) if (params != null) {
{ params.put(name, "" + v);
params.put( name, "" + v );
} }
return v; return v;
} }
public float getWayMaxspeed() public float getWayMaxspeed() {
{ return ctxWay.getBuildInVariable(wayIdxMaxspeed) / 3.6f;
return ctxWay.getBuildInVariable( wayIdxMaxspeed ) / 3.6f;
} }
public float getWayMaxspeedExplicit() public float getWayMaxspeedExplicit() {
{ return ctxWay.getBuildInVariable(wayIdxMaxspeedExplicit) / 3.6f;
return ctxWay.getBuildInVariable( wayIdxMaxspeedExplicit ) / 3.6f;
} }
public float getWayMinspeed() public float getWayMinspeed() {
{ return ctxWay.getBuildInVariable(wayIdxMinspeed) / 3.6f;
return ctxWay.getBuildInVariable( wayIdxMinspeed ) / 3.6f;
} }
public float getNodeMaxspeed() public float getNodeMaxspeed() {
{ return ctxNode.getBuildInVariable(nodeIdxMaxspeed) / 3.6f;
return ctxNode.getBuildInVariable( nodeIdxMaxspeed ) / 3.6f;
} }
/** /**
* get the effective speed limit from the way-limit and vmax/vmin * get the effective speed limit from the way-limit and vmax/vmin
*/ */
public double getEffectiveSpeedLimit( ) public double getEffectiveSpeedLimit() {
{
// performance related inline coding // performance related inline coding
double minspeed = getWayMinspeed(); double minspeed = getWayMinspeed();
double espeed = minspeed > vmax ? minspeed : vmax; double espeed = minspeed > vmax ? minspeed : vmax;
@ -133,30 +120,27 @@ final class KinematicModel extends OsmPathModel
return maxspeed < espeed ? maxspeed : espeed; return maxspeed < espeed ? maxspeed : espeed;
} }
/** /**
* get the breaking speed for current balance-power (pw) and effective speed limit (vl) * get the breaking speed for current balance-power (pw) and effective speed limit (vl)
*/ */
public double getBreakingSpeed( double vl ) public double getBreakingSpeed(double vl) {
{ if (vl == lastEffectiveLimit) {
if ( vl == lastEffectiveLimit )
{
return lastBreakingSpeed; return lastBreakingSpeed;
} }
double v = vl*0.8; double v = vl * 0.8;
double pw2 = pw+p_standby; double pw2 = pw + p_standby;
double e = recup_efficiency; double e = recup_efficiency;
double x0 = pw2/vl+f_air*e*vl*vl+(1.-e)*f_roll; double x0 = pw2 / vl + f_air * e * vl * vl + (1. - e) * f_roll;
for(int i=0;i<5;i++) for (int i = 0; i < 5; i++) {
{ double v2 = v * v;
double v2 = v*v; double x = pw2 / v + f_air * e * v2 - x0;
double x = pw2/v+f_air*e*v2 - x0; double dx = 2. * e * f_air * v - pw2 / v2;
double dx = 2.*e*f_air*v - pw2/v2; v -= x / dx;
v -= x/dx;
} }
lastEffectiveLimit = vl; lastEffectiveLimit = vl;
lastBreakingSpeed = v; lastBreakingSpeed = v;
return v; return v;
} }

View File

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

View File

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

View File

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

View File

@ -1,103 +1,98 @@
/** /**
* Container for an osm node * Container for an osm node
* *
* @author ab * @author ab
*/ */
package btools.router; package btools.router;
import btools.mapaccess.OsmNode; import btools.mapaccess.OsmNode;
import btools.util.CheapRuler; import btools.util.CheapRuler;
public class OsmNodeNamed extends OsmNode public class OsmNodeNamed extends OsmNode {
{ public String name;
public String name; public double radius; // radius of nogopoint (in meters)
public double radius; // radius of nogopoint (in meters) public double nogoWeight; // weight for nogopoint
public double nogoWeight; // weight for nogopoint public boolean isNogo = false;
public boolean isNogo = false;
public OsmNodeNamed() {
public OsmNodeNamed() }
{
} public OsmNodeNamed(OsmNode n) {
super(n.ilon, n.ilat);
public OsmNodeNamed( OsmNode n) }
{
super( n.ilon, n.ilat ); @Override
} public String toString() {
if (Double.isNaN(nogoWeight)) {
@Override return ilon + "," + ilat + "," + name;
public String toString() } else {
{ return ilon + "," + ilat + "," + name + "," + nogoWeight;
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;
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) { boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lat1 + lat2) >> 1 ); // First point is within the circle
if (isFirstPointWithinCircle) {
boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius; // Last point is within the circle
boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius; if (isLastPointWithinCircle) {
// First point is within the circle return totalSegmentLength;
if (isFirstPointWithinCircle) { }
// Last point is within the circle // Last point is not within the circle
if (isLastPointWithinCircle) { // Just swap points and go on with first first point not within the
return totalSegmentLength; // circle now.
} // Swap longitudes
// Last point is not within the circle int tmp = lon2;
// Just swap points and go on with first first point not within the lon2 = lon1;
// circle now. lon1 = tmp;
// Swap longitudes // Swap latitudes
int tmp = lon2; tmp = lat2;
lon2 = lon1; lat2 = lat1;
lon1 = tmp; lat1 = tmp;
// Swap latitudes // Fix boolean values
tmp = lat2; isLastPointWithinCircle = isFirstPointWithinCircle;
lat2 = lat1; isFirstPointWithinCircle = false;
lat1 = tmp; }
// Fix boolean values // Distance between the initial point and projection of center of
isLastPointWithinCircle = isFirstPointWithinCircle; // the circle on the current segment.
isFirstPointWithinCircle = false; double initialToProject = (
} (lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
// Distance between the initial point and projection of center of + (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
// the circle on the current segment. ) / totalSegmentLength;
double initialToProject = ( // Distance between the initial point and the center of the circle.
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0] double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1] // Half length of the segment within the circle
) / totalSegmentLength; double halfDistanceWithin = Math.sqrt(
// Distance between the initial point and the center of the circle. radius * radius - (
double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1); initialToCenter * initialToCenter -
// Half length of the segment within the circle initialToProject * initialToProject
double halfDistanceWithin = Math.sqrt( )
radius*radius - ( );
initialToCenter*initialToCenter - // Last point is within the circle
initialToProject*initialToProject if (isLastPointWithinCircle) {
) return halfDistanceWithin + (totalSegmentLength - initialToProject);
); }
// Last point is within the circle return 2 * halfDistanceWithin;
if (isLastPointWithinCircle) { }
return halfDistanceWithin + (totalSegmentLength - initialToProject);
} public static OsmNodeNamed decodeNogo(String s) {
return 2 * halfDistanceWithin; OsmNodeNamed n = new OsmNodeNamed();
} int idx1 = s.indexOf(',');
n.ilon = Integer.parseInt(s.substring(0, idx1));
public static OsmNodeNamed decodeNogo( String s ) int idx2 = s.indexOf(',', idx1 + 1);
{ n.ilat = Integer.parseInt(s.substring(idx1 + 1, idx2));
OsmNodeNamed n = new OsmNodeNamed(); int idx3 = s.indexOf(',', idx2 + 1);
int idx1 = s.indexOf( ',' ); if (idx3 == -1) {
n.ilon = Integer.parseInt( s.substring( 0, idx1 ) ); n.name = s.substring(idx2 + 1);
int idx2 = s.indexOf( ',', idx1+1 ); n.nogoWeight = Double.NaN;
n.ilat = Integer.parseInt( s.substring( idx1+1, idx2 ) ); } else {
int idx3 = s.indexOf( ',', idx2+1 ); n.name = s.substring(idx2 + 1, idx3);
if ( idx3 == -1) { n.nogoWeight = Double.parseDouble(s.substring(idx3 + 1));
n.name = s.substring( idx2 + 1 ); }
n.nogoWeight = Double.NaN; n.isNogo = true;
} else { return n;
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 * Container for link between two Osm nodes
* *
* @author ab * @author ab
*/ */
package btools.router; package btools.router;
import java.io.IOException; import java.io.IOException;
import btools.mapaccess.OsmLink; import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder; import btools.mapaccess.OsmLinkHolder;
import btools.mapaccess.OsmNode; import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmTransferNode; import btools.mapaccess.OsmTransferNode;
import btools.mapaccess.TurnRestriction; import btools.mapaccess.TurnRestriction;
import btools.util.CheapRuler; import btools.util.CheapRuler;
abstract class OsmPath implements OsmLinkHolder abstract class OsmPath implements OsmLinkHolder {
{ /**
/** * The cost of that path (a modified distance)
* The cost of that path (a modified distance) */
*/ public int cost = 0;
public int cost = 0;
// the elevation assumed for that path can have a value
// the elevation assumed for that path can have a value // if the corresponding node has not
// if the corresponding node has not public short selev;
public short selev;
public int airdistance = 0; // distance to endpos
public int airdistance = 0; // distance to endpos
protected OsmNode sourceNode;
protected OsmNode sourceNode; protected OsmNode targetNode;
protected OsmNode targetNode;
protected OsmLink link;
protected OsmLink link; public OsmPathElement originElement;
public OsmPathElement originElement; public OsmPathElement myElement;
public OsmPathElement myElement;
protected float traffic;
protected float traffic;
private OsmLinkHolder nextForLink = null;
private OsmLinkHolder nextForLink = null;
public int treedepth = 0;
public int treedepth = 0;
// the position of the waypoint just before
// the position of the waypoint just before // this path position (for angle calculation)
// this path position (for angle calculation) public int originLon;
public int originLon; public int originLat;
public int originLat;
// the classifier of the segment just before this paths position
// the classifier of the segment just before this paths position protected float lastClassifier;
protected float lastClassifier; protected float lastInitialCost;
protected float lastInitialCost;
protected int priorityclassifier;
protected int priorityclassifier;
private static final int PATH_START_BIT = 1;
private static final int PATH_START_BIT = 1; private static final int CAN_LEAVE_DESTINATION_BIT = 2;
private static final int CAN_LEAVE_DESTINATION_BIT = 2; private static final int IS_ON_DESTINATION_BIT = 4;
private static final int IS_ON_DESTINATION_BIT = 4; private static final int HAD_DESTINATION_START_BIT = 8;
private static final int HAD_DESTINATION_START_BIT = 8; protected int bitfield = PATH_START_BIT;
protected int bitfield = PATH_START_BIT;
private boolean getBit(int mask) {
private boolean getBit( int mask ) return (bitfield & mask) != 0;
{ }
return (bitfield & mask ) != 0;
} private void setBit(int mask, boolean bit) {
if (getBit(mask) != bit) {
private void setBit( int mask, boolean bit ) bitfield ^= mask;
{ }
if ( getBit( mask ) != bit ) }
{
bitfield ^= mask; public boolean didEnterDestinationArea() {
} return !getBit(HAD_DESTINATION_START_BIT) && getBit(IS_ON_DESTINATION_BIT);
} }
public boolean didEnterDestinationArea() public MessageData message;
{
return !getBit( HAD_DESTINATION_START_BIT ) && getBit( IS_ON_DESTINATION_BIT ); public void unregisterUpTree(RoutingContext rc) {
} try {
OsmPathElement pe = originElement;
public MessageData message; while (pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic) pe).unregister(rc)) {
pe = pe.origin;
public void unregisterUpTree( RoutingContext rc ) }
{ } catch (IOException ioe) {
try throw new RuntimeException(ioe);
{ }
OsmPathElement pe = originElement; }
while( pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic)pe).unregister(rc) )
{ public void registerUpTree() {
pe = pe.origin; if (originElement instanceof OsmPathElementWithTraffic) {
} OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) originElement;
} ot.register();
catch( IOException ioe ) ot.addTraffic(traffic);
{ }
throw new RuntimeException( ioe ); }
}
} public void init(OsmLink link) {
this.link = link;
public void registerUpTree() targetNode = link.getTarget(null);
{ selev = targetNode.getSElev();
if ( originElement instanceof OsmPathElementWithTraffic )
{ originLon = -1;
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)originElement; originLat = -1;
ot.register(); }
ot.addTraffic( traffic );
} public void init(OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc) {
} if (origin.myElement == null) {
origin.myElement = OsmPathElement.create(origin, rc.countTraffic);
public void init( OsmLink link ) }
{ this.originElement = origin.myElement;
this.link = link; this.link = link;
targetNode = link.getTarget( null ); this.sourceNode = origin.targetNode;
selev = targetNode.getSElev(); this.targetNode = link.getTarget(sourceNode);
this.cost = origin.cost;
originLon = -1; this.lastClassifier = origin.lastClassifier;
originLat = -1; this.lastInitialCost = origin.lastInitialCost;
} this.bitfield = origin.bitfield;
init(origin);
public void init( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc ) addAddionalPenalty(refTrack, detailMode, origin, link, rc);
{ }
if ( origin.myElement == null )
{ protected abstract void init(OsmPath orig);
origin.myElement = OsmPathElement.create( origin, rc.countTraffic );
} protected abstract void resetState();
this.originElement = origin.myElement;
this.link = link;
this.sourceNode = origin.targetNode; protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc) {
this.targetNode = link.getTarget( sourceNode ); byte[] description = link.descriptionBitmap;
this.cost = origin.cost; if (description == null) {
this.lastClassifier = origin.lastClassifier; return; // could be a beeline path
this.lastInitialCost = origin.lastInitialCost; }
this.bitfield = origin.bitfield;
init( origin ); boolean recordTransferNodes = detailMode || rc.countTraffic;
addAddionalPenalty(refTrack, detailMode, origin, link, rc );
} rc.nogoCost = 0.;
protected abstract void init( OsmPath orig ); // extract the 3 positions of the first section
int lon0 = origin.originLon;
protected abstract void resetState(); int lat0 = origin.originLat;
int lon1 = sourceNode.getILon();
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc ) int lat1 = sourceNode.getILat();
{ short ele1 = origin.selev;
byte[] description = link.descriptionBitmap;
if ( description == null ) int linkdisttotal = 0;
{
return; // could be a beeline path message = detailMode ? new MessageData() : null;
}
boolean isReverse = link.isReverse(sourceNode);
boolean recordTransferNodes = detailMode || rc.countTraffic;
// evaluate the way tags
rc.nogoCost = 0.; rc.expctxWay.evaluate(rc.inverseDirection ^ isReverse, description);
// extract the 3 positions of the first section
int lon0 = origin.originLon; // calculate the costfactor inputs
int lat0 = origin.originLat; float costfactor = rc.expctxWay.getCostfactor();
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
int lon1 = sourceNode.getILon(); int lastpriorityclassifier = priorityclassifier;
int lat1 = sourceNode.getILat(); priorityclassifier = (int) rc.expctxWay.getPriorityClassifier();
short ele1 = origin.selev;
// *** add initial cost if the classifier changed
int linkdisttotal = 0; float newClassifier = rc.expctxWay.getInitialClassifier();
float newInitialCost = rc.expctxWay.getInitialcost();
message = detailMode ? new MessageData() : null; float classifierDiff = newClassifier - lastClassifier;
if (newClassifier != 0. && lastClassifier != 0. && (classifierDiff > 0.0005 || classifierDiff < -0.0005)) {
boolean isReverse = link.isReverse( sourceNode ); float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost;
if (initialcost >= 1000000.) {
// evaluate the way tags cost = -1;
rc.expctxWay.evaluate( rc.inverseDirection ^ isReverse, description ); return;
}
// calculate the costfactor inputs int iicost = (int) initialcost;
float costfactor = rc.expctxWay.getCostfactor(); if (message != null) {
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f; message.linkinitcost += iicost;
int lastpriorityclassifier = priorityclassifier; }
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier(); cost += iicost;
}
// *** add initial cost if the classifier changed lastClassifier = newClassifier;
float newClassifier = rc.expctxWay.getInitialClassifier(); lastInitialCost = newInitialCost;
float newInitialCost = rc.expctxWay.getInitialcost();
float classifierDiff = newClassifier - lastClassifier; // *** destination logic: no destination access in between
if ( newClassifier != 0. && lastClassifier != 0. && ( classifierDiff > 0.0005 || classifierDiff < -0.0005 ) ) int classifiermask = (int) rc.expctxWay.getClassifierMask();
{ boolean newDestination = (classifiermask & 64) != 0;
float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost; boolean oldDestination = getBit(IS_ON_DESTINATION_BIT);
if ( initialcost >= 1000000. ) if (getBit(PATH_START_BIT)) {
{ setBit(PATH_START_BIT, false);
cost = -1; setBit(CAN_LEAVE_DESTINATION_BIT, newDestination);
return; setBit(HAD_DESTINATION_START_BIT, newDestination);
} } else {
if (oldDestination && !newDestination) {
int iicost = (int)initialcost; if (getBit(CAN_LEAVE_DESTINATION_BIT)) {
if ( message != null ) setBit(CAN_LEAVE_DESTINATION_BIT, false);
{ } else {
message.linkinitcost += iicost; cost = -1;
} return;
cost += iicost; }
} }
lastClassifier = newClassifier; }
lastInitialCost = newInitialCost; setBit(IS_ON_DESTINATION_BIT, newDestination);
// *** destination logic: no destination access in between
int classifiermask = (int)rc.expctxWay.getClassifierMask(); OsmTransferNode transferNode = link.geometry == null ? null
boolean newDestination = (classifiermask & 64) != 0; : rc.geometryDecoder.decodeGeometry(link.geometry, sourceNode, targetNode, isReverse);
boolean oldDestination = getBit( IS_ON_DESTINATION_BIT );
if ( getBit( PATH_START_BIT ) ) for (int nsection = 0; ; nsection++) {
{
setBit( PATH_START_BIT, false ); originLon = lon1;
setBit( CAN_LEAVE_DESTINATION_BIT, newDestination ); originLat = lat1;
setBit( HAD_DESTINATION_START_BIT, newDestination );
} int lon2;
else int lat2;
{ short ele2;
if ( oldDestination && !newDestination )
{ if (transferNode == null) {
if ( getBit( CAN_LEAVE_DESTINATION_BIT ) ) lon2 = targetNode.ilon;
{ lat2 = targetNode.ilat;
setBit( CAN_LEAVE_DESTINATION_BIT, false ); ele2 = targetNode.selev;
} } else {
else lon2 = transferNode.ilon;
{ lat2 = transferNode.ilat;
cost = -1; ele2 = transferNode.selev;
return; }
}
} boolean isStartpoint = lon0 == -1 && lat0 == -1;
}
setBit( IS_ON_DESTINATION_BIT, newDestination ); // 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
OsmTransferNode transferNode = link.geometry == null ? null ? TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode)
: rc.geometryDecoder.decodeGeometry( link.geometry, sourceNode, targetNode, isReverse ); : TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode)) {
cost = -1;
for(int nsection=0; ;nsection++) return;
{ }
}
originLon = lon1;
originLat = lat1; // if recording, new MessageData for each section (needed for turn-instructions)
if (message != null && message.wayKeyValues != null) {
int lon2; originElement.message = message;
int lat2; message = new MessageData();
short ele2; }
if ( transferNode == null ) int dist = rc.calcDistance(lon1, lat1, lon2, lat2);
{
lon2 = targetNode.ilon; boolean stopAtEndpoint = false;
lat2 = targetNode.ilat; if (rc.shortestmatch) {
ele2 = targetNode.selev; if (rc.isEndpoint) {
} stopAtEndpoint = true;
else ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
{ } else {
lon2 = transferNode.ilon; // we just start here, reset everything
lat2 = transferNode.ilat; cost = 0;
ele2 = transferNode.selev; resetState();
} lon0 = -1; // reset turncost-pipe
lat0 = -1;
boolean isStartpoint = lon0 == -1 && lat0 == -1; isStartpoint = true;
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints) if (recordTransferNodes) {
if ( nsection == 0 && rc.considerTurnRestrictions && !detailMode&& !isStartpoint ) if (rc.wayfraction > 0.) {
{ ele1 = interpolateEle(ele1, ele2, 1. - rc.wayfraction);
if ( rc.inverseDirection originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic);
? TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode ) } else {
: TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode ) ) originElement = null; // prevent duplicate point
{ }
cost = -1; }
return;
} if (rc.checkPendingEndpoint()) {
} dist = rc.calcDistance(rc.ilonshortest, rc.ilatshortest, lon2, lat2);
if (rc.shortestmatch) {
// if recording, new MessageData for each section (needed for turn-instructions) stopAtEndpoint = true;
if ( message != null && message.wayKeyValues != null ) ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
{ }
originElement.message = message; }
message = new MessageData(); }
} }
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 ); if (message != null) {
message.linkdist += dist;
boolean stopAtEndpoint = false; }
if ( rc.shortestmatch ) linkdisttotal += dist;
{
if ( rc.isEndpoint ) // apply a start-direction if appropriate (by faking the origin position)
{ if (isStartpoint) {
stopAtEndpoint = true; if (rc.startDirectionValid) {
ele2 = interpolateEle( ele1, ele2, rc.wayfraction ); double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
} double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lon0 + lat1) >> 1);
else lon0 = lon1 - (int) (1000. * Math.sin(dir) / lonlat2m[0]);
{ lat0 = lat1 - (int) (1000. * Math.cos(dir) / lonlat2m[1]);
// we just start here, reset everything } else {
cost = 0; lon0 = lon1 - (lon2 - lon1);
resetState(); lat0 = lat1 - (lat2 - lat1);
lon0 = -1; // reset turncost-pipe }
lat0 = -1; }
isStartpoint = true; double angle = rc.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
double cosangle = rc.anglemeter.getCosAngle();
if ( recordTransferNodes )
{ // *** elevation stuff
if ( rc.wayfraction > 0. ) double delta_h = 0.;
{ if (ele2 == Short.MIN_VALUE) ele2 = ele1;
ele1 = interpolateEle( ele1, ele2, 1. - rc.wayfraction ); if (ele1 != Short.MIN_VALUE) {
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic ); delta_h = (ele2 - ele1) / 4.;
} if (rc.inverseDirection) {
else delta_h = -delta_h;
{ }
originElement = null; // prevent duplicate point }
}
}
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2 / 4.;
if ( rc.checkPendingEndpoint() )
{ double sectionCost = processWaySection(rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier);
dist = rc.calcDistance( rc.ilonshortest, rc.ilatshortest, lon2, lat2 ); if ((sectionCost < 0. || costfactor > 9998. && !detailMode) || sectionCost + cost >= 2000000000.) {
if ( rc.shortestmatch ) cost = -1;
{ return;
stopAtEndpoint = true; }
ele2 = interpolateEle( ele1, ele2, rc.wayfraction );
} if (isTrafficBackbone) {
} sectionCost = 0.;
} }
}
cost += (int) sectionCost;
if ( message != null )
{ // calculate traffic
message.linkdist += dist; if (rc.countTraffic) {
} int minDist = (int) rc.trafficSourceMinDist;
linkdisttotal += dist; int cost2 = cost < minDist ? minDist : cost;
traffic += dist * rc.expctxWay.getTrafficSourceDensity() * Math.pow(cost2 / 10000.f, rc.trafficSourceExponent);
// apply a start-direction if appropriate (by faking the origin position) }
if ( isStartpoint )
{ // compute kinematic
if ( rc.startDirectionValid ) computeKinematic(rc, dist, delta_h, detailMode);
{
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD; if (message != null) {
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lon0 + lat1) >> 1 ); message.turnangle = (float) angle;
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / lonlat2m[0] ); message.time = (float) getTotalTime();
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) / lonlat2m[1] ); message.energy = (float) getTotalEnergy();
} message.priorityclassifier = priorityclassifier;
else message.classifiermask = classifiermask;
{ message.lon = lon2;
lon0 = lon1 - (lon2-lon1); message.lat = lat2;
lat0 = lat1 - (lat2-lat1); message.ele = ele2;
} message.wayKeyValues = rc.expctxWay.getKeyValueDescription(isReverse, description);
} }
double angle = rc.anglemeter.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 );
double cosangle = rc.anglemeter.getCosAngle(); if (stopAtEndpoint) {
if (recordTransferNodes) {
// *** elevation stuff originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic);
double delta_h = 0.; originElement.cost = cost;
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1; if (message != null) {
if ( ele1 != Short.MIN_VALUE ) originElement.message = message;
{ }
delta_h = (ele2 - ele1)/4.; }
if ( rc.inverseDirection ) if (rc.nogoCost < 0) {
{ cost = -1;
delta_h = -delta_h; } else {
} cost += rc.nogoCost;
} }
return;
}
if (transferNode == null) {
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.; // *** penalty for being part of the reference track
if (refTrack != null && refTrack.containsNode(targetNode) && refTrack.containsNode(sourceNode)) {
double sectionCost = processWaySection( rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier ); int reftrackcost = linkdisttotal;
if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. ) cost += reftrackcost;
{ }
cost = -1; selev = ele2;
return; break;
} }
transferNode = transferNode.next;
if ( isTrafficBackbone )
{ if (recordTransferNodes) {
sectionCost = 0.; originElement = OsmPathElement.create(lon2, lat2, ele2, originElement, rc.countTraffic);
} originElement.cost = cost;
originElement.addTraffic(traffic);
cost += (int)sectionCost; traffic = 0;
}
// calculate traffic lon0 = lon1;
if ( rc.countTraffic ) lat0 = lat1;
{ lon1 = lon2;
int minDist = (int)rc.trafficSourceMinDist; lat1 = lat2;
int cost2 = cost < minDist ? minDist : cost; ele1 = ele2;
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent); }
}
// check for nogo-matches (after the *actual* start of segment)
// compute kinematic if (rc.nogoCost < 0) {
computeKinematic( rc, dist, delta_h, detailMode ); cost = -1;
return;
if ( message != null ) } else {
{ cost += rc.nogoCost;
message.turnangle = (float)angle; }
message.time = (float)getTotalTime();
message.energy = (float)getTotalEnergy(); // add target-node costs
message.priorityclassifier = priorityclassifier; double targetCost = processTargetNode(rc);
message.classifiermask = classifiermask; if (targetCost < 0. || targetCost + cost >= 2000000000.) {
message.lon = lon2; cost = -1;
message.lat = lat2; return;
message.ele = ele2; }
message.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description ); cost += (int) targetCost;
} }
if ( stopAtEndpoint )
{ public short interpolateEle(short e1, short e2, double fraction) {
if ( recordTransferNodes ) if (e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE) {
{ return Short.MIN_VALUE;
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic ); }
originElement.cost = cost; return (short) (e1 * (1. - fraction) + e2 * fraction);
if ( message != null ) }
{
originElement.message = message; 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);
if ( rc.nogoCost < 0)
{ protected void computeKinematic(RoutingContext rc, double dist, double delta_h, boolean detailMode) {
cost = -1; }
}
else public abstract int elevationCorrection(RoutingContext rc);
{
cost += rc.nogoCost; public abstract boolean definitlyWorseThan(OsmPath p, RoutingContext rc);
}
return; public OsmNode getSourceNode() {
} return sourceNode;
}
if ( transferNode == null )
{ public OsmNode getTargetNode() {
// *** penalty for being part of the reference track return targetNode;
if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( sourceNode ) ) }
{
int reftrackcost = linkdisttotal; public OsmLink getLink() {
cost += reftrackcost; return link;
} }
selev = ele2;
break;
} public void setNextForLink(OsmLinkHolder holder) {
transferNode = transferNode.next; nextForLink = holder;
}
if ( recordTransferNodes )
{ public OsmLinkHolder getNextForLink() {
originElement = OsmPathElement.create( lon2, lat2, ele2, originElement, rc.countTraffic ); return nextForLink;
originElement.cost = cost; }
originElement.addTraffic( traffic );
traffic = 0; public double getTotalTime() {
} return 0.;
lon0 = lon1; }
lat0 = lat1;
lon1 = lon2; public double getTotalEnergy() {
lat1 = lat2; return 0.;
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; package btools.router;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import btools.mapaccess.OsmNode; import btools.mapaccess.OsmNode;
import btools.mapaccess.OsmPos; import btools.mapaccess.OsmPos;
import btools.util.CheapRuler; import btools.util.CheapRuler;
/** /**
* Container for link between two Osm nodes * Container for link between two Osm nodes
* *
* @author ab * @author ab
*/ */
public class OsmPathElement implements OsmPos public class OsmPathElement implements OsmPos {
{ private int ilat; // latitude
private int ilat; // latitude private int ilon; // longitude
private int ilon; // longitude private short selev; // longitude
private short selev; // longitude
public MessageData message = null; // description
public MessageData message = null; // description
public int cost;
public int cost;
// interface OsmPos
// interface OsmPos public final int getILat() {
public final int getILat() return ilat;
{ }
return ilat;
} public final int getILon() {
return ilon;
public final int getILon() }
{
return ilon; public final short getSElev() {
} return selev;
}
public final short getSElev()
{ public final double getElev() {
return selev; return selev / 4.;
} }
public final double getElev() public final float getTime() {
{ return message == null ? 0.f : message.time;
return selev / 4.; }
}
public final void setTime(float t) {
public final float getTime() if (message != null) {
{ message.time = t;
return message == null ? 0.f : message.time; }
} }
public final void setTime( float t ) public final float getEnergy() {
{ return message == null ? 0.f : message.energy;
if ( message != null ) }
{
message.time = t; public final void setEnergy(float e) {
} if (message != null) {
} message.energy = e;
}
public final float getEnergy() }
{
return message == null ? 0.f : message.energy; public final long getIdFromPos() {
} return ((long) ilon) << 32 | ilat;
}
public final void setEnergy( float e )
{ public final int calcDistance(OsmPos p) {
if ( message != null ) return (int) (CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0);
{ }
message.energy = e;
} public OsmPathElement origin;
}
// construct a path element from a path
public final long getIdFromPos() public static final OsmPathElement create(OsmPath path, boolean countTraffic) {
{ OsmNode n = path.getTargetNode();
return ((long)ilon)<<32 | ilat; OsmPathElement pe = create(n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic);
} pe.cost = path.cost;
pe.message = path.message;
public final int calcDistance( OsmPos p ) return pe;
{ }
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
} public static final OsmPathElement create(int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic) {
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
public OsmPathElement origin; pe.ilon = ilon;
pe.ilat = ilat;
// construct a path element from a path pe.selev = selev;
public static final OsmPathElement create( OsmPath path, boolean countTraffic ) pe.origin = origin;
{ return pe;
OsmNode n = path.getTargetNode(); }
OsmPathElement pe = create( n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic );
pe.cost = path.cost; protected OsmPathElement() {
pe.message = path.message; }
return pe;
} public void addTraffic(float traffic) {
}
public static final OsmPathElement create( int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic )
{ public String toString() {
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement(); return ilon + "_" + ilat;
pe.ilon = ilon; }
pe.ilat = ilat;
pe.selev = selev; public void writeToStream(DataOutput dos) throws IOException {
pe.origin = origin; dos.writeInt(ilat);
return pe; dos.writeInt(ilon);
} dos.writeShort(selev);
dos.writeInt(cost);
protected OsmPathElement() }
{
} public static OsmPathElement readFromStream(DataInput dis) throws IOException {
OsmPathElement pe = new OsmPathElement();
public void addTraffic( float traffic ) pe.ilat = dis.readInt();
{ pe.ilon = dis.readInt();
} pe.selev = dis.readShort();
pe.cost = dis.readInt();
public String toString() return pe;
{ }
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 * @author ab
*/ */
public final class OsmPathElementWithTraffic extends OsmPathElement public final class OsmPathElementWithTraffic extends OsmPathElement {
{
private int registerCount; private int registerCount;
private float farTraffic; private float farTraffic;
private float nearTraffic; private float nearTraffic;
public void register() public void register() {
{ if (registerCount++ == 0) {
if ( registerCount++ == 0 ) if (origin instanceof OsmPathElementWithTraffic) {
{ OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
if ( origin instanceof OsmPathElementWithTraffic )
{
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)origin;
ot.register(); ot.register();
ot.farTraffic += farTraffic; ot.farTraffic += farTraffic;
ot.nearTraffic += nearTraffic; ot.nearTraffic += nearTraffic;
@ -30,42 +26,36 @@ public final class OsmPathElementWithTraffic extends OsmPathElement
} }
} }
} }
@Override @Override
public void addTraffic( float traffic ) public void addTraffic(float traffic) {
{
this.farTraffic += traffic; this.farTraffic += traffic;
this.nearTraffic += traffic; this.nearTraffic += traffic;
} }
// unregister from origin if our registercount is 0, else do nothing // 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 public boolean unregister(RoutingContext rc) throws IOException {
{ if (--registerCount == 0) {
if ( --registerCount == 0 ) if (origin instanceof OsmPathElementWithTraffic) {
{ OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) origin;
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);
if ( costdelta > 0 && farTraffic > maxtraffic ) maxtraffic = farTraffic; int costdelta = cost - ot.cost;
ot.farTraffic += farTraffic * Math.exp(-costdelta / rc.farTrafficDecayLength);
int t2 = cost == ot.cost ? -1 : (int)(rc.farTrafficWeight*farTraffic + rc.nearTrafficWeight*nearTraffic); ot.nearTraffic += nearTraffic * Math.exp(-costdelta / rc.nearTrafficDecayLength);
if ( t2 > 4000 || t2 == -1 ) 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 ); // System.out.println( "unregistered: " + this + " origin=" + ot + " farTraffic =" + farTraffic + " nearTraffic =" + nearTraffic + " cost=" + cost );
if ( rc.trafficOutputStream != null ) if (rc.trafficOutputStream != null) {
{ rc.trafficOutputStream.writeLong(getIdFromPos());
rc.trafficOutputStream.writeLong( getIdFromPos()); rc.trafficOutputStream.writeLong(ot.getIdFromPos());
rc.trafficOutputStream.writeLong( ot.getIdFromPos()); rc.trafficOutputStream.writeInt(t2);
rc.trafficOutputStream.writeInt( t2 );
} }
} }
farTraffic = 0; farTraffic = 0;

View File

@ -11,11 +11,10 @@ import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionContextWay;
abstract class OsmPathModel abstract class OsmPathModel {
{
public abstract OsmPrePath createPrePath(); public abstract OsmPrePath createPrePath();
public abstract OsmPath createPath(); 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.OsmNode;
import btools.mapaccess.OsmTransferNode; import btools.mapaccess.OsmTransferNode;
public abstract class OsmPrePath public abstract class OsmPrePath {
{
protected OsmNode sourceNode; protected OsmNode sourceNode;
protected OsmNode targetNode; protected OsmNode targetNode;
protected OsmLink link; protected OsmLink link;
public OsmPrePath next; 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.link = link;
this.sourceNode = origin.getTargetNode(); this.sourceNode = origin.getTargetNode();
this.targetNode = link.getTarget( sourceNode ); this.targetNode = link.getTarget(sourceNode);
initPrePath(origin, rc ); 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.BExpressionContextWay;
import btools.expressions.BExpressionMetaData; import btools.expressions.BExpressionMetaData;
public final class ProfileCache public final class ProfileCache {
{
private static File lastLookupFile; private static File lastLookupFile;
private static long lastLookupTimestamp; private static long lastLookupTimestamp;
private BExpressionContextWay expctxWay; private BExpressionContextWay expctxWay;
private BExpressionContextNode expctxNode; private BExpressionContextNode expctxNode;
private File lastProfileFile; private File lastProfileFile;
private long lastProfileTimestamp; private long lastProfileTimestamp;
private boolean profilesBusy; private boolean profilesBusy;
private long lastUseTime; 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]; apc = new ProfileCache[size];
} }
public static synchronized boolean parseProfile( RoutingContext rc ) public static synchronized boolean parseProfile(RoutingContext rc) {
{ String profileBaseDir = System.getProperty("profileBaseDir");
String profileBaseDir = System.getProperty( "profileBaseDir" ); File profileDir;
File profileDir; File profileFile;
File profileFile; if (profileBaseDir == null) {
if ( profileBaseDir == null ) profileDir = new File(rc.localFunction).getParentFile();
{ profileFile = new File(rc.localFunction);
profileDir = new File( rc.localFunction ).getParentFile(); } else {
profileFile = new File( rc.localFunction ) ; profileDir = new File(profileBaseDir);
} profileFile = new File(profileDir, rc.localFunction + ".brf");
else }
{
profileDir = new File( profileBaseDir );
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ;
}
rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum()<<24; rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum() << 24;
File lookupFile = new File( profileDir, "lookups.dat" ); 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;
// check for re-use // invalidate cache at lookup-table update
for( int i=0; i<apc.length; i++) if (!(lookupFile.equals(lastLookupFile) && lookupFile.lastModified() == lastLookupTimestamp)) {
{ if (lastLookupFile != null) {
ProfileCache pc = apc[i]; System.out.println("******** invalidating profile-cache after lookup-file update ******** ");
}
if ( pc != null ) apc = new ProfileCache[apc.length];
{ lastLookupFile = lookupFile;
if ( (!pc.profilesBusy) && profileFile.equals( pc.lastProfileFile ) ) lastLookupTimestamp = lookupFile.lastModified();
{ }
if ( rc.profileTimestamp == pc.lastProfileTimestamp )
{ ProfileCache lru = null;
rc.expctxWay = pc.expctxWay; int unusedSlot = -1;
rc.expctxNode = pc.expctxNode;
rc.readGlobalConfig(); // check for re-use
pc.profilesBusy = true; for (int i = 0; i < apc.length; i++) {
return true; ProfileCache pc = apc[i];
}
lru = pc; // name-match but timestamp-mismatch -> we overide this one if (pc != null) {
unusedSlot = -1; if ((!pc.profilesBusy) && profileFile.equals(pc.lastProfileFile)) {
break; if (rc.profileTimestamp == pc.lastProfileTimestamp) {
} rc.expctxWay = pc.expctxWay;
if ( lru == null || lru.lastUseTime > pc.lastUseTime ) rc.expctxNode = pc.expctxNode;
{ rc.readGlobalConfig();
lru = pc; pc.profilesBusy = true;
return true;
} }
lru = pc; // name-match but timestamp-mismatch -> we overide this one
unusedSlot = -1;
break;
} }
else if ( unusedSlot < 0 ) if (lru == null || lru.lastUseTime > pc.lastUseTime) {
{ lru = pc;
unusedSlot = i;
} }
} 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" ); BExpressionMetaData meta = new BExpressionMetaData();
rc.expctxNode.parseFile( profileFile, "global" );
rc.readGlobalConfig(); rc.expctxWay = new BExpressionContextWay(rc.memoryclass * 512, meta);
rc.expctxNode = new BExpressionContextNode(0, meta);
if ( rc.processUnusedTags ) rc.expctxNode.setForeignContext(rc.expctxWay);
{
rc.expctxWay.setAllTagsUsed(); 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 ) if (lru.lastProfileFile != null) {
{ if (debug)
lru = new ProfileCache(); System.out.println("******* replacing profile of age " + ((System.currentTimeMillis() - lru.lastUseTime) / 1000L) + " sec " + lru.lastProfileFile + "->" + profileFile);
if ( unusedSlot >= 0 ) }
{
apc[unusedSlot] = lru;
if ( debug ) System.out.println( "******* adding new profile at idx=" + unusedSlot + " for " + profileFile );
}
}
if ( lru.lastProfileFile != null ) lru.lastProfileTimestamp = rc.profileTimestamp;
{ lru.lastProfileFile = profileFile;
if ( debug ) System.out.println( "******* replacing profile of age " + ((System.currentTimeMillis()-lru.lastUseTime)/1000L) + " sec " + lru.lastProfileFile + "->" + profileFile ); lru.expctxWay = rc.expctxWay;
} lru.expctxNode = rc.expctxNode;
lru.profilesBusy = true;
lru.lastProfileTimestamp = rc.profileTimestamp; lru.lastUseTime = System.currentTimeMillis();
lru.lastProfileFile = profileFile; return false;
lru.expctxWay = rc.expctxWay;
lru.expctxNode = rc.expctxNode;
lru.profilesBusy = true;
lru.lastUseTime = System.currentTimeMillis();
return false;
} }
public static synchronized void releaseProfile( RoutingContext rc ) public static synchronized void releaseProfile(RoutingContext rc) {
{ for (int i = 0; i < apc.length; i++) {
for( int i=0; i<apc.length; i++)
{
ProfileCache pc = apc[i]; ProfileCache pc = apc[i];
if ( pc != null ) if (pc != null) {
{
// only the thread that holds the cached instance can release it // 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; pc.profilesBusy = false;
break; 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; import btools.mapaccess.StorageConfigHelper;
public final class RoutingHelper public final class RoutingHelper {
{ public static File getAdditionalMaptoolDir(File segmentDir) {
public static File getAdditionalMaptoolDir( File segmentDir ) return StorageConfigHelper.getAdditionalMaptoolDir(segmentDir);
{ }
return StorageConfigHelper.getAdditionalMaptoolDir(segmentDir);
}
public static File getSecondarySegmentDir( File segmentDir ) public static File getSecondarySegmentDir(File segmentDir) {
{ return StorageConfigHelper.getSecondarySegmentDir(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;
}
private static boolean hasAnyDatafiles( File dir )
{ public static boolean hasDirectoryAnyDatafiles(File segmentDir) {
String[] fileNames = dir.list(); if (hasAnyDatafiles(segmentDir)) {
for( String fileName : fileNames ) return true;
{
if ( fileName.endsWith( ".rd5" ) ) return true;
}
return false;
} }
// 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; 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; import btools.mapaccess.OsmNode;
public final class SearchBoundary public final class SearchBoundary {
{
private int minlon0; private int minlon0;
private int minlat0; private int minlat0;
private int maxlon0; private int maxlon0;
private int maxlat0; private int maxlat0;
private int minlon; private int minlon;
private int minlat; private int minlat;
private int maxlon; private int maxlon;
private int maxlat; private int maxlat;
private int radius; private int radius;
private OsmNode p; private OsmNode p;
int direction; int direction;
/** /**
* @param radius Search radius in meters. * @param radius Search radius in meters.
*/ */
public SearchBoundary( OsmNode n, int radius, int direction ) public SearchBoundary(OsmNode n, int radius, int direction) {
{ this.radius = radius;
this.radius = radius; this.direction = direction;
this.direction = direction;
p = new OsmNode( n.ilon, n.ilat ); p = new OsmNode(n.ilon, n.ilat);
int lon = (n.ilon / 5000000 ) * 5000000; int lon = (n.ilon / 5000000) * 5000000;
int lat = (n.ilat / 5000000 ) * 5000000; int lat = (n.ilat / 5000000) * 5000000;
minlon0 = lon - 5000000; minlon0 = lon - 5000000;
minlat0 = lat - 5000000; minlat0 = lat - 5000000;
maxlon0 = lon + 10000000; maxlon0 = lon + 10000000;
maxlat0 = lat + 10000000; maxlat0 = lat + 10000000;
minlon = lon - 1000000; minlon = lon - 1000000;
minlat = lat - 1000000; minlat = lat - 1000000;
maxlon = lon + 6000000; maxlon = lon + 6000000;
maxlat = lat + 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;
} }
if (cost == 0) {
public static String getFileName( OsmNode n ) return n.ilon > minlon0 && n.ilon < maxlon0 && n.ilat > minlat0 && n.ilat < maxlat0;
{
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";
} }
return n.ilon > minlon && n.ilon < maxlon && n.ilat > minlat && n.ilat < maxlat;
}
public boolean isInBoundary( OsmNode n, int cost ) public int getBoundaryDistance(OsmNode n) {
{ switch (direction) {
if ( radius > 0 ) case 0:
{ return n.calcDistance(new OsmNode(n.ilon, minlat));
return n.calcDistance( p ) < radius; case 1:
} return n.calcDistance(new OsmNode(minlon, n.ilat));
if ( cost == 0 ) case 2:
{ return n.calcDistance(new OsmNode(n.ilon, maxlat));
return n.ilon > minlon0 && n.ilon < maxlon0 && n.ilat > minlat0 && n.ilat < maxlat0; case 3:
} return n.calcDistance(new OsmNode(maxlon, n.ilat));
return n.ilon > minlon && n.ilon < maxlon && n.ilat > minlat && n.ilat < maxlat; 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; import btools.expressions.BExpressionContextWay;
final class StdModel extends OsmPathModel final class StdModel extends OsmPathModel {
{ public OsmPrePath createPrePath() {
public OsmPrePath createPrePath()
{
return null; return null;
} }
public OsmPath createPath() public OsmPath createPath() {
{
return new StdPath(); return new StdPath();
} }
@ -29,11 +26,10 @@ final class StdModel extends OsmPathModel
@Override @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; ctxWay = expctxWay;
ctxNode = expctxNode; ctxNode = expctxNode;
BExpressionContext expctxGlobal = expctxWay; // just one of them... BExpressionContext expctxGlobal = expctxWay; // just one of them...
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -12,11 +12,11 @@ import btools.util.CheapRuler;
public class OsmNodeNamedTest { public class OsmNodeNamedTest {
static int toOsmLon(double lon) { 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) { 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 @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; package btools.router;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -22,26 +22,26 @@ public class OsmNogoPolygonTest {
static OsmNogoPolygon polygon; static OsmNogoPolygon polygon;
static OsmNogoPolygon polyline; 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[] 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[] 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) { 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) { 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 @BeforeClass
public static void setUp() throws Exception { public static void setUp() throws Exception {
polygon = new OsmNogoPolygon(true); polygon = new OsmNogoPolygon(true);
for (int i = 0; i<lons.length; i++) { for (int i = 0; i < lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y)); polygon.addVertex(toOsmLon(lons[i], OFFSET_X), toOsmLat(lats[i], OFFSET_Y));
} }
polyline = new OsmNogoPolygon(false); polyline = new OsmNogoPolygon(false);
for (int i = 0; i<lons.length; i++) { for (int i = 0; i < lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i], OFFSET_X),toOsmLat(lats[i], OFFSET_Y)); polyline.addVertex(toOsmLon(lons[i], OFFSET_X), toOsmLat(lats[i], OFFSET_Y));
} }
} }
@ -51,162 +51,162 @@ public class OsmNogoPolygonTest {
@Test @Test
public void testCalcBoundingCircle() { public void testCalcBoundingCircle() {
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( polygon.ilat ); double[] lonlat2m = CheapRuler.getLonLatToMeterScales(polygon.ilat);
double dlon2m = lonlat2m[0]; double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1]; double dlat2m = lonlat2m[1];
polygon.calcBoundingCircle(); polygon.calcBoundingCircle();
double r = polygon.radius; 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 dpx = (toOsmLon(lons[i], OFFSET_X) - polygon.ilon) * dlon2m;
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polygon.ilat) * dlat2m; double dpy = (toOsmLat(lats[i], OFFSET_Y) - polygon.ilat) * dlat2m;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy); double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
double diff = r-r1; double diff = r - r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0); assertTrue("i: " + i + " r(" + r + ") >= r1(" + r1 + ")", diff >= 0);
} }
polyline.calcBoundingCircle(); polyline.calcBoundingCircle();
r = polyline.radius; 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 dpx = (toOsmLon(lons[i], OFFSET_X) - polyline.ilon) * dlon2m;
double dpy = (toOsmLat(lats[i], OFFSET_Y) - polyline.ilat) * dlat2m; double dpy = (toOsmLat(lats[i], OFFSET_Y) - polyline.ilat) * dlat2m;
double r1 = Math.sqrt(dpx * dpx + dpy * dpy); double r1 = Math.sqrt(dpx * dpx + dpy * dpy);
double diff = r-r1; double diff = r - r1;
assertTrue("i: "+i+" r("+r+") >= r1("+r1+")", diff >= 0); assertTrue("i: " + i + " r(" + r + ") >= r1(" + r1 + ")", diff >= 0);
} }
} }
@Test @Test
public void testIsWithin() { 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[] 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, }; 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, }; boolean[] within = {true, false, false, false, false, true, true, true, true, true,};
for (int i=0; i<plons.length; i++) { 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))); assertEquals("(" + plons[i] + "," + plats[i] + ")", within[i], polygon.isWithin(toOsmLon(plons[i], OFFSET_X), toOsmLat(plats[i], OFFSET_Y)));
} }
} }
@Test @Test
public void testIntersectsPolygon() { 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[] 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[] 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[] 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 }; 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 }; boolean[] within = {false, false, false, true, true, true, false, true, true, true};
for (int i=0; i<p0lons.length; i++) { 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))); 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 @Test
public void testIntersectsPolyline() { 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[] 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[] 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[] 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 }; 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 }; boolean[] within = {false, false, false, true, true, true, false, true, true, false};
for (int i=0; i<p0lons.length; i++) { 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))); 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 @Test
public void testBelongsToLine() { public void testBelongsToLine() {
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 10,20)); assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 10, 20));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,10)); assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 20, 10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 20,10, 10,10)); assertTrue(OsmNogoPolygon.isOnLine(10, 10, 20, 10, 10, 10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,20, 10,10)); assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 20, 10, 10));
assertTrue(OsmNogoPolygon.isOnLine(10,15, 10,10, 10,20)); assertTrue(OsmNogoPolygon.isOnLine(10, 15, 10, 10, 10, 20));
assertTrue(OsmNogoPolygon.isOnLine(15,10, 10,10, 20,10)); assertTrue(OsmNogoPolygon.isOnLine(15, 10, 10, 10, 20, 10));
assertTrue(OsmNogoPolygon.isOnLine(10,10, 10,10, 20,30)); assertTrue(OsmNogoPolygon.isOnLine(10, 10, 10, 10, 20, 30));
assertTrue(OsmNogoPolygon.isOnLine(20,30, 10,10, 20,30)); assertTrue(OsmNogoPolygon.isOnLine(20, 30, 10, 10, 20, 30));
assertTrue(OsmNogoPolygon.isOnLine(15,20, 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, 10, 20));
assertFalse(OsmNogoPolygon.isOnLine(11,11, 10,10, 20,10)); assertFalse(OsmNogoPolygon.isOnLine(11, 11, 10, 10, 20, 10));
assertFalse(OsmNogoPolygon.isOnLine(15,21, 10,10, 20,30)); assertFalse(OsmNogoPolygon.isOnLine(15, 21, 10, 10, 20, 30));
assertFalse(OsmNogoPolygon.isOnLine(15,19, 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(0, -10, 10, 10, 20, 30));
assertFalse(OsmNogoPolygon.isOnLine(30,50, 10,10, 20,30)); assertFalse(OsmNogoPolygon.isOnLine(30, 50, 10, 10, 20, 30));
} }
@Test @Test
public void testDistanceWithinPolygon() { public void testDistanceWithinPolygon() {
// Testing polygon // Testing polygon
final double[] lons = { 2.333523, 2.333432, 2.333833, 2.333983, 2.334815, 2.334766 }; 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 }; final double[] lats = {48.823778, 48.824091, 48.82389, 48.824165, 48.824232, 48.82384};
OsmNogoPolygon polygon = new OsmNogoPolygon(true); OsmNogoPolygon polygon = new OsmNogoPolygon(true);
for (int i = 0; i < lons.length; i++) { for (int i = 0; i < lons.length; i++) {
polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0)); polygon.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
} }
OsmNogoPolygon polyline = new OsmNogoPolygon(false); OsmNogoPolygon polyline = new OsmNogoPolygon(false);
for (int i = 0; i < lons.length; i++) { for (int i = 0; i < lons.length; i++) {
polyline.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0)); polyline.addVertex(toOsmLon(lons[i], 0), toOsmLat(lats[i], 0));
} }
// Check with a segment with a single intersection with the polygon // Check with a segment with a single intersection with the polygon
int lon1 = toOsmLon(2.33308732509613, 0); int lon1 = toOsmLon(2.33308732509613, 0);
int lat1 = toOsmLat(48.8238790443901, 0); int lat1 = toOsmLat(48.8238790443901, 0);
int lon2 = toOsmLon(2.33378201723099, 0); int lon2 = toOsmLon(2.33378201723099, 0);
int lat2 = toOsmLat(48.8239585098974, 0); int lat2 = toOsmLat(48.8239585098974, 0);
assertEquals( assertEquals(
"Should give the correct length for a segment with a single intersection", "Should give the correct length for a segment with a single intersection",
17.5, 17.5,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2), polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 17.5 0.05 * 17.5
); );
// Check with a segment crossing multiple times the polygon // Check with a segment crossing multiple times the polygon
lon2 = toOsmLon(2.33488172292709, 0); lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0); lat2 = toOsmLat(48.8240891862353, 0);
assertEquals( assertEquals(
"Should give the correct length for a segment with multiple intersections", "Should give the correct length for a segment with multiple intersections",
85, 85,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2), polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 85 0.05 * 85
); );
// Check that it works when a point is within the polygon // Check that it works when a point is within the polygon
lon2 = toOsmLon(2.33433187007904, 0); lon2 = toOsmLon(2.33433187007904, 0);
lat2 = toOsmLat(48.8240238480664, 0); lat2 = toOsmLat(48.8240238480664, 0);
assertEquals( assertEquals(
"Should give the correct length when last point is within the polygon", "Should give the correct length when last point is within the polygon",
50, 50,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2), polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 50 0.05 * 50
); );
lon1 = toOsmLon(2.33433187007904, 0); lon1 = toOsmLon(2.33433187007904, 0);
lat1 = toOsmLat(48.8240238480664, 0); lat1 = toOsmLat(48.8240238480664, 0);
lon2 = toOsmLon(2.33488172292709, 0); lon2 = toOsmLon(2.33488172292709, 0);
lat2 = toOsmLat(48.8240891862353, 0); lat2 = toOsmLat(48.8240891862353, 0);
assertEquals( assertEquals(
"Should give the correct length when first point is within the polygon", "Should give the correct length when first point is within the polygon",
35, 35,
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2), polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * 35 0.05 * 35
); );
lon1 = toOsmLon(2.333523, 0); lon1 = toOsmLon(2.333523, 0);
lat1 = toOsmLat(48.823778, 0); lat1 = toOsmLat(48.823778, 0);
lon2 = toOsmLon(2.333432, 0); lon2 = toOsmLon(2.333432, 0);
lat2 = toOsmLat(48.824091, 0); lat2 = toOsmLat(48.824091, 0);
assertEquals( assertEquals(
"Should give the correct length if the segment overlaps with an edge of the polygon", "Should give the correct length if the segment overlaps with an edge of the polygon",
CheapRuler.distance(lon1, lat1, lon2, lat2), CheapRuler.distance(lon1, lat1, lon2, lat2),
polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2), polygon.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2) 0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
); );
lon1 = toOsmLon(2.333523, 0); lon1 = toOsmLon(2.333523, 0);
lat1 = toOsmLat(48.823778, 0); lat1 = toOsmLat(48.823778, 0);
lon2 = toOsmLon(2.3334775, 0); lon2 = toOsmLon(2.3334775, 0);
lat2 = toOsmLat(48.8239345, 0); lat2 = toOsmLat(48.8239345, 0);
assertEquals( assertEquals(
"Should give the correct length if the segment overlaps with a polyline", "Should give the correct length if the segment overlaps with a polyline",
CheapRuler.distance(lon1, lat1, lon2, lat2), CheapRuler.distance(lon1, lat1, lon2, lat2),
polyline.distanceWithinPolygon(lon1, lat1, lon2, lat2), polyline.distanceWithinPolygon(lon1, lat1, lon2, lat2),
0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2) 0.05 * CheapRuler.distance(lon1, lat1, lon2, lat2)
); );
} }
} }

View File

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

View File

@ -8,66 +8,93 @@ package btools.expressions;
import btools.codec.TagValueValidator; 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 boolean decodeForbidden = true;
private static String[] buildInVariables = private static String[] buildInVariables =
{ "costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask", "maxspeed" }; {"costfactor", "turncost", "uphillcostfactor", "downhillcostfactor", "initialcost", "nodeaccessgranted", "initialclassifier", "trafficsourcedensity", "istrafficbackbone", "priorityclassifier", "classifiermask", "maxspeed"};
protected String[] getBuildInVariableNames() protected String[] getBuildInVariableNames() {
{
return buildInVariables; return buildInVariables;
} }
public float getCostfactor() { return getBuildInVariable(0); } public float getCostfactor() {
public float getTurncost() { return getBuildInVariable(1); } return getBuildInVariable(0);
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 ) public float getTurncost() {
{ return getBuildInVariable(1);
super( "way", meta ); }
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 * 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 ) public BExpressionContextWay(int hashSize, BExpressionMetaData meta) {
{ super("way", hashSize, meta);
super( "way", hashSize, meta );
} }
@Override @Override
public int accessType( byte[] description ) public int accessType(byte[] description) {
{ evaluate(false, description);
evaluate( false, description );
float minCostFactor = getCostfactor(); float minCostFactor = getCostfactor();
if ( minCostFactor >= 9999.f ) if (minCostFactor >= 9999.f) {
{
setInverseVars(); setInverseVars();
float reverseCostFactor = getCostfactor(); float reverseCostFactor = getCostfactor();
if ( reverseCostFactor < minCostFactor ) if (reverseCostFactor < minCostFactor) {
{
minCostFactor = reverseCostFactor; minCostFactor = reverseCostFactor;
} }
} }
return minCostFactor < 9999.f ? 2 : decodeForbidden ? (minCostFactor < 10000.f ? 1 : 0) : 0; return minCostFactor < 9999.f ? 2 : decodeForbidden ? (minCostFactor < 10000.f ? 1 : 0) : 0;
} }
@Override @Override
public void setDecodeForbidden( boolean decodeForbidden ) public void setDecodeForbidden(boolean decodeForbidden) {
{ this.decodeForbidden = decodeForbidden;
this.decodeForbidden= decodeForbidden;
} }
} }

View File

@ -1,66 +1,56 @@
/** /**
* A lookup value with optional aliases * A lookup value with optional aliases
* * <p>
* toString just gives the primary value, * toString just gives the primary value,
* equals just compares against primary value * equals just compares against primary value
* matches() also compares aliases * matches() also compares aliases
* *
* @author ab * @author ab
*/ */
package btools.expressions; package btools.expressions;
import java.util.ArrayList; import java.util.ArrayList;
final class BExpressionLookupValue final class BExpressionLookupValue {
{ String value;
String value; ArrayList<String> aliases;
ArrayList<String> aliases;
@Override
@Override public String toString() {
public String toString() return value;
{ }
return value;
} public BExpressionLookupValue(String value) {
this.value = value;
public BExpressionLookupValue( String value ) }
{
this.value = value; public void addAlias(String alias) {
} if (aliases == null) aliases = new ArrayList<String>();
aliases.add(alias);
public void addAlias( String alias ) }
{
if ( aliases == null ) aliases = new ArrayList<String>(); @Override
aliases.add( alias ); public boolean equals(Object o) {
} if (o instanceof String) {
String v = (String) o;
@Override return value.equals(v);
public boolean equals( Object o ) }
{ if (o instanceof BExpressionLookupValue) {
if ( o instanceof String ) BExpressionLookupValue v = (BExpressionLookupValue) o;
{
String v = (String)o; return value.equals(v.value);
return value.equals( v ); }
} return false;
if ( o instanceof BExpressionLookupValue ) }
{
BExpressionLookupValue v = (BExpressionLookupValue)o; public boolean matches(String s) {
if (value.equals(s)) return true;
return value.equals( v.value ); if (aliases != null) {
} for (String alias : aliases) {
return false; if (alias.equals(s)) return true;
} }
}
public boolean matches( String s ) return false;
{ }
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; import btools.util.Crc32;
public final class BExpressionMetaData public final class BExpressionMetaData {
{ private static final String CONTEXT_TAG = "---context:";
private static final String CONTEXT_TAG = "---context:";
private static final String VERSION_TAG = "---lookupversion:"; private static final String VERSION_TAG = "---lookupversion:";
private static final String MINOR_VERSION_TAG = "---minorversion:"; private static final String MINOR_VERSION_TAG = "---minorversion:";
private static final String VARLENGTH_TAG = "---readvarlength"; private static final String VARLENGTH_TAG = "---readvarlength";
@ -31,59 +30,49 @@ public final class BExpressionMetaData
public short lookupVersion = -1; public short lookupVersion = -1;
public short lookupMinorVersion = -1; public short lookupMinorVersion = -1;
private HashMap<String,BExpressionContext> listeners = new HashMap<String,BExpressionContext>(); private HashMap<String, BExpressionContext> listeners = new HashMap<String, BExpressionContext>();
public void registerListener( String context, BExpressionContext ctx ) public void registerListener(String context, BExpressionContext ctx) {
{ listeners.put(context, ctx);
listeners.put( context, ctx );
} }
public void readMetaData( File lookupsFile ) public void readMetaData(File lookupsFile) {
{ try {
try BufferedReader br = new BufferedReader(new FileReader(lookupsFile));
{
BufferedReader br = new BufferedReader( new FileReader( lookupsFile ) ); BExpressionContext ctx = null;
BExpressionContext ctx = null; for (; ; ) {
String line = br.readLine();
for(;;) if (line == null) break;
{ line = line.trim();
String line = br.readLine(); if (line.length() == 0 || line.startsWith("#")) continue;
if ( line == null ) break; if (line.startsWith(CONTEXT_TAG)) {
line = line.trim(); ctx = listeners.get(line.substring(CONTEXT_TAG.length()));
if ( line.length() == 0 || line.startsWith( "#" ) ) continue; continue;
if ( line.startsWith( CONTEXT_TAG ) ) }
{ if (line.startsWith(VERSION_TAG)) {
ctx = listeners.get( line.substring( CONTEXT_TAG.length() ) ); lookupVersion = Short.parseShort(line.substring(VERSION_TAG.length()));
continue; 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 ) ) br.close();
{
lookupVersion = Short.parseShort( line.substring( VERSION_TAG.length() ) ); for (BExpressionContext c : listeners.values()) {
continue; c.finishMetaParsing();
} }
if ( line.startsWith( MINOR_VERSION_TAG ) )
{ } catch (Exception e) {
lookupMinorVersion = Short.parseShort( line.substring( MINOR_VERSION_TAG.length() ) ); throw new RuntimeException(e);
continue;
}
if ( line.startsWith( VARLENGTH_TAG ) ) // tag removed...
{
continue;
}
if ( ctx != null ) ctx.parseMetaLine( line );
} }
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; import btools.util.LruMapNode;
public final class CacheNode extends LruMapNode public final class CacheNode extends LruMapNode {
{
byte[] ab; byte[] ab;
float[] vars; float[] vars;
@Override @Override
public int hashCode() public int hashCode() {
{
return hash; return hash;
} }
@Override @Override
public boolean equals( Object o ) public boolean equals(Object o) {
{
CacheNode n = (CacheNode) o; CacheNode n = (CacheNode) o;
if ( hash != n.hash ) if (hash != n.hash) {
{
return false; return false;
} }
if ( ab == null ) if (ab == null) {
{
return true; // hack: null = crc match only 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.io.File;
import java.util.Random; import java.util.Random;
public final class ProfileComparator public final class ProfileComparator {
{ public static void main(String[] args) {
public static void main( String[] args ) if (args.length != 4) {
{ System.out.println("usage: java ProfileComparator <lookup-file> <profile1> <profile2> <nsamples>");
if ( args.length != 4 )
{
System.out.println( "usage: java ProfileComparator <lookup-file> <profile1> <profile2> <nsamples>" );
return; return;
} }
File lookupFile = new File( args[0] ); File lookupFile = new File(args[0]);
File profile1File = new File( args[1] ); File profile1File = new File(args[1]);
File profile2File = new File( args[2] ); File profile2File = new File(args[2]);
int nsamples = Integer.parseInt( args[3] ); int nsamples = Integer.parseInt(args[3]);
testContext( lookupFile, profile1File, profile2File, nsamples, false ); testContext(lookupFile, profile1File, profile2File, nsamples, false);
testContext( lookupFile, profile1File, profile2File, nsamples, true ); 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 // read lookup.dat + profiles
BExpressionMetaData meta1 = new BExpressionMetaData(); BExpressionMetaData meta1 = new BExpressionMetaData();
BExpressionMetaData meta2 = new BExpressionMetaData(); BExpressionMetaData meta2 = new BExpressionMetaData();
BExpressionContext expctx1 = nodeContext ? new BExpressionContextNode( meta1 ) : new BExpressionContextWay( meta1 ); BExpressionContext expctx1 = nodeContext ? new BExpressionContextNode(meta1) : new BExpressionContextWay(meta1);
BExpressionContext expctx2 = nodeContext ? new BExpressionContextNode( meta2 ) : new BExpressionContextWay( meta2 ); BExpressionContext expctx2 = nodeContext ? new BExpressionContextNode(meta2) : new BExpressionContextWay(meta2);
meta1.readMetaData( lookupFile ); meta1.readMetaData(lookupFile);
meta2.readMetaData( lookupFile ); meta2.readMetaData(lookupFile);
expctx1.parseFile( profile1File, "global" ); expctx1.parseFile(profile1File, "global");
expctx2.parseFile( profile2File, "global" ); expctx2.parseFile(profile2File, "global");
Random rnd = new Random(); Random rnd = new Random();
for( int i=0; i<nsamples; i++ ) for (int i = 0; i < nsamples; i++) {
{ int[] data = expctx1.generateRandomValues(rnd);
int[] data = expctx1.generateRandomValues( rnd ); expctx1.evaluate(data);
expctx1.evaluate( data ); expctx2.evaluate(data);
expctx2.evaluate( data );
expctx1.assertAllVariablesEqual(expctx2);
expctx1.assertAllVariablesEqual( expctx2 );
} }
} }
} }

View File

@ -4,24 +4,20 @@ import java.util.Arrays;
import btools.util.LruMapNode; import btools.util.LruMapNode;
public final class VarWrapper extends LruMapNode public final class VarWrapper extends LruMapNode {
{
float[] vars; float[] vars;
@Override @Override
public int hashCode() public int hashCode() {
{
return hash; return hash;
} }
@Override @Override
public boolean equals( Object o ) public boolean equals(Object o) {
{
VarWrapper n = (VarWrapper) o; VarWrapper n = (VarWrapper) o;
if ( hash != n.hash ) if (hash != n.hash) {
{
return false; 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.Assert;
import org.junit.Test; import org.junit.Test;
public class EncodeDecodeTest public class EncodeDecodeTest {
{
@Test @Test
public void encodeDecodeTest() public void encodeDecodeTest() {
{ URL testpurl = this.getClass().getResource("/dummy.txt");
URL testpurl = this.getClass().getResource( "/dummy.txt" );
File workingDir = new File(testpurl.getFile()).getParentFile(); 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" ); //File lookupFile = new File( profileDir, "lookups.dat" );
// add a test lookup // add a test lookup
URL testlookup = this.getClass().getResource( "/lookups_test.dat" ); URL testlookup = this.getClass().getResource("/lookups_test.dat");
File lookupFile = new File( testlookup.getPath() ); File lookupFile = new File(testlookup.getPath());
// read lookup.dat + trekking.brf // read lookup.dat + trekking.brf
BExpressionMetaData meta = new BExpressionMetaData(); BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextWay expctxWay = new BExpressionContextWay( meta ); BExpressionContextWay expctxWay = new BExpressionContextWay(meta);
meta.readMetaData( lookupFile ); meta.readMetaData(lookupFile);
expctxWay.parseFile( new File( profileDir, "trekking.brf" ), "global" ); expctxWay.parseFile(new File(profileDir, "trekking.brf"), "global");
String[] tags = { String[] tags = {
"highway=residential", "highway=residential",
"oneway=yes", "oneway=yes",
"depth=1'6\"", "depth=1'6\"",
// "depth=6 feet", // "depth=6 feet",
"maxheight=5.1m", "maxheight=5.1m",
"maxdraft=~3 mt", "maxdraft=~3 mt",
"reversedirection=yes" "reversedirection=yes"
}; };
// encode the tags into 64 bit description word // encode the tags into 64 bit description word
int[] lookupData = expctxWay.createNewLookupData(); int[] lookupData = expctxWay.createNewLookupData();
for( String arg: tags ) for (String arg : tags) {
{ int idx = arg.indexOf('=');
int idx = arg.indexOf( '=' ); if (idx < 0)
if ( idx < 0 ) throw new IllegalArgumentException( "bad argument (should be <tag>=<value>): " + arg ); throw new IllegalArgumentException("bad argument (should be <tag>=<value>): " + arg);
String key = arg.substring( 0, idx ); String key = arg.substring(0, idx);
String value = arg.substring( idx+1 ); String value = arg.substring(idx + 1);
expctxWay.addLookupValue( key, value, lookupData ); expctxWay.addLookupValue(key, value, lookupData);
} }
byte[] description = expctxWay.encode(lookupData); byte[] description = expctxWay.encode(lookupData);
// calculate the cost factor from that description // 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(); 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.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
public class ConvertLidarTile public class ConvertLidarTile {
{
public static int NROWS; public static int NROWS;
public static int NCOLS; public static int NCOLS;
@ -21,78 +20,63 @@ public class ConvertLidarTile
static short[] imagePixels; static short[] imagePixels;
private static void readHgtZip( String filename, int rowOffset, int colOffset ) throws Exception private static void readHgtZip(String filename, int rowOffset, int colOffset) throws Exception {
{ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(filename)));
ZipInputStream zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( filename ) ) ); try {
try for (; ; ) {
{
for ( ;; )
{
ZipEntry ze = zis.getNextEntry(); ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".hgt" ) ) if (ze.getName().endsWith(".hgt")) {
{ readHgtFromStream(zis, rowOffset, colOffset);
readHgtFromStream( zis, rowOffset, colOffset );
return; return;
} }
} }
} } finally {
finally
{
zis.close(); zis.close();
} }
} }
private static void readHgtFromStream( InputStream is, int rowOffset, int colOffset ) private static void readHgtFromStream(InputStream is, int rowOffset, int colOffset)
throws Exception throws Exception {
{ DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
DataInputStream dis = new DataInputStream( new BufferedInputStream( is ) ); for (int ir = 0; ir < 1201; ir++) {
for ( int ir = 0; ir < 1201; ir++ )
{
int row = rowOffset + ir; int row = rowOffset + ir;
for ( int ic = 0; ic < 1201; ic++ ) for (int ic = 0; ic < 1201; ic++) {
{
int col = colOffset + ic; int col = colOffset + ic;
int i1 = dis.read(); // msb first! int i1 = dis.read(); // msb first!
int i0 = dis.read(); int i0 = dis.read();
if ( i0 == -1 || i1 == -1 ) if (i0 == -1 || i1 == -1)
throw new RuntimeException( "unexcepted end of file reading hgt entry!" ); 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; val = NODATA;
} }
setPixel( row, col, val ); setPixel(row, col, val);
} }
} }
} }
private static void setPixel( int row, int col, short val ) private static void setPixel(int row, int col, short val) {
{ if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
if ( row >= 0 && row < NROWS && col >= 0 && col < NCOLS )
{
imagePixels[row * NCOLS + col] = val; imagePixels[row * NCOLS + col] = val;
} }
} }
private static short getPixel( int row, int col ) private static short getPixel(int row, int col) {
{ if (row >= 0 && row < NROWS && col >= 0 && col < NCOLS) {
if ( row >= 0 && row < NROWS && col >= 0 && col < NCOLS )
{
return imagePixels[row * NCOLS + col]; return imagePixels[row * NCOLS + col];
} }
return NODATA; 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; int extraBorder = 0;
NROWS = 5 * 1200 + 1 + 2 * extraBorder; NROWS = 5 * 1200 + 1 + 2 * extraBorder;
@ -101,34 +85,27 @@ public class ConvertLidarTile
imagePixels = new short[NROWS * NCOLS]; // 650 MB ! imagePixels = new short[NROWS * NCOLS]; // 650 MB !
// prefill as NODATA // prefill as NODATA
for ( int row = 0; row < NROWS; row++ ) for (int row = 0; row < NROWS; row++) {
{ for (int col = 0; col < NCOLS; col++) {
for ( int col = 0; col < NCOLS; col++ )
{
imagePixels[row * NCOLS + col] = NODATA; imagePixels[row * NCOLS + col] = NODATA;
} }
} }
for ( int latIdx = -1; latIdx <= 5; latIdx++ ) for (int latIdx = -1; latIdx <= 5; latIdx++) {
{
int latDegree = latDegreeStart + 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 lonDegree = lonDegreeStart + lonIdx;
int colOffset = extraBorder + lonIdx * 1200; int colOffset = extraBorder + lonIdx * 1200;
String filename = inputDir + "/" + formatLat( latDegree ) + formatLon( lonDegree ) + ".zip"; String filename = inputDir + "/" + formatLat(latDegree) + formatLon(lonDegree) + ".zip";
File f = new File( filename ); File f = new File(filename);
if ( f.exists() && f.length() > 0 ) if (f.exists() && f.length() > 0) {
{ System.out.println("exist: " + filename);
System.out.println( "exist: " + filename ); readHgtZip(filename, rowOffset, colOffset);
readHgtZip( filename, rowOffset, colOffset ); } else {
} System.out.println("none : " + filename);
else
{
System.out.println( "none : " + filename );
} }
} }
} }
@ -142,79 +119,71 @@ public class ConvertLidarTile
raster.halfcol = halfCol5; raster.halfcol = halfCol5;
raster.noDataValue = NODATA; raster.noDataValue = NODATA;
raster.cellsize = 1 / 1200.; raster.cellsize = 1 / 1200.;
raster.xllcorner = lonDegreeStart - ( 0.5 + extraBorder ) * raster.cellsize; raster.xllcorner = lonDegreeStart - (0.5 + extraBorder) * raster.cellsize;
raster.yllcorner = latDegreeStart - ( 0.5 + extraBorder ) * raster.cellsize; raster.yllcorner = latDegreeStart - (0.5 + extraBorder) * raster.cellsize;
raster.eval_array = imagePixels; raster.eval_array = imagePixels;
// encode the raster // encode the raster
OutputStream os = new BufferedOutputStream( new FileOutputStream( outputFile ) ); OutputStream os = new BufferedOutputStream(new FileOutputStream(outputFile));
new RasterCoder().encodeRaster( raster, os ); new RasterCoder().encodeRaster(raster, os);
os.close(); os.close();
// decode the raster // decode the raster
InputStream is = new BufferedInputStream( new FileInputStream( outputFile ) ); InputStream is = new BufferedInputStream(new FileInputStream(outputFile));
SrtmRaster raster2 = new RasterCoder().decodeRaster( is ); SrtmRaster raster2 = new RasterCoder().decodeRaster(is);
is.close(); is.close();
short[] pix2 = raster2.eval_array; short[] pix2 = raster2.eval_array;
if ( pix2.length != imagePixels.length ) if (pix2.length != imagePixels.length)
throw new RuntimeException( "length mismatch!" ); throw new RuntimeException("length mismatch!");
// compare decoding result // compare decoding result
for ( int row = 0; row < NROWS; row++ ) for (int row = 0; row < NROWS; row++) {
{
int colstep = halfCol5 ? 2 : 1; 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; int idx = row * NCOLS + col;
short p2 = pix2[idx]; short p2 = pix2[idx];
if ( p2 != imagePixels[idx] ) if (p2 != imagePixels[idx]) {
{ throw new RuntimeException("content mismatch: p2=" + p2 + " p1=" + imagePixels[idx]);
throw new RuntimeException( "content mismatch: p2=" + p2 + " p1=" + imagePixels[idx] );
} }
} }
} }
} }
private static String formatLon( int lon ) private static String formatLon(int lon) {
{ if (lon >= 180)
if ( lon >= 180 )
lon -= 180; // TODO: w180 oder E180 ? lon -= 180; // TODO: w180 oder E180 ?
String s = "E"; String s = "E";
if ( lon < 0 ) if (lon < 0) {
{
lon = -lon; lon = -lon;
s = "E"; s = "E";
} }
String n = "000" + lon; 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"; String s = "N";
if ( lat < 0 ) if (lat < 0) {
{
lat = -lat; lat = -lat;
s = "S"; s = "S";
} }
String n = "00" + lat; 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 public static void main(String[] args) throws Exception {
{ String filename90 = args[0];
String filename90 = args[0]; String filename30 = filename90.substring(0, filename90.length() - 3) + "bef";
String filename30 = filename90.substring( 0, filename90.length() - 3 ) + "bef";
int srtmLonIdx = Integer.parseInt( filename90.substring( 5, 7 ).toLowerCase() ); int srtmLonIdx = Integer.parseInt(filename90.substring(5, 7).toLowerCase());
int srtmLatIdx = Integer.parseInt( filename90.substring( 8, 10 ).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; int ilat_base = 150 - srtmLatIdx * 5 - 90;
doConvert( args[1], ilon_base, ilat_base, filename30 ); doConvert(args[1], ilon_base, ilat_base, filename30);
} }
} }

View File

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

View File

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

View File

@ -1,171 +1,158 @@
/** /**
* common base class for the map-filters * common base class for the map-filters
* *
* @author ab * @author ab
*/ */
package btools.mapcreator; package btools.mapcreator;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import btools.util.DiffCoderDataOutputStream; import btools.util.DiffCoderDataOutputStream;
public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener public abstract class MapCreatorBase implements WayListener, NodeListener, RelationListener {
{ private DiffCoderDataOutputStream[] tileOutStreams;
private DiffCoderDataOutputStream[] tileOutStreams; protected File outTileDir;
protected File outTileDir;
protected HashMap<String, String> tags;
protected HashMap<String,String> tags;
public void putTag(String key, String value) {
public void putTag( String key, String value ) if (tags == null) tags = new HashMap<String, String>();
{ tags.put(key, 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 String getTag( String key ) }
{
return tags == null ? null : tags.get( key ); public HashMap<String, String> getTagsOrNull() {
} return tags;
}
public HashMap<String,String> getTagsOrNull()
{ public void setTags(HashMap<String, String> tags) {
return tags; this.tags = tags;
} }
public void setTags( HashMap<String,String> tags ) protected static long readId(DataInputStream is) throws IOException {
{ int offset = is.readByte();
this.tags = tags; if (offset == 32) return -1;
} long i = is.readInt();
i = i << 5;
protected static long readId( DataInputStream is) throws IOException return i | offset;
{ }
int offset = is.readByte();
if ( offset == 32 ) return -1; protected static void writeId(DataOutputStream o, long id) throws IOException {
long i = is.readInt(); if (id == -1) {
i = i << 5; o.writeByte(32);
return i | offset; return;
} }
int offset = (int) (id & 0x1f);
protected static void writeId( DataOutputStream o, long id ) throws IOException int i = (int) (id >> 5);
{ o.writeByte(offset);
if ( id == -1 ) o.writeInt(i);
{ }
o.writeByte( 32 );
return;
} protected static File[] sortBySizeAsc(File[] files) {
int offset = (int)( id & 0x1f ); int n = files.length;
int i = (int)( id >> 5 ); long[] sizes = new long[n];
o.writeByte( offset ); File[] sorted = new File[n];
o.writeInt( i ); 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;
protected static File[] sortBySizeAsc( File[] files ) for (int i = 0; i < n; i++) {
{ if (sizes[i] != -1 && (idx == -1 || sizes[i] < min)) {
int n = files.length; min = sizes[i];
long[] sizes = new long[n]; idx = i;
File[] sorted = new File[n]; }
for( int i=0; i<n; i++ ) sizes[i] = files[i].length(); }
for(int nf=0; nf<n; nf++) sizes[idx] = -1;
{ sorted[nf] = files[idx];
int idx = -1; }
long min = -1; return sorted;
for( int i=0; i<n; i++ ) }
{
if ( sizes[i] != -1 && ( idx == -1 || sizes[i] < min ) ) protected File fileFromTemplate(File template, File dir, String suffix) {
{ String filename = template.getName();
min = sizes[i]; filename = filename.substring(0, filename.length() - 3) + suffix;
idx = i; return new File(dir, filename);
} }
}
sizes[idx] = -1; protected DataInputStream createInStream(File inFile) throws IOException {
sorted[nf] = files[idx]; return new DataInputStream(new BufferedInputStream(new FileInputStream(inFile)));
} }
return sorted;
} protected DiffCoderDataOutputStream createOutStream(File outFile) throws IOException {
return new DiffCoderDataOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
protected File fileFromTemplate( File template, File dir, String suffix ) }
{
String filename = template.getName(); protected DiffCoderDataOutputStream getOutStreamForTile(int tileIndex) throws Exception {
filename = filename.substring( 0, filename.length() - 3 ) + suffix; if (tileOutStreams == null) {
return new File( dir, filename ); tileOutStreams = new DiffCoderDataOutputStream[64];
} }
protected DataInputStream createInStream( File inFile ) throws IOException if (tileOutStreams[tileIndex] == null) {
{ tileOutStreams[tileIndex] = createOutStream(new File(outTileDir, getNameForTile(tileIndex)));
return new DataInputStream( new BufferedInputStream ( new FileInputStream( inFile ) ) ); }
} return tileOutStreams[tileIndex];
}
protected DiffCoderDataOutputStream createOutStream( File outFile ) throws IOException
{ protected String getNameForTile(int tileIndex) {
return new DiffCoderDataOutputStream( new BufferedOutputStream( new FileOutputStream( outFile ) ) ); throw new IllegalArgumentException("getNameForTile not implemented");
} }
protected DiffCoderDataOutputStream getOutStreamForTile( int tileIndex ) throws Exception protected void closeTileOutStreams() throws Exception {
{ if (tileOutStreams == null) {
if ( tileOutStreams == null ) return;
{ }
tileOutStreams = new DiffCoderDataOutputStream[64]; for (int tileIndex = 0; tileIndex < tileOutStreams.length; tileIndex++) {
} if (tileOutStreams[tileIndex] != null) tileOutStreams[tileIndex].close();
tileOutStreams[tileIndex] = null;
if ( tileOutStreams[tileIndex] == null ) }
{ }
tileOutStreams[tileIndex] = createOutStream( new File( outTileDir, getNameForTile( tileIndex ) ) );
}
return tileOutStreams[tileIndex]; // interface dummys
}
@Override
protected String getNameForTile( int tileIndex ) public void nodeFileStart(File nodefile) throws Exception {
{ }
throw new IllegalArgumentException( "getNameForTile not implemented" );
} @Override
public void nextNode(NodeData n) throws Exception {
protected void closeTileOutStreams() throws Exception }
{
if ( tileOutStreams == null ) @Override
{ public void nodeFileEnd(File nodefile) throws Exception {
return; }
}
for( int tileIndex=0; tileIndex<tileOutStreams.length; tileIndex++ ) @Override
{ public boolean wayFileStart(File wayfile) throws Exception {
if ( tileOutStreams[tileIndex] != null ) tileOutStreams[tileIndex].close(); return true;
tileOutStreams[tileIndex] = null; }
}
} @Override
public void nextWay(WayData data) throws Exception {
}
// interface dummys
@Override
@Override public void wayFileEnd(File wayfile) throws Exception {
public void nodeFileStart( File nodefile ) throws Exception {} }
@Override @Override
public void nextNode( NodeData n ) throws Exception {} public void nextRelation(RelationData data) throws Exception {
}
@Override
public void nodeFileEnd( File nodefile ) throws Exception {} @Override
public void nextRestriction(RelationData data, long fromWid, long toWid, long viaNid) 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; package btools.mapcreator;
import java.io.File; import java.io.File;
/** /**
* NodeCutter does 1 step in map-processing: * NodeCutter does 1 step in map-processing:
* * <p>
* - cuts the 45*30 node tiles into 5*5 pieces * - cuts the 45*30 node tiles into 5*5 pieces
* *
* @author ab * @author ab
*/ */
public class NodeCutter extends MapCreatorBase public class NodeCutter extends MapCreatorBase {
{ private int lonoffset;
private int lonoffset; private int latoffset;
private int latoffset;
public static void main(String[] args) throws Exception {
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("*** NodeCutter: Cut big node-tiles into 5x5 tiles"); System.out.println("usage: java NodeCutter <node-tiles-in> <node-tiles-out>");
if (args.length != 2) return;
{ }
System.out.println("usage: java NodeCutter <node-tiles-in> <node-tiles-out>" ); new NodeCutter().process(new File(args[0]), new File(args[1]));
return; }
}
new NodeCutter().process( new File( args[0] ), new File( args[1] ) ); public void init(File nodeTilesOut) {
} this.outTileDir = nodeTilesOut;
}
public void init( File nodeTilesOut )
{ public void process(File nodeTilesIn, File nodeTilesOut) throws Exception {
this.outTileDir = nodeTilesOut; init(nodeTilesOut);
}
new NodeIterator(this, true).processDir(nodeTilesIn, ".tlf");
public void process( File nodeTilesIn, File nodeTilesOut ) throws Exception }
{
init( nodeTilesOut ); @Override
public void nodeFileStart(File nodefile) throws Exception {
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tlf" ); lonoffset = -1;
} latoffset = -1;
}
@Override
public void nodeFileStart( File nodefile ) throws Exception @Override
{ public void nextNode(NodeData n) throws Exception {
lonoffset = -1; n.writeTo(getOutStreamForTile(getTileIndex(n.ilon, n.ilat)));
latoffset = -1; }
}
@Override
@Override public void nodeFileEnd(File nodeFile) throws Exception {
public void nextNode( NodeData n ) throws Exception closeTileOutStreams();
{ }
n.writeTo( getOutStreamForTile( getTileIndex( n.ilon, n.ilat ) ) );
} private int getTileIndex(int ilon, int ilat) {
int lonoff = (ilon / 45000000) * 45;
@Override int latoff = (ilat / 30000000) * 30;
public void nodeFileEnd( File nodeFile ) throws Exception if (lonoffset == -1) lonoffset = lonoff;
{ if (latoffset == -1) latoffset = latoff;
closeTileOutStreams(); if (lonoff != lonoffset || latoff != latoffset)
} throw new IllegalArgumentException("inconsistent node: " + ilon + " " + ilat);
private int getTileIndex( int ilon, int ilat ) int lon = (ilon / 5000000) % 9;
{ int lat = (ilat / 5000000) % 6;
int lonoff = (ilon / 45000000 ) * 45; if (lon < 0 || lon > 8 || lat < 0 || lat > 5)
int latoff = (ilat / 30000000 ) * 30; throw new IllegalArgumentException("illegal pos: " + ilon + "," + ilat);
if ( lonoffset == -1 ) lonoffset = lonoff; return lon * 6 + lat;
if ( latoffset == -1 ) latoffset = latoff; }
if ( lonoff != lonoffset || latoff != latoffset )
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
protected String getNameForTile(int tileIndex) {
int lon = (ilon / 5000000) % 9; int lon = (tileIndex / 6) * 5 + lonoffset - 180;
int lat = (ilat / 5000000) % 6; int lat = (tileIndex % 6) * 5 + latoffset - 90;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat ); String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
return lon*6 + lat; String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
} return slon + "_" + slat + ".n5d";
}
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; package btools.mapcreator;
import btools.util.DiffCoderDataInputStream; import btools.util.DiffCoderDataInputStream;
import btools.util.DiffCoderDataOutputStream; import btools.util.DiffCoderDataOutputStream;
/** /**
* Container for node data on the preprocessor level * Container for node data on the preprocessor level
* *
* @author ab * @author ab
*/ */
public class NodeData extends MapCreatorBase public class NodeData extends MapCreatorBase {
{ public long nid;
public long nid; public int ilon;
public int ilon; public int ilat;
public int ilat; public byte[] description;
public byte[] description; public short selev = Short.MIN_VALUE;
public short selev = Short.MIN_VALUE;
public NodeData(long id, double lon, double lat) {
public NodeData( long id, double lon, double lat ) nid = id;
{ ilat = (int) ((lat + 90.) * 1000000. + 0.5);
nid = id; ilon = (int) ((lon + 180.) * 1000000. + 0.5);
ilat = (int)( ( lat + 90. )*1000000. + 0.5); }
ilon = (int)( ( lon + 180. )*1000000. + 0.5);
} public NodeData(DiffCoderDataInputStream dis) throws Exception {
nid = dis.readDiffed(0);
public NodeData( DiffCoderDataInputStream dis ) throws Exception ilon = (int) dis.readDiffed(1);
{ ilat = (int) dis.readDiffed(2);
nid = dis.readDiffed( 0 ); int mode = dis.readByte();
ilon = (int)dis.readDiffed( 1 ); if ((mode & 1) != 0) {
ilat = (int)dis.readDiffed( 2 ); int dlen = dis.readShort();
int mode = dis.readByte(); description = new byte[dlen];
if ( ( mode & 1 ) != 0 ) { int dlen = dis.readShort(); description = new byte[dlen]; dis.readFully( description ); } dis.readFully(description);
if ( ( mode & 2 ) != 0 ) selev = dis.readShort(); }
} if ((mode & 2) != 0) selev = dis.readShort();
}
public void writeTo( DiffCoderDataOutputStream dos ) throws Exception
{ public void writeTo(DiffCoderDataOutputStream dos) throws Exception {
dos.writeDiffed( nid, 0 ); dos.writeDiffed(nid, 0);
dos.writeDiffed( ilon, 1 ); dos.writeDiffed(ilon, 1);
dos.writeDiffed( ilat, 2 ); dos.writeDiffed(ilat, 2);
int mode = (description == null ? 0 : 1 ) | ( selev == Short.MIN_VALUE ? 0 : 2 ); int mode = (description == null ? 0 : 1) | (selev == Short.MIN_VALUE ? 0 : 2);
dos.writeByte( (byte) mode); dos.writeByte((byte) mode);
if ( ( mode & 1 ) != 0 ) { dos.writeShort( description.length ); dos.write( description ); } if ((mode & 1) != 0) {
if ( ( mode & 2 ) != 0 ) dos.writeShort( selev ); dos.writeShort(description.length);
} dos.write(description);
} }
if ((mode & 2) != 0) dos.writeShort(selev);
}
}

View File

@ -1,92 +1,80 @@
package btools.mapcreator; package btools.mapcreator;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import btools.util.DenseLongMap; import btools.util.DenseLongMap;
import btools.util.DiffCoderDataOutputStream; import btools.util.DiffCoderDataOutputStream;
import btools.util.TinyDenseLongMap; import btools.util.TinyDenseLongMap;
/** /**
* NodeFilter does 1 step in map-processing: * NodeFilter does 1 step in map-processing:
* * <p>
* - filters out unused nodes according to the way file * - filters out unused nodes according to the way file
* *
* @author ab * @author ab
*/ */
public class NodeFilter extends MapCreatorBase public class NodeFilter extends MapCreatorBase {
{ private DiffCoderDataOutputStream nodesOutStream;
private DiffCoderDataOutputStream nodesOutStream; private File nodeTilesOut;
private File nodeTilesOut; protected DenseLongMap nodebitmap;
protected DenseLongMap nodebitmap;
public static void main(String[] args) throws Exception {
public static void main(String[] args) throws Exception System.out.println("*** NodeFilter: Filter way related nodes");
{ if (args.length != 3) {
System.out.println("*** NodeFilter: Filter way related nodes"); System.out.println("usage: java NodeFilter <node-tiles-in> <way-file-in> <node-tiles-out>");
if (args.length != 3) return;
{ }
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]));
} }
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 init() throws Exception
{ public void process(File nodeTilesIn, File wayFileIn, File nodeTilesOut) throws Exception {
nodebitmap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 512 ) : new TinyDenseLongMap(); init();
}
this.nodeTilesOut = nodeTilesOut;
public void process( File nodeTilesIn, File wayFileIn, File nodeTilesOut ) throws Exception
{ // read the wayfile into a bitmap of used nodes
init(); new WayIterator(this, false).processFile(wayFileIn);
this.nodeTilesOut = nodeTilesOut; // finally filter all node files
new NodeIterator(this, true).processDir(nodeTilesIn, ".tls");
// read the wayfile into a bitmap of used nodes }
new WayIterator( this, false ).processFile( wayFileIn );
@Override
// finally filter all node files public void nextWay(WayData data) throws Exception {
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tls" ); int nnodes = data.nodes.size();
} for (int i = 0; i < nnodes; i++) {
nodebitmap.put(data.nodes.get(i), 0);
@Override }
public void nextWay( WayData data ) throws Exception }
{
int nnodes = data.nodes.size(); @Override
for (int i=0; i<nnodes; i++ ) public void nodeFileStart(File nodefile) throws Exception {
{ String filename = nodefile.getName();
nodebitmap.put( data.nodes.get(i), 0 ); File outfile = new File(nodeTilesOut, filename);
} nodesOutStream = new DiffCoderDataOutputStream(new BufferedOutputStream(new FileOutputStream(outfile)));
} }
@Override @Override
public void nodeFileStart( File nodefile ) throws Exception public void nextNode(NodeData n) throws Exception {
{ if (isRelevant(n)) {
String filename = nodefile.getName(); n.writeTo(nodesOutStream);
File outfile = new File( nodeTilesOut, filename ); }
nodesOutStream = new DiffCoderDataOutputStream( new BufferedOutputStream ( new FileOutputStream( outfile ) ) ); }
}
public boolean isRelevant(NodeData n) {
@Override // check if node passes bitmap
public void nextNode( NodeData n ) throws Exception return nodebitmap.getInt(n.nid) == 0; // 0 -> bit set, -1 -> unset
{ }
if ( isRelevant( n ) )
{ @Override
n.writeTo( nodesOutStream ); public void nodeFileEnd(File nodeFile) throws Exception {
} nodesOutStream.close();
} }
}
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; package btools.mapcreator;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import btools.util.DiffCoderDataInputStream; import btools.util.DiffCoderDataInputStream;
/** /**
* Iterate over a singe nodefile or a directory * Iterate over a singe nodefile or a directory
* of nodetiles and feed the nodes to the callback listener * of nodetiles and feed the nodes to the callback listener
* *
* @author ab * @author ab
*/ */
public class NodeIterator extends MapCreatorBase public class NodeIterator extends MapCreatorBase {
{ private NodeListener listener;
private NodeListener listener; private boolean delete;
private boolean delete;
public NodeIterator(NodeListener nodeListener, boolean deleteAfterReading) {
public NodeIterator( NodeListener nodeListener, boolean deleteAfterReading ) listener = nodeListener;
{ delete = deleteAfterReading;
listener = nodeListener; }
delete = deleteAfterReading;
} public void processDir(File indir, String inSuffix) throws Exception {
if (!indir.isDirectory()) {
public void processDir( File indir, String inSuffix ) throws Exception throw new IllegalArgumentException("not a directory: " + indir);
{ }
if ( !indir.isDirectory() )
{ File[] af = sortBySizeAsc(indir.listFiles());
throw new IllegalArgumentException( "not a directory: " + indir ); for (int i = 0; i < af.length; i++) {
} File nodefile = af[i];
if (nodefile.getName().endsWith(inSuffix)) {
File[] af = sortBySizeAsc( indir.listFiles() ); processFile(nodefile);
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)));
public void processFile(File nodefile) throws Exception try {
{ for (; ; ) {
System.out.println( "*** NodeIterator reading: " + nodefile ); NodeData n = new NodeData(di);
listener.nextNode(n);
listener.nodeFileStart( nodefile ); }
} catch (EOFException eof) {
DiffCoderDataInputStream di = new DiffCoderDataInputStream( new BufferedInputStream ( new FileInputStream( nodefile ) ) ); di.close();
try }
{ listener.nodeFileEnd(nodefile);
for(;;) if (delete && "true".equals(System.getProperty("deletetmpfiles"))) {
{ nodefile.delete();
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; package btools.mapcreator;
import java.io.File; import java.io.File;
/** /**
* Callbacklistener for NodeIterator * Callbacklistener for NodeIterator
* *
* @author ab * @author ab
*/ */
public interface NodeListener public interface NodeListener {
{ void nodeFileStart(File nodefile) throws Exception;
void nodeFileStart( File nodefile ) throws Exception;
void nextNode(NodeData data) throws Exception;
void nextNode( NodeData data ) throws Exception;
void nodeFileEnd(File nodefile) throws Exception;
void nodeFileEnd( File nodefile ) throws Exception; }
}

View File

@ -1,332 +1,293 @@
/** /**
* This program * This program
* - reads an *.osm from stdin * - reads an *.osm from stdin
* - writes 45*30 degree node tiles + a way file + a rel file * - writes 45*30 degree node tiles + a way file + a rel file
* *
* @author ab * @author ab
*/ */
package btools.mapcreator; package btools.mapcreator;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import btools.expressions.BExpressionContextNode; import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay; import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData; import btools.expressions.BExpressionMetaData;
public class OsmCutter extends MapCreatorBase public class OsmCutter extends MapCreatorBase {
{ private long recordCnt;
private long recordCnt; private long nodesParsed;
private long nodesParsed; private long waysParsed;
private long waysParsed; private long relsParsed;
private long relsParsed; private long changesetsParsed;
private long changesetsParsed;
private DataOutputStream wayDos;
private DataOutputStream wayDos; private DataOutputStream cyclewayDos;
private DataOutputStream cyclewayDos; private DataOutputStream restrictionsDos;
private DataOutputStream restrictionsDos;
public WayCutter wayCutter;
public WayCutter wayCutter; public RestrictionCutter restrictionCutter;
public RestrictionCutter restrictionCutter; public NodeFilter nodeFilter;
public NodeFilter nodeFilter;
public static void main(String[] args) throws Exception {
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("*** OsmCutter: cut an osm map in node-tiles + a way file"); 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>");
if (args.length != 6 && args.length != 7) System.out.println("or : java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile> <inputfile> ");
{ return;
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 OsmCutter().process( , new File(args[2])
new File( args[0] ) , new File(args[3])
, new File( args[1] ) , new File(args[4])
, new File( args[2] ) , new File(args[5])
, new File( args[3] ) , args.length > 6 ? new File(args[6]) : null
, new File( args[4] ) );
, new File( args[5] ) }
, args.length > 6 ? new File( args[6] ) : null
); private BExpressionContextWay _expctxWay;
} private BExpressionContextNode _expctxNode;
private BExpressionContextWay _expctxWay; // private BExpressionContextWay _expctxWayStat;
private BExpressionContextNode _expctxNode; // private BExpressionContextNode _expctxNodeStat;
// private BExpressionContextWay _expctxWayStat; public void process(File lookupFile, File outTileDir, File wayFile, File relFile, File resFile, File profileFile, File mapFile) throws Exception {
// private BExpressionContextNode _expctxNodeStat; if (!lookupFile.exists()) {
throw new IllegalArgumentException("lookup-file: " + lookupFile + " does not exist");
public void process (File lookupFile, File outTileDir, File wayFile, File relFile, File resFile, File profileFile, File mapFile ) throws Exception }
{
if ( !lookupFile.exists() ) BExpressionMetaData meta = new BExpressionMetaData();
{
throw new IllegalArgumentException( "lookup-file: " + lookupFile + " does not exist" ); _expctxWay = new BExpressionContextWay(meta);
} _expctxNode = new BExpressionContextNode(meta);
meta.readMetaData(lookupFile);
BExpressionMetaData meta = new BExpressionMetaData(); _expctxWay.parseFile(profileFile, "global");
_expctxWay = new BExpressionContextWay( meta );
_expctxNode = new BExpressionContextNode( meta ); // _expctxWayStat = new BExpressionContextWay( null );
meta.readMetaData( lookupFile ); // _expctxNodeStat = new BExpressionContextNode( null );
_expctxWay.parseFile( profileFile, "global" );
this.outTileDir = outTileDir;
if (!outTileDir.isDirectory())
// _expctxWayStat = new BExpressionContextWay( null ); throw new RuntimeException("out tile directory " + outTileDir + " does not exist");
// _expctxNodeStat = new BExpressionContextNode( null );
wayDos = wayFile == null ? null : new DataOutputStream(new BufferedOutputStream(new FileOutputStream(wayFile)));
this.outTileDir = outTileDir; cyclewayDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(relFile)));
if ( !outTileDir.isDirectory() ) throw new RuntimeException( "out tile directory " + outTileDir + " does not exist" ); if (resFile != null) {
restrictionsDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(resFile)));
wayDos = wayFile == null ? null : new DataOutputStream( new BufferedOutputStream( new FileOutputStream( wayFile ) ) ); }
cyclewayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( relFile ) ) );
if ( resFile != null ) // read the osm map into memory
{ long t0 = System.currentTimeMillis();
restrictionsDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( resFile ) ) ); new OsmParser().readMap(mapFile, this, this, this);
} long t1 = System.currentTimeMillis();
// read the osm map into memory System.out.println("parsing time (ms) =" + (t1 - t0));
long t0 = System.currentTimeMillis();
new OsmParser().readMap( mapFile, this, this, this ); // close all files
long t1 = System.currentTimeMillis(); closeTileOutStreams();
if (wayDos != null) {
System.out.println( "parsing time (ms) =" + (t1-t0) ); wayDos.close();
}
// close all files cyclewayDos.close();
closeTileOutStreams(); if (restrictionsDos != null) {
if ( wayDos != null ) restrictionsDos.close();
{ }
wayDos.close();
} // System.out.println( "-------- way-statistics -------- " );
cyclewayDos.close(); // _expctxWayStat.dumpStatistics();
if ( restrictionsDos != null ) // System.out.println( "-------- node-statistics -------- " );
{ // _expctxNodeStat.dumpStatistics();
restrictionsDos.close();
} System.out.println(statsLine());
}
// System.out.println( "-------- way-statistics -------- " );
// _expctxWayStat.dumpStatistics(); private void checkStats() {
// System.out.println( "-------- node-statistics -------- " ); if ((++recordCnt % 100000) == 0) System.out.println(statsLine());
// _expctxNodeStat.dumpStatistics(); }
System.out.println( statsLine() ); private String statsLine() {
} return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed;
}
private void checkStats()
{
if ( (++recordCnt % 100000) == 0 ) System.out.println( statsLine() ); @Override
} public void nextNode(NodeData n) throws Exception {
nodesParsed++;
private String statsLine() checkStats();
{
return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed; if (n.getTagsOrNull() != null) {
} int[] lookupData = _expctxNode.createNewLookupData();
for (Map.Entry<String, String> e : n.getTagsOrNull().entrySet()) {
_expctxNode.addLookupValue(e.getKey(), e.getValue(), lookupData);
@Override // _expctxNodeStat.addLookupValue( key, value, null );
public void nextNode( NodeData n ) throws Exception }
{ n.description = _expctxNode.encode(lookupData);
nodesParsed++; }
checkStats(); // write node to file
int tileIndex = getTileIndex(n.ilon, n.ilat);
if ( n.getTagsOrNull() != null ) if (tileIndex >= 0) {
{ n.writeTo(getOutStreamForTile(tileIndex));
int[] lookupData = _expctxNode.createNewLookupData(); if (wayCutter != null) {
for( Map.Entry<String,String> e : n.getTagsOrNull().entrySet() ) wayCutter.nextNode(n);
{ }
_expctxNode.addLookupValue( e.getKey(), e.getValue(), lookupData ); }
// _expctxNodeStat.addLookupValue( key, value, null ); }
}
n.description = _expctxNode.encode(lookupData);
} private void generatePseudoTags(HashMap<String, String> map) {
// write node to file // add pseudo.tags for concrete:lanes and concrete:plates
int tileIndex = getTileIndex( n.ilon, n.ilat );
if ( tileIndex >= 0 ) String concrete = null;
{ for (Map.Entry<String, String> e : map.entrySet()) {
n.writeTo( getOutStreamForTile( tileIndex ) ); String key = e.getKey();
if ( wayCutter != null )
{ if ("concrete".equals(key)) {
wayCutter.nextNode( n ); return;
} }
} if ("surface".equals(key)) {
} String value = e.getValue();
if (value.startsWith("concrete:")) {
concrete = value.substring("concrete:".length());
private void generatePseudoTags( HashMap<String,String> map ) }
{ }
// add pseudo.tags for concrete:lanes and concrete:plates }
if (concrete != null) {
String concrete = null; map.put("concrete", concrete);
for( Map.Entry<String,String> e : map.entrySet() ) }
{ }
String key = e.getKey();
if ( "concrete".equals( key ) ) @Override
{ public void nextWay(WayData w) throws Exception {
return; waysParsed++;
} checkStats();
if ( "surface".equals( key ) )
{ // encode tags
String value = e.getValue(); if (w.getTagsOrNull() == null) return;
if ( value.startsWith( "concrete:" ) )
{ generatePseudoTags(w.getTagsOrNull());
concrete = value.substring( "concrete:".length() );
} int[] lookupData = _expctxWay.createNewLookupData();
} for (String key : w.getTagsOrNull().keySet()) {
} String value = w.getTag(key);
if ( concrete != null ) _expctxWay.addLookupValue(key, value.replace(' ', '_'), lookupData);
{ // _expctxWayStat.addLookupValue( key, value, null );
map.put( "concrete", concrete ); }
} w.description = _expctxWay.encode(lookupData);
}
if (w.description == null) return;
@Override // filter according to profile
public void nextWay( WayData w ) throws Exception _expctxWay.evaluate(false, w.description);
{ boolean ok = _expctxWay.getCostfactor() < 10000.;
waysParsed++; _expctxWay.evaluate(true, w.description);
checkStats(); ok |= _expctxWay.getCostfactor() < 10000.;
if (!ok) return;
// encode tags
if ( w.getTagsOrNull() == null ) return; if (wayDos != null) {
w.writeTo(wayDos);
generatePseudoTags( w.getTagsOrNull() ); }
if (wayCutter != null) {
int[] lookupData = _expctxWay.createNewLookupData(); wayCutter.nextWay(w);
for( String key : w.getTagsOrNull().keySet() ) }
{ if (nodeFilter != null) {
String value = w.getTag( key ); nodeFilter.nextWay(w);
_expctxWay.addLookupValue( key, value.replace( ' ', '_' ), lookupData ); }
// _expctxWayStat.addLookupValue( key, value, null ); }
}
w.description = _expctxWay.encode(lookupData); @Override
public void nextRelation(RelationData r) throws Exception {
if ( w.description == null ) return; relsParsed++;
checkStats();
// filter according to profile
_expctxWay.evaluate( false, w.description ); String route = r.getTag("route");
boolean ok = _expctxWay.getCostfactor() < 10000.; // filter out non-cycle relations
_expctxWay.evaluate( true, w.description ); if (route == null) {
ok |= _expctxWay.getCostfactor() < 10000.; return;
if ( !ok ) return; }
if ( wayDos != null ) String network = r.getTag("network");
{ if (network == null) network = "";
w.writeTo( wayDos ); String state = r.getTag("state");
} if (state == null) state = "";
if ( wayCutter != null ) writeId(cyclewayDos, r.rid);
{ cyclewayDos.writeUTF(route);
wayCutter.nextWay( w ); cyclewayDos.writeUTF(network);
} cyclewayDos.writeUTF(state);
if ( nodeFilter != null ) for (int i = 0; i < r.ways.size(); i++) {
{ long wid = r.ways.get(i);
nodeFilter.nextWay( w ); writeId(cyclewayDos, wid);
} }
} writeId(cyclewayDos, -1);
}
@Override
public void nextRelation( RelationData r ) throws Exception @Override
{ public void nextRestriction(RelationData r, long fromWid, long toWid, long viaNid) throws Exception {
relsParsed++; String type = r.getTag("type");
checkStats(); if (type == null || !"restriction".equals(type)) {
return;
String route = r.getTag( "route" ); }
// filter out non-cycle relations short exceptions = 0;
if ( route == null ) String except = r.getTag("except");
{ if (except != null) {
return; exceptions |= toBit("bicycle", 0, except);
} exceptions |= toBit("motorcar", 1, except);
exceptions |= toBit("agricultural", 2, except);
String network = r.getTag( "network" ); exceptions |= toBit("forestry", 2, except);
if ( network == null ) network = ""; exceptions |= toBit("psv", 3, except);
String state = r.getTag( "state" ); exceptions |= toBit("hgv", 4, except);
if ( state == null ) state = ""; }
writeId( cyclewayDos, r.rid );
cyclewayDos.writeUTF( route ); for (String restrictionKey : r.getTagsOrNull().keySet()) {
cyclewayDos.writeUTF( network ); if (!(restrictionKey.equals("restriction") || restrictionKey.startsWith("restriction:"))) {
cyclewayDos.writeUTF( state ); continue;
for ( int i=0; i<r.ways.size();i++ ) }
{ String restriction = r.getTag(restrictionKey);
long wid = r.ways.get(i);
writeId( cyclewayDos, wid ); RestrictionData res = new RestrictionData();
} res.restrictionKey = restrictionKey;
writeId( cyclewayDos, -1 ); res.restriction = restriction;
} res.exceptions = exceptions;
res.fromWid = fromWid;
@Override res.toWid = toWid;
public void nextRestriction( RelationData r, long fromWid, long toWid, long viaNid ) throws Exception res.viaNid = viaNid;
{
String type = r.getTag( "type" ); if (restrictionsDos != null) {
if ( type == null || !"restriction".equals( type ) ) res.writeTo(restrictionsDos);
{ }
return; if (restrictionCutter != null) {
} restrictionCutter.nextRestriction(res);
short exceptions = 0; }
String except = r.getTag( "except" ); }
if ( except != null ) }
{
exceptions |= toBit( "bicycle" , 0, except ); private static short toBit(String tag, int bitpos, String s) {
exceptions |= toBit( "motorcar" , 1, except ); return (short) (s.indexOf(tag) < 0 ? 0 : 1 << bitpos);
exceptions |= toBit( "agricultural" , 2, except ); }
exceptions |= toBit( "forestry" , 2, except );
exceptions |= toBit( "psv" , 3, except ); private int getTileIndex(int ilon, int ilat) {
exceptions |= toBit( "hgv" , 4, except ); int lon = ilon / 45000000;
} int lat = ilat / 30000000;
if (lon < 0 || lon > 7 || lat < 0 || lat > 5) {
for( String restrictionKey : r.getTagsOrNull().keySet() ) System.out.println("warning: ignoring illegal pos: " + ilon + "," + ilat);
{ return -1;
if ( !( restrictionKey.equals( "restriction" ) || restrictionKey.startsWith( "restriction:" ) ) ) }
{ return lon * 6 + lat;
continue; }
}
String restriction = r.getTag( restrictionKey ); protected String getNameForTile(int tileIndex) {
int lon = (tileIndex / 6) * 45 - 180;
RestrictionData res = new RestrictionData(); int lat = (tileIndex % 6) * 30 - 90;
res.restrictionKey = restrictionKey; String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
res.restriction = restriction; String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
res.exceptions = exceptions; return slon + "_" + slat + ".ntl";
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; import java.io.File;
public class OsmFastCutter extends MapCreatorBase public class OsmFastCutter extends MapCreatorBase {
{ public static void main(String[] args) throws Exception {
public static void main(String[] args) throws Exception
{
System.out.println("*** OsmFastCutter: cut an osm map in node-tiles + way-tiles"); 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>"; 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("usage: bzip2 -dc <map> | " + common);
System.out.println("or : " + common + " <inputfile> " ); System.out.println("or : " + common + " <inputfile> ");
return; return;
} }
doCut( doCut(
new File( args[0] ) new File(args[0])
, new File( args[1] ) , new File(args[1])
, new File( args[2] ) , new File(args[2])
, new File( args[3] ) , new File(args[3])
, new File( args[4] ) , new File(args[4])
, new File( args[5] ) , new File(args[5])
, new File( args[6] ) , new File(args[6])
, new File( args[7] ) , new File(args[7])
, new File( args[8] ) , new File(args[8])
, new File( args[9] ) , new File(args[9])
, new File( args[10] ) , new File(args[10])
, args.length > 11 ? new File( args[11] ) : null , 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 **** // **** run OsmCutter ****
OsmCutter cutter = new OsmCutter(); OsmCutter cutter = new OsmCutter();
// ... inject WayCutter // ... inject WayCutter
cutter.wayCutter = new WayCutter(); cutter.wayCutter = new WayCutter();
cutter.wayCutter.init( wayDir ); cutter.wayCutter.init(wayDir);
// ... inject RestrictionCutter // ... inject RestrictionCutter
cutter.restrictionCutter = new 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 // ... inject NodeFilter
NodeFilter nodeFilter = new NodeFilter(); NodeFilter nodeFilter = new NodeFilter();
nodeFilter.init(); nodeFilter.init();
cutter.nodeFilter = nodeFilter; 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.wayCutter.finish();
cutter.restrictionCutter.finish(); cutter.restrictionCutter.finish();
cutter = null; cutter = null;
@ -67,20 +63,20 @@ public class OsmFastCutter extends MapCreatorBase
//... inject RelationMerger //... inject RelationMerger
wayCut5.relMerger = new RelationMerger(); wayCut5.relMerger = new RelationMerger();
wayCut5.relMerger.init( relFile, lookupFile, profileReport, profileCheck ); wayCut5.relMerger.init(relFile, lookupFile, profileReport, profileCheck);
// ... inject RestrictionCutter5 // ... inject RestrictionCutter5
wayCut5.restrictionCutter5 = new 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 //... inject NodeFilter
wayCut5.nodeFilter = nodeFilter; wayCut5.nodeFilter = nodeFilter;
// ... inject NodeCutter // ... inject NodeCutter
wayCut5.nodeCutter = new 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) * Container for link between two Osm nodes (pre-pocessor version)
* *
* @author ab * @author ab
*/ */
package btools.mapcreator; package btools.mapcreator;
public class OsmLinkP public class OsmLinkP {
{ /**
/** * The description bitmap is mainly the way description
* The description bitmap is mainly the way description * used to calculate the costfactor
* used to calculate the costfactor */
*/ public byte[] descriptionBitmap;
public byte[] descriptionBitmap;
/**
/** * The target is either the next link or the target node
* The target is either the next link or the target node */
*/ protected OsmNodeP sourceNode;
protected OsmNodeP sourceNode; protected OsmNodeP targetNode;
protected OsmNodeP targetNode;
protected OsmLinkP previous;
protected OsmLinkP previous; protected OsmLinkP next;
protected OsmLinkP next;
public OsmLinkP(OsmNodeP source, OsmNodeP target) {
public OsmLinkP( OsmNodeP source, OsmNodeP target ) sourceNode = source;
{ targetNode = target;
sourceNode = source; }
targetNode = target;
} protected OsmLinkP() {
}
protected OsmLinkP()
{ public final boolean counterLinkWritten() {
} return descriptionBitmap == null;
}
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) {
* Set the relevant next-pointer for the given source next = link;
*/ } else if (targetNode == source) {
public void setNext( OsmLinkP link, OsmNodeP source ) previous = link;
{ } else {
if ( sourceNode == source ) throw new IllegalArgumentException("internal error: setNext: unknown source");
{ }
next = link; }
}
else if ( targetNode == source ) /**
{ * Get the relevant next-pointer for the given source
previous = link; */
} public OsmLinkP getNext(OsmNodeP source) {
else if (sourceNode == source) {
{ return next;
throw new IllegalArgumentException( "internal error: setNext: unknown source" ); } else if (targetNode == source) {
} return previous;
} } else {
throw new IllegalArgumentException("internal error: gextNext: unknown source");
/** }
* Get the relevant next-pointer for the given source }
*/
public OsmLinkP getNext( OsmNodeP source ) /**
{ * Get the relevant target-node for the given source
if ( sourceNode == source ) */
{ public OsmNodeP getTarget(OsmNodeP source) {
return next; if (sourceNode == source) {
} return targetNode;
else if ( targetNode == source ) } else if (targetNode == source) {
{ return sourceNode;
return previous; } else {
} throw new IllegalArgumentException("internal error: getTarget: unknown source");
else }
{ }
throw new IllegalArgumentException( "internal error: gextNext: unknown source" );
} /**
} * Check if reverse link for the given source
*/
/** public boolean isReverse(OsmNodeP source) {
* Get the relevant target-node for the given source if (sourceNode == source) {
*/ return false;
public OsmNodeP getTarget( OsmNodeP source ) } else if (targetNode == source) {
{ return true;
if ( sourceNode == source ) } else {
{ throw new IllegalArgumentException("internal error: isReverse: unknown 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.MicroCache;
import btools.codec.MicroCache2; import btools.codec.MicroCache2;
public class OsmNodeP extends OsmLinkP public class OsmNodeP extends OsmLinkP {
{
/** /**
* The latitude * The latitude
*/ */
@ -40,311 +39,261 @@ public class OsmNodeP extends OsmLinkP
public byte bits = 0; public byte bits = 0;
// interface OsmPos // interface OsmPos
public int getILat() public int getILat() {
{
return ilat; return ilat;
} }
public int getILon() public int getILon() {
{
return ilon; return ilon;
} }
public short getSElev() public short getSElev() {
{
// if all bridge or all tunnel, elevation=no-data // 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.; return selev / 4.;
} }
// populate and return the inherited link, if available, // populate and return the inherited link, if available,
// else create a new one // else create a new one
public OsmLinkP createLink( OsmNodeP source ) public OsmLinkP createLink(OsmNodeP source) {
{ if (sourceNode == null && targetNode == null) {
if ( sourceNode == null && targetNode == null )
{
// inherited instance is available, use this // inherited instance is available, use this
sourceNode = source; sourceNode = source;
targetNode = this; targetNode = this;
source.addLink( this ); source.addLink(this);
return this; return this;
} }
OsmLinkP link = new OsmLinkP( source, this ); OsmLinkP link = new OsmLinkP(source, this);
addLink( link ); addLink(link);
source.addLink( link ); source.addLink(link);
return link; return link;
} }
// memory-squeezing-hack: OsmLinkP's "previous" also used as firstlink.. // memory-squeezing-hack: OsmLinkP's "previous" also used as firstlink..
public void addLink( OsmLinkP link ) public void addLink(OsmLinkP link) {
{ link.setNext(previous, this);
link.setNext( previous, this );
previous = link; previous = link;
} }
public OsmLinkP getFirstLink() public OsmLinkP getFirstLink() {
{
return sourceNode == null && targetNode == null ? previous : this; return sourceNode == null && targetNode == null ? previous : this;
} }
public byte[] getNodeDecsription() public byte[] getNodeDecsription() {
{
return null; return null;
} }
public RestrictionData getFirstRestriction() public RestrictionData getFirstRestriction() {
{
return null; return null;
} }
public void writeNodeData( MicroCache mc, OsmTrafficMap trafficMap ) throws IOException public void writeNodeData(MicroCache mc, OsmTrafficMap trafficMap) throws IOException {
{
boolean valid = true; boolean valid = true;
if ( mc instanceof MicroCache2 ) if (mc instanceof MicroCache2) {
{ valid = writeNodeData2((MicroCache2) mc, trafficMap);
valid = writeNodeData2( (MicroCache2) mc, trafficMap ); } else
} throw new IllegalArgumentException("unknown cache version: " + mc.getClass());
else if (valid) {
throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() ); mc.finishNode(getIdFromPos());
if ( valid ) } else {
{
mc.finishNode( getIdFromPos() );
}
else
{
mc.discardNode(); mc.discardNode();
} }
} }
public void checkDuplicateTargets() public void checkDuplicateTargets() {
{ HashMap<OsmNodeP, OsmLinkP> targets = new HashMap<OsmNodeP, OsmLinkP>();
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; OsmLinkP link = link0;
OsmNodeP origin = this; OsmNodeP origin = this;
OsmNodeP target = null; OsmNodeP target = null;
// first pass just to see if that link is consistent // first pass just to see if that link is consistent
while (link != null) while (link != null) {
{ target = link.getTarget(origin);
target = link.getTarget( origin ); if (!target.isTransferNode()) {
if ( !target.isTransferNode() )
{
break; break;
} }
// next link is the one (of two), does does'nt point back // next link is the one (of two), does does'nt point back
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) ) for (link = target.getFirstLink(); link != null; link = link.getNext(target)) {
{ if (link.getTarget(target) != origin)
if ( link.getTarget( target ) != origin )
break; break;
} }
origin = target; origin = target;
} }
if ( link == null ) continue; if (link == null) continue;
OsmLinkP oldLink = targets.put( target, link0 ); OsmLinkP oldLink = targets.put(target, link0);
if ( oldLink != null ) if (oldLink != null) {
{ unifyLink(oldLink);
unifyLink( oldLink ); unifyLink(link0);
unifyLink( link0 );
} }
} }
} }
private void unifyLink( OsmLinkP link ) private void unifyLink(OsmLinkP link) {
{ if (link.isReverse(this)) return;
if ( link.isReverse( this ) ) return; OsmNodeP target = link.getTarget(this);
OsmNodeP target = link.getTarget( this ); if (target.isTransferNode()) {
if ( target.isTransferNode() )
{
target.incWayCount(); target.incWayCount();
} }
} }
public boolean writeNodeData2( MicroCache2 mc, OsmTrafficMap trafficMap ) throws IOException public boolean writeNodeData2(MicroCache2 mc, OsmTrafficMap trafficMap) throws IOException {
{
boolean hasLinks = false; boolean hasLinks = false;
// write turn restrictions // write turn restrictions
RestrictionData r = getFirstRestriction(); RestrictionData r = getFirstRestriction();
while( r != null ) while (r != null) {
{ if (r.isValid() && r.fromLon != 0 && r.toLon != 0) {
if ( r.isValid() && r.fromLon != 0 && r.toLon != 0 ) mc.writeBoolean(true); // restriction follows
{ mc.writeShort(r.exceptions);
mc.writeBoolean( true ); // restriction follows mc.writeBoolean(r.isPositive());
mc.writeShort( r.exceptions ); mc.writeInt(r.fromLon);
mc.writeBoolean( r.isPositive() ); mc.writeInt(r.fromLat);
mc.writeInt( r.fromLon ); mc.writeInt(r.toLon);
mc.writeInt( r.fromLat ); mc.writeInt(r.toLat);
mc.writeInt( r.toLon );
mc.writeInt( r.toLat );
} }
r = r.next; r = r.next;
} }
mc.writeBoolean( false ); // end restritions mc.writeBoolean(false); // end restritions
mc.writeShort( getSElev() ); mc.writeShort(getSElev());
mc.writeVarBytes( getNodeDecsription() ); mc.writeVarBytes(getNodeDecsription());
// buffer internal reverse links // buffer internal reverse links
ArrayList<OsmNodeP> internalReverse = new ArrayList<OsmNodeP>(); 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; OsmLinkP link = link0;
OsmNodeP origin = this; OsmNodeP origin = this;
OsmNodeP target = null; OsmNodeP target = null;
ArrayList<OsmNodeP> linkNodes = new ArrayList<OsmNodeP>(); ArrayList<OsmNodeP> linkNodes = new ArrayList<OsmNodeP>();
linkNodes.add( this ); linkNodes.add(this);
// first pass just to see if that link is consistent // first pass just to see if that link is consistent
while (link != null) while (link != null) {
{ target = link.getTarget(origin);
target = link.getTarget( origin ); linkNodes.add(target);
linkNodes.add( target );
if ( !target.isTransferNode() ) if (!target.isTransferNode()) {
{
break; break;
} }
// next link is the one (of two), does does'nt point back // next link is the one (of two), does does'nt point back
for ( link = target.getFirstLink(); link != null; link = link.getNext( target ) ) for (link = target.getFirstLink(); link != null; link = link.getNext(target)) {
{ if (link.getTarget(target) != origin)
if ( link.getTarget( target ) != origin )
break; break;
} }
if ( link != null && link.descriptionBitmap != link0.descriptionBitmap ) if (link != null && link.descriptionBitmap != link0.descriptionBitmap) {
{ throw new IllegalArgumentException("assertion failed: description change along transfer nodes");
throw new IllegalArgumentException( "assertion failed: description change along transfer nodes" );
} }
origin = target; origin = target;
} }
if ( link == null ) if (link == null)
continue; // dead end continue; // dead end
if ( target == this ) if (target == this)
continue; // self-ref continue; // self-ref
hasLinks = true; hasLinks = true;
// internal reverse links later // internal reverse links later
boolean isReverse = link0.isReverse( this ); boolean isReverse = link0.isReverse(this);
if ( isReverse ) if (isReverse) {
{ if (mc.isInternal(target.ilon, target.ilat)) {
if ( mc.isInternal( target.ilon, target.ilat ) ) internalReverse.add(target);
{
internalReverse.add( target );
continue; continue;
} }
} }
// add traffic simulation, if present // add traffic simulation, if present
byte[] description = link0.descriptionBitmap; byte[] description = link0.descriptionBitmap;
if ( trafficMap != null ) if (trafficMap != null) {
{ description = trafficMap.addTrafficClass(linkNodes, description);
description = trafficMap.addTrafficClass( linkNodes, description );
} }
// write link data // write link data
int sizeoffset = mc.writeSizePlaceHolder(); int sizeoffset = mc.writeSizePlaceHolder();
mc.writeVarLengthSigned( target.ilon - ilon ); mc.writeVarLengthSigned(target.ilon - ilon);
mc.writeVarLengthSigned( target.ilat - ilat ); mc.writeVarLengthSigned(target.ilat - ilat);
mc.writeModeAndDesc( isReverse, description ); mc.writeModeAndDesc(isReverse, description);
if ( !isReverse && linkNodes.size() > 2 ) // write geometry for forward links only if (!isReverse && linkNodes.size() > 2) // write geometry for forward links only
{ {
DPFilter.doDPFilter( linkNodes ); DPFilter.doDPFilter(linkNodes);
origin = this; 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); OsmNodeP tranferNode = linkNodes.get(i);
if ( ( tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT ) != 0 ) if ((tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT) != 0) {
{ mc.writeVarLengthSigned(tranferNode.ilon - origin.ilon);
mc.writeVarLengthSigned( tranferNode.ilon - origin.ilon ); mc.writeVarLengthSigned(tranferNode.ilat - origin.ilat);
mc.writeVarLengthSigned( tranferNode.ilat - origin.ilat ); mc.writeVarLengthSigned(tranferNode.getSElev() - origin.getSElev());
mc.writeVarLengthSigned( tranferNode.getSElev() - origin.getSElev() );
origin = tranferNode; origin = tranferNode;
} }
} }
} }
mc.injectSize( sizeoffset ); mc.injectSize(sizeoffset);
} }
while (internalReverse.size() > 0) while (internalReverse.size() > 0) {
{
int nextIdx = 0; int nextIdx = 0;
if ( internalReverse.size() > 1 ) if (internalReverse.size() > 1) {
{
int max32 = Integer.MIN_VALUE; int max32 = Integer.MIN_VALUE;
for ( int i = 0; i < internalReverse.size(); i++ ) for (int i = 0; i < internalReverse.size(); i++) {
{ int id32 = mc.shrinkId(internalReverse.get(i).getIdFromPos());
int id32 = mc.shrinkId( internalReverse.get( i ).getIdFromPos() ); if (id32 > max32) {
if ( id32 > max32 )
{
max32 = id32; max32 = id32;
nextIdx = i; nextIdx = i;
} }
} }
} }
OsmNodeP target = internalReverse.remove( nextIdx ); OsmNodeP target = internalReverse.remove(nextIdx);
int sizeoffset = mc.writeSizePlaceHolder(); int sizeoffset = mc.writeSizePlaceHolder();
mc.writeVarLengthSigned( target.ilon - ilon ); mc.writeVarLengthSigned(target.ilon - ilon);
mc.writeVarLengthSigned( target.ilat - ilat ); mc.writeVarLengthSigned(target.ilat - ilat);
mc.writeModeAndDesc( true, null ); mc.writeModeAndDesc(true, null);
mc.injectSize( sizeoffset ); mc.injectSize(sizeoffset);
} }
return hasLinks; return hasLinks;
} }
public String toString2() public String toString2() {
{ return (ilon - 180000000) + "_" + (ilat - 90000000) + "_" + (selev / 4);
return ( ilon - 180000000 ) + "_" + ( ilat - 90000000 ) + "_" + ( selev / 4 );
} }
public long getIdFromPos() public long getIdFromPos() {
{ return ((long) ilon) << 32 | ilat;
return ( (long) ilon ) << 32 | ilat;
} }
public boolean isBorderNode() public boolean isBorderNode() {
{ return (bits & BORDER_BIT) != 0;
return ( bits & BORDER_BIT ) != 0;
} }
public boolean hasTraffic() public boolean hasTraffic() {
{ return (bits & TRAFFIC_BIT) != 0;
return ( bits & TRAFFIC_BIT ) != 0;
} }
/** /**
* Not really count the ways, just detect if more than one * Not really count the ways, just detect if more than one
*/ */
public void incWayCount() public void incWayCount() {
{ if ((bits & ANY_WAY_BIT) != 0) {
if ( ( bits & ANY_WAY_BIT ) != 0 )
{
bits |= MULTI_WAY_BIT; bits |= MULTI_WAY_BIT;
} }
bits |= ANY_WAY_BIT; bits |= ANY_WAY_BIT;
} }
public boolean isTransferNode() public boolean isTransferNode() {
{ return (bits & BORDER_BIT) == 0 && (bits & MULTI_WAY_BIT) == 0 && _linkCnt() == 2;
return ( bits & BORDER_BIT ) == 0 && ( bits & MULTI_WAY_BIT ) == 0 && _linkCnt() == 2;
} }
private int _linkCnt() private int _linkCnt() {
{
int cnt = 0; int cnt = 0;
for ( OsmLinkP link = getFirstLink(); link != null; link = link.getNext( this ) ) for (OsmLinkP link = getFirstLink(); link != null; link = link.getNext(this)) {
{
cnt++; cnt++;
} }
return cnt; return cnt;

View File

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

View File

@ -1,236 +1,200 @@
package btools.mapcreator; package btools.mapcreator;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
/** /**
* Parser for OSM data * Parser for OSM data
* *
* @author ab * @author ab
*/ */
public class OsmParser extends MapCreatorBase public class OsmParser extends MapCreatorBase {
{ private BufferedReader _br;
private BufferedReader _br;
private NodeListener nListener;
private NodeListener nListener; private WayListener wListener;
private WayListener wListener; private RelationListener rListener;
private RelationListener rListener;
public void readMap(File mapFile,
public void readMap( File mapFile, NodeListener nListener,
NodeListener nListener, WayListener wListener,
WayListener wListener, RelationListener rListener) throws Exception {
RelationListener rListener ) throws Exception
{ this.nListener = nListener;
this.wListener = wListener;
this.nListener = nListener; this.rListener = rListener;
this.wListener = wListener;
this.rListener = rListener; if (mapFile == null) {
_br = new BufferedReader(new InputStreamReader(System.in));
if ( mapFile == null ) } else {
{ if (mapFile.getName().endsWith(".gz")) {
_br = new BufferedReader(new InputStreamReader(System.in)); _br = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(mapFile))));
} } else {
else _br = new BufferedReader(new InputStreamReader(new FileInputStream(mapFile)));
{ }
if ( mapFile.getName().endsWith( ".gz" ) ) }
{
_br = new BufferedReader(new InputStreamReader( new GZIPInputStream( new FileInputStream( mapFile ) ) ) ); for (; ; ) {
} String line = _br.readLine();
else if (line == null) break;
{
_br = new BufferedReader(new InputStreamReader( new FileInputStream( mapFile ) ) ); if (checkNode(line)) continue;
} if (checkWay(line)) continue;
} if (checkRelation(line)) continue;
if (checkChangeset(line)) continue;
for(;;) }
{
String line = _br.readLine(); if (mapFile != null) {
if ( line == null ) break; _br.close();
}
if ( checkNode( line ) ) continue; }
if ( checkWay( line ) ) continue;
if ( checkRelation( line ) ) continue;
if ( checkChangeset( line ) ) continue; private boolean checkNode(String line) throws Exception {
} int idx0 = line.indexOf("<node id=\"");
if (idx0 < 0) return false;
if ( mapFile != null ) idx0 += 10;
{ int idx1 = line.indexOf('"', idx0);
_br.close();
} long nodeId = Long.parseLong(line.substring(idx0, idx1));
}
int idx2 = line.indexOf(" lat=\"");
if (idx2 < 0) return false;
private boolean checkNode( String line ) throws Exception idx2 += 6;
{ int idx3 = line.indexOf('"', idx2);
int idx0 = line.indexOf( "<node id=\"" ); double lat = Double.parseDouble(line.substring(idx2, idx3));
if ( idx0 < 0 ) return false; int idx4 = line.indexOf(" lon=\"");
idx0 += 10; if (idx4 < 0) return false;
int idx1 = line.indexOf( '"', idx0 ); idx4 += 6;
int idx5 = line.indexOf('"', idx4);
long nodeId = Long.parseLong( line.substring( idx0, idx1 ) ); double lon = Double.parseDouble(line.substring(idx4, idx5));
int idx2 = line.indexOf( " lat=\"" ); NodeData n = new NodeData(nodeId, lon, lat);
if ( idx2 < 0 ) return false;
idx2 += 6; if (!line.endsWith("/>")) {
int idx3 = line.indexOf( '"', idx2 ); // read additional tags
double lat = Double.parseDouble( line.substring( idx2, idx3 ) ); for (; ; ) {
int idx4 = line.indexOf( " lon=\"" ); String l2 = _br.readLine();
if ( idx4 < 0 ) return false; if (l2 == null) return false;
idx4 += 6;
int idx5 = line.indexOf( '"', idx4 ); int i2;
double lon = Double.parseDouble( line.substring( idx4, idx5 ) ); if ((i2 = l2.indexOf("<tag k=\"")) >= 0) { // property-tag
i2 += 8;
NodeData n = new NodeData( nodeId, lon, lat ); int ri2 = l2.indexOf('"', i2);
String key = l2.substring(i2, ri2);
if ( !line.endsWith( "/>" ) ) i2 = l2.indexOf(" v=\"", ri2);
{ if (i2 >= 0) {
// read additional tags i2 += 4;
for(;;) int ri3 = l2.indexOf('"', i2);
{ String value = l2.substring(i2, ri3);
String l2 = _br.readLine();
if ( l2 == null ) return false; n.putTag(key, value);
}
int i2; } else if (l2.indexOf("</node>") >= 0) { // end-tag
if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 ) break;
{ // property-tag }
i2 += 8; }
int ri2 = l2.indexOf( '"', i2 ); }
String key = l2.substring( i2, ri2 ); nListener.nextNode(n);
i2 = l2.indexOf( " v=\"", ri2 ); return true;
if ( i2 >= 0 ) }
{
i2 += 4;
int ri3 = l2.indexOf( '"', i2 ); private boolean checkWay(String line) throws Exception {
String value = l2.substring( i2, ri3 ); int idx0 = line.indexOf("<way id=\"");
if (idx0 < 0) return false;
n.putTag( key, value );
} idx0 += 9;
} int idx1 = line.indexOf('"', idx0);
else if ( l2.indexOf( "</node>" ) >= 0 ) long id = Long.parseLong(line.substring(idx0, idx1));
{ // end-tag
break; WayData w = new WayData(id);
}
} // read the nodes
} for (; ; ) {
nListener.nextNode( n ); String l2 = _br.readLine();
return true; if (l2 == null) return false;
}
int i2;
if ((i2 = l2.indexOf("<nd ref=\"")) >= 0) { // node reference
private boolean checkWay( String line ) throws Exception i2 += 9;
{ int ri2 = l2.indexOf('"', i2);
int idx0 = line.indexOf( "<way id=\"" ); long nid = Long.parseLong(l2.substring(i2, ri2));
if ( idx0 < 0 ) return false; w.nodes.add(nid);
} else if ((i2 = l2.indexOf("<tag k=\"")) >= 0) { // property-tag
idx0 += 9; i2 += 8;
int idx1 = line.indexOf( '"', idx0 ); int ri2 = l2.indexOf('"', i2);
long id = Long.parseLong( line.substring( idx0, idx1 ) ); String key = l2.substring(i2, ri2);
i2 = l2.indexOf(" v=\"", ri2);
WayData w = new WayData( id ); if (i2 >= 0) {
i2 += 4;
// read the nodes int ri3 = l2.indexOf('"', i2);
for(;;) String value = l2.substring(i2, ri3);
{ w.putTag(key, value);
String l2 = _br.readLine(); }
if ( l2 == null ) return false; } else if (l2.indexOf("</way>") >= 0) { // end-tag
break;
int i2; }
if ( (i2 = l2.indexOf( "<nd ref=\"" )) >= 0 ) }
{ // node reference wListener.nextWay(w);
i2 += 9; return true;
int ri2 = l2.indexOf( '"', i2 ); }
long nid = Long.parseLong( l2.substring( i2, ri2 ) );
w.nodes.add( nid ); private boolean checkChangeset(String line) throws Exception {
} int idx0 = line.indexOf("<changeset id=\"");
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 ) if (idx0 < 0) return false;
{ // property-tag
i2 += 8; if (!line.endsWith("/>")) {
int ri2 = l2.indexOf( '"', i2 ); int loopcheck = 0;
String key = l2.substring( i2, ri2 ); for (; ; ) {
i2 = l2.indexOf( " v=\"", ri2 ); String l2 = _br.readLine();
if ( i2 >= 0 ) if (l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000) break;
{ }
i2 += 4; }
int ri3 = l2.indexOf( '"', i2 ); return true;
String value = l2.substring( i2, ri3 ); }
w.putTag( key, value );
} private boolean checkRelation(String line) throws Exception {
} int idx0 = line.indexOf("<relation id=\"");
else if ( l2.indexOf( "</way>" ) >= 0 ) if (idx0 < 0) return false;
{ // end-tag
break; idx0 += 14;
} int idx1 = line.indexOf('"', idx0);
} long rid = Long.parseLong(line.substring(idx0, idx1));
wListener.nextWay( w );
return true; RelationData r = new RelationData(rid);
}
// read the nodes
private boolean checkChangeset( String line ) throws Exception for (; ; ) {
{ String l2 = _br.readLine();
int idx0 = line.indexOf( "<changeset id=\"" ); if (l2 == null) return false;
if ( idx0 < 0 ) return false;
int i2;
if ( !line.endsWith( "/>" ) ) if ((i2 = l2.indexOf("<member type=\"way\" ref=\"")) >= 0) { // node reference
{ i2 += 24;
int loopcheck = 0; int ri2 = l2.indexOf('"', i2);
for(;;) long wid = Long.parseLong(l2.substring(i2, ri2));
{ r.ways.add(wid);
String l2 = _br.readLine(); } else if ((i2 = l2.indexOf("<tag k=\"")) >= 0) { // property-tag
if ( l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000 ) break; i2 += 8;
} int ri2 = l2.indexOf('"', i2);
} String key = l2.substring(i2, ri2);
return true; i2 = l2.indexOf(" v=\"", ri2);
} if (i2 >= 0) {
i2 += 4;
private boolean checkRelation( String line ) throws Exception int ri3 = l2.indexOf('"', i2);
{ String value = l2.substring(i2, ri3);
int idx0 = line.indexOf( "<relation id=\"" ); r.putTag(key, value);
if ( idx0 < 0 ) return false; }
} else if (l2.indexOf("</relation>") >= 0) { // end-tag
idx0 += 14; break;
int idx1 = line.indexOf( '"', idx0 ); }
long rid = Long.parseLong( line.substring( idx0, idx1 ) ); }
rListener.nextRelation(r);
RelationData r = new RelationData( rid ); return true;
}
// 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; import btools.util.FrozenLongMap;
public class OsmTrafficMap public class OsmTrafficMap {
{
int minLon; int minLon;
int minLat; int minLat;
int maxLon; int maxLon;
@ -38,243 +37,206 @@ public class OsmTrafficMap
private int totalChanges = 0; private int totalChanges = 0;
private int supressedChanges = 0; private int supressedChanges = 0;
private boolean doNotAdd = false; private boolean doNotAdd = false;
private boolean debug = false; private boolean debug = false;
public OsmTrafficMap( BExpressionContextWay expctxWay ) public OsmTrafficMap(BExpressionContextWay expctxWay) {
{
this.expctxWay = expctxWay; this.expctxWay = expctxWay;
debug = Boolean.getBoolean( "debugTrafficMap" ); debug = Boolean.getBoolean("debugTrafficMap");
} }
public static class OsmTrafficElement public static class OsmTrafficElement {
{
public long node2; public long node2;
public int traffic; public int traffic;
public OsmTrafficElement next; public OsmTrafficElement next;
} }
private CompactLongMap<OsmTrafficElement> map = new CompactLongMap<OsmTrafficElement>(); private CompactLongMap<OsmTrafficElement> map = new CompactLongMap<OsmTrafficElement>();
public void loadAll( File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways ) throws Exception public void loadAll(File file, int minLon, int minLat, int maxLon, int maxLat, boolean includeMotorways) throws Exception {
{ load(file, minLon, minLat, maxLon, maxLat, includeMotorways);
load( file, minLon, minLat, maxLon, maxLat, includeMotorways );
// check for old traffic data // check for old traffic data
oldTrafficFile = new File( file.getParentFile(), file.getName() + "_old" ); oldTrafficFile = new File(file.getParentFile(), file.getName() + "_old");
if ( oldTrafficFile.exists() ) if (oldTrafficFile.exists()) {
{ oldTrafficClasses = new OsmTrafficMap(null);
oldTrafficClasses = new OsmTrafficMap( null );
oldTrafficClasses.doNotAdd = true; oldTrafficClasses.doNotAdd = true;
oldTrafficClasses.load( oldTrafficFile, minLon, minLat, maxLon, maxLat, false ); oldTrafficClasses.load(oldTrafficFile, minLon, minLat, maxLon, maxLat, false);
} }
// check for old traffic data // check for old traffic data
newTrafficFile = new File( file.getParentFile(), file.getName() + "_new" ); newTrafficFile = new File(file.getParentFile(), file.getName() + "_new");
newTrafficDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( newTrafficFile ) ) ); newTrafficDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newTrafficFile)));
} }
public void finish() throws Exception public void finish() throws Exception {
{ if (newTrafficDos != null) {
if ( newTrafficDos != null )
{
newTrafficDos.close(); newTrafficDos.close();
newTrafficDos = null; newTrafficDos = null;
oldTrafficFile.delete(); oldTrafficFile.delete();
newTrafficFile.renameTo( oldTrafficFile ); newTrafficFile.renameTo(oldTrafficFile);
System.out.println( "TrafficMap: changes total=" + totalChanges + " supressed=" + supressedChanges ); 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.minLon = minLon;
this.minLat = minLat; this.minLat = minLat;
this.maxLon = maxLon; this.maxLon = maxLon;
this.maxLat = maxLat; this.maxLat = maxLat;
int trafficElements = 0; int trafficElements = 0;
DataInputStream is = new DataInputStream( new BufferedInputStream( new FileInputStream( file ) ) ); DataInputStream is = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
try try {
{ for (; ; ) {
for(;;) long n1 = is.readLong();
{ long n2 = is.readLong();
long n1 = is.readLong(); int traffic = is.readInt();
long n2 = is.readLong(); if (traffic == -1 && !includeMotorways) {
int traffic = is.readInt(); continue;
if ( traffic == -1 && !includeMotorways ) }
{ if (isInsideBounds(n1) || isInsideBounds(n2)) {
continue; if (addElement(n1, n2, traffic)) {
} trafficElements++;
if ( isInsideBounds( n1 ) || isInsideBounds( n2 ) )
{
if ( addElement( n1, n2, traffic ) )
{
trafficElements++;
}
} }
} }
} }
catch( EOFException eof ) {} } catch (EOFException eof) {
finally{ is.close(); } } finally {
is.close();
map = new FrozenLongMap<OsmTrafficElement>( map ); }
System.out.println( "read traffic-elements: " + trafficElements );
map = new FrozenLongMap<OsmTrafficElement>(map);
System.out.println("read traffic-elements: " + trafficElements);
} }
public boolean addElement( long n1, long n2, int traffic ) public boolean addElement(long n1, long n2, int traffic) {
{ OsmTrafficElement e = getElement(n1, n2);
OsmTrafficElement e = getElement( n1, n2 ); if (e == null) {
if ( e == null )
{
e = new OsmTrafficElement(); e = new OsmTrafficElement();
e.node2 = n2; e.node2 = n2;
e.traffic = traffic; e.traffic = traffic;
OsmTrafficElement e0 = map.get( n1 ); OsmTrafficElement e0 = map.get(n1);
if ( e0 != null ) if (e0 != null) {
{ while (e0.next != null) {
while( e0.next != null )
{
e0 = e0.next; e0 = e0.next;
} }
e0.next = e; e0.next = e;
} } else {
else map.fastPut(n1, e);
{
map.fastPut( n1, e );
} }
return true; return true;
} }
if ( doNotAdd ) if (doNotAdd) {
{ e.traffic = Math.max(e.traffic, traffic);
e.traffic = Math.max( e.traffic, traffic ); } else {
}
else
{
e.traffic = e.traffic == -1 || traffic == -1 ? -1 : e.traffic + traffic; e.traffic = e.traffic == -1 || traffic == -1 ? -1 : e.traffic + traffic;
} }
return false; return false;
} }
private boolean isInsideBounds( long id ) private boolean isInsideBounds(long id) {
{ int ilon = (int) (id >> 32);
int ilon = (int)(id >> 32); int ilat = (int) (id & 0xffffffff);
int ilat = (int)(id & 0xffffffff);
return ilon >= minLon && ilon < maxLon && ilat >= minLat && ilat < maxLat; 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 // 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; return e == null ? 0 : e.traffic;
} }
public int getTrafficClassForTraffic( int traffic ) public int getTrafficClassForTraffic(int traffic) {
{ if (traffic < 0) return -1;
if ( traffic < 0 ) return -1; if (traffic < 40000) return 0;
if ( traffic < 40000 ) return 0; if (traffic < 80000) return 2;
if ( traffic < 80000 ) return 2; if (traffic < 160000) return 3;
if ( traffic < 160000 ) return 3; if (traffic < 320000) return 4;
if ( traffic < 320000 ) return 4; if (traffic < 640000) return 5;
if ( traffic < 640000 ) return 5; if (traffic < 1280000) return 6;
if ( traffic <1280000 ) return 6;
return 7; return 7;
} }
private int getTraffic( long n1, long n2 ) private int getTraffic(long n1, long n2) {
{ OsmTrafficElement e1 = getElement(n1, n2);
OsmTrafficElement e1 = getElement( n1, n2 );
int traffic1 = e1 == null ? 0 : e1.traffic; int traffic1 = e1 == null ? 0 : e1.traffic;
OsmTrafficElement e2 = getElement( n2, n1 ); OsmTrafficElement e2 = getElement(n2, n1);
int traffic2 = e2 == null ? 0 : e2.traffic; int traffic2 = e2 == null ? 0 : e2.traffic;
return traffic1 == -1 || traffic2 == -1 ? -1 : traffic1 > traffic2 ? traffic1 : traffic2; return traffic1 == -1 || traffic2 == -1 ? -1 : traffic1 > traffic2 ? traffic1 : traffic2;
} }
public void freeze() public void freeze() {
{
} }
private OsmTrafficElement getElement( long n1, long n2 ) private OsmTrafficElement getElement(long n1, long n2) {
{ OsmTrafficElement e = map.get(n1);
OsmTrafficElement e = map.get( n1 ); while (e != null) {
while( e != null ) if (e.node2 == n2) {
{
if ( e.node2 == n2 )
{
return e; return e;
} }
e = e.next; e = e.next;
} }
return null; return null;
} }
public OsmTrafficElement getElement( long n ) public OsmTrafficElement getElement(long n) {
{ return map.get(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 distance = 0.;
double sum = 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 n1 = linkNodes.get(i);
OsmNodeP n2 = linkNodes.get(i+1); OsmNodeP n2 = linkNodes.get(i + 1);
int traffic = getTraffic( n1.getIdFromPos(), n2.getIdFromPos() ); int traffic = getTraffic(n1.getIdFromPos(), n2.getIdFromPos());
double dist = CheapRuler.distance( n1.ilon, n1.ilat, n2.ilon, n2.ilat ); double dist = CheapRuler.distance(n1.ilon, n1.ilat, n2.ilon, n2.ilat);
distance += dist; distance += dist;
sum += dist*traffic; sum += dist * traffic;
} }
if ( distance == 0. ) if (distance == 0.) {
{
return description; return description;
} }
int traffic = (int)(sum/distance + 0.5); int traffic = (int) (sum / distance + 0.5);
long id0 = linkNodes.get(0).getIdFromPos(); long id0 = linkNodes.get(0).getIdFromPos();
long id1 = linkNodes.get(linkNodes.size()-1).getIdFromPos(); long id1 = linkNodes.get(linkNodes.size() - 1).getIdFromPos();
int trafficClass = getTrafficClassForTraffic( traffic ); int trafficClass = getTrafficClassForTraffic(traffic);
// delta suppression: keep old traffic classes within some buffer range // delta suppression: keep old traffic classes within some buffer range
if ( oldTrafficClasses != null ) if (oldTrafficClasses != null) {
{ int oldTrafficClass = oldTrafficClasses.getTrafficClass(id0, id1);
int oldTrafficClass = oldTrafficClasses.getTrafficClass( id0, id1 ); if (oldTrafficClass != trafficClass) {
if ( oldTrafficClass != trafficClass )
{
totalChanges++; totalChanges++;
boolean supressChange = boolean supressChange =
oldTrafficClass == getTrafficClassForTraffic( (int)(traffic*1.3) ) oldTrafficClass == getTrafficClassForTraffic((int) (traffic * 1.3))
|| oldTrafficClass == getTrafficClassForTraffic( (int)(traffic*0.77) ); || oldTrafficClass == getTrafficClassForTraffic((int) (traffic * 0.77));
if ( debug ) if (debug) {
{ System.out.println("traffic class change " + oldTrafficClass + "->" + trafficClass + " supress=" + supressChange);
System.out.println( "traffic class change " + oldTrafficClass + "->" + trafficClass + " supress=" + supressChange );
} }
if ( supressChange ) if (supressChange) {
{
trafficClass = oldTrafficClass; trafficClass = oldTrafficClass;
supressedChanges++; supressedChanges++;
} }
} }
} }
if ( trafficClass > 0 ) if (trafficClass > 0) {
{ newTrafficDos.writeLong(id0);
newTrafficDos.writeLong( id0 ); newTrafficDos.writeLong(id1);
newTrafficDos.writeLong( id1 ); newTrafficDos.writeInt(trafficClass);
newTrafficDos.writeInt( trafficClass );
expctxWay.decode(description);
expctxWay.decode( description ); expctxWay.addLookupValue("estimated_traffic_class", trafficClass + 1);
expctxWay.addLookupValue( "estimated_traffic_class", trafficClass + 1 );
return expctxWay.encode(); return expctxWay.encode();
} }
return description; return description;

View File

@ -1,229 +1,194 @@
package btools.mapcreator; package btools.mapcreator;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import btools.util.CompactLongSet; import btools.util.CompactLongSet;
import btools.util.DiffCoderDataOutputStream; import btools.util.DiffCoderDataOutputStream;
import btools.util.FrozenLongSet; import btools.util.FrozenLongSet;
/** /**
* PosUnifier does 3 steps in map-processing: * PosUnifier does 3 steps in map-processing:
* * <p>
* - unify positions - add srtm elevation data - make a bordernodes file * - unify positions - add srtm elevation data - make a bordernodes file
* containing net data from the bordernids-file just containing ids * containing net data from the bordernids-file just containing ids
* *
* @author ab * @author ab
*/ */
public class PosUnifier extends MapCreatorBase public class PosUnifier extends MapCreatorBase {
{ private DiffCoderDataOutputStream nodesOutStream;
private DiffCoderDataOutputStream nodesOutStream; private DiffCoderDataOutputStream borderNodesOut;
private DiffCoderDataOutputStream borderNodesOut; private File nodeTilesOut;
private File nodeTilesOut; private CompactLongSet[] positionSets;
private CompactLongSet[] positionSets;
private HashMap<String, SrtmRaster> srtmmap;
private HashMap<String, SrtmRaster> srtmmap; private int lastSrtmLonIdx;
private int lastSrtmLonIdx; private int lastSrtmLatIdx;
private int lastSrtmLatIdx; private SrtmRaster lastSrtmRaster;
private SrtmRaster lastSrtmRaster; private String srtmdir;
private String srtmdir;
private CompactLongSet borderNids;
private CompactLongSet borderNids;
public static void main(String[] args) throws Exception {
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( "*** PosUnifier: Unify position values and enhance elevation" ); System.out.println("usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <srtm-data-dir>");
if ( args.length != 5 ) return;
{ }
System.out.println( "usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <srtm-data-dir>" ); new PosUnifier().process(new File(args[0]), new File(args[1]), new File(args[2]), new File(args[3]), args[4]);
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;
public void process( File nodeTilesIn, File nodeTilesOut, File bordernidsinfile, File bordernodesoutfile, String srtmdir ) throws Exception
{ // read border nids set
this.nodeTilesOut = nodeTilesOut; DataInputStream dis = createInStream(bordernidsinfile);
this.srtmdir = srtmdir; borderNids = new CompactLongSet();
try {
// read border nids set for (; ; ) {
DataInputStream dis = createInStream( bordernidsinfile ); long nid = readId(dis);
borderNids = new CompactLongSet(); if (!borderNids.contains(nid))
try borderNids.fastAdd(nid);
{ }
for ( ;; ) } catch (EOFException eof) {
{ dis.close();
long nid = readId( dis ); }
if ( !borderNids.contains( nid ) ) borderNids = new FrozenLongSet(borderNids);
borderNids.fastAdd( nid );
} // process all files
} borderNodesOut = createOutStream(bordernodesoutfile);
catch (EOFException eof) new NodeIterator(this, true).processDir(nodeTilesIn, ".n5d");
{ borderNodesOut.close();
dis.close(); }
}
borderNids = new FrozenLongSet( borderNids ); @Override
public void nodeFileStart(File nodefile) throws Exception {
// process all files resetSrtm();
borderNodesOut = createOutStream( bordernodesoutfile );
new NodeIterator( this, true ).processDir( nodeTilesIn, ".n5d" ); nodesOutStream = createOutStream(fileFromTemplate(nodefile, nodeTilesOut, "u5d"));
borderNodesOut.close();
} positionSets = new CompactLongSet[2500];
}
@Override
public void nodeFileStart( File nodefile ) throws Exception @Override
{ public void nextNode(NodeData n) throws Exception {
resetSrtm(); SrtmRaster srtm = srtmForNode(n.ilon, n.ilat);
n.selev = srtm == null ? Short.MIN_VALUE : srtm.getElevation(n.ilon, n.ilat);
nodesOutStream = createOutStream( fileFromTemplate( nodefile, nodeTilesOut, "u5d" ) );
findUniquePos(n);
positionSets = new CompactLongSet[2500];
} n.writeTo(nodesOutStream);
if (borderNids.contains(n.nid)) {
@Override n.writeTo(borderNodesOut);
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 ); @Override
public void nodeFileEnd(File nodeFile) throws Exception {
findUniquePos( n ); nodesOutStream.close();
}
n.writeTo( nodesOutStream );
if ( borderNids.contains( n.nid ) ) private boolean checkAdd(int lon, int lat) {
{ int slot = ((lon % 5000000) / 100000) * 50 + ((lat % 5000000) / 100000);
n.writeTo( borderNodesOut ); long id = ((long) lon) << 32 | lat;
} CompactLongSet set = positionSets[slot];
} if (set == null) {
positionSets[slot] = set = new CompactLongSet();
@Override }
public void nodeFileEnd( File nodeFile ) throws Exception if (!set.contains(id)) {
{ set.fastAdd(id);
nodesOutStream.close(); return true;
} }
return false;
private boolean checkAdd( int lon, int lat ) }
{
int slot = ((lon%5000000)/100000)*50 + ((lat%5000000)/100000);
long id = ( (long) lon ) << 32 | lat; private void findUniquePos(NodeData n) {
CompactLongSet set = positionSets[slot]; if (!checkAdd(n.ilon, n.ilat)) {
if ( set == null ) _findUniquePos(n);
{ }
positionSets[slot] = set = new CompactLongSet(); }
}
if ( !set.contains( id ) ) private void _findUniquePos(NodeData n) {
{ // fix the position for uniqueness
set.fastAdd( id ); int lonmod = n.ilon % 1000000;
return true; int londelta = lonmod < 500000 ? 1 : -1;
} int latmod = n.ilat % 1000000;
return false; 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)) {
private void findUniquePos( NodeData n ) n.ilon = lon;
{ n.ilat = lat;
if ( !checkAdd( n.ilon, n.ilat ) ) return;
{ }
_findUniquePos( n ); }
} }
} System.out.println("*** WARNING: cannot unify position for: " + n.ilon + " " + n.ilat);
}
private void _findUniquePos( NodeData n )
{ /**
// fix the position for uniqueness * get the srtm data set for a position srtm coords are
int lonmod = n.ilon % 1000000; * srtm_<srtmLon>_<srtmLat> where srtmLon = 180 + lon, srtmLat = 60 - lat
int londelta = lonmod < 500000 ? 1 : -1; */
int latmod = n.ilat % 1000000; private SrtmRaster srtmForNode(int ilon, int ilat) throws Exception {
int latdelta = latmod < 500000 ? 1 : -1; int srtmLonIdx = (ilon + 5000000) / 5000000;
for ( int latsteps = 0; latsteps < 100; latsteps++ ) int srtmLatIdx = (654999999 - ilat) / 5000000 - 100; // ugly negative rounding...
{
for ( int lonsteps = 0; lonsteps <= latsteps; lonsteps++ ) if (srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx) {
{ return lastSrtmRaster;
int lon = n.ilon + lonsteps * londelta; }
int lat = n.ilat + latsteps * latdelta; lastSrtmLonIdx = srtmLonIdx;
if ( checkAdd( lon, lat ) ) lastSrtmLatIdx = srtmLatIdx;
{
n.ilon = lon; String slonidx = "0" + srtmLonIdx;
n.ilat = lat; String slatidx = "0" + srtmLatIdx;
return; String filename = "srtm_" + slonidx.substring(slonidx.length() - 2) + "_" + slatidx.substring(slatidx.length() - 2);
}
} lastSrtmRaster = srtmmap.get(filename);
} if (lastSrtmRaster == null && !srtmmap.containsKey(filename)) {
System.out.println( "*** WARNING: cannot unify position for: " + n.ilon + " " + n.ilat ); 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);
* get the srtm data set for a position srtm coords are try {
* srtm_<srtmLon>_<srtmLat> where srtmLon = 180 + lon, srtmLat = 60 - lat InputStream isc = new BufferedInputStream(new FileInputStream(f));
*/ lastSrtmRaster = new RasterCoder().decodeRaster(isc);
private SrtmRaster srtmForNode( int ilon, int ilat ) throws Exception isc.close();
{ } catch (Exception e) {
int srtmLonIdx = ( ilon + 5000000 ) / 5000000; System.out.println("**** ERROR reading " + f + " ****");
int srtmLatIdx = ( 654999999 - ilat ) / 5000000 - 100; // ugly negative rounding... }
srtmmap.put(filename, lastSrtmRaster);
if ( srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx ) return lastSrtmRaster;
{ }
return lastSrtmRaster;
} f = new File(new File(srtmdir), filename + ".zip");
lastSrtmLonIdx = srtmLonIdx; System.out.println("reading: " + f + " ilon=" + ilon + " ilat=" + ilat);
lastSrtmLatIdx = srtmLatIdx; if (f.exists()) {
try {
String slonidx = "0" + srtmLonIdx; lastSrtmRaster = new SrtmData(f).getRaster();
String slatidx = "0" + srtmLatIdx; } catch (Exception e) {
String filename = "srtm_" + slonidx.substring( slonidx.length()-2 ) + "_" + slatidx.substring( slatidx.length()-2 ); System.out.println("**** ERROR reading " + f + " ****");
}
lastSrtmRaster = srtmmap.get( filename ); }
if ( lastSrtmRaster == null && !srtmmap.containsKey( filename ) ) srtmmap.put(filename, lastSrtmRaster);
{ }
File f = new File( new File( srtmdir ), filename + ".bef" ); return lastSrtmRaster;
System.out.println( "checking: " + f + " ilon=" + ilon + " ilat=" + ilat ); }
if ( f.exists() )
{ private void resetSrtm() {
System.out.println( "*** reading: " + f ); srtmmap = new HashMap<String, SrtmRaster>();
try lastSrtmLonIdx = -1;
{ lastSrtmLatIdx = -1;
InputStream isc = new BufferedInputStream( new FileInputStream( f ) ); lastSrtmRaster = null;
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; package btools.mapcreator;
import java.io.*; import java.io.*;
import btools.util.*; import btools.util.*;
// //
// Encode/decode a raster // Encode/decode a raster
// //
public class RasterCoder public class RasterCoder {
{ public void encodeRaster(SrtmRaster raster, OutputStream os) throws IOException {
public void encodeRaster(SrtmRaster raster, OutputStream os) throws IOException
{
DataOutputStream dos = new DataOutputStream(os); DataOutputStream dos = new DataOutputStream(os);
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
@ -29,8 +28,7 @@ public class RasterCoder
System.out.println("finished encoding in " + (t1 - t0) + " ms"); 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); DataInputStream dis = new DataInputStream(is);
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
@ -46,78 +44,65 @@ public class RasterCoder
raster.eval_array = new short[raster.ncols * raster.nrows]; raster.eval_array = new short[raster.ncols * raster.nrows];
_decodeRaster(raster, is); _decodeRaster(raster, is);
raster.usingWeights = raster.ncols > 6001; raster.usingWeights = raster.ncols > 6001;
long t1 = System.currentTimeMillis(); 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; 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); MixCoderDataOutputStream mco = new MixCoderDataOutputStream(os);
int nrows = raster.nrows; int nrows = raster.nrows;
int ncols = raster.ncols; int ncols = raster.ncols;
short[] pixels = raster.eval_array; short[] pixels = raster.eval_array;
int colstep = raster.halfcol ? 2 : 1; 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 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]; short val = pixels[row * ncols + col];
if ( val == -32766 ) if (val == -32766) {
{
val = lastval; // replace remaining (border) skips val = lastval; // replace remaining (border) skips
} } else {
else
{
lastval = val; lastval = val;
} }
// remap nodata // remap nodata
int code = val == Short.MIN_VALUE ? -1 : ( val < 0 ? val-1 : val ); int code = val == Short.MIN_VALUE ? -1 : (val < 0 ? val - 1 : val);
mco.writeMixed( code ); mco.writeMixed(code);
} }
} }
mco.flush(); 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); MixCoderDataInputStream mci = new MixCoderDataInputStream(is);
int nrows = raster.nrows; int nrows = raster.nrows;
int ncols = raster.ncols; int ncols = raster.ncols;
short[] pixels = raster.eval_array; short[] pixels = raster.eval_array;
int colstep = raster.halfcol ? 2 : 1; int colstep = raster.halfcol ? 2 : 1;
for (int row = 0; row < nrows; row++) for (int row = 0; row < nrows; row++) {
{ for (int col = 0; col < ncols; col += colstep) {
for (int col = 0; col < ncols; col += colstep )
{
int code = mci.readMixed(); int code = mci.readMixed();
// remap nodata // remap nodata
int v30 = code == -1 ? Short.MIN_VALUE : ( code < 0 ? code + 1 : code ); int v30 = code == -1 ? Short.MIN_VALUE : (code < 0 ? code + 1 : code);
if ( raster.usingWeights && v30 > -32766 ) if (raster.usingWeights && v30 > -32766) {
{
v30 *= 2; v30 *= 2;
} }
pixels[row * ncols + col] = (short) ( v30 ); pixels[row * ncols + col] = (short) (v30);
} }
if ( raster.halfcol ) if (raster.halfcol) {
{ for (int col = 1; col < ncols - 1; col += colstep) {
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];
int l = (int)pixels[row * ncols + col - 1];
int r = (int)pixels[row * ncols + col + 1];
short v30 = Short.MIN_VALUE; // nodata short v30 = Short.MIN_VALUE; // nodata
if ( l > -32766 && r > -32766 ) if (l > -32766 && r > -32766) {
{ v30 = (short) ((l + r) / 2);
v30 = (short)((l+r)/2);
} }
pixels[row * ncols + col] = v30; pixels[row * ncols + col] = v30;
} }

View File

@ -1,27 +1,24 @@
package btools.mapcreator; package btools.mapcreator;
import btools.util.LongList; import btools.util.LongList;
/** /**
* Container for relation data on the preprocessor level * Container for relation data on the preprocessor level
* *
* @author ab * @author ab
*/ */
public class RelationData extends MapCreatorBase public class RelationData extends MapCreatorBase {
{ public long rid;
public long rid; public long description;
public long description; public LongList ways;
public LongList ways;
public RelationData(long id) {
public RelationData( long id ) rid = id;
{ ways = new LongList(16);
rid = id; }
ways = new LongList( 16 );
} public RelationData(long id, LongList ways) {
rid = id;
public RelationData( long id, LongList ways ) this.ways = ways;
{ }
rid = id; }
this.ways = ways;
}
}

View File

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

View File

@ -10,63 +10,52 @@ import btools.util.TinyDenseLongMap;
/** /**
* WayCutter does 2 step in map-processing: * WayCutter does 2 step in map-processing:
* * <p>
* - cut the way file into 45*30 - pieces * - cut the way file into 45*30 - pieces
* - enrich ways with relation information * - enrich ways with relation information
* *
* @author ab * @author ab
*/ */
public class RelationStatistics extends MapCreatorBase public class RelationStatistics extends MapCreatorBase {
{ public static void main(String[] args) throws Exception {
public static void main(String[] args) throws Exception
{
System.out.println("*** RelationStatistics: count relation networks"); System.out.println("*** RelationStatistics: count relation networks");
if (args.length != 1) if (args.length != 1) {
{ System.out.println("usage: java WayCutter <relation-file>");
System.out.println("usage: java WayCutter <relation-file>" );
return; return;
} }
new RelationStatistics().process( new File( args[0] ) ); new RelationStatistics().process(new File(args[0]));
} }
public void process( File relationFileIn ) throws Exception public void process(File relationFileIn) throws Exception {
{ HashMap<String, long[]> relstats = new HashMap<String, long[]>();
HashMap<String,long[]> relstats = new HashMap<String,long[]>();
DataInputStream dis = createInStream(relationFileIn);
DataInputStream dis = createInStream( relationFileIn ); try {
try for (; ; ) {
{ long rid = readId(dis);
for(;;)
{
long rid = readId( dis );
String network = dis.readUTF(); String network = dis.readUTF();
int waycount = 0; int waycount = 0;
for(;;) for (; ; ) {
{ long wid = readId(dis);
long wid = readId( dis ); if (wid == -1) break;
if ( wid == -1 ) break;
waycount++; waycount++;
} }
long[] stat = relstats.get( network ); long[] stat = relstats.get(network);
if ( stat == null ) if (stat == null) {
{
stat = new long[2]; stat = new long[2];
relstats.put( network, stat ); relstats.put(network, stat);
} }
stat[0]++; stat[0]++;
stat[1] += waycount; stat[1] += waycount;
} }
} } catch (EOFException eof) {
catch( EOFException eof )
{
dis.close(); dis.close();
} }
for( String network : relstats.keySet() ) for (String network : relstats.keySet()) {
{ long[] stat = relstats.get(network);
long[] stat = relstats.get( network ); System.out.println("network: " + network + " has " + stat[0] + " relations with " + stat[1] + " ways");
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 * RestrictionCutter writes Restrictions to tiles
* * <p>
* - cut the way file into 45*30 - pieces * - cut the way file into 45*30 - pieces
* - enrich ways with relation information * - enrich ways with relation information
* *
* @author ab * @author ab
*/ */
public class RestrictionCutter extends MapCreatorBase public class RestrictionCutter extends MapCreatorBase {
{
private WayCutter wayCutter; private WayCutter wayCutter;
public void init( File outTileDir, WayCutter wayCutter ) throws Exception public void init(File outTileDir, WayCutter wayCutter) throws Exception {
{
outTileDir.mkdir(); outTileDir.mkdir();
this.outTileDir = outTileDir; this.outTileDir = outTileDir;
this.wayCutter = wayCutter; this.wayCutter = wayCutter;
} }
public void finish() throws Exception public void finish() throws Exception {
{
closeTileOutStreams(); closeTileOutStreams();
} }
public void nextRestriction( RestrictionData data ) throws Exception public void nextRestriction(RestrictionData data) throws Exception {
{ int tileIndex = wayCutter.getTileIndexForNid(data.viaNid);
int tileIndex = wayCutter.getTileIndexForNid( data.viaNid ); if (tileIndex != -1) {
if ( tileIndex != -1 ) data.writeTo(getOutStreamForTile(tileIndex));
{
data.writeTo( getOutStreamForTile( tileIndex ) );
} }
} }
protected String getNameForTile( int tileIndex ) protected String getNameForTile(int tileIndex) {
{ String name = wayCutter.getNameForTile(tileIndex);
String name = wayCutter.getNameForTile( tileIndex ); return name.substring(0, name.length() - 3) + "rtl";
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: * RestrictionCutter5 does 1 step in map-processing:
* * <p>
* - cut the 45*30 restriction files into 5*5 pieces * - cut the 45*30 restriction files into 5*5 pieces
* *
* @author ab * @author ab
*/ */
public class RestrictionCutter5 extends MapCreatorBase public class RestrictionCutter5 extends MapCreatorBase {
{
private WayCutter5 wayCutter5; private WayCutter5 wayCutter5;
public void init( File outTileDir, WayCutter5 wayCutter5 ) throws Exception public void init(File outTileDir, WayCutter5 wayCutter5) throws Exception {
{
outTileDir.mkdir(); outTileDir.mkdir();
this.outTileDir = outTileDir; this.outTileDir = outTileDir;
this.wayCutter5 = wayCutter5; this.wayCutter5 = wayCutter5;
} }
public void finish() throws Exception public void finish() throws Exception {
{
closeTileOutStreams(); closeTileOutStreams();
} }
public void nextRestriction( RestrictionData data ) throws Exception public void nextRestriction(RestrictionData data) throws Exception {
{ int tileIndex = wayCutter5.getTileIndexForNid(data.viaNid);
int tileIndex = wayCutter5.getTileIndexForNid( data.viaNid ); if (tileIndex != -1) {
if ( tileIndex != -1 ) data.writeTo(getOutStreamForTile(tileIndex));
{
data.writeTo( getOutStreamForTile( tileIndex ) );
} }
} }
protected String getNameForTile( int tileIndex ) protected String getNameForTile(int tileIndex) {
{ String name = wayCutter5.getNameForTile(tileIndex);
String name = wayCutter5.getNameForTile( tileIndex ); return name.substring(0, name.length() - 3) + "rt5";
return name.substring( 0, name.length()-3 ) + "rt5";
} }
} }

View File

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

View File

@ -1,195 +1,166 @@
package btools.mapcreator; package btools.mapcreator;
/** /**
* This is a wrapper for a 5*5 degree srtm file in ascii/zip-format * 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 * - filter out unused nodes according to the way file
* - enhance with SRTM elevation data * - enhance with SRTM elevation data
* - split further in smaller (5*5 degree) tiles * - split further in smaller (5*5 degree) tiles
* *
* @author ab * @author ab
*/ */
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
public class SrtmData public class SrtmData {
{ private SrtmRaster raster;
private SrtmRaster raster;
public SrtmData(File file) throws Exception {
public SrtmData( File file ) throws Exception raster = new SrtmRaster();
{
raster = new SrtmRaster(); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
try {
ZipInputStream zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( file ) ) ); for (; ; ) {
try ZipEntry ze = zis.getNextEntry();
{ if (ze.getName().endsWith(".asc")) {
for ( ;; ) readFromStream(zis);
{ return;
ZipEntry ze = zis.getNextEntry(); }
if ( ze.getName().endsWith( ".asc" ) ) }
{ } finally {
readFromStream( zis ); zis.close();
return; }
} }
}
} public SrtmRaster getRaster() {
finally return raster;
{ }
zis.close();
} private String secondToken(String s) {
} StringTokenizer tk = new StringTokenizer(s, " ");
tk.nextToken();
public SrtmRaster getRaster() return tk.nextToken();
{ }
return raster;
} public void readFromStream(InputStream is) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
private String secondToken( String s ) int linenr = 0;
{ for (; ; ) {
StringTokenizer tk = new StringTokenizer( s, " " ); linenr++;
tk.nextToken(); if (linenr <= 6) {
return tk.nextToken(); String line = br.readLine();
} if (linenr == 1)
raster.ncols = Integer.parseInt(secondToken(line));
public void readFromStream( InputStream is ) throws Exception else if (linenr == 2)
{ raster.nrows = Integer.parseInt(secondToken(line));
BufferedReader br = new BufferedReader( new InputStreamReader( is ) ); else if (linenr == 3)
int linenr = 0; raster.xllcorner = Double.parseDouble(secondToken(line));
for ( ;; ) else if (linenr == 4)
{ raster.yllcorner = Double.parseDouble(secondToken(line));
linenr++; else if (linenr == 5)
if ( linenr <= 6 ) raster.cellsize = Double.parseDouble(secondToken(line));
{ else if (linenr == 6) {
String line = br.readLine(); // nodata ignored here ( < -250 assumed nodata... )
if ( linenr == 1 ) // raster.noDataValue = Short.parseShort( secondToken( line ) );
raster.ncols = Integer.parseInt( secondToken( line ) ); raster.eval_array = new short[raster.ncols * raster.nrows];
else if ( linenr == 2 ) }
raster.nrows = Integer.parseInt( secondToken( line ) ); } else {
else if ( linenr == 3 ) int row = 0;
raster.xllcorner = Double.parseDouble( secondToken( line ) ); int col = 0;
else if ( linenr == 4 ) int n = 0;
raster.yllcorner = Double.parseDouble( secondToken( line ) ); boolean negative = false;
else if ( linenr == 5 ) for (; ; ) {
raster.cellsize = Double.parseDouble( secondToken( line ) ); int c = br.read();
else if ( linenr == 6 ) if (c < 0)
{ break;
// nodata ignored here ( < -250 assumed nodata... ) if (c == ' ') {
// raster.noDataValue = Short.parseShort( secondToken( line ) ); if (negative)
raster.eval_array = new short[raster.ncols * raster.nrows]; n = -n;
} short val = n < -250 ? Short.MIN_VALUE : (short) (n);
}
else raster.eval_array[row * raster.ncols + col] = val;
{ if (++col == raster.ncols) {
int row = 0; col = 0;
int col = 0; ++row;
int n = 0; }
boolean negative = false; n = 0;
for ( ;; ) negative = false;
{ } else if (c >= '0' && c <= '9') {
int c = br.read(); n = 10 * n + (c - '0');
if ( c < 0 ) } else if (c == '-') {
break; negative = true;
if ( c == ' ' ) }
{ }
if ( negative ) break;
n = -n; }
short val = n < -250 ? Short.MIN_VALUE : (short) (n); }
br.close();
raster.eval_array[row * raster.ncols + col] = val; }
if ( ++col == raster.ncols )
{ public static void main(String[] args) throws Exception {
col = 0; String fromDir = args[0];
++row; String toDir = args[1];
}
n = 0; File[] files = new File(fromDir).listFiles();
negative = false; for (File f : files) {
} if (!f.getName().endsWith(".zip")) {
else if ( c >= '0' && c <= '9' ) continue;
{ }
n = 10 * n + ( c - '0' ); System.out.println("*** reading: " + f);
} long t0 = System.currentTimeMillis();
else if ( c == '-' ) SrtmRaster raster = new SrtmData(f).getRaster();
{ long t1 = System.currentTimeMillis();
negative = true; String name = f.getName();
}
} long zipTime = t1 - t0;
break;
} File fbef = new File(new File(toDir), name.substring(0, name.length() - 3) + "bef");
} System.out.println("recoding: " + f + " to " + fbef);
br.close(); OutputStream osbef = new BufferedOutputStream(new FileOutputStream(fbef));
} new RasterCoder().encodeRaster(raster, osbef);
osbef.close();
public static void main( String[] args ) throws Exception
{ System.out.println("*** re-reading: " + fbef);
String fromDir = args[0];
String toDir = args[1]; long t2 = System.currentTimeMillis();
InputStream isc = new BufferedInputStream(new FileInputStream(fbef));
File[] files = new File( fromDir ).listFiles(); SrtmRaster raster2 = new RasterCoder().decodeRaster(isc);
for( File f : files ) isc.close();
{ long t3 = System.currentTimeMillis();
if ( !f.getName().endsWith( ".zip" ) )
{ long befTime = t3 - t2;
continue;
} System.out.println("*** zip-time: " + zipTime + "*** bef-time: " + befTime);
System.out.println( "*** reading: " + f );
long t0 = System.currentTimeMillis(); String s1 = raster.toString();
SrtmRaster raster = new SrtmData( f ).getRaster(); String s2 = raster2.toString();
long t1 = System.currentTimeMillis();
String name = f.getName(); if (!s1.equals(s2)) {
throw new IllegalArgumentException("missmatch: " + s1 + "<--->" + s2);
long zipTime = t1-t0; }
File fbef = new File( new File( toDir ), name.substring( 0, name.length()-3 ) + "bef" ); int cols = raster.ncols;
System.out.println( "recoding: " + f + " to " + fbef ); int rows = raster.nrows;
OutputStream osbef = new BufferedOutputStream( new FileOutputStream( fbef ) ); for (int c = 0; c < cols; c++) {
new RasterCoder().encodeRaster( raster, osbef ); for (int r = 0; r < rows; r++) {
osbef.close(); int idx = r * cols + c;
System.out.println( "*** re-reading: " + fbef ); if (raster.eval_array[idx] != raster2.eval_array[idx]) {
throw new IllegalArgumentException("missmatch: at " + c + "," + r + ": " + raster.eval_array[idx] + "<--->" + raster2.eval_array[idx]);
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 * @author ab
*/ */
public class SrtmRaster public class SrtmRaster {
{
public int ncols; public int ncols;
public int nrows; public int nrows;
public boolean halfcol; public boolean halfcol;
@ -22,99 +21,93 @@ public class SrtmRaster
private boolean missingData = false; private boolean missingData = false;
public short getElevation( int ilon, int ilat ) public short getElevation(int ilon, int ilat) {
{
double lon = ilon / 1000000. - 180.; double lon = ilon / 1000000. - 180.;
double lat = ilat / 1000000. - 90.; double lat = ilat / 1000000. - 90.;
if ( usingWeights ) if (usingWeights) {
{ return getElevationFromShiftWeights(lon, lat);
return getElevationFromShiftWeights( lon, lat );
} }
// no weights calculated, use 2d linear interpolation // no weights calculated, use 2d linear interpolation
double dcol = (lon - xllcorner)/cellsize -0.5; double dcol = (lon - xllcorner) / cellsize - 0.5;
double drow = (lat - yllcorner)/cellsize -0.5; double drow = (lat - yllcorner) / cellsize - 0.5;
int row = (int)drow; int row = (int) drow;
int col = (int)dcol; int col = (int) dcol;
if ( col < 0 ) col = 0; if (col < 0) col = 0;
if ( col >= ncols-1 ) col = ncols - 2; if (col >= ncols - 1) col = ncols - 2;
if ( row < 0 ) row = 0; if (row < 0) row = 0;
if ( row >= nrows-1 ) row = nrows - 2; if (row >= nrows - 1) row = nrows - 2;
double wrow = drow-row; double wrow = drow - row;
double wcol = dcol-col; double wcol = dcol - col;
missingData = false; missingData = false;
// System.out.println( "wrow=" + wrow + " wcol=" + wcol + " row=" + row + " col=" + col ); // System.out.println( "wrow=" + wrow + " wcol=" + wcol + " row=" + row + " col=" + col );
double eval = (1.-wrow)*(1.-wcol)*get(row ,col ) double eval = (1. - wrow) * (1. - wcol) * get(row, col)
+ ( wrow)*(1.-wcol)*get(row+1,col ) + (wrow) * (1. - wcol) * get(row + 1, col)
+ (1.-wrow)*( wcol)*get(row ,col+1) + (1. - wrow) * (wcol) * get(row, col + 1)
+ ( wrow)*( wcol)*get(row+1,col+1); + (wrow) * (wcol) * get(row + 1, col + 1);
// System.out.println( "eval=" + eval ); // 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 ) private short get(int r, int c) {
{ short e = eval_array[(nrows - 1 - r) * ncols + c];
short e = eval_array[ (nrows-1-r)*ncols + c ]; if (e == Short.MIN_VALUE) missingData = true;
if ( e == Short.MIN_VALUE ) missingData = true;
return e; return e;
} }
private short getElevationFromShiftWeights( double lon, double lat ) private short getElevationFromShiftWeights(double lon, double lat) {
{
// calc lat-idx and -weight // calc lat-idx and -weight
double alat = lat < 0. ? - lat : lat; double alat = lat < 0. ? -lat : lat;
alat /= 5.; alat /= 5.;
int latIdx = (int)alat; int latIdx = (int) alat;
double wlat = alat - latIdx; double wlat = alat - latIdx;
double dcol = (lon - xllcorner)/cellsize; double dcol = (lon - xllcorner) / cellsize;
double drow = (lat - yllcorner)/cellsize; double drow = (lat - yllcorner) / cellsize;
int row = (int)drow; int row = (int) drow;
int col = (int)dcol; int col = (int) dcol;
double dgx = (dcol-col)*gridSteps; double dgx = (dcol - col) * gridSteps;
double dgy = (drow-row)*gridSteps; double dgy = (drow - row) * gridSteps;
// System.out.println( "wrow=" + wrow + " wcol=" + wcol + " row=" + row + " col=" + col ); // System.out.println( "wrow=" + wrow + " wcol=" + wcol + " row=" + row + " col=" + col );
int gx = (int)(dgx); int gx = (int) (dgx);
int gy = (int)(dgy); int gy = (int) (dgy);
double wx = dgx-gx; double wx = dgx - gx;
double wy = dgy-gy; double wy = dgy - gy;
double w00 = (1.-wx)*(1.-wy); double w00 = (1. - wx) * (1. - wy);
double w01 = (1.-wx)*( wy); double w01 = (1. - wx) * (wy);
double w10 = ( wx)*(1.-wy); double w10 = (wx) * (1. - wy);
double w11 = ( wx)*( wy); double w11 = (wx) * (wy);
Weights[][] w0 = getWeights( latIdx ); Weights[][] w0 = getWeights(latIdx);
Weights[][] w1 = getWeights( latIdx+1 ); Weights[][] w1 = getWeights(latIdx + 1);
missingData = false; missingData = false;
double m0 = w00*getElevation( w0[gx ][gy ], row, col ) double m0 = w00 * getElevation(w0[gx][gy], row, col)
+ w01*getElevation( w0[gx ][gy+1], row, col ) + w01 * getElevation(w0[gx][gy + 1], row, col)
+ w10*getElevation( w0[gx+1][gy ], row, col ) + w10 * getElevation(w0[gx + 1][gy], row, col)
+ w11*getElevation( w0[gx+1][gy+1], row, col ); + w11 * getElevation(w0[gx + 1][gy + 1], row, col);
double m1 = w00*getElevation( w1[gx ][gy ], row, col ) double m1 = w00 * getElevation(w1[gx][gy], row, col)
+ w01*getElevation( w1[gx ][gy+1], row, col ) + w01 * getElevation(w1[gx][gy + 1], row, col)
+ w10*getElevation( w1[gx+1][gy ], row, col ) + w10 * getElevation(w1[gx + 1][gy], row, col)
+ w11*getElevation( w1[gx+1][gy+1], row, col ); + w11 * getElevation(w1[gx + 1][gy + 1], row, col);
if ( missingData ) return Short.MIN_VALUE; if (missingData) return Short.MIN_VALUE;
double m = (1.-wlat) * m0 + wlat * m1; double m = (1. - wlat) * m0 + wlat * m1;
return (short)(m * 2); 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 ) private double getElevation(Weights w, int row, int col) {
{ if (missingData) {
if ( missingData )
{
return 0.; return 0.;
} }
int nx = w.nx; int nx = w.nx;
@ -126,64 +119,53 @@ public class SrtmRaster
rmf.reset(); rmf.reset();
for( int ix = 0; ix < nx; ix ++ ) for (int ix = 0; ix < nx; ix++) {
{ for (int iy = 0; iy < ny; iy++) {
for( int iy = 0; iy < ny; iy ++ ) short val = get(row + iy - my, col + ix - mx);
{ rmf.addSample(w.getWeight(ix, iy), val);
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 nx;
int ny; int ny;
double[] weights; double[] weights;
long total = 0; long total = 0;
Weights( int nx, int ny ) Weights(int nx, int ny) {
{
this.nx = nx; this.nx = nx;
this.ny = ny; this.ny = ny;
weights = new double[nx*ny]; weights = new double[nx * ny];
} }
void inc( int ix, int iy ) void inc(int ix, int iy) {
{ weights[iy * nx + ix] += 1.;
weights[ iy*nx + ix ] += 1.;
total++; total++;
} }
void normalize( boolean verbose ) void normalize(boolean verbose) {
{ for (int iy = 0; iy < ny; iy++) {
for( int iy =0; iy < ny; iy++ )
{
StringBuilder sb = verbose ? new StringBuilder() : null; StringBuilder sb = verbose ? new StringBuilder() : null;
for( int ix =0; ix < nx; ix++ ) for (int ix = 0; ix < nx; ix++) {
{ weights[iy * nx + ix] /= total;
weights[ iy*nx + ix ] /= total; if (sb != null) {
if ( sb != null ) int iweight = (int) (1000 * weights[iy * nx + ix] + 0.5);
{
int iweight = (int)(1000*weights[ iy*nx + ix ] + 0.5 );
String sval = " " + iweight; String sval = " " + iweight;
sb.append( sval.substring( sval.length() - 4 ) ); sb.append(sval.substring(sval.length() - 4));
} }
} }
if ( sb != null ) if (sb != null) {
{ System.out.println(sb);
System.out.println( sb );
System.out.println(); System.out.println();
} }
} }
} }
double getWeight( int ix, int iy ) double getWeight(int ix, int iy) {
{ return weights[iy * nx + ix];
return weights[ iy*nx + ix ];
} }
} }
@ -193,19 +175,16 @@ public class SrtmRaster
private static double filterCenterFraction = 0.2; private static double filterCenterFraction = 0.2;
private static double filterDiscRadius = 4.999; // in pixels private static double filterDiscRadius = 4.999; // in pixels
static static {
{ String sRadius = System.getProperty("filterDiscRadius");
String sRadius = System.getProperty( "filterDiscRadius" ); if (sRadius != null && sRadius.length() > 0) {
if ( sRadius != null && sRadius.length() > 0 ) filterDiscRadius = Integer.parseInt(sRadius);
{ System.out.println("using filterDiscRadius = " + filterDiscRadius);
filterDiscRadius = Integer.parseInt( sRadius );
System.out.println( "using filterDiscRadius = " + filterDiscRadius );
} }
String sFraction = System.getProperty( "filterCenterFraction" ); String sFraction = System.getProperty("filterCenterFraction");
if ( sFraction != null && sFraction.length() > 0 ) if (sFraction != null && sFraction.length() > 0) {
{ filterCenterFraction = Integer.parseInt(sFraction) / 100.;
filterCenterFraction = Integer.parseInt( sFraction ) / 100.; System.out.println("using filterCenterFraction = " + filterCenterFraction);
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 // calculate interpolation weights from the overlap of a probe disc of given radius at given latitude
// ( latIndex = 0 -> 0 deg, latIndex = 16 -> 80 degree) // ( 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; int idx = latIndex < 16 ? latIndex : 16;
Weights[][] res = allShiftWeights[idx]; Weights[][] res = allShiftWeights[idx];
if ( res == null ) if (res == null) {
{ res = calcWeights(idx);
res = calcWeights( idx );
allShiftWeights[idx] = res; allShiftWeights[idx] = res;
} }
return res; return res;
} }
private static Weights[][] calcWeights( int latIndex ) private static Weights[][] calcWeights(int latIndex) {
{ double coslat = Math.cos(latIndex * 5. / 57.3);
double coslat = Math.cos( latIndex * 5. / 57.3 );
// radius in pixel units // radius in pixel units
double ry = filterDiscRadius; double ry = filterDiscRadius;
double rx = ry / coslat; double rx = ry / coslat;
// gridsize is 2*radius + 1 cell // gridsize is 2*radius + 1 cell
int nx = ((int)rx) *2 + 3; int nx = ((int) rx) * 2 + 3;
int ny = ((int)ry) *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 mx = nx / 2; // mean pixels
int my = ny / 2; int my = ny / 2;
// create a matrix for the relative intergrid-position // create a matrix for the relative intergrid-position
Weights[][] shiftWeights = new Weights[gridSteps+1][]; Weights[][] shiftWeights = new Weights[gridSteps + 1][];
// loop the intergrid-position // loop the intergrid-position
for( int gx=0; gx<=gridSteps; gx++ ) for (int gx = 0; gx <= gridSteps; gx++) {
{ shiftWeights[gx] = new Weights[gridSteps + 1];
shiftWeights[gx] = new Weights[gridSteps+1]; double x0 = mx + ((double) gx) / gridSteps;
double x0 = mx + ( (double)gx ) / gridSteps;
for( int gy=0; gy<=gridSteps; gy++ ) for (int gy = 0; gy <= gridSteps; gy++) {
{ double y0 = my + ((double) gy) / gridSteps;
double y0 = my + ( (double)gy ) / gridSteps;
// create the weight-matrix // create the weight-matrix
Weights weights = new Weights( nx, ny ); Weights weights = new Weights(nx, ny);
shiftWeights[gx][gy] = weights; shiftWeights[gx][gy] = weights;
double sampleStep = 0.001; double sampleStep = 0.001;
for( double x = -1. + sampleStep/2.; x < 1.; x += sampleStep ) for (double x = -1. + sampleStep / 2.; x < 1.; x += sampleStep) {
{ double mx2 = 1. - x * x;
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 ) for (double y = -1. + sampleStep / 2.; y < 1.; y += sampleStep) {
{ if (y * y > mx2) {
if ( y*y > mx2 )
{
continue; continue;
} }
// we are in the ellipse, see what pixel we are on // we are in the ellipse, see what pixel we are on
int y_idx = (int)(y0 + y*ry); int y_idx = (int) (y0 + y * ry);
weights.inc( x_idx, y_idx ); weights.inc(x_idx, y_idx);
} }
} }
weights.normalize( true ); weights.normalize(true);
} }
} }
return shiftWeights; return shiftWeights;
} }
@Override @Override
public String toString() public String toString() {
{
return ncols + "," + nrows + "," + halfcol + "," + xllcorner + "," + yllcorner + "," + cellsize + "," + noDataValue + "," + usingWeights; return ncols + "," + nrows + "," + halfcol + "," + xllcorner + "," + yllcorner + "," + cellsize + "," + noDataValue + "," + usingWeights;
} }
} }

View File

@ -1,112 +1,98 @@
package btools.mapcreator; package btools.mapcreator;
import java.io.File; import java.io.File;
import btools.util.DenseLongMap; import btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap; import btools.util.TinyDenseLongMap;
/** /**
* WayCutter does 2 step in map-processing: * WayCutter does 2 step in map-processing:
* * <p>
* - cut the way file into 45*30 - pieces * - cut the way file into 45*30 - pieces
* - enrich ways with relation information * - enrich ways with relation information
* *
* @author ab * @author ab
*/ */
public class WayCutter extends MapCreatorBase public class WayCutter extends MapCreatorBase {
{ private DenseLongMap tileIndexMap;
private DenseLongMap tileIndexMap;
public static void main(String[] args) throws Exception {
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("*** WayCutter: Soft-Cut way-data into tiles"); System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out>");
if (args.length != 3)
{ return;
System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out>" ); }
new WayCutter().process(new File(args[0]), new File(args[1]), new File(args[2]));
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);
public void process( File nodeTilesIn, File wayFileIn, File wayTilesOut ) throws Exception new NodeIterator(this, false).processDir(nodeTilesIn, ".tlf");
{
init( wayTilesOut ); // *** finally process the way-file, cutting into pieces
new WayIterator(this, true).processFile(wayFileIn);
new NodeIterator( this, false ).processDir( nodeTilesIn, ".tlf" ); finish();
}
// *** finally process the way-file, cutting into pieces
new WayIterator( this, true ).processFile( wayFileIn ); public void init(File wayTilesOut) throws Exception {
finish(); this.outTileDir = wayTilesOut;
}
// *** read all nodes into tileIndexMap
public void init( File wayTilesOut ) throws Exception tileIndexMap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap() : new TinyDenseLongMap();
{ }
this.outTileDir = wayTilesOut;
public void finish() throws Exception {
// *** read all nodes into tileIndexMap closeTileOutStreams();
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap(); }
}
@Override
public void finish() throws Exception public void nextNode(NodeData n) throws Exception {
{ tileIndexMap.put(n.nid, getTileIndex(n.ilon, n.ilat));
closeTileOutStreams(); }
}
@Override
@Override public void nextWay(WayData data) throws Exception {
public void nextNode( NodeData n ) throws Exception long waytileset = 0;
{ int nnodes = data.nodes.size();
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) );
} // determine the tile-index for each node
for (int i = 0; i < nnodes; i++) {
@Override int tileIndex = tileIndexMap.getInt(data.nodes.get(i));
public void nextWay( WayData data ) throws Exception if (tileIndex != -1) {
{ waytileset |= (1L << tileIndex);
long waytileset = 0; }
int nnodes = data.nodes.size(); }
// determine the tile-index for each node // now write way to all tiles hit
for (int i=0; i<nnodes; i++ ) for (int tileIndex = 0; tileIndex < 54; tileIndex++) {
{ if ((waytileset & (1L << tileIndex)) == 0) {
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) ); continue;
if ( tileIndex != -1 ) }
{ data.writeTo(getOutStreamForTile(tileIndex));
waytileset |= ( 1L << tileIndex ); }
} }
}
// now write way to all tiles hit public int getTileIndexForNid(long nid) {
for( int tileIndex=0; tileIndex<54; tileIndex++ ) return tileIndexMap.getInt(nid);
{ }
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{ private int getTileIndex(int ilon, int ilat) {
continue; int lon = ilon / 45000000;
} int lat = ilat / 30000000;
data.writeTo( getOutStreamForTile( tileIndex ) ); if (lon < 0 || lon > 7 || lat < 0 || lat > 5)
} throw new IllegalArgumentException("illegal pos: " + ilon + "," + ilat);
} return lon * 6 + lat;
}
public int getTileIndexForNid( long nid ) public String getNameForTile(int tileIndex) {
{ int lon = (tileIndex / 6) * 45 - 180;
return tileIndexMap.getInt( nid ); int lat = (tileIndex % 6) * 30 - 90;
} String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
private int getTileIndex( int ilon, int ilat ) return slon + "_" + slat + ".wtl";
{ }
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; package btools.mapcreator;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.EOFException; import java.io.EOFException;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import btools.util.DenseLongMap; import btools.util.DenseLongMap;
import btools.util.TinyDenseLongMap; import btools.util.TinyDenseLongMap;
/** /**
* WayCutter5 does 2 step in map-processing: * WayCutter5 does 2 step in map-processing:
* * <p>
* - cut the 45*30 way files into 5*5 pieces * - cut the 45*30 way files into 5*5 pieces
* - create a file containing all border node ids * - create a file containing all border node ids
* *
* @author ab * @author ab
*/ */
public class WayCutter5 extends MapCreatorBase public class WayCutter5 extends MapCreatorBase {
{ private DataOutputStream borderNidsOutStream;
private DataOutputStream borderNidsOutStream; private DenseLongMap tileIndexMap;
private DenseLongMap tileIndexMap; private File nodeTilesIn;
private File nodeTilesIn; private int lonoffset;
private int lonoffset; private int latoffset;
private int latoffset;
public RelationMerger relMerger;
public RelationMerger relMerger; public NodeFilter nodeFilter;
public NodeFilter nodeFilter; public NodeCutter nodeCutter;
public NodeCutter nodeCutter; public RestrictionCutter5 restrictionCutter5;
public RestrictionCutter5 restrictionCutter5;
public static void main(String[] args) throws Exception {
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("*** WayCutter5: Soft-Cut way-data into tiles"); System.out.println("usage: java WayCutter5 <node-tiles-in> <way-tiles-in> <way-tiles-out> <border-nids-out>");
if (args.length != 4) return;
{ }
System.out.println("usage: java WayCutter5 <node-tiles-in> <way-tiles-in> <way-tiles-out> <border-nids-out>" ); new WayCutter5().process(new File(args[0]), new File(args[1]), new File(args[2]), new File(args[3]));
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;
public void process( File nodeTilesIn, File wayTilesIn, File wayTilesOut, File borderNidsOut ) throws Exception
{ borderNidsOutStream = createOutStream(borderNidsOut);
this.nodeTilesIn = nodeTilesIn;
this.outTileDir = wayTilesOut; new WayIterator(this, true).processDir(wayTilesIn, ".wtl");
borderNidsOutStream = createOutStream( borderNidsOut ); borderNidsOutStream.close();
}
new WayIterator( this, true ).processDir( wayTilesIn, ".wtl" );
@Override
borderNidsOutStream.close(); public boolean wayFileStart(File wayfile) throws Exception {
} // read corresponding node-file into tileIndexMap
String name = wayfile.getName();
@Override String nodefilename = name.substring(0, name.length() - 3) + "ntl";
public boolean wayFileStart( File wayfile ) throws Exception File nodefile = new File(nodeTilesIn, nodefilename);
{
// read corresponding node-file into tileIndexMap tileIndexMap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap() : new TinyDenseLongMap();
String name = wayfile.getName(); lonoffset = -1;
String nodefilename = name.substring( 0, name.length()-3 ) + "ntl"; latoffset = -1;
File nodefile = new File( nodeTilesIn, nodefilename );
if (nodeCutter != null) {
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap(); nodeCutter.nodeFileStart(null);
lonoffset = -1; }
latoffset = -1; new NodeIterator(this, nodeCutter != null).processFile(nodefile);
if ( nodeCutter != null ) if (restrictionCutter5 != null) {
{ String resfilename = name.substring(0, name.length() - 3) + "rtl";
nodeCutter.nodeFileStart( null ); File resfile = new File("restrictions", resfilename);
}
new NodeIterator( this, nodeCutter != null ).processFile( nodefile ); if (resfile.exists()) {
// read restrictions for nodes in nodesMap
if ( restrictionCutter5 != null ) DataInputStream di = new DataInputStream(new BufferedInputStream(new FileInputStream(resfile)));
{ int ntr = 0;
String resfilename = name.substring( 0, name.length()-3 ) + "rtl"; try {
File resfile = new File( "restrictions", resfilename ); for (; ; ) {
RestrictionData res = new RestrictionData(di);
if ( resfile.exists() ) restrictionCutter5.nextRestriction(res);
{ ntr++;
// read restrictions for nodes in nodesMap }
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( resfile ) ) ); } catch (EOFException eof) {
int ntr = 0; di.close();
try }
{ System.out.println("read " + ntr + " turn-restrictions");
for(;;) }
{ }
RestrictionData res = new RestrictionData( di ); return true;
restrictionCutter5.nextRestriction( res ); }
ntr++;
} @Override
} public void nextNode(NodeData n) throws Exception {
catch( EOFException eof ) if (nodeFilter != null) {
{ if (!nodeFilter.isRelevant(n)) {
di.close(); return;
} }
System.out.println( "read " + ntr + " turn-restrictions" ); }
} if (nodeCutter != null) {
} nodeCutter.nextNode(n);
return true; }
}
tileIndexMap.put(n.nid, getTileIndex(n.ilon, n.ilat));
@Override }
public void nextNode( NodeData n ) throws Exception
{ @Override
if ( nodeFilter != null ) public void nextWay(WayData data) throws Exception {
{ long waytileset = 0;
if ( !nodeFilter.isRelevant( n ) ) int nnodes = data.nodes.size();
{ int[] tiForNode = new int[nnodes];
return;
} // determine the tile-index for each node
} for (int i = 0; i < nnodes; i++) {
if ( nodeCutter != null ) int tileIndex = tileIndexMap.getInt(data.nodes.get(i));
{ if (tileIndex != -1) {
nodeCutter.nextNode( n ); waytileset |= (1L << tileIndex);
} }
tiForNode[i] = tileIndex;
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) ); }
}
if (relMerger != null) {
@Override relMerger.nextWay(data);
public void nextWay( WayData data ) throws Exception }
{
long waytileset = 0; // now write way to all tiles hit
int nnodes = data.nodes.size(); for (int tileIndex = 0; tileIndex < 54; tileIndex++) {
int[] tiForNode = new int[nnodes]; if ((waytileset & (1L << tileIndex)) == 0) {
continue;
// determine the tile-index for each node }
for (int i=0; i<nnodes; i++ ) data.writeTo(getOutStreamForTile(tileIndex));
{ }
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) );
if ( tileIndex != -1 ) // and write edge nodes to the border-nid file
{ for (int i = 0; i < nnodes; i++) {
waytileset |= ( 1L << tileIndex ); int ti = tiForNode[i];
} if (ti != -1) {
tiForNode[i] = tileIndex; if ((i > 0 && tiForNode[i - 1] != ti) || (i + 1 < nnodes && tiForNode[i + 1] != ti)) {
} writeId(borderNidsOutStream, data.nodes.get(i));
}
if ( relMerger != null ) }
{ }
relMerger.nextWay( data ); }
}
@Override
// now write way to all tiles hit public void wayFileEnd(File wayFile) throws Exception {
for( int tileIndex=0; tileIndex<54; tileIndex++ ) closeTileOutStreams();
{ if (nodeCutter != null) {
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 ) nodeCutter.nodeFileEnd(null);
{ }
continue; if (restrictionCutter5 != null) {
} restrictionCutter5.finish();
data.writeTo( getOutStreamForTile( tileIndex ) ); }
} }
// and write edge nodes to the border-nid file public int getTileIndexForNid(long nid) {
for( int i=0; i < nnodes; i++ ) return tileIndexMap.getInt(nid);
{ }
int ti = tiForNode[i];
if ( ti != -1 ) private int getTileIndex(int ilon, int ilat) {
{ int lonoff = (ilon / 45000000) * 45;
if ( ( i > 0 && tiForNode[i-1] != ti ) || (i+1 < nnodes && tiForNode[i+1] != ti ) ) int latoff = (ilat / 30000000) * 30;
{ if (lonoffset == -1) lonoffset = lonoff;
writeId( borderNidsOutStream, data.nodes.get(i) ); 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;
@Override if (lon < 0 || lon > 8 || lat < 0 || lat > 5)
public void wayFileEnd( File wayFile ) throws Exception throw new IllegalArgumentException("illegal pos: " + ilon + "," + ilat);
{ return lon * 6 + lat;
closeTileOutStreams(); }
if ( nodeCutter != null )
{
nodeCutter.nodeFileEnd( null ); protected String getNameForTile(int tileIndex) {
} int lon = (tileIndex / 6) * 5 + lonoffset - 180;
if ( restrictionCutter5 != null ) int lat = (tileIndex % 6) * 5 + latoffset - 90;
{ String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
restrictionCutter5.finish(); String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
} return slon + "_" + slat + ".wt5";
} }
}
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; package btools.mapcreator;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import btools.util.LongList; import btools.util.LongList;
/** /**
* Container for waydata on the preprocessor level * Container for waydata on the preprocessor level
* *
* @author ab * @author ab
*/ */
public class WayData extends MapCreatorBase public class WayData extends MapCreatorBase {
{ public long wid;
public long wid; public byte[] description;
public byte[] description; public LongList nodes;
public LongList nodes;
public WayData(long id) {
public WayData( long id ) wid = id;
{ nodes = new LongList(16);
wid = id; }
nodes = new LongList( 16 );
} public WayData(long id, LongList nodes) {
wid = id;
public WayData( long id, LongList nodes ) this.nodes = nodes;
{ }
wid = id;
this.nodes = nodes; public WayData(DataInputStream di) throws Exception {
} nodes = new LongList(16);
wid = readId(di);
public WayData( DataInputStream di ) throws Exception int dlen = di.readByte();
{ description = new byte[dlen];
nodes = new LongList( 16 ); di.readFully(description);
wid = readId( di) ; for (; ; ) {
int dlen = di.readByte(); description = new byte[dlen]; di.readFully( description ); long nid = readId(di);
for (;;) if (nid == -1) break;
{ nodes.add(nid);
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);
public void writeTo( DataOutputStream dos ) throws Exception dos.write(description);
{ int size = nodes.size();
writeId( dos, wid ); for (int i = 0; i < size; i++) {
dos.writeByte( description.length ); dos.write( description ); writeId(dos, nodes.get(i));
int size = nodes.size(); }
for( int i=0; i < size; i++ ) writeId(dos, -1); // stopbyte
{ }
writeId( dos, nodes.get( i ) ); }
}
writeId( dos, -1 ); // stopbyte
}
}

View File

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

View File

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

View File

@ -1,54 +1,53 @@
package btools.mapcreator; package btools.mapcreator;
import java.util.Random; import java.util.Random;
import java.util.HashMap; import java.util.HashMap;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.net.URL;
import java.io.File; import java.net.URL;
import java.io.File;
public class MapcreatorTest
{ public class MapcreatorTest {
@Test @Test
public void mapcreatorTest() throws Exception public void mapcreatorTest() throws Exception {
{ URL mapurl = this.getClass().getResource("/dreieich.osm.gz");
URL mapurl = this.getClass().getResource( "/dreieich.osm.gz" ); Assert.assertTrue("test-osm-map dreieich.osm not found", mapurl != null);
Assert.assertTrue( "test-osm-map dreieich.osm not found", mapurl != null ); File mapFile = new File(mapurl.getFile());
File mapFile = new File(mapurl.getFile()); File workingDir = mapFile.getParentFile();
File workingDir = mapFile.getParentFile(); File profileDir = new File(workingDir, "/../../../../misc/profiles2");
File profileDir = new File( workingDir, "/../../../../misc/profiles2" ); File tmpdir = new File(workingDir, "tmp");
File tmpdir = new File( workingDir, "tmp" ); tmpdir.mkdir();
tmpdir.mkdir();
File nodes = new File(tmpdir, "nodetiles");
File nodes = new File( tmpdir, "nodetiles" ); nodes.mkdir();
nodes.mkdir(); File ways = new File(tmpdir, "waytiles");
File ways = new File( tmpdir, "waytiles" ); ways.mkdir();
ways.mkdir(); File nodes55 = new File(tmpdir, "nodes55");
File nodes55 = new File( tmpdir, "nodes55" ); nodes55.mkdir();
nodes55.mkdir(); File ways55 = new File(tmpdir, "waytiles55");
File ways55 = new File( tmpdir, "waytiles55" ); ways55.mkdir();
ways55.mkdir(); File lookupFile = new File(profileDir, "lookups.dat");
File lookupFile = new File( profileDir, "lookups.dat" ); File relFile = new File(tmpdir, "cycleways.dat");
File relFile = new File( tmpdir, "cycleways.dat" ); File resFile = new File(tmpdir, "restrictions.dat");
File resFile = new File( tmpdir, "restrictions.dat" ); File profileAll = new File(profileDir, "all.brf");
File profileAll = new File( profileDir, "all.brf" ); File profileReport = new File(profileDir, "trekking.brf");
File profileReport = new File( profileDir, "trekking.brf" ); File profileCheck = new File(profileDir, "softaccess.brf");
File profileCheck = new File( profileDir, "softaccess.brf" ); File borderFile = new File(tmpdir, "bordernids.dat");
File borderFile = new File( tmpdir, "bordernids.dat" );
new OsmFastCutter().doCut(lookupFile, nodes, ways, nodes55, ways55, borderFile, relFile, resFile, profileAll, profileReport, profileCheck, mapFile);
new OsmFastCutter().doCut( lookupFile, nodes, ways, nodes55, ways55, borderFile, relFile, resFile, profileAll, profileReport, profileCheck, mapFile );
// run PosUnifier
// run PosUnifier File unodes55 = new File(tmpdir, "unodes55");
File unodes55 = new File( tmpdir, "unodes55" ); File bordernodes = new File(tmpdir, "bordernodes.dat");
File bordernodes = new File( tmpdir, "bordernodes.dat" ); unodes55.mkdir();
unodes55.mkdir(); new PosUnifier().process(nodes55, unodes55, borderFile, bordernodes, "/private-backup/srtm");
new PosUnifier().process( nodes55, unodes55, borderFile, bordernodes, "/private-backup/srtm" );
// run WayLinker
// run WayLinker File segments = new File(tmpdir, "segments");
File segments = new File( tmpdir, "segments" ); segments.mkdir();
segments.mkdir(); new WayLinker().process(unodes55, ways55, bordernodes, resFile, lookupFile, profileAll, segments, "rd5");
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 * DirectWeaver does the same decoding as MicroCache2, but decodes directly
* into the instance-graph, not into the intermediate nodes-cache * 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 long id64Base;
private int size = 0; private int size = 0;
public DirectWeaver( StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes ) public DirectWeaver(StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes) {
{ super(null);
super( null );
int cellsize = 1000000 / divisor; 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 wayTagCoder = new TagValueCoder(bc, dataBuffers, wayValidator);
TagValueCoder nodeTagCoder = new TagValueCoder( bc, dataBuffers, null ); TagValueCoder nodeTagCoder = new TagValueCoder(bc, dataBuffers, null);
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder( bc ); NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder( bc ); NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc); NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLatDiff = 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; 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]; OsmNode[] nodes = new OsmNode[size];
for( int n = 0; n<size; n++ ) for (int n = 0; n < size; n++) {
{ long id = expandId(faid[n]);
long id = expandId( faid[n] ); int ilon = (int) (id >> 32);
int ilon = (int) ( id >> 32 ); int ilat = (int) (id & 0xffffffff);
int ilat = (int) ( id & 0xffffffff ); OsmNode node = hollowNodes.get(ilon, ilat);
OsmNode node = hollowNodes.get( ilon, ilat ); if (node == null) {
if ( node == null ) node = new OsmNode(ilon, ilat);
{ } else {
node = new OsmNode( ilon, ilat );
}
else
{
node.visitID = 1; node.visitID = 1;
hollowNodes.remove( node ); hollowNodes.remove(node);
} }
nodes[n] = 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; ab = dataBuffers.bbuf1;
aboffset = 0; aboffset = 0;
int selev = 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]; OsmNode node = nodes[n];
int ilon = node.ilon; int ilon = node.ilon;
int ilat = node.ilat; int ilat = node.ilat;
// future escapes (turn restrictions?) // future escapes (turn restrictions?)
short trExceptions = 0; short trExceptions = 0;
for(;;) for (; ; ) {
{
int featureId = bc.decodeVarBits(); int featureId = bc.decodeVarBits();
if ( featureId == 0 ) break; if (featureId == 0) break;
int bitsize = bc.decodeNoisyNumber( 5 ); int bitsize = bc.decodeNoisyNumber(5);
if ( featureId == 2 ) // exceptions to turn-restriction if (featureId == 2) // exceptions to turn-restriction
{ {
trExceptions = (short)bc.decodeBounded( 1023 ); trExceptions = (short) bc.decodeBounded(1023);
} } else if (featureId == 1) // turn-restriction
else if ( featureId == 1 ) // turn-restriction
{ {
TurnRestriction tr = new TurnRestriction(); TurnRestriction tr = new TurnRestriction();
tr.exceptions = trExceptions; tr.exceptions = trExceptions;
trExceptions = 0; trExceptions = 0;
tr.isPositive = bc.decodeBit(); tr.isPositive = bc.decodeBit();
tr.fromLon = ilon + bc.decodeNoisyDiff( 10 ); tr.fromLon = ilon + bc.decodeNoisyDiff(10);
tr.fromLat = ilat + bc.decodeNoisyDiff( 10 ); tr.fromLat = ilat + bc.decodeNoisyDiff(10);
tr.toLon = ilon + bc.decodeNoisyDiff( 10 ); tr.toLon = ilon + bc.decodeNoisyDiff(10);
tr.toLat = ilat + bc.decodeNoisyDiff( 10 ); tr.toLat = ilat + bc.decodeNoisyDiff(10);
node.addTurnRestriction( tr ); node.addTurnRestriction(tr);
} } else {
else for (int i = 0; i < bitsize; i++) bc.decodeBit(); // unknown feature, just skip
{
for( int i=0; i< bitsize; i++ ) bc.decodeBit(); // unknown feature, just skip
} }
} }
selev += nodeEleDiff.decodeSignedValue(); selev += nodeEleDiff.decodeSignedValue();
node.selev = (short)selev; node.selev = (short) selev;
TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet(); TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet();
node.nodeDescription = nodeTags == null ? null : nodeTags.data; // TODO: unified? node.nodeDescription = nodeTags == null ? null : nodeTags.data; // TODO: unified?
int links = bc.decodeNoisyNumber( 1 ); int links = bc.decodeNoisyNumber(1);
for( int li=0; li<links; li++ ) for (int li = 0; li < links; li++) {
{
int nodeIdx = n + nodeIdxDiff.decodeSignedValue(); int nodeIdx = n + nodeIdxDiff.decodeSignedValue();
int dlon_remaining; int dlon_remaining;
int dlat_remaining; int dlat_remaining;
boolean isReverse = false; boolean isReverse = false;
if ( nodeIdx != n ) // internal (forward-) link if (nodeIdx != n) // internal (forward-) link
{ {
dlon_remaining = nodes[nodeIdx].ilon - ilon; dlon_remaining = nodes[nodeIdx].ilon - ilon;
dlat_remaining = nodes[nodeIdx].ilat - ilat; dlat_remaining = nodes[nodeIdx].ilat - ilat;
} } else {
else
{
isReverse = bc.decodeBit(); isReverse = bc.decodeBit();
dlon_remaining = extLonDiff.decodeSignedValue(); dlon_remaining = extLonDiff.decodeSignedValue();
dlat_remaining = extLatDiff.decodeSignedValue(); dlat_remaining = extLatDiff.decodeSignedValue();
@ -131,104 +118,92 @@ public final class DirectWeaver extends ByteDataWriter
int linklon = ilon + dlon_remaining; int linklon = ilon + dlon_remaining;
int linklat = ilat + dlat_remaining; int linklat = ilat + dlat_remaining;
aboffset = 0; 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; WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher;
int ilontarget = ilon + dlon_remaining; int ilontarget = ilon + dlon_remaining;
int ilattarget = ilat + dlat_remaining; int ilattarget = ilat + dlat_remaining;
if ( matcher != null ) if (matcher != null) {
{ if (!matcher.start(ilon, ilat, ilontarget, ilattarget)) {
if ( !matcher.start( ilon, ilat, ilontarget, ilattarget ) )
{
matcher = null; matcher = null;
} }
} }
int transcount = bc.decodeVarBits(); int transcount = bc.decodeVarBits();
int count = transcount+1; int count = transcount + 1;
for( int i=0; i<transcount; i++ ) for (int i = 0; i < transcount; i++) {
{ int dlon = bc.decodePredictedValue(dlon_remaining / count);
int dlon = bc.decodePredictedValue( dlon_remaining/count ); int dlat = bc.decodePredictedValue(dlat_remaining / count);
int dlat = bc.decodePredictedValue( dlat_remaining/count );
dlon_remaining -= dlon; dlon_remaining -= dlon;
dlat_remaining -= dlat; dlat_remaining -= dlat;
count--; count--;
int elediff = transEleDiff.decodeSignedValue(); int elediff = transEleDiff.decodeSignedValue();
if ( wayTags != null ) if (wayTags != null) {
{ writeVarLengthSigned(dlon);
writeVarLengthSigned( dlon ); writeVarLengthSigned(dlat);
writeVarLengthSigned( dlat ); writeVarLengthSigned(elediff);
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; byte[] geometry = null;
if ( aboffset > 0 ) if (aboffset > 0) {
{
geometry = new byte[aboffset]; 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]; OsmNode node2 = nodes[nodeIdx];
OsmLink link = node.isLinkUnused() ? node : ( node2.isLinkUnused() ? node2 : null ); OsmLink link = node.isLinkUnused() ? node : (node2.isLinkUnused() ? node2 : null);
if ( link == null ) if (link == null) {
{
link = new OsmLink(); link = new OsmLink();
} }
link.descriptionBitmap = wayTags.data; link.descriptionBitmap = wayTags.data;
link.geometry = geometry; link.geometry = geometry;
node.addLink( link, isReverse, node2 ); node.addLink(link, isReverse, node2);
} } else // weave external link
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; node.visitID = 1;
} }
} }
} // ... loop over links } // ... loop over links
} // ... loop over nodes } // ... loop over nodes
hollowNodes.cleanupAndCount( nodes ); hollowNodes.cleanupAndCount(nodes);
} }
private static final long[] id32_00 = new long[1024]; private static final long[] id32_00 = new long[1024];
private static final long[] id32_10 = new long[1024]; private static final long[] id32_10 = new long[1024];
private static final long[] id32_20 = new long[1024]; private static final long[] id32_20 = new long[1024];
static static {
{ for (int i = 0; i < 1024; i++) {
for( int i=0; i<1024; i++ ) id32_00[i] = _expandId(i);
{ id32_10[i] = _expandId(i << 10);
id32_00[i] = _expandId( i ); id32_20[i] = _expandId(i << 20);
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 dlon = 0;
int dlat = 0; int dlat = 0;
for( int bm = 1; bm < 0x8000; bm <<= 1 ) for (int bm = 1; bm < 0x8000; bm <<= 1) {
{ if ((id32 & 1) != 0) dlon |= bm;
if ( (id32 & 1) != 0 ) dlon |= bm; if ((id32 & 2) != 0) dlat |= bm;
if ( (id32 & 2) != 0 ) dlat |= bm;
id32 >>= 2; id32 >>= 2;
} }
return ((long)dlon)<<32 | dlat; return ((long) dlon) << 32 | dlat;
} }
public long expandId( int id32 ) public long expandId(int id32) {
{ return id64Base + id32_00[id32 & 1023] + id32_10[(id32 >> 10) & 1023] + id32_20[(id32 >> 20) & 1023];
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; import btools.util.ByteDataReader;
public final class GeometryDecoder public final class GeometryDecoder {
{ private ByteDataReader r = new ByteDataReader(null);
private ByteDataReader r = new ByteDataReader( null );
private OsmTransferNode[] cachedNodes; private OsmTransferNode[] cachedNodes;
private int nCachedNodes = 128; private int nCachedNodes = 128;
@ -19,63 +18,53 @@ public final class GeometryDecoder
private boolean lastReverse; private boolean lastReverse;
private byte[] lastGeometry; private byte[] lastGeometry;
public GeometryDecoder() public GeometryDecoder() {
{
// create some caches // create some caches
cachedNodes = new OsmTransferNode[nCachedNodes]; cachedNodes = new OsmTransferNode[nCachedNodes];
for( int i=0; i<nCachedNodes; i++ ) for (int i = 0; i < nCachedNodes; i++) {
{
cachedNodes[i] = new OsmTransferNode(); cachedNodes[i] = new OsmTransferNode();
} }
} }
public OsmTransferNode decodeGeometry( byte[] geometry, OsmNode sourceNode, OsmNode targetNode, boolean reverseLink ) public OsmTransferNode decodeGeometry(byte[] geometry, OsmNode sourceNode, OsmNode targetNode, boolean reverseLink) {
{ if ((lastGeometry == geometry) && (lastReverse == 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; 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; import btools.mapaccess.OsmNode;
public final class MatchedWaypoint public final class MatchedWaypoint {
{
public OsmNode node1; public OsmNode node1;
public OsmNode node2; public OsmNode node2;
public OsmNode crosspoint; public OsmNode crosspoint;
public OsmNode waypoint; public OsmNode waypoint;
public String name; // waypoint name used in error messages public String name; // waypoint name used in error messages
public double radius; // distance in meter between waypoint and crosspoint public double radius; // distance in meter between waypoint and crosspoint
public boolean hasUpdate; public boolean hasUpdate;
public void writeToStream( DataOutput dos ) throws IOException public void writeToStream(DataOutput dos) throws IOException {
{ dos.writeInt(node1.ilat);
dos.writeInt( node1.ilat ); dos.writeInt(node1.ilon);
dos.writeInt( node1.ilon ); dos.writeInt(node2.ilat);
dos.writeInt( node2.ilat ); dos.writeInt(node2.ilon);
dos.writeInt( node2.ilon ); dos.writeInt(crosspoint.ilat);
dos.writeInt( crosspoint.ilat ); dos.writeInt(crosspoint.ilon);
dos.writeInt( crosspoint.ilon ); dos.writeInt(waypoint.ilat);
dos.writeInt( waypoint.ilat ); dos.writeInt(waypoint.ilon);
dos.writeInt( waypoint.ilon ); dos.writeDouble(radius);
dos.writeDouble( radius );
} }
public static MatchedWaypoint readFromStream( DataInput dis ) throws IOException public static MatchedWaypoint readFromStream(DataInput dis) throws IOException {
{ MatchedWaypoint mwp = new MatchedWaypoint();
MatchedWaypoint mwp = new MatchedWaypoint(); mwp.node1 = new OsmNode();
mwp.node1 = new OsmNode(); mwp.node2 = new OsmNode();
mwp.node2 = new OsmNode(); mwp.crosspoint = new OsmNode();
mwp.crosspoint = new OsmNode(); mwp.waypoint = new OsmNode();
mwp.waypoint = new OsmNode();
mwp.node1.ilat = dis.readInt(); mwp.node1.ilat = dis.readInt();
mwp.node1.ilon = dis.readInt(); mwp.node1.ilon = dis.readInt();
mwp.node2.ilat = dis.readInt(); mwp.node2.ilat = dis.readInt();
mwp.node2.ilon = dis.readInt(); mwp.node2.ilon = dis.readInt();
mwp.crosspoint.ilat = dis.readInt(); mwp.crosspoint.ilat = dis.readInt();
mwp.crosspoint.ilon = dis.readInt(); mwp.crosspoint.ilon = dis.readInt();
mwp.waypoint.ilat = dis.readInt(); mwp.waypoint.ilat = dis.readInt();
mwp.waypoint.ilon = dis.readInt(); mwp.waypoint.ilon = dis.readInt();
mwp.radius = dis.readDouble(); mwp.radius = dis.readDouble();
return mwp; return mwp;
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,182 +1,155 @@
/** /**
* Container for link between two Osm nodes * Container for link between two Osm nodes
* *
* @author ab * @author ab
*/ */
package btools.mapaccess; package btools.mapaccess;
public class OsmLink {
public class OsmLink /**
{ * The description bitmap contains the waytags (valid for both directions)
/** */
* The description bitmap contains the waytags (valid for both directions) public byte[] descriptionBitmap;
*/
public byte[] descriptionBitmap; /**
* The geometry contains intermediate nodes, null for none (valid for both directions)
/** */
* The geometry contains intermediate nodes, null for none (valid for both directions) public byte[] geometry;
*/
public byte[] geometry; // a link logically knows only its target, but for the reverse link, source and target are swapped
protected OsmNode n1;
// a link logically knows only its target, but for the reverse link, source and target are swapped protected OsmNode n2;
protected OsmNode n1;
protected OsmNode n2; // same for the next-link-for-node pointer: previous applies to the reverse link
protected OsmLink previous;
// same for the next-link-for-node pointer: previous applies to the reverse link protected OsmLink next;
protected OsmLink previous;
protected OsmLink next; private OsmLinkHolder reverselinkholder = null;
private OsmLinkHolder firstlinkholder = null;
private OsmLinkHolder reverselinkholder = null;
private OsmLinkHolder firstlinkholder = null; protected OsmLink() {
}
protected OsmLink()
{ public OsmLink(OsmNode source, OsmNode target) {
} n1 = source;
n2 = target;
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;
* Get the relevant target-node for the given source /* if ( n2 != null && n2 != source )
*/ {
public final OsmNode getTarget( OsmNode source ) return n2;
{ }
return n2 != source && n2 != null ? n2 : n1; else if ( n1 != null && n1 != source )
/* if ( n2 != null && n2 != source ) {
{ return n1;
return n2; }
} else
else if ( n1 != null && n1 != source ) {
{ new Throwable( "ups" ).printStackTrace();
return n1; throw new IllegalArgumentException( "internal error: getTarget: unknown source; " + source + " n1=" + n1 + " n2=" + n2 );
} } */
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 )
* Get the relevant next-pointer for the given source {
*/ return next;
public final OsmLink getNext( OsmNode source ) }
{ else if ( n1 != null && n1 != source )
return n2 != source && n2 != null ? next : previous; {
/* if ( n2 != null && n2 != source ) return previous;
{ }
return next; else
} {
else if ( n1 != null && n1 != source ) throw new IllegalArgumentException( "internal error: gextNext: unknown source" );
{ } */
return previous; }
}
else /**
{ * Reset this link for the given direction
throw new IllegalArgumentException( "internal error: gextNext: unknown source" ); */
} */ protected final OsmLink clear(OsmNode source) {
} OsmLink n;
if (n2 != null && n2 != source) {
/** n = next;
* Reset this link for the given direction next = null;
*/ n2 = null;
protected final OsmLink clear( OsmNode source ) firstlinkholder = null;
{ } else if (n1 != null && n1 != source) {
OsmLink n; n = previous;
if ( n2 != null && n2 != source ) previous = null;
{ n1 = null;
n = next; reverselinkholder = null;
next = null; } else {
n2 = null; throw new IllegalArgumentException("internal error: setNext: unknown source");
firstlinkholder = null; }
} if (n1 == null && n2 == null) {
else if ( n1 != null && n1 != source ) descriptionBitmap = null;
{ geometry = null;
n = previous; }
previous = null; return n;
n1 = null; }
reverselinkholder = null;
} public final void setFirstLinkHolder(OsmLinkHolder holder, OsmNode source) {
else if (n2 != null && n2 != source) {
{ firstlinkholder = holder;
throw new IllegalArgumentException( "internal error: setNext: unknown source" ); } else if (n1 != null && n1 != source) {
} reverselinkholder = holder;
if ( n1 == null && n2 == null ) } else {
{ throw new IllegalArgumentException("internal error: setFirstLinkHolder: unknown source");
descriptionBitmap = null; }
geometry = null; }
}
return n; public final OsmLinkHolder getFirstLinkHolder(OsmNode source) {
} if (n2 != null && n2 != source) {
return firstlinkholder;
public final void setFirstLinkHolder( OsmLinkHolder holder, OsmNode source ) } else if (n1 != null && n1 != source) {
{ return reverselinkholder;
if ( n2 != null && n2 != source ) } else {
{ throw new IllegalArgumentException("internal error: getFirstLinkHolder: unknown source");
firstlinkholder = holder; }
} }
else if ( n1 != null && n1 != source )
{ public final boolean isReverse(OsmNode source) {
reverselinkholder = holder; return n1 != source && n1 != null;
} /* if ( n2 != null && n2 != source )
else {
{ return false;
throw new IllegalArgumentException( "internal error: setFirstLinkHolder: unknown source" ); }
} else if ( n1 != null && n1 != source )
} {
return true;
public final OsmLinkHolder getFirstLinkHolder( OsmNode source ) }
{ else
if ( n2 != null && n2 != source ) {
{ throw new IllegalArgumentException( "internal error: isReverse: unknown source" );
return firstlinkholder; } */
} }
else if ( n1 != null && n1 != source )
{ public final boolean isBidirectional() {
return reverselinkholder; return n1 != null && n2 != null;
} }
else
{ public final boolean isLinkUnused() {
throw new IllegalArgumentException( "internal error: getFirstLinkHolder: unknown source" ); return n1 == null && n2 == null;
} }
}
public final void addLinkHolder(OsmLinkHolder holder, OsmNode source) {
public final boolean isReverse( OsmNode source ) OsmLinkHolder firstHolder = getFirstLinkHolder(source);
{ if (firstHolder != null) {
return n1 != source && n1 != null; holder.setNextForLink(firstHolder);
/* if ( n2 != null && n2 != source ) }
{ setFirstLinkHolder(holder, 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 * Container for routig configs
* *
* @author ab * @author ab
*/ */
package btools.mapaccess; package btools.mapaccess;
public interface OsmLinkHolder public interface OsmLinkHolder {
{ void setNextForLink(OsmLinkHolder holder);
void setNextForLink( OsmLinkHolder holder );
OsmLinkHolder getNextForLink();
OsmLinkHolder getNextForLink(); }
}

View File

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

View File

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

View File

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

View File

@ -1,19 +1,16 @@
/** /**
* Container for link between two Osm nodes * Container for link between two Osm nodes
* *
* @author ab * @author ab
*/ */
package btools.mapaccess; package btools.mapaccess;
public final class OsmTransferNode {
public OsmTransferNode next;
public final class OsmTransferNode
{ public int ilon;
public OsmTransferNode next; public int ilat;
public short selev;
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.ByteDataReader;
import btools.util.Crc32; import btools.util.Crc32;
final public class PhysicalFile final public class PhysicalFile {
{
RandomAccessFile ra = null; RandomAccessFile ra = null;
long[] fileIndex = new long[25]; long[] fileIndex = new long[25];
int[] fileHeaderCrcs; int[] fileHeaderCrcs;
private int fileIndexCrc; private int fileIndexCrc;
public long creationTime; public long creationTime;
String fileName; String fileName;
public int divisor = 80; public int divisor = 80;
public static void main( String[] args ) public static void main(String[] args) {
{
MicroCache.debug = true; MicroCache.debug = true;
try { try {
checkFileIntegrity( new File( args[0] ) ); checkFileIntegrity(new File(args[0]));
} catch (IOException e) { } catch (IOException e) {
System.err.println( "************************************" ); System.err.println("************************************");
e.printStackTrace(); 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 * @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; PhysicalFile pf = null;
try try {
{
DataBuffers dataBuffers = new DataBuffers(); DataBuffers dataBuffers = new DataBuffers();
pf = new PhysicalFile( f, dataBuffers, -1, -1 ); pf = new PhysicalFile(f, dataBuffers, -1, -1);
int div = pf.divisor; 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 ); OsmFile osmf = new OsmFile(pf, lonDegree, latDegree, dataBuffers);
if ( osmf.hasData() ) if (osmf.hasData())
for ( int lonIdx = 0; lonIdx < div; lonIdx++ ) for (int lonIdx = 0; lonIdx < div; lonIdx++)
for ( int latIdx = 0; latIdx < div; latIdx++ ) for (int latIdx = 0; latIdx < div; latIdx++)
osmf.createMicroCache( lonDegree * div + lonIdx, latDegree * div + latIdx, dataBuffers, null, null, MicroCache.debug, null ); osmf.createMicroCache(lonDegree * div + lonIdx, latDegree * div + latIdx, dataBuffers, null, null, MicroCache.debug, null);
} }
} }
} } finally {
finally if (pf != null)
{ try {
if ( pf != null )
try
{
pf.ra.close(); pf.ra.close();
} } catch (Exception ee) {
catch (Exception ee)
{
} }
} }
return null; 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(); fileName = f.getName();
byte[] iobuffer = dataBuffers.iobuffer; byte[] iobuffer = dataBuffers.iobuffer;
ra = new RandomAccessFile( f, "r" ); ra = new RandomAccessFile(f, "r");
ra.readFully( iobuffer, 0, 200 ); ra.readFully(iobuffer, 0, 200);
fileIndexCrc = Crc32.crc( iobuffer, 0, 200 ); fileIndexCrc = Crc32.crc(iobuffer, 0, 200);
ByteDataReader dis = new ByteDataReader( iobuffer ); ByteDataReader dis = new ByteDataReader(iobuffer);
for( int i=0; i<25; i++ ) for (int i = 0; i < 25; i++) {
{
long lv = dis.readLong(); long lv = dis.readLong();
short readVersion = (short)(lv >> 48); short readVersion = (short) (lv >> 48);
if ( i == 0 && lookupVersion != -1 && readVersion != lookupVersion ) if (i == 0 && lookupVersion != -1 && readVersion != lookupVersion) {
{ throw new IOException("lookup version mismatch (old rd5?) lookups.dat="
throw new IOException( "lookup version mismatch (old rd5?) lookups.dat=" + lookupVersion + " " + f.getAbsolutePath() + "=" + readVersion);
+ lookupVersion + " " + f. getAbsolutePath() + "=" + readVersion );
} }
fileIndex[i] = lv & 0xffffffffffffL; fileIndex[i] = lv & 0xffffffffffffL;
} }
@ -103,36 +91,30 @@ final public class PhysicalFile
long len = ra.length(); long len = ra.length();
long pos = fileIndex[24]; 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.seek(pos);
ra.readFully( iobuffer, 0, extraLen ); ra.readFully(iobuffer, 0, extraLen);
dis = new ByteDataReader( iobuffer ); dis = new ByteDataReader(iobuffer);
creationTime = dis.readLong(); creationTime = dis.readLong();
int crcData = dis.readInt(); int crcData = dis.readInt();
if ( crcData == fileIndexCrc ) if (crcData == fileIndexCrc) {
{
divisor = 80; // old format divisor = 80; // old format
} } else if ((crcData ^ 2) == fileIndexCrc) {
else if ( (crcData ^ 2) == fileIndexCrc )
{
divisor = 32; // new format divisor = 32; // new format
} } else {
else throw new IOException("top index checksum error");
{
throw new IOException( "top index checksum error" );
} }
fileHeaderCrcs = new int[25]; fileHeaderCrcs = new int[25];
for( int i=0; i<25; i++ ) for (int i = 0; i < 25; i++) {
{
fileHeaderCrcs[i] = dis.readInt(); fileHeaderCrcs[i] = dis.readInt();
} }
} }

View File

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