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,16 +11,15 @@ 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];
} }
@ -29,16 +27,14 @@ public class LinkedListContainer
* 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;
} }
@ -48,13 +44,11 @@ public class LinkedListContainer
* @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,10 +177,9 @@ 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);
} }
/** /**
@ -214,9 +187,8 @@ public class MicroCache extends ByteDataWriter
* *
* @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" );
} }
/** /**
@ -224,29 +196,25 @@ public class MicroCache extends ByteDataWriter
* *
* @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" );
} }
/** /**
@ -254,150 +222,123 @@ public class MicroCache extends ByteDataWriter
* *
* @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,78 +9,73 @@ 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 ) public byte[] readUnified(int len, IByteArrayUnifier u) {
{ byte[] b = u.unify(ab, aboffset, len);
byte[] b = u.unify( ab, aboffset, len ); aboffset += len;
aboffset += len; return b;
return b;
} }
public MicroCache2( StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher ) public MicroCache2(StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher) {
{ super(null);
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;
int[] alon = size > dataBuffers.alon.length ? new int[size] : dataBuffers.alon; if (debug)
int[] alat = size > dataBuffers.alat.length ? new int[size] : dataBuffers.alat; System.out.println("*** decoding cache of size=" + size + " for lonIdx=" + lonIdx + " latIdx=" + latIdx);
if ( debug ) System.out.println( "*** decoding cache of size=" + size + " for lonIdx=" + lonIdx + " latIdx=" + latIdx ); bc.decodeSortedArray(faid, 0, size, 29, 0);
bc.decodeSortedArray( faid, 0, size, 29, 0 ); for (int n = 0; n < size; n++) {
long id64 = expandId(faid[n]);
for( int n = 0; n<size; n++ ) alon[n] = (int) (id64 >> 32);
{ alat[n] = (int) (id64 & 0xffffffff);
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];
@ -88,49 +83,44 @@ public final class MicroCache2 extends MicroCache
// 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();
@ -138,78 +128,72 @@ public final class MicroCache2 extends MicroCache
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;
@ -218,13 +202,11 @@ public final class MicroCache2 extends MicroCache
// 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();
@ -340,91 +313,89 @@ public final class MicroCache2 extends MicroCache
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;
@ -434,85 +405,78 @@ public final class MicroCache2 extends MicroCache
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 );
extLonDiff.encodeSignedValue( ilonlink - ilon );
extLatDiff.encodeSignedValue( ilatlink - ilat );
if ( dostats ) bc.assignBits( "externalNode" );
}
wayTagCoder.encodeTagValueSet( description );
if ( dostats ) bc.assignBits( "wayDescIdx" );
if ( !isReverse ) if (!isReverse) {
{ byte[] geometry = readDataUntil(endPointer);
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,9 +25,8 @@ public final class StatCoderContext extends BitCoderContext
} }
public StatCoderContext( byte[] ab ) public StatCoderContext(byte[] ab) {
{ super(ab);
super( ab );
} }
/** /**
@ -40,18 +35,15 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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;
@ -63,17 +55,14 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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();
@ -85,19 +74,16 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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);
} }
/** /**
@ -106,10 +92,9 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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 );
} }
/** /**
@ -118,19 +103,16 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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 );
} }
} }
@ -140,18 +122,14 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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;
} }
} }
@ -164,17 +142,15 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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);
} }
/** /**
@ -183,16 +159,14 @@ public final class StatCoderContext extends BitCoderContext
* *
* @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]);
} }
/** /**
@ -202,29 +176,21 @@ public final class StatCoderContext extends BitCoderContext
* 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();
} }
@ -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,26 +120,23 @@ 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;

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,9 +6,7 @@
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;
@ -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

@ -8,26 +8,22 @@ 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) public OsmNodeNamed(OsmNode n) {
{ super(n.ilon, n.ilat);
super( n.ilon, n.ilat );
} }
@Override @Override
public String toString() public String toString() {
{ if (Double.isNaN(nogoWeight)) {
if ( Double.isNaN(nogoWeight ) ) {
return ilon + "," + ilat + "," + name; return ilon + "," + ilat + "," + name;
} else { } else {
return ilon + "," + ilat + "," + name + "," + nogoWeight; return ilon + "," + ilat + "," + name + "," + nogoWeight;
@ -35,7 +31,7 @@ public class OsmNodeNamed extends OsmNode
} }
public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) { public double distanceWithinRadius(int lon1, int lat1, int lon2, int lat2, double totalSegmentLength) {
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lat1 + lat2) >> 1 ); double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lat1 + lat2) >> 1);
boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius; boolean isFirstPointWithinCircle = CheapRuler.distance(lon1, lat1, ilon, ilat) < radius;
boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius; boolean isLastPointWithinCircle = CheapRuler.distance(lon2, lat2, ilon, ilat) < radius;
@ -64,15 +60,15 @@ public class OsmNodeNamed extends OsmNode
// the circle on the current segment. // the circle on the current segment.
double initialToProject = ( double initialToProject = (
(lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0] (lon2 - lon1) * (ilon - lon1) * lonlat2m[0] * lonlat2m[0]
+ (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1] + (lat2 - lat1) * (ilat - lat1) * lonlat2m[1] * lonlat2m[1]
) / totalSegmentLength; ) / totalSegmentLength;
// Distance between the initial point and the center of the circle. // Distance between the initial point and the center of the circle.
double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1); double initialToCenter = CheapRuler.distance(ilon, ilat, lon1, lat1);
// Half length of the segment within the circle // Half length of the segment within the circle
double halfDistanceWithin = Math.sqrt( double halfDistanceWithin = Math.sqrt(
radius*radius - ( radius * radius - (
initialToCenter*initialToCenter - initialToCenter * initialToCenter -
initialToProject*initialToProject initialToProject * initialToProject
) )
); );
// Last point is within the circle // Last point is within the circle
@ -82,20 +78,19 @@ public class OsmNodeNamed extends OsmNode
return 2 * halfDistanceWithin; return 2 * halfDistanceWithin;
} }
public static OsmNodeNamed decodeNogo( String s ) public static OsmNodeNamed decodeNogo(String s) {
{
OsmNodeNamed n = new OsmNodeNamed(); OsmNodeNamed n = new OsmNodeNamed();
int idx1 = s.indexOf( ',' ); int idx1 = s.indexOf(',');
n.ilon = Integer.parseInt( s.substring( 0, idx1 ) ); n.ilon = Integer.parseInt(s.substring(0, idx1));
int idx2 = s.indexOf( ',', idx1+1 ); int idx2 = s.indexOf(',', idx1 + 1);
n.ilat = Integer.parseInt( s.substring( idx1+1, idx2 ) ); n.ilat = Integer.parseInt(s.substring(idx1 + 1, idx2));
int idx3 = s.indexOf( ',', idx2+1 ); int idx3 = s.indexOf(',', idx2 + 1);
if ( idx3 == -1) { if (idx3 == -1) {
n.name = s.substring( idx2 + 1 ); n.name = s.substring(idx2 + 1);
n.nogoWeight = Double.NaN; n.nogoWeight = Double.NaN;
} else { } else {
n.name = s.substring( idx2+1, idx3 ); n.name = s.substring(idx2 + 1, idx3);
n.nogoWeight = Double.parseDouble( s.substring( idx3 + 1 ) ); n.nogoWeight = Double.parseDouble(s.substring(idx3 + 1));
} }
n.isNogo = true; n.isNogo = true;
return n; return n;

View File

@ -1,12 +1,11 @@
/********************************************************************************************** /**********************************************************************************************
Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de Copyright (C) 2018 Norbert Truchsess norbert.truchsess@t-online.de
The following methods are based on work of Dan Sunday published at: The following methods are based on work of Dan Sunday published at:
http://geomalgorithms.com/a03-_inclusion.html http://geomalgorithms.com/a03-_inclusion.html
cn_PnPoly, wn_PnPoly, inSegment, intersect2D_2Segments cn_PnPoly, wn_PnPoly, inSegment, intersect2D_2Segments
**********************************************************************************************/
**********************************************************************************************/
package btools.router; package btools.router;
import java.util.ArrayList; import java.util.ArrayList;
@ -14,15 +13,12 @@ import java.util.List;
import btools.util.CheapRuler; import btools.util.CheapRuler;
public class OsmNogoPolygon extends OsmNodeNamed public class OsmNogoPolygon extends OsmNodeNamed {
{ public final static class Point {
public final static class Point
{
public final int y; public final int y;
public final int x; public final int x;
Point(final int lon, final int lat) Point(final int lon, final int lat) {
{
x = lon; x = lon;
y = lat; y = lat;
} }
@ -32,66 +28,58 @@ public class OsmNogoPolygon extends OsmNodeNamed
public final boolean isClosed; public final boolean isClosed;
public OsmNogoPolygon(boolean closed) public OsmNogoPolygon(boolean closed) {
{
this.isClosed = closed; this.isClosed = closed;
this.isNogo = true; this.isNogo = true;
this.name = ""; this.name = "";
} }
public final void addVertex(int lon, int lat) public final void addVertex(int lon, int lat) {
{
points.add(new Point(lon, lat)); points.add(new Point(lon, lat));
} }
/** /**
* calcBoundingCircle is inspired by the algorithm described on * calcBoundingCircle is inspired by the algorithm described on
* http://geomalgorithms.com/a08-_containers.html * http://geomalgorithms.com/a08-_containers.html
* (fast computation of bounding circly in c). It is not as fast (the original * (fast computation of bounding circly in c). It is not as fast (the original
* algorithm runs in linear time), as it may do more iterations but it takes * algorithm runs in linear time), as it may do more iterations but it takes
* into account the coslat-factor being used for the linear approximation that * into account the coslat-factor being used for the linear approximation that
* is also used in other places of brouter does change when moving the centerpoint * is also used in other places of brouter does change when moving the centerpoint
* with each iteration. * with each iteration.
* This is done to ensure the calculated radius being used * This is done to ensure the calculated radius being used
* in RoutingContext.calcDistance will actually contain the whole polygon. * in RoutingContext.calcDistance will actually contain the whole polygon.
* * <p>
* For reasonable distributed vertices the implemented algorithm runs in O(n*ln(n)). * For reasonable distributed vertices the implemented algorithm runs in O(n*ln(n)).
* As this is only run once on initialization of OsmNogoPolygon this methods * As this is only run once on initialization of OsmNogoPolygon this methods
* overall usage of cpu is neglegible in comparism to the cpu-usage of the * overall usage of cpu is neglegible in comparism to the cpu-usage of the
* actual routing algoritm. * actual routing algoritm.
*/ */
public void calcBoundingCircle() public void calcBoundingCircle() {
{
int cxmin, cxmax, cymin, cymax; int cxmin, cxmax, cymin, cymax;
cxmin = cymin = Integer.MAX_VALUE; cxmin = cymin = Integer.MAX_VALUE;
cxmax = cymax = Integer.MIN_VALUE; cxmax = cymax = Integer.MIN_VALUE;
// first calculate a starting center point as center of boundingbox // first calculate a starting center point as center of boundingbox
for (int i = 0; i < points.size(); i++) for (int i = 0; i < points.size(); i++) {
{
final Point p = points.get(i); final Point p = points.get(i);
if (p.x < cxmin) if (p.x < cxmin) {
{
cxmin = p.x; cxmin = p.x;
} }
if (p.x > cxmax) if (p.x > cxmax) {
{
cxmax = p.x; cxmax = p.x;
} }
if (p.y < cymin) if (p.y < cymin) {
{
cymin = p.y; cymin = p.y;
} }
if (p.y > cymax) if (p.y > cymax) {
{
cymax = p.y; cymax = p.y;
} }
} }
int cx = (cxmax+cxmin) / 2; // center of circle int cx = (cxmax + cxmin) / 2; // center of circle
int cy = (cymax+cymin) / 2; int cy = (cymax + cymin) / 2;
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( cy ); // conversion-factors at the center of circle double[] lonlat2m = CheapRuler.getLonLatToMeterScales(cy); // conversion-factors at the center of circle
double dlon2m = lonlat2m[0]; double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1]; double dlat2m = lonlat2m[1];
@ -100,48 +88,43 @@ public class OsmNogoPolygon extends OsmNodeNamed
double dmax = 0; // length of vector from center to point double dmax = 0; // length of vector from center to point
int i_max = -1; int i_max = -1;
do do {
{
// now identify the point outside of the circle that has the greatest distance // now identify the point outside of the circle that has the greatest distance
for (int i = 0; i < points.size(); i++) for (int i = 0; i < points.size(); i++) {
{
final Point p = points.get(i); final Point p = points.get(i);
// to get precisely the same results as in RoutingContext.calcDistance() // to get precisely the same results as in RoutingContext.calcDistance()
// it's crucial to use the factors of the center! // it's crucial to use the factors of the center!
final double x1 = (cx - p.x) * dlon2m; final double x1 = (cx - p.x) * dlon2m;
final double y1 = (cy - p.y) * dlat2m; final double y1 = (cy - p.y) * dlat2m;
final double dist = Math.sqrt( x1*x1 + y1*y1 ); final double dist = Math.sqrt(x1 * x1 + y1 * y1);
if (dist <= rad) if (dist <= rad) {
{
continue; continue;
} }
if (dist > dmax) if (dist > dmax) {
{
// new maximum distance found // new maximum distance found
dmax = dist; dmax = dist;
i_max = i; i_max = i;
} }
} }
if (i_max < 0) if (i_max < 0) {
{ break; // leave loop when no point outside the circle is found any more.
break; // leave loop when no point outside the circle is found any more.
} }
final double dd = 0.5 * (1 - rad / dmax); final double dd = 0.5 * (1 - rad / dmax);
final Point p = points.get(i_max); // calculate new radius to just include this point final Point p = points.get(i_max); // calculate new radius to just include this point
cx += (int)(dd * (p.x - cx) + 0.5); // shift center toward point cx += (int) (dd * (p.x - cx) + 0.5); // shift center toward point
cy += (int)(dd * (p.y - cy) + 0.5); cy += (int) (dd * (p.y - cy) + 0.5);
// get new factors at shifted centerpoint // get new factors at shifted centerpoint
lonlat2m = CheapRuler.getLonLatToMeterScales( cy ); lonlat2m = CheapRuler.getLonLatToMeterScales(cy);
dlon2m = lonlat2m[0]; dlon2m = lonlat2m[0];
dlat2m = lonlat2m[1]; dlat2m = lonlat2m[1];
final double x1 = (cx - p.x) * dlon2m; final double x1 = (cx - p.x) * dlon2m;
final double y1 = (cy - p.y) * dlat2m; final double y1 = (cy - p.y) * dlat2m;
dmax = rad = Math.sqrt( x1*x1 + y1*y1 ); dmax = rad = Math.sqrt(x1 * x1 + y1 * y1);
i_max = -1; i_max = -1;
} }
while (true); while (true);
@ -152,31 +135,28 @@ public class OsmNogoPolygon extends OsmNodeNamed
return; return;
} }
/** /**
* tests whether a segment defined by lon and lat of two points does either * tests whether a segment defined by lon and lat of two points does either
* intersect the polygon or any of the endpoints (or both) are enclosed by * intersect the polygon or any of the endpoints (or both) are enclosed by
* the polygon. For this test the winding-number algorithm is * the polygon. For this test the winding-number algorithm is
* being used. That means a point being within an overlapping region of the * being used. That means a point being within an overlapping region of the
* polygon is also taken as being 'inside' the polygon. * polygon is also taken as being 'inside' the polygon.
* *
* @param lon0 longitude of start point * @param lon0 longitude of start point
* @param lat0 latitude of start point * @param lat0 latitude of start point
* @param lon1 longitude of end point * @param lon1 longitude of end point
* @param lat1 latitude of start point * @param lat1 latitude of start point
* @return true if segment or any of it's points are 'inside' of polygon * @return true if segment or any of it's points are 'inside' of polygon
*/ */
public boolean intersects(int lon0, int lat0, int lon1, int lat1) public boolean intersects(int lon0, int lat0, int lon1, int lat1) {
{ final Point p0 = new Point(lon0, lat0);
final Point p0 = new Point (lon0,lat0); final Point p1 = new Point(lon1, lat1);
final Point p1 = new Point (lon1,lat1); int i_last = points.size() - 1;
int i_last = points.size()-1; Point p2 = points.get(isClosed ? i_last : 0);
Point p2 = points.get(isClosed ? i_last : 0 ); for (int i = isClosed ? 0 : 1; i <= i_last; i++) {
for (int i = isClosed ? 0 : 1 ; i <= i_last; i++)
{
Point p3 = points.get(i); Point p3 = points.get(i);
// does it intersect with at least one of the polygon's segments? // does it intersect with at least one of the polygon's segments?
if (intersect2D_2Segments(p0,p1,p2,p3) > 0) if (intersect2D_2Segments(p0, p1, p2, p3) > 0) {
{
return true; return true;
} }
p2 = p3; p2 = p3;
@ -184,15 +164,12 @@ public class OsmNogoPolygon extends OsmNodeNamed
return false; return false;
} }
public boolean isOnPolyline( long px, long py ) public boolean isOnPolyline(long px, long py) {
{ int i_last = points.size() - 1;
int i_last = points.size()-1;
Point p1 = points.get(0); Point p1 = points.get(0);
for (int i = 1 ; i <= i_last; i++) for (int i = 1; i <= i_last; i++) {
{
final Point p2 = points.get(i); final Point p2 = points.get(i);
if (OsmNogoPolygon.isOnLine(px,py,p1.x,p1.y,p2.x,p2.y)) if (OsmNogoPolygon.isOnLine(px, py, p1.x, p1.y, p2.x, p2.y)) {
{
return true; return true;
} }
p1 = p2; p1 = p2;
@ -200,37 +177,35 @@ public class OsmNogoPolygon extends OsmNodeNamed
return false; return false;
} }
public static boolean isOnLine( long px, long py, long p0x, long p0y, long p1x, long p1y ) public static boolean isOnLine(long px, long py, long p0x, long p0y, long p1x, long p1y) {
{ final double v10x = px - p0x;
final double v10x = px-p0x; final double v10y = py - p0y;
final double v10y = py-p0y; final double v12x = p1x - p0x;
final double v12x = p1x-p0x; final double v12y = p1y - p0y;
final double v12y = p1y-p0y;
if ( v10x == 0 ) // P0->P1 vertical? if (v10x == 0) // P0->P1 vertical?
{ {
if ( v10y == 0 ) // P0 == P1? if (v10y == 0) // P0 == P1?
{ {
return true; return true;
} }
if ( v12x != 0 ) // P1->P2 not vertical? if (v12x != 0) // P1->P2 not vertical?
{ {
return false; return false;
} }
return ( v12y / v10y ) >= 1; // P1->P2 at least as long as P1->P0? return (v12y / v10y) >= 1; // P1->P2 at least as long as P1->P0?
} }
if ( v10y == 0 ) // P0->P1 horizontal? if (v10y == 0) // P0->P1 horizontal?
{ {
if ( v12y != 0 ) // P1->P2 not horizontal? if (v12y != 0) // P1->P2 not horizontal?
{ {
return false; return false;
} }
// if ( P10x == 0 ) // P0 == P1? already tested // if ( P10x == 0 ) // P0 == P1? already tested
return ( v12x / v10x ) >= 1; // P1->P2 at least as long as P1->P0? return (v12x / v10x) >= 1; // P1->P2 at least as long as P1->P0?
} }
final double kx = v12x / v10x; final double kx = v12x / v10x;
if ( kx < 1 ) if (kx < 1) {
{
return false; return false;
} }
return kx == v12y / v10y; return kx == v12y / v10y;
@ -242,19 +217,19 @@ public class OsmNogoPolygon extends OsmNodeNamed
this code, and cannot be held liable for any real or imagined damage this code, and cannot be held liable for any real or imagined damage
resulting from its use. Users of this code must verify correctness for resulting from its use. Users of this code must verify correctness for
their application. */ their application. */
/**
* winding number test for a point in a polygon /**
* * winding number test for a point in a polygon
* @param px longitude of the point to check *
* @param py latitude of the point to check * @param px longitude of the point to check
* @return a boolean whether the point is within the polygon or not. * @param py latitude of the point to check
*/ * @return a boolean whether the point is within the polygon or not.
public boolean isWithin(final long px, final long py) */
{ public boolean isWithin(final long px, final long py) {
int wn = 0; // the winding number counter int wn = 0; // the winding number counter
// loop through all edges of the polygon // loop through all edges of the polygon
final int i_last = points.size()-1; final int i_last = points.size() - 1;
final Point p0 = points.get(isClosed ? i_last : 0); final Point p0 = points.get(isClosed ? i_last : 0);
long p0x = p0.x; // need to use long to avoid overflow in products long p0x = p0.x; // need to use long to avoid overflow in products
long p0y = p0.y; long p0y = p0.y;
@ -266,8 +241,7 @@ public class OsmNogoPolygon extends OsmNodeNamed
final long p1x = p1.x; final long p1x = p1.x;
final long p1y = p1.y; final long p1y = p1.y;
if (OsmNogoPolygon.isOnLine(px, py, p0x, p0y, p1x, p1y)) if (OsmNogoPolygon.isOnLine(px, py, p0x, p0y, p1x, p1y)) {
{
return true; return true;
} }
@ -275,18 +249,15 @@ public class OsmNogoPolygon extends OsmNodeNamed
{ {
if (p1y > py) // an upward crossing if (p1y > py) // an upward crossing
{ // p left of edge { // p left of edge
if (((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) > 0) if (((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) > 0) {
{
++wn; // have a valid up intersect ++wn; // have a valid up intersect
} }
} }
} } else // start y > p.y (no test needed)
else // start y > p.y (no test needed)
{ {
if (p1y <= py) // a downward crossing if (p1y <= py) // a downward crossing
{ // p right of edge { // p right of edge
if (((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) < 0) if (((p1x - p0x) * (py - p0y) - (px - p0x) * (p1y - p0y)) < 0) {
{
--wn; // have a valid down intersect --wn; // have a valid down intersect
} }
} }
@ -304,20 +275,18 @@ public class OsmNogoPolygon extends OsmNodeNamed
* @param lat1 Integer latitude of the first point of the segment. * @param lat1 Integer latitude of the first point of the segment.
* @param lon2 Integer longitude of the last point of the segment. * @param lon2 Integer longitude of the last point of the segment.
* @param lat2 Integer latitude of the last point of the segment. * @param lat2 Integer latitude of the last point of the segment.
*
* @return The length, in meters, of the portion of the segment which is * @return The length, in meters, of the portion of the segment which is
* included in the polygon. * included in the polygon.
*/ */
public double distanceWithinPolygon(int lon1, int lat1, int lon2, int lat2) { public double distanceWithinPolygon(int lon1, int lat1, int lon2, int lat2) {
double distance = 0.; double distance = 0.;
// Extremities of the segments // Extremities of the segments
final Point p1 = new Point (lon1, lat1); final Point p1 = new Point(lon1, lat1);
final Point p2 = new Point (lon2, lat2); final Point p2 = new Point(lon2, lat2);
Point previousIntersectionOnSegment = null; Point previousIntersectionOnSegment = null;
if (isWithin(lon1, lat1)) if (isWithin(lon1, lat1)) {
{
// Start point of the segment is within the polygon, this is the first // Start point of the segment is within the polygon, this is the first
// "intersection". // "intersection".
previousIntersectionOnSegment = p1; previousIntersectionOnSegment = p1;
@ -325,14 +294,12 @@ public class OsmNogoPolygon extends OsmNodeNamed
// Loop over edges of the polygon to find intersections // Loop over edges of the polygon to find intersections
int i_last = points.size() - 1; int i_last = points.size() - 1;
for (int i = (isClosed ? 0 : 1), j = (isClosed ? i_last : 0); i <= i_last; j = i++) for (int i = (isClosed ? 0 : 1), j = (isClosed ? i_last : 0); i <= i_last; j = i++) {
{
Point edgePoint1 = points.get(j); Point edgePoint1 = points.get(j);
Point edgePoint2 = points.get(i); Point edgePoint2 = points.get(i);
int intersectsEdge = intersect2D_2Segments(p1, p2, edgePoint1, edgePoint2); int intersectsEdge = intersect2D_2Segments(p1, p2, edgePoint1, edgePoint2);
if (isClosed && intersectsEdge == 1) if (isClosed && intersectsEdge == 1) {
{
// Intersects with a (closed) polygon edge on a single point // Intersects with a (closed) polygon edge on a single point
// Distance is zero when crossing a polyline. // Distance is zero when crossing a polyline.
// Let's find this intersection point // Let's find this intersection point
@ -350,7 +317,7 @@ public class OsmNogoPolygon extends OsmNodeNamed
); );
if ( if (
previousIntersectionOnSegment != null previousIntersectionOnSegment != null
&& isWithin( && isWithin(
(intersection.x + previousIntersectionOnSegment.x) >> 1, (intersection.x + previousIntersectionOnSegment.x) >> 1,
(intersection.y + previousIntersectionOnSegment.y) >> 1 (intersection.y + previousIntersectionOnSegment.y) >> 1
) )
@ -363,8 +330,7 @@ public class OsmNogoPolygon extends OsmNodeNamed
); );
} }
previousIntersectionOnSegment = intersection; previousIntersectionOnSegment = intersection;
} } else if (intersectsEdge == 2) {
else if (intersectsEdge == 2) {
// Segment and edge overlaps // Segment and edge overlaps
// FIXME: Could probably be done in a smarter way // FIXME: Could probably be done in a smarter way
distance += Math.min( distance += Math.min(
@ -384,7 +350,7 @@ public class OsmNogoPolygon extends OsmNodeNamed
if ( if (
previousIntersectionOnSegment != null previousIntersectionOnSegment != null
&& isWithin(lon2, lat2) && isWithin(lon2, lat2)
) { ) {
// Last point is within the polygon, add the remaining missing distance. // Last point is within the polygon, add the remaining missing distance.
distance += CheapRuler.distance( distance += CheapRuler.distance(
@ -401,44 +367,39 @@ public class OsmNogoPolygon extends OsmNodeNamed
this code, and cannot be held liable for any real or imagined damage this code, and cannot be held liable for any real or imagined damage
resulting from its use. Users of this code must verify correctness for resulting from its use. Users of this code must verify correctness for
their application. */ their application. */
/**
* inSegment(): determine if a point is inside a segment /**
* * inSegment(): determine if a point is inside a segment
* @param p a point *
* @param seg_p0 starting point of segment * @param p a point
* @param seg_p1 ending point of segment * @param seg_p0 starting point of segment
* @return 1 = P is inside S * @param seg_p1 ending point of segment
* 0 = P is not inside S * @return 1 = P is inside S
*/ * 0 = P is not inside S
private static boolean inSegment( final Point p, final Point seg_p0, final Point seg_p1) */
{ private static boolean inSegment(final Point p, final Point seg_p0, final Point seg_p1) {
final int sp0x = seg_p0.x; final int sp0x = seg_p0.x;
final int sp1x = seg_p1.x; final int sp1x = seg_p1.x;
if (sp0x != sp1x) // S is not vertical if (sp0x != sp1x) // S is not vertical
{ {
final int px = p.x; final int px = p.x;
if (sp0x <= px && px <= sp1x) if (sp0x <= px && px <= sp1x) {
{
return true; return true;
} }
if (sp0x >= px && px >= sp1x) if (sp0x >= px && px >= sp1x) {
{
return true; return true;
} }
} } else // S is vertical, so test y coordinate
else // S is vertical, so test y coordinate
{ {
final int sp0y = seg_p0.y; final int sp0y = seg_p0.y;
final int sp1y = seg_p1.y; final int sp1y = seg_p1.y;
final int py = p.y; final int py = p.y;
if (sp0y <= py && py <= sp1y) if (sp0y <= py && py <= sp1y) {
{
return true; return true;
} }
if (sp0y >= py && py >= sp1y) if (sp0y >= py && py >= sp1y) {
{
return true; return true;
} }
} }
@ -451,18 +412,19 @@ public class OsmNogoPolygon extends OsmNodeNamed
this code, and cannot be held liable for any real or imagined damage this code, and cannot be held liable for any real or imagined damage
resulting from its use. Users of this code must verify correctness for resulting from its use. Users of this code must verify correctness for
their application. */ their application. */
/**
* intersect2D_2Segments(): find the 2D intersection of 2 finite segments /**
* @param s1p0 start point of segment 1 * intersect2D_2Segments(): find the 2D intersection of 2 finite segments
* @param s1p1 end point of segment 1 *
* @param s2p0 start point of segment 2 * @param s1p0 start point of segment 1
* @param s2p1 end point of segment 2 * @param s1p1 end point of segment 1
* @return 0=disjoint (no intersect) * @param s2p0 start point of segment 2
* 1=intersect in unique point I0 * @param s2p1 end point of segment 2
* 2=overlap in segment from I0 to I1 * @return 0=disjoint (no intersect)
*/ * 1=intersect in unique point I0
private static int intersect2D_2Segments( final Point s1p0, final Point s1p1, final Point s2p0, final Point s2p1 ) * 2=overlap in segment from I0 to I1
{ */
private static int intersect2D_2Segments(final Point s1p0, final Point s1p1, final Point s2p0, final Point s2p1) {
final long ux = s1p1.x - s1p0.x; // vector u = S1P1-S1P0 (segment 1) final long ux = s1p1.x - s1p0.x; // vector u = S1P1-S1P0 (segment 1)
final long uy = s1p1.y - s1p0.y; final long uy = s1p1.y - s1p0.y;
final long vx = s2p1.x - s2p0.x; // vector v = S2P1-S2P0 (segment 2) final long vx = s2p1.x - s2p0.x; // vector v = S2P1-S2P0 (segment 2)
@ -475,8 +437,7 @@ public class OsmNogoPolygon extends OsmNodeNamed
// test if they are parallel (includes either being a point) // test if they are parallel (includes either being a point)
if (d == 0) // S1 and S2 are parallel if (d == 0) // S1 and S2 are parallel
{ {
if ((ux * wy - uy * wx) != 0 || (vx * wy - vy * wx) != 0) if ((ux * wy - uy * wx) != 0 || (vx * wy - vy * wx) != 0) {
{
return 0; // they are NOT collinear return 0; // they are NOT collinear
} }
@ -500,28 +461,24 @@ public class OsmNogoPolygon extends OsmNodeNamed
double t0, t1; // endpoints of S1 in eqn for S2 double t0, t1; // endpoints of S1 in eqn for S2
final int w2x = s1p1.x - s2p0.x; // vector w2 = S1P1-S2P0 (from start of segment 2 to end of segment 1) final int w2x = s1p1.x - s2p0.x; // vector w2 = S1P1-S2P0 (from start of segment 2 to end of segment 1)
final int w2y = s1p1.y - s2p0.y; final int w2y = s1p1.y - s2p0.y;
if (vx != 0) if (vx != 0) {
{
t0 = wx / vx; t0 = wx / vx;
t1 = w2x / vx; t1 = w2x / vx;
} } else {
else
{
t0 = wy / vy; t0 = wy / vy;
t1 = w2y / vy; t1 = w2y / vy;
} }
if (t0 > t1) // must have t0 smaller than t1 if (t0 > t1) // must have t0 smaller than t1
{ {
final double t=t0; // swap if not final double t = t0; // swap if not
t0=t1; t0 = t1;
t1=t; t1 = t;
} }
if (t0 > 1 || t1 < 0) if (t0 > 1 || t1 < 0) {
{
return 0; // NO overlap return 0; // NO overlap
} }
t0 = t0<0? 0 : t0; // clip to min 0 t0 = t0 < 0 ? 0 : t0; // clip to min 0
t1 = t1>1? 1 : t1; // clip to max 1 t1 = t1 > 1 ? 1 : t1; // clip to max 1
return (t0 == t1) ? 1 : 2; // return 1 if intersect is a point return (t0 == t1) ? 1 : 2; // return 1 if intersect is a point
} }

View File

@ -14,8 +14,7 @@ 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)
*/ */
@ -57,90 +56,74 @@ abstract class OsmPath implements OsmLinkHolder
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 ) private void setBit(int mask, boolean bit) {
{ if (getBit(mask) != bit) {
if ( getBit( mask ) != bit )
{
bitfield ^= mask; bitfield ^= mask;
} }
} }
public boolean didEnterDestinationArea() public boolean didEnterDestinationArea() {
{ return !getBit(HAD_DESTINATION_START_BIT) && getBit(IS_ON_DESTINATION_BIT);
return !getBit( HAD_DESTINATION_START_BIT ) && getBit( IS_ON_DESTINATION_BIT );
} }
public MessageData message; public MessageData message;
public void unregisterUpTree( RoutingContext rc ) public void unregisterUpTree(RoutingContext rc) {
{ try {
try
{
OsmPathElement pe = originElement; OsmPathElement pe = originElement;
while( pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic)pe).unregister(rc) ) while (pe instanceof OsmPathElementWithTraffic && ((OsmPathElementWithTraffic) pe).unregister(rc)) {
{
pe = pe.origin; pe = pe.origin;
} }
} } catch (IOException ioe) {
catch( IOException ioe ) throw new RuntimeException(ioe);
{
throw new RuntimeException( ioe );
} }
} }
public void registerUpTree() public void registerUpTree() {
{ if (originElement instanceof OsmPathElementWithTraffic) {
if ( originElement instanceof OsmPathElementWithTraffic ) OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic) originElement;
{
OsmPathElementWithTraffic ot = (OsmPathElementWithTraffic)originElement;
ot.register(); ot.register();
ot.addTraffic( traffic ); ot.addTraffic(traffic);
} }
} }
public void init( OsmLink link ) public void init(OsmLink link) {
{
this.link = link; this.link = link;
targetNode = link.getTarget( null ); targetNode = link.getTarget(null);
selev = targetNode.getSElev(); selev = targetNode.getSElev();
originLon = -1; originLon = -1;
originLat = -1; originLat = -1;
} }
public void init( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc ) public void init(OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode, RoutingContext rc) {
{ if (origin.myElement == null) {
if ( origin.myElement == null ) origin.myElement = OsmPathElement.create(origin, rc.countTraffic);
{
origin.myElement = OsmPathElement.create( origin, rc.countTraffic );
} }
this.originElement = origin.myElement; this.originElement = origin.myElement;
this.link = link; this.link = link;
this.sourceNode = origin.targetNode; this.sourceNode = origin.targetNode;
this.targetNode = link.getTarget( sourceNode ); this.targetNode = link.getTarget(sourceNode);
this.cost = origin.cost; this.cost = origin.cost;
this.lastClassifier = origin.lastClassifier; this.lastClassifier = origin.lastClassifier;
this.lastInitialCost = origin.lastInitialCost; this.lastInitialCost = origin.lastInitialCost;
this.bitfield = origin.bitfield; this.bitfield = origin.bitfield;
init( origin ); init(origin);
addAddionalPenalty(refTrack, detailMode, origin, link, rc ); addAddionalPenalty(refTrack, detailMode, origin, link, rc);
} }
protected abstract void init( OsmPath orig ); protected abstract void init(OsmPath orig);
protected abstract void resetState(); protected abstract void resetState();
protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc ) protected void addAddionalPenalty(OsmTrack refTrack, boolean detailMode, OsmPath origin, OsmLink link, RoutingContext rc) {
{
byte[] description = link.descriptionBitmap; byte[] description = link.descriptionBitmap;
if ( description == null ) if (description == null) {
{
return; // could be a beeline path return; // could be a beeline path
} }
@ -160,34 +143,31 @@ abstract class OsmPath implements OsmLinkHolder
message = detailMode ? new MessageData() : null; message = detailMode ? new MessageData() : null;
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);
// calculate the costfactor inputs // calculate the costfactor inputs
float costfactor = rc.expctxWay.getCostfactor(); float costfactor = rc.expctxWay.getCostfactor();
boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f; boolean isTrafficBackbone = cost == 0 && rc.expctxWay.getIsTrafficBackbone() > 0.f;
int lastpriorityclassifier = priorityclassifier; int lastpriorityclassifier = priorityclassifier;
priorityclassifier = (int)rc.expctxWay.getPriorityClassifier(); priorityclassifier = (int) rc.expctxWay.getPriorityClassifier();
// *** add initial cost if the classifier changed // *** add initial cost if the classifier changed
float newClassifier = rc.expctxWay.getInitialClassifier(); float newClassifier = rc.expctxWay.getInitialClassifier();
float newInitialCost = rc.expctxWay.getInitialcost(); float newInitialCost = rc.expctxWay.getInitialcost();
float classifierDiff = newClassifier - lastClassifier; float classifierDiff = newClassifier - lastClassifier;
if ( newClassifier != 0. && lastClassifier != 0. && ( classifierDiff > 0.0005 || classifierDiff < -0.0005 ) ) if (newClassifier != 0. && lastClassifier != 0. && (classifierDiff > 0.0005 || classifierDiff < -0.0005)) {
{
float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost; float initialcost = rc.inverseDirection ? lastInitialCost : newInitialCost;
if ( initialcost >= 1000000. ) if (initialcost >= 1000000.) {
{
cost = -1; cost = -1;
return; return;
} }
int iicost = (int)initialcost; int iicost = (int) initialcost;
if ( message != null ) if (message != null) {
{
message.linkinitcost += iicost; message.linkinitcost += iicost;
} }
cost += iicost; cost += iicost;
@ -196,38 +176,30 @@ abstract class OsmPath implements OsmLinkHolder
lastInitialCost = newInitialCost; lastInitialCost = newInitialCost;
// *** destination logic: no destination access in between // *** destination logic: no destination access in between
int classifiermask = (int)rc.expctxWay.getClassifierMask(); int classifiermask = (int) rc.expctxWay.getClassifierMask();
boolean newDestination = (classifiermask & 64) != 0; boolean newDestination = (classifiermask & 64) != 0;
boolean oldDestination = getBit( IS_ON_DESTINATION_BIT ); boolean oldDestination = getBit(IS_ON_DESTINATION_BIT);
if ( getBit( PATH_START_BIT ) ) if (getBit(PATH_START_BIT)) {
{ setBit(PATH_START_BIT, false);
setBit( PATH_START_BIT, false ); setBit(CAN_LEAVE_DESTINATION_BIT, newDestination);
setBit( CAN_LEAVE_DESTINATION_BIT, newDestination ); setBit(HAD_DESTINATION_START_BIT, newDestination);
setBit( HAD_DESTINATION_START_BIT, newDestination ); } else {
} if (oldDestination && !newDestination) {
else if (getBit(CAN_LEAVE_DESTINATION_BIT)) {
{ setBit(CAN_LEAVE_DESTINATION_BIT, false);
if ( oldDestination && !newDestination ) } else {
{
if ( getBit( CAN_LEAVE_DESTINATION_BIT ) )
{
setBit( CAN_LEAVE_DESTINATION_BIT, false );
}
else
{
cost = -1; cost = -1;
return; return;
} }
} }
} }
setBit( IS_ON_DESTINATION_BIT, newDestination ); setBit(IS_ON_DESTINATION_BIT, newDestination);
OsmTransferNode transferNode = link.geometry == null ? null OsmTransferNode transferNode = link.geometry == null ? null
: rc.geometryDecoder.decodeGeometry( link.geometry, sourceNode, targetNode, isReverse ); : rc.geometryDecoder.decodeGeometry(link.geometry, sourceNode, targetNode, isReverse);
for(int nsection=0; ;nsection++) for (int nsection = 0; ; nsection++) {
{
originLon = lon1; originLon = lon1;
originLat = lat1; originLat = lat1;
@ -236,14 +208,11 @@ abstract class OsmPath implements OsmLinkHolder
int lat2; int lat2;
short ele2; short ele2;
if ( transferNode == null ) if (transferNode == null) {
{
lon2 = targetNode.ilon; lon2 = targetNode.ilon;
lat2 = targetNode.ilat; lat2 = targetNode.ilat;
ele2 = targetNode.selev; ele2 = targetNode.selev;
} } else {
else
{
lon2 = transferNode.ilon; lon2 = transferNode.ilon;
lat2 = transferNode.ilat; lat2 = transferNode.ilat;
ele2 = transferNode.selev; ele2 = transferNode.selev;
@ -252,36 +221,29 @@ abstract class OsmPath implements OsmLinkHolder
boolean isStartpoint = lon0 == -1 && lat0 == -1; boolean isStartpoint = lon0 == -1 && lat0 == -1;
// check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints) // check turn restrictions (n detail mode (=final pass) no TR to not mess up voice hints)
if ( nsection == 0 && rc.considerTurnRestrictions && !detailMode&& !isStartpoint ) if (nsection == 0 && rc.considerTurnRestrictions && !detailMode && !isStartpoint) {
{ if (rc.inverseDirection
if ( rc.inverseDirection ? TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode)
? TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon2, lat2, lon0, lat0, rc.bikeMode || rc.footMode, rc.carMode ) : TurnRestriction.isTurnForbidden(sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode)) {
: TurnRestriction.isTurnForbidden( sourceNode.firstRestriction, lon0, lat0, lon2, lat2, rc.bikeMode || rc.footMode, rc.carMode ) )
{
cost = -1; cost = -1;
return; return;
} }
} }
// if recording, new MessageData for each section (needed for turn-instructions) // if recording, new MessageData for each section (needed for turn-instructions)
if ( message != null && message.wayKeyValues != null ) if (message != null && message.wayKeyValues != null) {
{
originElement.message = message; originElement.message = message;
message = new MessageData(); message = new MessageData();
} }
int dist = rc.calcDistance( lon1, lat1, lon2, lat2 ); int dist = rc.calcDistance(lon1, lat1, lon2, lat2);
boolean stopAtEndpoint = false; boolean stopAtEndpoint = false;
if ( rc.shortestmatch ) if (rc.shortestmatch) {
{ if (rc.isEndpoint) {
if ( rc.isEndpoint )
{
stopAtEndpoint = true; stopAtEndpoint = true;
ele2 = interpolateEle( ele1, ele2, rc.wayfraction ); ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
} } else {
else
{
// we just start here, reset everything // we just start here, reset everything
cost = 0; cost = 0;
resetState(); resetState();
@ -289,138 +251,111 @@ abstract class OsmPath implements OsmLinkHolder
lat0 = -1; lat0 = -1;
isStartpoint = true; isStartpoint = true;
if ( recordTransferNodes ) if (recordTransferNodes) {
{ if (rc.wayfraction > 0.) {
if ( rc.wayfraction > 0. ) ele1 = interpolateEle(ele1, ele2, 1. - rc.wayfraction);
{ originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic);
ele1 = interpolateEle( ele1, ele2, 1. - rc.wayfraction ); } else {
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele1, null, rc.countTraffic );
}
else
{
originElement = null; // prevent duplicate point originElement = null; // prevent duplicate point
} }
} }
if ( rc.checkPendingEndpoint() ) if (rc.checkPendingEndpoint()) {
{ dist = rc.calcDistance(rc.ilonshortest, rc.ilatshortest, lon2, lat2);
dist = rc.calcDistance( rc.ilonshortest, rc.ilatshortest, lon2, lat2 ); if (rc.shortestmatch) {
if ( rc.shortestmatch )
{
stopAtEndpoint = true; stopAtEndpoint = true;
ele2 = interpolateEle( ele1, ele2, rc.wayfraction ); ele2 = interpolateEle(ele1, ele2, rc.wayfraction);
} }
} }
} }
} }
if ( message != null ) if (message != null) {
{
message.linkdist += dist; message.linkdist += dist;
} }
linkdisttotal += dist; linkdisttotal += dist;
// apply a start-direction if appropriate (by faking the origin position) // apply a start-direction if appropriate (by faking the origin position)
if ( isStartpoint ) if (isStartpoint) {
{ if (rc.startDirectionValid) {
if ( rc.startDirectionValid )
{
double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD; double dir = rc.startDirection.intValue() * CheapRuler.DEG_TO_RAD;
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lon0 + lat1) >> 1 ); double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lon0 + lat1) >> 1);
lon0 = lon1 - (int) ( 1000. * Math.sin( dir ) / lonlat2m[0] ); lon0 = lon1 - (int) (1000. * Math.sin(dir) / lonlat2m[0]);
lat0 = lat1 - (int) ( 1000. * Math.cos( dir ) / lonlat2m[1] ); lat0 = lat1 - (int) (1000. * Math.cos(dir) / lonlat2m[1]);
} } else {
else lon0 = lon1 - (lon2 - lon1);
{ lat0 = lat1 - (lat2 - lat1);
lon0 = lon1 - (lon2-lon1);
lat0 = lat1 - (lat2-lat1);
} }
} }
double angle = rc.anglemeter.calcAngle( lon0, lat0, lon1, lat1, lon2, lat2 ); double angle = rc.anglemeter.calcAngle(lon0, lat0, lon1, lat1, lon2, lat2);
double cosangle = rc.anglemeter.getCosAngle(); double cosangle = rc.anglemeter.getCosAngle();
// *** elevation stuff // *** elevation stuff
double delta_h = 0.; double delta_h = 0.;
if ( ele2 == Short.MIN_VALUE ) ele2 = ele1; if (ele2 == Short.MIN_VALUE) ele2 = ele1;
if ( ele1 != Short.MIN_VALUE ) if (ele1 != Short.MIN_VALUE) {
{ delta_h = (ele2 - ele1) / 4.;
delta_h = (ele2 - ele1)/4.; if (rc.inverseDirection) {
if ( rc.inverseDirection )
{
delta_h = -delta_h; delta_h = -delta_h;
} }
} }
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2 / 4.;
double sectionCost = processWaySection(rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier);
double elevation = ele2 == Short.MIN_VALUE ? 100. : ele2/4.; if ((sectionCost < 0. || costfactor > 9998. && !detailMode) || sectionCost + cost >= 2000000000.) {
double sectionCost = processWaySection( rc, dist, delta_h, elevation, angle, cosangle, isStartpoint, nsection, lastpriorityclassifier );
if ( ( sectionCost < 0. || costfactor > 9998. && !detailMode ) || sectionCost + cost >= 2000000000. )
{
cost = -1; cost = -1;
return; return;
} }
if ( isTrafficBackbone ) if (isTrafficBackbone) {
{
sectionCost = 0.; sectionCost = 0.;
} }
cost += (int)sectionCost; cost += (int) sectionCost;
// calculate traffic // calculate traffic
if ( rc.countTraffic ) if (rc.countTraffic) {
{ int minDist = (int) rc.trafficSourceMinDist;
int minDist = (int)rc.trafficSourceMinDist;
int cost2 = cost < minDist ? minDist : cost; int cost2 = cost < minDist ? minDist : cost;
traffic += dist*rc.expctxWay.getTrafficSourceDensity()*Math.pow(cost2/10000.f,rc.trafficSourceExponent); traffic += dist * rc.expctxWay.getTrafficSourceDensity() * Math.pow(cost2 / 10000.f, rc.trafficSourceExponent);
} }
// compute kinematic // compute kinematic
computeKinematic( rc, dist, delta_h, detailMode ); computeKinematic(rc, dist, delta_h, detailMode);
if ( message != null ) if (message != null) {
{ message.turnangle = (float) angle;
message.turnangle = (float)angle; message.time = (float) getTotalTime();
message.time = (float)getTotalTime(); message.energy = (float) getTotalEnergy();
message.energy = (float)getTotalEnergy();
message.priorityclassifier = priorityclassifier; message.priorityclassifier = priorityclassifier;
message.classifiermask = classifiermask; message.classifiermask = classifiermask;
message.lon = lon2; message.lon = lon2;
message.lat = lat2; message.lat = lat2;
message.ele = ele2; message.ele = ele2;
message.wayKeyValues = rc.expctxWay.getKeyValueDescription( isReverse, description ); message.wayKeyValues = rc.expctxWay.getKeyValueDescription(isReverse, description);
} }
if ( stopAtEndpoint ) if (stopAtEndpoint) {
{ if (recordTransferNodes) {
if ( recordTransferNodes ) originElement = OsmPathElement.create(rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic);
{
originElement = OsmPathElement.create( rc.ilonshortest, rc.ilatshortest, ele2, originElement, rc.countTraffic );
originElement.cost = cost; originElement.cost = cost;
if ( message != null ) if (message != null) {
{
originElement.message = message; originElement.message = message;
} }
} }
if ( rc.nogoCost < 0) if (rc.nogoCost < 0) {
{
cost = -1; cost = -1;
} } else {
else
{
cost += rc.nogoCost; cost += rc.nogoCost;
} }
return; return;
} }
if ( transferNode == null ) if (transferNode == null) {
{
// *** penalty for being part of the reference track // *** penalty for being part of the reference track
if ( refTrack != null && refTrack.containsNode( targetNode ) && refTrack.containsNode( sourceNode ) ) if (refTrack != null && refTrack.containsNode(targetNode) && refTrack.containsNode(sourceNode)) {
{
int reftrackcost = linkdisttotal; int reftrackcost = linkdisttotal;
cost += reftrackcost; cost += reftrackcost;
} }
@ -429,11 +364,10 @@ abstract class OsmPath implements OsmLinkHolder
} }
transferNode = transferNode.next; transferNode = transferNode.next;
if ( recordTransferNodes ) if (recordTransferNodes) {
{ originElement = OsmPathElement.create(lon2, lat2, ele2, originElement, rc.countTraffic);
originElement = OsmPathElement.create( lon2, lat2, ele2, originElement, rc.countTraffic );
originElement.cost = cost; originElement.cost = cost;
originElement.addTraffic( traffic ); originElement.addTraffic(traffic);
traffic = 0; traffic = 0;
} }
lon0 = lon1; lon0 = lon1;
@ -444,81 +378,67 @@ abstract class OsmPath implements OsmLinkHolder
} }
// check for nogo-matches (after the *actual* start of segment) // check for nogo-matches (after the *actual* start of segment)
if ( rc.nogoCost < 0) if (rc.nogoCost < 0) {
{
cost = -1; cost = -1;
return; return;
} } else {
else
{
cost += rc.nogoCost; cost += rc.nogoCost;
} }
// add target-node costs // add target-node costs
double targetCost = processTargetNode( rc ); double targetCost = processTargetNode(rc);
if ( targetCost < 0. || targetCost + cost >= 2000000000. ) if (targetCost < 0. || targetCost + cost >= 2000000000.) {
{
cost = -1; cost = -1;
return; return;
} }
cost += (int)targetCost; cost += (int) targetCost;
} }
public short interpolateEle( short e1, short e2, double fraction ) public short interpolateEle(short e1, short e2, double fraction) {
{ if (e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE) {
if ( e1 == Short.MIN_VALUE || e2 == Short.MIN_VALUE )
{
return Short.MIN_VALUE; return Short.MIN_VALUE;
} }
return (short)( e1*(1.-fraction) + e2*fraction ); 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 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 abstract double processTargetNode(RoutingContext rc);
protected void computeKinematic( RoutingContext rc, double dist, double delta_h, boolean detailMode ) protected void computeKinematic(RoutingContext rc, double dist, double delta_h, boolean detailMode) {
{
} }
public abstract int elevationCorrection( RoutingContext rc ); public abstract int elevationCorrection(RoutingContext rc);
public abstract boolean definitlyWorseThan( OsmPath p, RoutingContext rc ); public abstract boolean definitlyWorseThan(OsmPath p, RoutingContext rc);
public OsmNode getSourceNode() public OsmNode getSourceNode() {
{
return sourceNode; return sourceNode;
} }
public OsmNode getTargetNode() public OsmNode getTargetNode() {
{
return targetNode; return targetNode;
} }
public OsmLink getLink() public OsmLink getLink() {
{
return link; return link;
} }
public void setNextForLink( OsmLinkHolder holder ) public void setNextForLink(OsmLinkHolder holder) {
{
nextForLink = holder; nextForLink = holder;
} }
public OsmLinkHolder getNextForLink() public OsmLinkHolder getNextForLink() {
{
return nextForLink; return nextForLink;
} }
public double getTotalTime() public double getTotalTime() {
{
return 0.; return 0.;
} }
public double getTotalEnergy() public double getTotalEnergy() {
{
return 0.; return 0.;
} }
} }

View File

@ -14,8 +14,7 @@ import btools.util.CheapRuler;
* @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
@ -25,76 +24,62 @@ public class OsmPathElement implements OsmPos
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() 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 float getTime() public final float getTime() {
{
return message == null ? 0.f : message.time; return message == null ? 0.f : message.time;
} }
public final void setTime( float t ) public final void setTime(float t) {
{ if (message != null) {
if ( message != null )
{
message.time = t; message.time = t;
} }
} }
public final float getEnergy() public final float getEnergy() {
{
return message == null ? 0.f : message.energy; return message == null ? 0.f : message.energy;
} }
public final void setEnergy( float e ) public final void setEnergy(float e) {
{ if (message != null) {
if ( message != null )
{
message.energy = e; message.energy = e;
} }
} }
public final long getIdFromPos() public final long getIdFromPos() {
{ return ((long) ilon) << 32 | ilat;
return ((long)ilon)<<32 | ilat;
} }
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 OsmPathElement origin; public OsmPathElement origin;
// construct a path element from a path // construct a path element from a path
public static final OsmPathElement create( OsmPath path, boolean countTraffic ) public static final OsmPathElement create(OsmPath path, boolean countTraffic) {
{
OsmNode n = path.getTargetNode(); OsmNode n = path.getTargetNode();
OsmPathElement pe = create( n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic ); OsmPathElement pe = create(n.getILon(), n.getILat(), path.selev, path.originElement, countTraffic);
pe.cost = path.cost; pe.cost = path.cost;
pe.message = path.message; pe.message = path.message;
return pe; return pe;
} }
public static final OsmPathElement create( int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic ) public static final OsmPathElement create(int ilon, int ilat, short selev, OsmPathElement origin, boolean countTraffic) {
{
OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement(); OsmPathElement pe = countTraffic ? new OsmPathElementWithTraffic() : new OsmPathElement();
pe.ilon = ilon; pe.ilon = ilon;
pe.ilat = ilat; pe.ilat = ilat;
@ -103,34 +88,29 @@ public class OsmPathElement implements OsmPos
return pe; return pe;
} }
protected OsmPathElement() protected OsmPathElement() {
{
} }
public void addTraffic( float traffic ) public void addTraffic(float traffic) {
{
} }
public String toString() public String toString() {
{
return ilon + "_" + ilat; return ilon + "_" + ilat;
} }
public void writeToStream( DataOutput dos ) throws IOException public void writeToStream(DataOutput dos) throws IOException {
{ dos.writeInt(ilat);
dos.writeInt( ilat ); dos.writeInt(ilon);
dos.writeInt( ilon ); dos.writeShort(selev);
dos.writeShort( selev ); dos.writeInt(cost);
dos.writeInt( cost );
} }
public static OsmPathElement readFromStream( DataInput dis ) throws IOException public static OsmPathElement readFromStream(DataInput dis) throws IOException {
{ OsmPathElement pe = new OsmPathElement();
OsmPathElement pe = new OsmPathElement(); pe.ilat = dis.readInt();
pe.ilat = dis.readInt(); pe.ilon = dis.readInt();
pe.ilon = dis.readInt(); pe.selev = dis.readShort();
pe.selev = dis.readShort(); pe.cost = dis.readInt();
pe.cost = dis.readInt(); return pe;
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;
@ -32,40 +28,34 @@ 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; int costdelta = cost - ot.cost;
ot.farTraffic += farTraffic*Math.exp(-costdelta/rc.farTrafficDecayLength); ot.farTraffic += farTraffic * Math.exp(-costdelta / rc.farTrafficDecayLength);
ot.nearTraffic += nearTraffic*Math.exp(-costdelta/rc.nearTrafficDecayLength); ot.nearTraffic += nearTraffic * Math.exp(-costdelta / rc.nearTrafficDecayLength);
if ( costdelta > 0 && farTraffic > maxtraffic ) maxtraffic = farTraffic; if (costdelta > 0 && farTraffic > maxtraffic) maxtraffic = farTraffic;
int t2 = cost == ot.cost ? -1 : (int)(rc.farTrafficWeight*farTraffic + rc.nearTrafficWeight*nearTraffic); int t2 = cost == ot.cost ? -1 : (int) (rc.farTrafficWeight * farTraffic + rc.nearTrafficWeight * nearTraffic);
if ( t2 > 4000 || t2 == -1 ) 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,8 +11,7 @@ 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;
@ -25,132 +24,112 @@ public final class ProfileCache
private long lastUseTime; private long lastUseTime;
private static ProfileCache[] apc = new ProfileCache[1]; private static ProfileCache[] apc = new ProfileCache[1];
private static boolean debug = Boolean.getBoolean( "debugProfileCache" ); private static boolean debug = Boolean.getBoolean("debugProfileCache");
public static synchronized void setSize( int size ) 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 ); rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum() << 24;
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ; 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();
}
rc.profileTimestamp = profileFile.lastModified() + rc.getKeyValueChecksum()<<24; ProfileCache lru = null;
File lookupFile = new File( profileDir, "lookups.dat" ); int unusedSlot = -1;
// invalidate cache at lookup-table update // check for re-use
if ( !(lookupFile.equals( lastLookupFile ) && lookupFile.lastModified() == lastLookupTimestamp ) ) for (int i = 0; i < apc.length; i++) {
{
if ( lastLookupFile != null )
{
System.out.println( "******** invalidating profile-cache after lookup-file update ******** " );
}
apc = new ProfileCache[apc.length];
lastLookupFile = lookupFile;
lastLookupTimestamp = lookupFile.lastModified();
}
ProfileCache lru = null;
int unusedSlot =-1;
// check for re-use
for( int i=0; i<apc.length; i++)
{
ProfileCache pc = apc[i];
if ( pc != null )
{
if ( (!pc.profilesBusy) && profileFile.equals( pc.lastProfileFile ) )
{
if ( rc.profileTimestamp == pc.lastProfileTimestamp )
{
rc.expctxWay = pc.expctxWay;
rc.expctxNode = pc.expctxNode;
rc.readGlobalConfig();
pc.profilesBusy = true;
return true;
}
lru = pc; // name-match but timestamp-mismatch -> we overide this one
unusedSlot = -1;
break;
}
if ( lru == null || lru.lastUseTime > pc.lastUseTime )
{
lru = pc;
}
}
else if ( unusedSlot < 0 )
{
unusedSlot = i;
}
}
BExpressionMetaData meta = new BExpressionMetaData();
rc.expctxWay = new BExpressionContextWay( rc.memoryclass * 512, meta );
rc.expctxNode = new BExpressionContextNode( 0, meta );
rc.expctxNode.setForeignContext( rc.expctxWay );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode.parseFile( profileFile, "global" );
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.lastProfileFile != null )
{
if ( debug ) System.out.println( "******* replacing profile of age " + ((System.currentTimeMillis()-lru.lastUseTime)/1000L) + " sec " + lru.lastProfileFile + "->" + profileFile );
}
lru.lastProfileTimestamp = rc.profileTimestamp;
lru.lastProfileFile = profileFile;
lru.expctxWay = rc.expctxWay;
lru.expctxNode = rc.expctxNode;
lru.profilesBusy = true;
lru.lastUseTime = System.currentTimeMillis();
return false;
}
public static synchronized void releaseProfile( RoutingContext rc )
{
for( int i=0; i<apc.length; i++)
{
ProfileCache pc = apc[i]; ProfileCache pc = apc[i];
if ( pc != null ) if (pc != null) {
{ if ((!pc.profilesBusy) && profileFile.equals(pc.lastProfileFile)) {
if (rc.profileTimestamp == pc.lastProfileTimestamp) {
rc.expctxWay = pc.expctxWay;
rc.expctxNode = pc.expctxNode;
rc.readGlobalConfig();
pc.profilesBusy = true;
return true;
}
lru = pc; // name-match but timestamp-mismatch -> we overide this one
unusedSlot = -1;
break;
}
if (lru == null || lru.lastUseTime > pc.lastUseTime) {
lru = pc;
}
} else if (unusedSlot < 0) {
unusedSlot = i;
}
}
BExpressionMetaData meta = new BExpressionMetaData();
rc.expctxWay = new BExpressionContextWay(rc.memoryclass * 512, meta);
rc.expctxNode = new BExpressionContextNode(0, meta);
rc.expctxNode.setForeignContext(rc.expctxWay);
meta.readMetaData(new File(profileDir, "lookups.dat"));
rc.expctxWay.parseFile(profileFile, "global");
rc.expctxNode.parseFile(profileFile, "global");
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.lastProfileFile != null) {
if (debug)
System.out.println("******* replacing profile of age " + ((System.currentTimeMillis() - lru.lastUseTime) / 1000L) + " sec " + lru.lastProfileFile + "->" + profileFile);
}
lru.lastProfileTimestamp = rc.profileTimestamp;
lru.lastProfileFile = profileFile;
lru.expctxWay = rc.expctxWay;
lru.expctxNode = rc.expctxNode;
lru.profilesBusy = true;
lru.lastUseTime = System.currentTimeMillis();
return false;
}
public static synchronized void releaseProfile(RoutingContext rc) {
for (int i = 0; i < apc.length; i++) {
ProfileCache pc = apc[i];
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;
} }

View File

@ -20,30 +20,28 @@ import btools.mapaccess.OsmNode;
import btools.util.CheapAngleMeter; import btools.util.CheapAngleMeter;
import btools.util.CheapRuler; import btools.util.CheapRuler;
public final class RoutingContext public final class RoutingContext {
{ public void setAlternativeIdx(int idx) {
public void setAlternativeIdx(int idx )
{
alternativeIdx = idx; alternativeIdx = idx;
} }
public int getAlternativeIdx(int min, int max)
{ public int getAlternativeIdx(int min, int max) {
return alternativeIdx < min ? min : (alternativeIdx > max ? max : alternativeIdx); return alternativeIdx < min ? min : (alternativeIdx > max ? max : alternativeIdx);
} }
public int alternativeIdx = 0; public int alternativeIdx = 0;
public String localFunction; public String localFunction;
public long profileTimestamp; public long profileTimestamp;
public Map<String,String> keyValues; public Map<String, String> keyValues;
public String rawTrackPath; public String rawTrackPath;
public String getProfileName() public String getProfileName() {
{
String name = localFunction == null ? "unknown" : localFunction; String name = localFunction == null ? "unknown" : localFunction;
if ( name.endsWith( ".brf" ) ) name = name.substring( 0, localFunction.length() - 4 ); if (name.endsWith(".brf")) name = name.substring(0, localFunction.length() - 4);
int idx = name.lastIndexOf( File.separatorChar ); int idx = name.lastIndexOf(File.separatorChar);
if ( idx >= 0 ) name = name.substring( idx+1 ); if (idx >= 0) name = name.substring(idx + 1);
return name; return name;
} }
@ -81,129 +79,117 @@ public final class RoutingContext
public double waypointCatchingRange; public double waypointCatchingRange;
private void setModel( String className ) private void setModel(String className) {
{ if (className == null) {
if ( className == null )
{
pm = new StdModel(); pm = new StdModel();
} } else {
else try {
{ Class clazz = Class.forName(className);
try
{
Class clazz = Class.forName( className );
pm = (OsmPathModel) clazz.newInstance(); pm = (OsmPathModel) clazz.newInstance();
} } catch (Exception e) {
catch( Exception e ) throw new RuntimeException("Cannot create path-model: " + e);
{
throw new RuntimeException( "Cannot create path-model: " + e );
} }
} }
initModel(); initModel();
} }
public void initModel() public void initModel() {
{ pm.init(expctxWay, expctxNode, keyValues);
pm.init( expctxWay, expctxNode, keyValues );
} }
public long getKeyValueChecksum() public long getKeyValueChecksum() {
{
long s = 0L; long s = 0L;
if ( keyValues != null ) if (keyValues != null) {
{ for (Map.Entry<String, String> e : keyValues.entrySet()) {
for( Map.Entry<String,String> e : keyValues.entrySet() )
{
s += e.getKey().hashCode() + e.getValue().hashCode(); s += e.getKey().hashCode() + e.getValue().hashCode();
} }
} }
return s; return s;
} }
public void readGlobalConfig() public void readGlobalConfig() {
{
BExpressionContext expctxGlobal = expctxWay; // just one of them... BExpressionContext expctxGlobal = expctxWay; // just one of them...
if (keyValues != null) { if (keyValues != null) {
// add parameter to context // add parameter to context
for (Map.Entry<String, String> e : keyValues.entrySet()) { for (Map.Entry<String, String> e : keyValues.entrySet()) {
float f = Float.parseFloat(e.getValue()); float f = Float.parseFloat(e.getValue());
expctxWay.setVariableValue(e.getKey(), f, false ); expctxWay.setVariableValue(e.getKey(), f, false);
expctxNode.setVariableValue(e.getKey(), f, false ); expctxNode.setVariableValue(e.getKey(), f, false);
} }
} }
setModel( expctxGlobal._modelClass ); setModel(expctxGlobal._modelClass);
downhillcostdiv = (int)expctxGlobal.getVariableValue( "downhillcost", 0.f ); downhillcostdiv = (int) expctxGlobal.getVariableValue("downhillcost", 0.f);
downhillcutoff = (int)(expctxGlobal.getVariableValue( "downhillcutoff", 0.f )*10000); downhillcutoff = (int) (expctxGlobal.getVariableValue("downhillcutoff", 0.f) * 10000);
uphillcostdiv = (int)expctxGlobal.getVariableValue( "uphillcost", 0.f ); uphillcostdiv = (int) expctxGlobal.getVariableValue("uphillcost", 0.f);
uphillcutoff = (int)(expctxGlobal.getVariableValue( "uphillcutoff", 0.f )*10000); uphillcutoff = (int) (expctxGlobal.getVariableValue("uphillcutoff", 0.f) * 10000);
if ( downhillcostdiv != 0 ) downhillcostdiv = 1000000/downhillcostdiv; if (downhillcostdiv != 0) downhillcostdiv = 1000000 / downhillcostdiv;
if ( uphillcostdiv != 0 ) uphillcostdiv = 1000000/uphillcostdiv; if (uphillcostdiv != 0) uphillcostdiv = 1000000 / uphillcostdiv;
carMode = 0.f != expctxGlobal.getVariableValue( "validForCars", 0.f ); carMode = 0.f != expctxGlobal.getVariableValue("validForCars", 0.f);
bikeMode = 0.f != expctxGlobal.getVariableValue( "validForBikes", 0.f ); bikeMode = 0.f != expctxGlobal.getVariableValue("validForBikes", 0.f);
footMode = 0.f != expctxGlobal.getVariableValue( "validForFoot", 0.f ); footMode = 0.f != expctxGlobal.getVariableValue("validForFoot", 0.f);
waypointCatchingRange = expctxGlobal.getVariableValue( "waypointCatchingRange", 250.f ); waypointCatchingRange = expctxGlobal.getVariableValue("waypointCatchingRange", 250.f);
// turn-restrictions not used per default for foot profiles // turn-restrictions not used per default for foot profiles
considerTurnRestrictions = 0.f != expctxGlobal.getVariableValue( "considerTurnRestrictions", footMode ? 0.f : 1.f ); considerTurnRestrictions = 0.f != expctxGlobal.getVariableValue("considerTurnRestrictions", footMode ? 0.f : 1.f);
// process tags not used in the profile (to have them in the data-tab) // process tags not used in the profile (to have them in the data-tab)
processUnusedTags = 0.f != expctxGlobal.getVariableValue( "processUnusedTags", 0.f ); processUnusedTags = 0.f != expctxGlobal.getVariableValue("processUnusedTags", 0.f);
forceSecondaryData = 0.f != expctxGlobal.getVariableValue( "forceSecondaryData", 0.f ); forceSecondaryData = 0.f != expctxGlobal.getVariableValue("forceSecondaryData", 0.f);
pass1coefficient = expctxGlobal.getVariableValue( "pass1coefficient", 1.5f ); pass1coefficient = expctxGlobal.getVariableValue("pass1coefficient", 1.5f);
pass2coefficient = expctxGlobal.getVariableValue( "pass2coefficient", 0.f ); pass2coefficient = expctxGlobal.getVariableValue("pass2coefficient", 0.f);
elevationpenaltybuffer = (int)(expctxGlobal.getVariableValue( "elevationpenaltybuffer", 5.f )*1000000); elevationpenaltybuffer = (int) (expctxGlobal.getVariableValue("elevationpenaltybuffer", 5.f) * 1000000);
elevationmaxbuffer = (int)(expctxGlobal.getVariableValue( "elevationmaxbuffer", 10.f )*1000000); elevationmaxbuffer = (int) (expctxGlobal.getVariableValue("elevationmaxbuffer", 10.f) * 1000000);
elevationbufferreduce = (int)(expctxGlobal.getVariableValue( "elevationbufferreduce", 0.f )*10000); elevationbufferreduce = (int) (expctxGlobal.getVariableValue("elevationbufferreduce", 0.f) * 10000);
cost1speed = expctxGlobal.getVariableValue( "cost1speed", 22.f ); cost1speed = expctxGlobal.getVariableValue("cost1speed", 22.f);
additionalcostfactor = expctxGlobal.getVariableValue( "additionalcostfactor", 1.5f ); additionalcostfactor = expctxGlobal.getVariableValue("additionalcostfactor", 1.5f);
changetime = expctxGlobal.getVariableValue( "changetime", 180.f ); changetime = expctxGlobal.getVariableValue("changetime", 180.f);
buffertime = expctxGlobal.getVariableValue( "buffertime", 120.f ); buffertime = expctxGlobal.getVariableValue("buffertime", 120.f);
waittimeadjustment = expctxGlobal.getVariableValue( "waittimeadjustment", 0.9f ); waittimeadjustment = expctxGlobal.getVariableValue("waittimeadjustment", 0.9f);
inittimeadjustment = expctxGlobal.getVariableValue( "inittimeadjustment", 0.2f ); inittimeadjustment = expctxGlobal.getVariableValue("inittimeadjustment", 0.2f);
starttimeoffset = expctxGlobal.getVariableValue( "starttimeoffset", 0.f ); starttimeoffset = expctxGlobal.getVariableValue("starttimeoffset", 0.f);
transitonly = expctxGlobal.getVariableValue( "transitonly", 0.f ) != 0.f; transitonly = expctxGlobal.getVariableValue("transitonly", 0.f) != 0.f;
farTrafficWeight = expctxGlobal.getVariableValue( "farTrafficWeight", 2.f ); farTrafficWeight = expctxGlobal.getVariableValue("farTrafficWeight", 2.f);
nearTrafficWeight = expctxGlobal.getVariableValue( "nearTrafficWeight", 2.f ); nearTrafficWeight = expctxGlobal.getVariableValue("nearTrafficWeight", 2.f);
farTrafficDecayLength = expctxGlobal.getVariableValue( "farTrafficDecayLength", 30000.f ); farTrafficDecayLength = expctxGlobal.getVariableValue("farTrafficDecayLength", 30000.f);
nearTrafficDecayLength = expctxGlobal.getVariableValue( "nearTrafficDecayLength", 3000.f ); nearTrafficDecayLength = expctxGlobal.getVariableValue("nearTrafficDecayLength", 3000.f);
trafficDirectionFactor = expctxGlobal.getVariableValue( "trafficDirectionFactor", 0.9f ); trafficDirectionFactor = expctxGlobal.getVariableValue("trafficDirectionFactor", 0.9f);
trafficSourceExponent = expctxGlobal.getVariableValue( "trafficSourceExponent", -0.7f ); trafficSourceExponent = expctxGlobal.getVariableValue("trafficSourceExponent", -0.7f);
trafficSourceMinDist = expctxGlobal.getVariableValue( "trafficSourceMinDist", 3000.f ); trafficSourceMinDist = expctxGlobal.getVariableValue("trafficSourceMinDist", 3000.f);
showspeed = 0.f != expctxGlobal.getVariableValue( "showspeed", 0.f ); showspeed = 0.f != expctxGlobal.getVariableValue("showspeed", 0.f);
showSpeedProfile = 0.f != expctxGlobal.getVariableValue( "showSpeedProfile", 0.f ); showSpeedProfile = 0.f != expctxGlobal.getVariableValue("showSpeedProfile", 0.f);
inverseRouting = 0.f != expctxGlobal.getVariableValue( "inverseRouting", 0.f ); inverseRouting = 0.f != expctxGlobal.getVariableValue("inverseRouting", 0.f);
int tiMode = (int)expctxGlobal.getVariableValue( "turnInstructionMode", 0.f ); int tiMode = (int) expctxGlobal.getVariableValue("turnInstructionMode", 0.f);
if ( tiMode != 1 ) // automatic selection from coordinate source if (tiMode != 1) // automatic selection from coordinate source
{ {
turnInstructionMode = tiMode; turnInstructionMode = tiMode;
} }
turnInstructionCatchingRange = expctxGlobal.getVariableValue( "turnInstructionCatchingRange", 40.f ); turnInstructionCatchingRange = expctxGlobal.getVariableValue("turnInstructionCatchingRange", 40.f);
turnInstructionRoundabouts = expctxGlobal.getVariableValue( "turnInstructionRoundabouts", 1.f ) != 0.f; turnInstructionRoundabouts = expctxGlobal.getVariableValue("turnInstructionRoundabouts", 1.f) != 0.f;
// Speed computation model (for bikes) // Speed computation model (for bikes)
// Total mass (biker + bike + luggages or hiker), in kg // Total mass (biker + bike + luggages or hiker), in kg
totalMass = expctxGlobal.getVariableValue( "totalMass", 90.f ); totalMass = expctxGlobal.getVariableValue("totalMass", 90.f);
// Max speed (before braking), in km/h in profile and m/s in code // Max speed (before braking), in km/h in profile and m/s in code
if (footMode) { if (footMode) {
maxSpeed = expctxGlobal.getVariableValue( "maxSpeed", 6.f ) / 3.6; maxSpeed = expctxGlobal.getVariableValue("maxSpeed", 6.f) / 3.6;
} else { } else {
maxSpeed = expctxGlobal.getVariableValue( "maxSpeed", 45.f ) / 3.6; maxSpeed = expctxGlobal.getVariableValue("maxSpeed", 45.f) / 3.6;
} }
// Equivalent surface for wind, S * C_x, F = -1/2 * S * C_x * v^2 = - S_C_x * v^2 // Equivalent surface for wind, S * C_x, F = -1/2 * S * C_x * v^2 = - S_C_x * v^2
S_C_x = expctxGlobal.getVariableValue( "S_C_x", 0.5f * 0.45f ); S_C_x = expctxGlobal.getVariableValue("S_C_x", 0.5f * 0.45f);
// Default resistance of the road, F = - m * g * C_r (for good quality road) // Default resistance of the road, F = - m * g * C_r (for good quality road)
defaultC_r = expctxGlobal.getVariableValue( "C_r", 0.01f ); defaultC_r = expctxGlobal.getVariableValue("C_r", 0.01f);
// Constant power of the biker (in W) // Constant power of the biker (in W)
bikerPower = expctxGlobal.getVariableValue( "bikerPower", 100.f ); bikerPower = expctxGlobal.getVariableValue("bikerPower", 100.f);
} }
public List<OsmNodeNamed> poipoints; public List<OsmNodeNamed> poipoints;
@ -256,22 +242,19 @@ public final class RoutingContext
public double defaultC_r; public double defaultC_r;
public double bikerPower; public double bikerPower;
public static void prepareNogoPoints( List<OsmNodeNamed> nogos ) public static void prepareNogoPoints(List<OsmNodeNamed> nogos) {
{ for (OsmNodeNamed nogo : nogos) {
for( OsmNodeNamed nogo : nogos ) if (nogo instanceof OsmNogoPolygon) {
{
if (nogo instanceof OsmNogoPolygon)
{
continue; continue;
} }
String s = nogo.name; String s = nogo.name;
int idx = s.indexOf( ' ' ); int idx = s.indexOf(' ');
if ( idx > 0 ) s = s.substring( 0 , idx ); if (idx > 0) s = s.substring(0, idx);
int ir = 20; // default radius int ir = 20; // default radius
if ( s.length() > 4 ) if (s.length() > 4) {
{ try {
try { ir = Integer.parseInt( s.substring( 4 ) ); } ir = Integer.parseInt(s.substring(4));
catch( Exception e ) { /* ignore */ } } catch (Exception e) { /* ignore */ }
} }
// Radius of the nogo point in meters // Radius of the nogo point in meters
nogo.radius = ir; nogo.radius = ir;
@ -281,8 +264,7 @@ public final class RoutingContext
/** /**
* restore the full nogolist previously saved by cleanNogoList * restore the full nogolist previously saved by cleanNogoList
*/ */
public void restoreNogoList() public void restoreNogoList() {
{
nogopoints = nogopoints_all; nogopoints = nogopoints_all;
} }
@ -292,46 +274,38 @@ public final class RoutingContext
* *
* @return true if all wayoints are all in the same (full-weigth) nogo area (triggering bee-line-mode) * @return true if all wayoints are all in the same (full-weigth) nogo area (triggering bee-line-mode)
*/ */
public void cleanNogoList( List<OsmNode> waypoints ) public void cleanNogoList(List<OsmNode> waypoints) {
{
nogopoints_all = nogopoints; nogopoints_all = nogopoints;
if ( nogopoints == null ) return; if (nogopoints == null) return;
List<OsmNodeNamed> nogos = new ArrayList<OsmNodeNamed>(); List<OsmNodeNamed> nogos = new ArrayList<OsmNodeNamed>();
for( OsmNodeNamed nogo : nogopoints ) for (OsmNodeNamed nogo : nogopoints) {
{
boolean goodGuy = true; boolean goodGuy = true;
for( OsmNode wp : waypoints ) for (OsmNode wp : waypoints) {
{ if (wp.calcDistance(nogo) < nogo.radius
if ( wp.calcDistance( nogo ) < nogo.radius && (!(nogo instanceof OsmNogoPolygon)
&& (!(nogo instanceof OsmNogoPolygon) || (((OsmNogoPolygon) nogo).isClosed
|| (((OsmNogoPolygon)nogo).isClosed ? ((OsmNogoPolygon) nogo).isWithin(wp.ilon, wp.ilat)
? ((OsmNogoPolygon)nogo).isWithin(wp.ilon, wp.ilat) : ((OsmNogoPolygon) nogo).isOnPolyline(wp.ilon, wp.ilat)))) {
: ((OsmNogoPolygon)nogo).isOnPolyline(wp.ilon, wp.ilat))))
{
goodGuy = false; goodGuy = false;
} }
} }
if ( goodGuy ) nogos.add( nogo ); if (goodGuy) nogos.add(nogo);
} }
nogopoints = nogos.isEmpty() ? null : nogos; nogopoints = nogos.isEmpty() ? null : nogos;
} }
public boolean allInOneNogo( List<OsmNode> waypoints ) public boolean allInOneNogo(List<OsmNode> waypoints) {
{ if (nogopoints == null) return false;
if ( nogopoints == null ) return false;
boolean allInTotal = false; boolean allInTotal = false;
for( OsmNodeNamed nogo : nogopoints ) for (OsmNodeNamed nogo : nogopoints) {
{ boolean allIn = Double.isNaN(nogo.nogoWeight);
boolean allIn = Double.isNaN( nogo.nogoWeight ); for (OsmNode wp : waypoints) {
for( OsmNode wp : waypoints ) int dist = wp.calcDistance(nogo);
{ if (dist < nogo.radius
int dist = wp.calcDistance( nogo ); && (!(nogo instanceof OsmNogoPolygon)
if ( dist < nogo.radius || (((OsmNogoPolygon) nogo).isClosed
&& (!(nogo instanceof OsmNogoPolygon) ? ((OsmNogoPolygon) nogo).isWithin(wp.ilon, wp.ilat)
|| (((OsmNogoPolygon)nogo).isClosed : ((OsmNogoPolygon) nogo).isOnPolyline(wp.ilon, wp.ilat)))) {
? ((OsmNogoPolygon)nogo).isWithin(wp.ilon, wp.ilat)
: ((OsmNogoPolygon)nogo).isOnPolyline(wp.ilon, wp.ilat))))
{
continue; continue;
} }
allIn = false; allIn = false;
@ -341,93 +315,84 @@ public final class RoutingContext
return allInTotal; return allInTotal;
} }
public long[] getNogoChecksums() public long[] getNogoChecksums() {
{
long[] cs = new long[3]; long[] cs = new long[3];
int n = nogopoints == null ? 0 : nogopoints.size(); int n = nogopoints == null ? 0 : nogopoints.size();
for( int i=0; i<n; i++ ) for (int i = 0; i < n; i++) {
{
OsmNodeNamed nogo = nogopoints.get(i); OsmNodeNamed nogo = nogopoints.get(i);
cs[0] += nogo.ilon; cs[0] += nogo.ilon;
cs[1] += nogo.ilat; cs[1] += nogo.ilat;
// 10 is an arbitrary constant to get sub-integer precision in the checksum // 10 is an arbitrary constant to get sub-integer precision in the checksum
cs[2] += (long) ( nogo.radius*10.); cs[2] += (long) (nogo.radius * 10.);
} }
return cs; return cs;
} }
public void setWaypoint( OsmNodeNamed wp, boolean endpoint ) public void setWaypoint(OsmNodeNamed wp, boolean endpoint) {
{ setWaypoint(wp, null, endpoint);
setWaypoint( wp, null, endpoint );
} }
public void setWaypoint( OsmNodeNamed wp, OsmNodeNamed pendingEndpoint, boolean endpoint ) public void setWaypoint(OsmNodeNamed wp, OsmNodeNamed pendingEndpoint, boolean endpoint) {
{
keepnogopoints = nogopoints; keepnogopoints = nogopoints;
nogopoints = new ArrayList<OsmNodeNamed>(); nogopoints = new ArrayList<OsmNodeNamed>();
nogopoints.add( wp ); nogopoints.add(wp);
if ( keepnogopoints != null ) nogopoints.addAll( keepnogopoints ); if (keepnogopoints != null) nogopoints.addAll(keepnogopoints);
isEndpoint = endpoint; isEndpoint = endpoint;
this.pendingEndpoint = pendingEndpoint; this.pendingEndpoint = pendingEndpoint;
} }
public boolean checkPendingEndpoint() public boolean checkPendingEndpoint() {
{ if (pendingEndpoint != null) {
if ( pendingEndpoint != null )
{
isEndpoint = true; isEndpoint = true;
nogopoints.set( 0, pendingEndpoint ); nogopoints.set(0, pendingEndpoint);
pendingEndpoint = null; pendingEndpoint = null;
return true; return true;
} }
return false; return false;
} }
public void unsetWaypoint() public void unsetWaypoint() {
{
nogopoints = keepnogopoints; nogopoints = keepnogopoints;
pendingEndpoint = null; pendingEndpoint = null;
isEndpoint = false; isEndpoint = false;
} }
public int calcDistance( int lon1, int lat1, int lon2, int lat2 ) public int calcDistance(int lon1, int lat1, int lon2, int lat2) {
{ double[] lonlat2m = CheapRuler.getLonLatToMeterScales((lat1 + lat2) >> 1);
double[] lonlat2m = CheapRuler.getLonLatToMeterScales( (lat1+lat2) >> 1 );
double dlon2m = lonlat2m[0]; double dlon2m = lonlat2m[0];
double dlat2m = lonlat2m[1]; double dlat2m = lonlat2m[1];
double dx = (lon2 - lon1 ) * dlon2m; double dx = (lon2 - lon1) * dlon2m;
double dy = (lat2 - lat1 ) * dlat2m; double dy = (lat2 - lat1) * dlat2m;
double d = Math.sqrt( dy*dy + dx*dx ); double d = Math.sqrt(dy * dy + dx * dx);
shortestmatch = false; shortestmatch = false;
if ( nogopoints != null && !nogopoints.isEmpty() && d > 0. ) if (nogopoints != null && !nogopoints.isEmpty() && d > 0.) {
{ for (int ngidx = 0; ngidx < nogopoints.size(); ngidx++) {
for( int ngidx = 0; ngidx < nogopoints.size(); ngidx++ )
{
OsmNodeNamed nogo = nogopoints.get(ngidx); OsmNodeNamed nogo = nogopoints.get(ngidx);
double x1 = (lon1 - nogo.ilon) * dlon2m; double x1 = (lon1 - nogo.ilon) * dlon2m;
double y1 = (lat1 - nogo.ilat) * dlat2m; double y1 = (lat1 - nogo.ilat) * dlat2m;
double x2 = (lon2 - nogo.ilon) * dlon2m; double x2 = (lon2 - nogo.ilon) * dlon2m;
double y2 = (lat2 - nogo.ilat) * dlat2m; double y2 = (lat2 - nogo.ilat) * dlat2m;
double r12 = x1*x1 + y1*y1; double r12 = x1 * x1 + y1 * y1;
double r22 = x2*x2 + y2*y2; double r22 = x2 * x2 + y2 * y2;
double radius = Math.abs( r12 < r22 ? y1*dx - x1*dy : y2*dx - x2*dy ) / d; double radius = Math.abs(r12 < r22 ? y1 * dx - x1 * dy : y2 * dx - x2 * dy) / d;
if ( radius < nogo.radius ) // 20m if (radius < nogo.radius) // 20m
{ {
double s1 = x1*dx + y1*dy; double s1 = x1 * dx + y1 * dy;
double s2 = x2*dx + y2*dy; double s2 = x2 * dx + y2 * dy;
if ( s1 < 0. ) { s1 = -s1; s2 = -s2; } if (s1 < 0.) {
if ( s2 > 0. ) s1 = -s1;
{ s2 = -s2;
radius = Math.sqrt( s1 < s2 ? r12 : r22 );
if ( radius > nogo.radius ) continue;
} }
if ( nogo.isNogo ) if (s2 > 0.) {
{ radius = Math.sqrt(s1 < s2 ? r12 : r22);
if (radius > nogo.radius) continue;
}
if (nogo.isNogo) {
if (!(nogo instanceof OsmNogoPolygon)) { // nogo is a circle if (!(nogo instanceof OsmNogoPolygon)) { // nogo is a circle
if (Double.isNaN(nogo.nogoWeight)) { if (Double.isNaN(nogo.nogoWeight)) {
// default nogo behaviour (ignore completely) // default nogo behaviour (ignore completely)
@ -436,46 +401,37 @@ public final class RoutingContext
// nogo weight, compute distance within the circle // nogo weight, compute distance within the circle
nogoCost = nogo.distanceWithinRadius(lon1, lat1, lon2, lat2, d) * nogo.nogoWeight; nogoCost = nogo.distanceWithinRadius(lon1, lat1, lon2, lat2, d) * nogo.nogoWeight;
} }
} } else if (((OsmNogoPolygon) nogo).intersects(lon1, lat1, lon2, lat2)) {
else if (((OsmNogoPolygon)nogo).intersects(lon1, lat1, lon2, lat2))
{
// nogo is a polyline/polygon, we have to check there is indeed // nogo is a polyline/polygon, we have to check there is indeed
// an intersection in this case (radius check is not enough). // an intersection in this case (radius check is not enough).
if (Double.isNaN(nogo.nogoWeight)) { if (Double.isNaN(nogo.nogoWeight)) {
// default nogo behaviour (ignore completely) // default nogo behaviour (ignore completely)
nogoCost = -1; nogoCost = -1;
} else { } else {
if (((OsmNogoPolygon)nogo).isClosed) { if (((OsmNogoPolygon) nogo).isClosed) {
// compute distance within the polygon // compute distance within the polygon
nogoCost = ((OsmNogoPolygon)nogo).distanceWithinPolygon(lon1, lat1, lon2, lat2) * nogo.nogoWeight; nogoCost = ((OsmNogoPolygon) nogo).distanceWithinPolygon(lon1, lat1, lon2, lat2) * nogo.nogoWeight;
} else { } else {
// for a polyline, just add a constant penalty // for a polyline, just add a constant penalty
nogoCost = nogo.nogoWeight; nogoCost = nogo.nogoWeight;
} }
} }
} }
} } else {
else
{
shortestmatch = true; shortestmatch = true;
nogo.radius = radius; // shortest distance to way nogo.radius = radius; // shortest distance to way
// calculate remaining distance // calculate remaining distance
if ( s2 < 0. ) if (s2 < 0.) {
{ wayfraction = -s2 / (d * d);
wayfraction = -s2 / (d*d); double xm = x2 - wayfraction * dx;
double xm = x2 - wayfraction*dx; double ym = y2 - wayfraction * dy;
double ym = y2 - wayfraction*dy; ilonshortest = (int) (xm / dlon2m + nogo.ilon);
ilonshortest = (int)(xm / dlon2m + nogo.ilon); ilatshortest = (int) (ym / dlat2m + nogo.ilat);
ilatshortest = (int)(ym / dlat2m + nogo.ilat); } else if (s1 > s2) {
}
else if ( s1 > s2 )
{
wayfraction = 0.; wayfraction = 0.;
ilonshortest = lon2; ilonshortest = lon2;
ilatshortest = lat2; ilatshortest = lat2;
} } else {
else
{
wayfraction = 1.; wayfraction = 1.;
ilonshortest = lon1; ilonshortest = lon1;
ilatshortest = lat1; ilatshortest = lat1;
@ -485,51 +441,44 @@ public final class RoutingContext
// *after* the shortest distance point. In case of a shortest-match // *after* the shortest distance point. In case of a shortest-match
// we use the reduced way segment for nogo-matching, in order not // we use the reduced way segment for nogo-matching, in order not
// to cut our escape-way if we placed a nogo just in front of where we are // to cut our escape-way if we placed a nogo just in front of where we are
if ( isEndpoint ) if (isEndpoint) {
{
wayfraction = 1. - wayfraction; wayfraction = 1. - wayfraction;
lon2 = ilonshortest; lon2 = ilonshortest;
lat2 = ilatshortest; lat2 = ilatshortest;
} } else {
else
{
nogoCost = 0.; nogoCost = 0.;
lon1 = ilonshortest; lon1 = ilonshortest;
lat1 = ilatshortest; lat1 = ilatshortest;
} }
dx = (lon2 - lon1 ) * dlon2m; dx = (lon2 - lon1) * dlon2m;
dy = (lat2 - lat1 ) * dlat2m; dy = (lat2 - lat1) * dlat2m;
d = Math.sqrt( dy*dy + dx*dx ); d = Math.sqrt(dy * dy + dx * dx);
} }
} }
} }
} }
return (int)(d + 1.0 ); return (int) (d + 1.0);
} }
public OsmPathModel pm; public OsmPathModel pm;
public OsmPrePath createPrePath( OsmPath origin, OsmLink link ) public OsmPrePath createPrePath(OsmPath origin, OsmLink link) {
{
OsmPrePath p = pm.createPrePath(); OsmPrePath p = pm.createPrePath();
if ( p != null ) if (p != null) {
{ p.init(origin, link, this);
p.init( origin, link, this );
} }
return p; return p;
} }
public OsmPath createPath( OsmLink link ) public OsmPath createPath(OsmLink link) {
{
OsmPath p = pm.createPath(); OsmPath p = pm.createPath();
p.init( link ); p.init(link);
return p; return p;
} }
public OsmPath createPath( OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode ) public OsmPath createPath(OsmPath origin, OsmLink link, OsmTrack refTrack, boolean detailMode) {
{
OsmPath p = pm.createPath(); OsmPath p = pm.createPath();
p.init( origin, link, refTrack, detailMode, this ); p.init(origin, link, refTrack, detailMode, this);
return p; return p;
} }

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 ) public static boolean hasDirectoryAnyDatafiles(File segmentDir) {
{ if (hasAnyDatafiles(segmentDir)) {
if ( hasAnyDatafiles( segmentDir ) ) return true;
{
return true;
}
// check secondary, too
File secondary = StorageConfigHelper.getSecondarySegmentDir( segmentDir );
if ( secondary != null )
{
return hasAnyDatafiles( secondary );
}
return false;
} }
// check secondary, too
File secondary = StorageConfigHelper.getSecondarySegmentDir(segmentDir);
if (secondary != null) {
return hasAnyDatafiles(secondary);
}
return false;
}
private static boolean hasAnyDatafiles( File dir ) private static boolean hasAnyDatafiles(File dir) {
{ String[] fileNames = dir.list();
String[] fileNames = dir.list(); for (String fileName : fileNames) {
for( String fileName : fileNames ) if (fileName.endsWith(".rd5")) return true;
{
if ( fileName.endsWith( ".rd5" ) ) return true;
}
return false;
} }
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,8 +26,7 @@ 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;

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:
return "TSHR";
case TRU:
return "TRU";
case RNDB:
return "RNDB" + roundaboutExit;
case RNLB:
return "RNLB" + (-roundaboutExit);
default:
throw new IllegalArgumentException("unknown command: " + cmd);
} }
} }
public String getSymbolString() public String getSymbolString() {
{ switch (cmd) {
switch ( cmd ) case TU:
{ return "TU";
case TU : return "TU"; case TSHL:
case TSHL : return "TSHL"; return "TSHL";
case TL : return "Left"; case TL:
case TSLL : return "TSLL"; return "Left";
case KL : return "TSLL"; // ? case TSLL:
case C : return "Straight"; return "TSLL";
case KR : return "TSLR"; // ? case KL:
case TSLR : return "TSLR"; return "TSLL"; // ?
case TR : return "Right"; case C:
case TSHR : return "TSHR"; return "Straight";
case TRU : return "TU"; case KR:
case RNDB : return "RNDB" + roundaboutExit; return "TSLR"; // ?
case RNLB : return "RNLB" + (-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 String getMessageString() public String getMessageString() {
{ switch (cmd) {
switch ( cmd ) case TU:
{ return "u-turn";
case TU : return "u-turn"; case TSHL:
case TSHL : return "sharp left"; return "sharp left";
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 "slight left";
case KR : return "keep right"; case KL:
case TSLR : return "slight right"; return "keep left";
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 "keep right";
case RNLB : return "Take exit " + (-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 getLocusAction() public int getLocusAction() {
{ switch (cmd) {
switch ( cmd ) case TU:
{ return 13;
case TU : return 13; case TSHL:
case TSHL : return 5; return 5;
case TL : return 4; case TL:
case TSLL : return 3; return 4;
case KL : return 9; // ? case TSLL:
case C : return 1; return 3;
case KR : return 10; // ? case KL:
case TSLR : return 6; return 9; // ?
case TR : return 7; case C:
case TSHR : return 8; return 1;
case TRU : return 14; case KR:
case RNDB : return 26 + roundaboutExit; return 10; // ?
case RNLB : return 26 - 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 int getOruxAction() public int getOruxAction() {
{ switch (cmd) {
switch ( cmd ) case TU:
{ return 1003;
case TU : return 1003; case TSHL:
case TSHL : return 1019; return 1019;
case TL : return 1000; case TL:
case TSLL : return 1017; return 1000;
case KL : return 1015; // ? case TSLL:
case C : return 1002; return 1017;
case KR : return 1014; // ? case KL:
case TSLR : return 1016; return 1015; // ?
case TR : return 1001; case C:
case TSHR : return 1018; return 1002;
case TRU : return 1003; case KR:
case RNDB : return 1008 + roundaboutExit; return 1014; // ?
case RNLB : return 1008 + roundaboutExit; case TSLR:
default : throw new IllegalArgumentException( "unknown command: " + cmd ); 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() 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

@ -2,8 +2,7 @@ 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;
@ -37,36 +36,29 @@ final class BExpression
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 private static BExpression parse(BExpressionContext ctx, int level, String optionalToken) throws Exception {
{
boolean brackets = false; boolean brackets = false;
String operator = ctx.parseToken(); String operator = ctx.parseToken();
if ( optionalToken != null && optionalToken.equals( operator ) ) if (optionalToken != null && optionalToken.equals(operator)) {
{
operator = ctx.parseToken(); operator = ctx.parseToken();
} }
if ( "(".equals( operator ) ) if ("(".equals(operator)) {
{
brackets = true; brackets = true;
operator = ctx.parseToken(); operator = ctx.parseToken();
} }
if ( operator == null ) if (operator == null) {
{ if (level == 0) return null;
if ( level == 0 ) return null; else throw new IllegalArgumentException("unexpected end of file");
else throw new IllegalArgumentException( "unexpected end of file" );
} }
if ( level == 0 ) if (level == 0) {
{ if (!"assign".equals(operator)) {
if ( !"assign".equals( operator ) ) throw new IllegalArgumentException("operator " + operator + " is invalid on toplevel (only 'assign' allowed)");
{
throw new IllegalArgumentException( "operator " + operator + " is invalid on toplevel (only 'assign' allowed)" );
} }
} }
@ -74,227 +66,190 @@ final class BExpression
int nops = 3; int nops = 3;
boolean ifThenElse = false; boolean ifThenElse = false;
if ( "switch".equals( operator ) ) if ("switch".equals(operator)) {
{
exp.typ = SWITCH_EXP; exp.typ = SWITCH_EXP;
} } else if ("if".equals(operator)) {
else if ( "if".equals( operator ) )
{
exp.typ = SWITCH_EXP; exp.typ = SWITCH_EXP;
ifThenElse = true; ifThenElse = true;
} } else {
else
{
nops = 2; // check binary expressions nops = 2; // check binary expressions
if ( "or".equals( operator ) ) if ("or".equals(operator)) {
{
exp.typ = OR_EXP; exp.typ = OR_EXP;
} } else if ("and".equals(operator)) {
else if ( "and".equals( operator ) )
{
exp.typ = AND_EXP; exp.typ = AND_EXP;
} } else if ("multiply".equals(operator)) {
else if ( "multiply".equals( operator ) )
{
exp.typ = MULTIPLY_EXP; exp.typ = MULTIPLY_EXP;
} } else if ("add".equals(operator)) {
else if ( "add".equals( operator ) )
{
exp.typ = ADD_EXP; exp.typ = ADD_EXP;
} } else if ("max".equals(operator)) {
else if ( "max".equals( operator ) )
{
exp.typ = MAX_EXP; exp.typ = MAX_EXP;
} } else if ("min".equals(operator)) {
else if ( "min".equals( operator ) )
{
exp.typ = MIN_EXP; exp.typ = MIN_EXP;
} } else if ("equal".equals(operator)) {
else if ( "equal".equals( operator ) )
{
exp.typ = EQUAL_EXP; exp.typ = EQUAL_EXP;
} } else if ("greater".equals(operator)) {
else if ( "greater".equals( operator ) )
{
exp.typ = GREATER_EXP; exp.typ = GREATER_EXP;
} } else if ("sub".equals(operator)) {
else if ( "sub".equals( operator ) )
{
exp.typ = SUB_EXP; exp.typ = SUB_EXP;
} } else if ("lesser".equals(operator)) {
else if ( "lesser".equals( operator ) )
{
exp.typ = LESSER_EXP; exp.typ = LESSER_EXP;
} } else if ("xor".equals(operator)) {
else if ( "xor".equals( operator ) )
{
exp.typ = XOR_EXP; exp.typ = XOR_EXP;
} } else {
else
{
nops = 1; // check unary expressions nops = 1; // check unary expressions
if ( "assign".equals( operator ) ) if ("assign".equals(operator)) {
{ if (level > 0) throw new IllegalArgumentException("assign operator within expression");
if ( level > 0 ) throw new IllegalArgumentException( "assign operator within expression" );
exp.typ = ASSIGN_EXP; exp.typ = ASSIGN_EXP;
String variable = ctx.parseToken(); String variable = ctx.parseToken();
if ( variable == null ) throw new IllegalArgumentException( "unexpected end of file" ); if (variable == null) throw new IllegalArgumentException("unexpected end of file");
if ( variable.indexOf( '=' ) >= 0 ) throw new IllegalArgumentException( "variable name cannot contain '=': " + variable ); if (variable.indexOf('=') >= 0)
if ( variable.indexOf( ':' ) >= 0 ) throw new IllegalArgumentException( "cannot assign context-prefixed variable: " + variable ); throw new IllegalArgumentException("variable name cannot contain '=': " + variable);
exp.variableIdx = ctx.getVariableIdx( variable, true ); if (variable.indexOf(':') >= 0)
if ( exp.variableIdx < ctx.getMinWriteIdx() ) throw new IllegalArgumentException( "cannot assign to readonly variable " + variable ); throw new IllegalArgumentException("cannot assign context-prefixed variable: " + variable);
} exp.variableIdx = ctx.getVariableIdx(variable, true);
else if ( "not".equals( operator ) ) if (exp.variableIdx < ctx.getMinWriteIdx())
{ throw new IllegalArgumentException("cannot assign to readonly variable " + variable);
} else if ("not".equals(operator)) {
exp.typ = NOT_EXP; exp.typ = NOT_EXP;
} } else {
else
{
nops = 0; // check elemantary expressions nops = 0; // check elemantary expressions
int idx = operator.indexOf( '=' ); int idx = operator.indexOf('=');
if ( idx >= 0 ) if (idx >= 0) {
{
exp.typ = LOOKUP_EXP; exp.typ = LOOKUP_EXP;
String name = operator.substring( 0, idx ); String name = operator.substring(0, idx);
String values = operator.substring( idx+1 ); String values = operator.substring(idx + 1);
exp.lookupNameIdx = ctx.getLookupNameIdx( name ); exp.lookupNameIdx = ctx.getLookupNameIdx(name);
if ( exp.lookupNameIdx < 0 ) if (exp.lookupNameIdx < 0) {
{ throw new IllegalArgumentException("unknown lookup name: " + name);
throw new IllegalArgumentException( "unknown lookup name: " + name );
} }
ctx.markLookupIdxUsed( exp.lookupNameIdx ); ctx.markLookupIdxUsed(exp.lookupNameIdx);
StringTokenizer tk = new StringTokenizer( values, "|" ); StringTokenizer tk = new StringTokenizer(values, "|");
int nt = tk.countTokens(); int nt = tk.countTokens();
int nt2 = nt == 0 ? 1 : nt; int nt2 = nt == 0 ? 1 : nt;
exp.lookupValueIdxArray = new int[nt2]; exp.lookupValueIdxArray = new int[nt2];
for( int ti=0; ti<nt2; ti++ ) for (int ti = 0; ti < nt2; ti++) {
{
String value = ti < nt ? tk.nextToken() : ""; String value = ti < nt ? tk.nextToken() : "";
exp.lookupValueIdxArray[ti] = ctx.getLookupValueIdx( exp.lookupNameIdx, value ); exp.lookupValueIdxArray[ti] = ctx.getLookupValueIdx(exp.lookupNameIdx, value);
if ( exp.lookupValueIdxArray[ti] < 0 ) if (exp.lookupValueIdxArray[ti] < 0) {
{ throw new IllegalArgumentException("unknown lookup value: " + value);
throw new IllegalArgumentException( "unknown lookup value: " + value );
} }
} }
} } else if ((idx = operator.indexOf(':')) >= 0) {
else if ( ( idx = operator.indexOf( ':' ) ) >= 0 )
{
/* /*
use of variable values use of variable values
assign no_height assign no_height
switch and not maxheight= switch and not maxheight=
lesser v:maxheight my_height true lesser v:maxheight my_height true
false false
*/ */
if (operator.startsWith("v:")) { if (operator.startsWith("v:")) {
String name = operator.substring(2); String name = operator.substring(2);
exp.typ = VARIABLE_GET_EXP; exp.typ = VARIABLE_GET_EXP;
exp.lookupNameIdx = ctx.getLookupNameIdx( name ); exp.lookupNameIdx = ctx.getLookupNameIdx(name);
} else { } else {
String context = operator.substring( 0, idx ); String context = operator.substring(0, idx);
String varname = operator.substring( idx+1 ); String varname = operator.substring(idx + 1);
exp.typ = FOREIGN_VARIABLE_EXP; exp.typ = FOREIGN_VARIABLE_EXP;
exp.variableIdx = ctx.getForeignVariableIdx( context, varname ); exp.variableIdx = ctx.getForeignVariableIdx(context, varname);
} }
} } else if ((idx = ctx.getVariableIdx(operator, false)) >= 0) {
else if ( (idx = ctx.getVariableIdx( operator, false )) >= 0 )
{
exp.typ = VARIABLE_EXP; exp.typ = VARIABLE_EXP;
exp.variableIdx = idx; exp.variableIdx = idx;
} } else if ("true".equals(operator)) {
else if ( "true".equals( operator ) )
{
exp.numberValue = 1.f; exp.numberValue = 1.f;
exp.typ = NUMBER_EXP; exp.typ = NUMBER_EXP;
} } else if ("false".equals(operator)) {
else if ( "false".equals( operator ) )
{
exp.numberValue = 0.f; exp.numberValue = 0.f;
exp.typ = NUMBER_EXP; exp.typ = NUMBER_EXP;
} } else {
else try {
{ exp.numberValue = Float.parseFloat(operator);
try
{
exp.numberValue = Float.parseFloat( operator );
exp.typ = NUMBER_EXP; exp.typ = NUMBER_EXP;
} } catch (NumberFormatException nfe) {
catch( NumberFormatException nfe ) throw new IllegalArgumentException("unknown expression: " + operator);
{
throw new IllegalArgumentException( "unknown expression: " + operator );
} }
} }
} }
} }
} }
// parse operands // parse operands
if ( nops > 0 ) if (nops > 0) {
{ exp.op1 = BExpression.parse(ctx, level + 1, exp.typ == ASSIGN_EXP ? "=" : null);
exp.op1 = BExpression.parse( ctx, level+1, exp.typ == ASSIGN_EXP ? "=" : null );
} }
if ( nops > 1 ) if (nops > 1) {
{ if (ifThenElse) checkExpectedToken(ctx, "then");
if ( ifThenElse ) checkExpectedToken( ctx, "then" ); exp.op2 = BExpression.parse(ctx, level + 1, null);
exp.op2 = BExpression.parse( ctx, level+1, null );
} }
if ( nops > 2 ) if (nops > 2) {
{ if (ifThenElse) checkExpectedToken(ctx, "else");
if ( ifThenElse ) checkExpectedToken( ctx, "else" ); exp.op3 = BExpression.parse(ctx, level + 1, null);
exp.op3 = BExpression.parse( ctx, level+1, null );
} }
if ( brackets ) if (brackets) {
{ checkExpectedToken(ctx, ")");
checkExpectedToken( ctx, ")" );
} }
return exp; return exp;
} }
private static void checkExpectedToken( BExpressionContext ctx, String expected ) throws Exception private static void checkExpectedToken(BExpressionContext ctx, String expected) throws Exception {
{
String token = ctx.parseToken(); String token = ctx.parseToken();
if ( ! expected.equals( token ) ) if (!expected.equals(token)) {
{ throw new IllegalArgumentException("unexpected token: " + token + ", expected: " + expected);
throw new IllegalArgumentException( "unexpected token: " + token + ", expected: " + expected );
} }
} }
// Evaluate the expression // Evaluate the expression
public float evaluate( BExpressionContext ctx ) public float evaluate(BExpressionContext ctx) {
{ switch (typ) {
switch( typ ) case OR_EXP:
{ return op1.evaluate(ctx) != 0.f ? 1.f : (op2.evaluate(ctx) != 0.f ? 1.f : 0.f);
case OR_EXP: return op1.evaluate(ctx) != 0.f ? 1.f : ( op2.evaluate(ctx) != 0.f ? 1.f : 0.f ); case XOR_EXP:
case XOR_EXP: return ( (op1.evaluate(ctx) != 0.f) ^ ( op2.evaluate(ctx) != 0.f ) ? 1.f : 0.f ); 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 AND_EXP:
case ADD_EXP: return op1.evaluate(ctx) + op2.evaluate(ctx); return op1.evaluate(ctx) != 0.f ? (op2.evaluate(ctx) != 0.f ? 1.f : 0.f) : 0.f;
case SUB_EXP: return op1.evaluate(ctx) - op2.evaluate(ctx); case ADD_EXP:
case MULTIPLY_EXP: return op1.evaluate(ctx) * op2.evaluate(ctx); return op1.evaluate(ctx) + op2.evaluate(ctx);
case MAX_EXP: return max( op1.evaluate(ctx), op2.evaluate(ctx) ); case SUB_EXP:
case MIN_EXP: return min( op1.evaluate(ctx), op2.evaluate(ctx) ); return op1.evaluate(ctx) - op2.evaluate(ctx);
case EQUAL_EXP: return op1.evaluate(ctx) == op2.evaluate(ctx) ? 1.f : 0.f; case MULTIPLY_EXP:
case GREATER_EXP: return op1.evaluate(ctx) > op2.evaluate(ctx) ? 1.f : 0.f; return op1.evaluate(ctx) * op2.evaluate(ctx);
case LESSER_EXP: return op1.evaluate(ctx) < op2.evaluate(ctx) ? 1.f : 0.f; case MAX_EXP:
case SWITCH_EXP: return op1.evaluate(ctx) != 0.f ? op2.evaluate(ctx) : op3.evaluate(ctx); return max(op1.evaluate(ctx), op2.evaluate(ctx));
case ASSIGN_EXP: return ctx.assign( variableIdx, op1.evaluate(ctx) ); case MIN_EXP:
case LOOKUP_EXP: return ctx.getLookupMatch( lookupNameIdx, lookupValueIdxArray ); return min(op1.evaluate(ctx), op2.evaluate(ctx));
case NUMBER_EXP: return numberValue; case EQUAL_EXP:
case VARIABLE_EXP: return ctx.getVariableValue( variableIdx ); return op1.evaluate(ctx) == op2.evaluate(ctx) ? 1.f : 0.f;
case FOREIGN_VARIABLE_EXP: return ctx.getForeignVariableValue( variableIdx ); case GREATER_EXP:
case VARIABLE_GET_EXP: return ctx.getLookupValue(lookupNameIdx); return op1.evaluate(ctx) > op2.evaluate(ctx) ? 1.f : 0.f;
case NOT_EXP: return op1.evaluate(ctx) == 0.f ? 1.f : 0.f; case LESSER_EXP:
default: throw new IllegalArgumentException( "unknown op-code: " + typ ); 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 ) private float max(float v1, float v2) {
{
return v1 > v2 ? v1 : v2; return v1 > v2 ? v1 : v2;
} }
private float min( float v1, float v2 ) private float min(float v1, float v2) {
{
return v1 < v2 ? v1 : 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,57 +8,85 @@ 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;
} }
} }
@ -66,8 +94,7 @@ public final class BExpressionContextWay extends BExpressionContext implements T
} }
@Override @Override
public void setDecodeForbidden( boolean decodeForbidden ) public void setDecodeForbidden(boolean decodeForbidden) {
{ this.decodeForbidden = decodeForbidden;
this.decodeForbidden= decodeForbidden;
} }
} }

View File

@ -1,6 +1,6 @@
/** /**
* 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
@ -11,53 +11,43 @@ 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 ) public BExpressionLookupValue(String value) {
{
this.value = value; this.value = value;
} }
public void addAlias( String alias ) public void addAlias(String alias) {
{ if (aliases == null) aliases = new ArrayList<String>();
if ( aliases == null ) aliases = new ArrayList<String>(); aliases.add(alias);
aliases.add( alias );
} }
@Override @Override
public boolean equals( Object o ) public boolean equals(Object o) {
{ if (o instanceof String) {
if ( o instanceof String ) String v = (String) o;
{ return value.equals(v);
String v = (String)o;
return value.equals( v );
} }
if ( o instanceof BExpressionLookupValue ) if (o instanceof BExpressionLookupValue) {
{ BExpressionLookupValue v = (BExpressionLookupValue) o;
BExpressionLookupValue v = (BExpressionLookupValue)o;
return value.equals( v.value ); return value.equals(v.value);
} }
return false; return false;
} }
public boolean matches( String s ) public boolean matches(String s) {
{ if (value.equals(s)) return true;
if ( value.equals( s ) ) return true; if (aliases != null) {
if ( aliases != null ) for (String alias : aliases) {
{ if (alias.equals(s)) return true;
for( String alias : aliases )
{
if ( alias.equals( s ) ) return true;
} }
} }
return false; 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(;;) for (; ; ) {
{ String line = br.readLine();
String line = br.readLine(); if (line == null) break;
if ( line == null ) break; line = line.trim();
line = line.trim(); if (line.length() == 0 || line.startsWith("#")) continue;
if ( line.length() == 0 || line.startsWith( "#" ) ) continue; if (line.startsWith(CONTEXT_TAG)) {
if ( line.startsWith( CONTEXT_TAG ) ) ctx = listeners.get(line.substring(CONTEXT_TAG.length()));
{ continue;
ctx = listeners.get( line.substring( CONTEXT_TAG.length() ) ); }
continue; if (line.startsWith(VERSION_TAG)) {
lookupVersion = Short.parseShort(line.substring(VERSION_TAG.length()));
continue;
}
if (line.startsWith(MINOR_VERSION_TAG)) {
lookupMinorVersion = Short.parseShort(line.substring(MINOR_VERSION_TAG.length()));
continue;
}
if (line.startsWith(VARLENGTH_TAG)) // tag removed...
{
continue;
}
if (ctx != null) ctx.parseMetaLine(line);
} }
if ( line.startsWith( VERSION_TAG ) ) 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,54 +4,47 @@ 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

@ -17,126 +17,104 @@ 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>();
if ( tags == null ) tags = new HashMap<String,String>(); tags.put(key, value);
tags.put( key, value );
} }
public String getTag( String key ) public String getTag(String key) {
{ return tags == null ? null : tags.get(key);
return tags == null ? null : tags.get( key );
} }
public HashMap<String,String> getTagsOrNull() public HashMap<String, String> getTagsOrNull() {
{
return tags; return tags;
} }
public void setTags( HashMap<String,String> tags ) public void setTags(HashMap<String, String> tags) {
{
this.tags = tags; this.tags = tags;
} }
protected static long readId( DataInputStream is) throws IOException protected static long readId(DataInputStream is) throws IOException {
{ int offset = is.readByte();
int offset = is.readByte(); if (offset == 32) return -1;
if ( offset == 32 ) return -1; long i = is.readInt();
long i = is.readInt(); i = i << 5;
i = i << 5; return i | offset;
return i | offset;
} }
protected static void writeId( DataOutputStream o, long id ) throws IOException protected static void writeId(DataOutputStream o, long id) throws IOException {
{ if (id == -1) {
if ( id == -1 ) o.writeByte(32);
{ return;
o.writeByte( 32 ); }
return; int offset = (int) (id & 0x1f);
int i = (int) (id >> 5);
o.writeByte(offset);
o.writeInt(i);
}
protected static File[] sortBySizeAsc(File[] files) {
int n = files.length;
long[] sizes = new long[n];
File[] sorted = new File[n];
for (int i = 0; i < n; i++) sizes[i] = files[i].length();
for (int nf = 0; nf < n; nf++) {
int idx = -1;
long min = -1;
for (int i = 0; i < n; i++) {
if (sizes[i] != -1 && (idx == -1 || sizes[i] < min)) {
min = sizes[i];
idx = i;
}
} }
int offset = (int)( id & 0x1f ); sizes[idx] = -1;
int i = (int)( id >> 5 ); sorted[nf] = files[idx];
o.writeByte( offset ); }
o.writeInt( i ); return sorted;
} }
protected File fileFromTemplate(File template, File dir, String suffix) {
protected static File[] sortBySizeAsc( File[] files )
{
int n = files.length;
long[] sizes = new long[n];
File[] sorted = new File[n];
for( int i=0; i<n; i++ ) sizes[i] = files[i].length();
for(int nf=0; nf<n; nf++)
{
int idx = -1;
long min = -1;
for( int i=0; i<n; i++ )
{
if ( sizes[i] != -1 && ( idx == -1 || sizes[i] < min ) )
{
min = sizes[i];
idx = i;
}
}
sizes[idx] = -1;
sorted[nf] = files[idx];
}
return sorted;
}
protected File fileFromTemplate( File template, File dir, String suffix )
{
String filename = template.getName(); String filename = template.getName();
filename = filename.substring( 0, filename.length() - 3 ) + suffix; filename = filename.substring(0, filename.length() - 3) + suffix;
return new File( dir, filename ); return new File(dir, filename);
} }
protected DataInputStream createInStream( File inFile ) throws IOException protected DataInputStream createInStream(File inFile) throws IOException {
{ return new DataInputStream(new BufferedInputStream(new FileInputStream(inFile)));
return new DataInputStream( new BufferedInputStream ( new FileInputStream( inFile ) ) ); }
}
protected DiffCoderDataOutputStream createOutStream( File outFile ) throws IOException protected DiffCoderDataOutputStream createOutStream(File outFile) throws IOException {
{ return new DiffCoderDataOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
return new DiffCoderDataOutputStream( new BufferedOutputStream( new FileOutputStream( outFile ) ) ); }
}
protected DiffCoderDataOutputStream getOutStreamForTile( int tileIndex ) throws Exception protected DiffCoderDataOutputStream getOutStreamForTile(int tileIndex) throws Exception {
{ if (tileOutStreams == null) {
if ( tileOutStreams == null )
{
tileOutStreams = new DiffCoderDataOutputStream[64]; tileOutStreams = new DiffCoderDataOutputStream[64];
} }
if ( tileOutStreams[tileIndex] == null ) if (tileOutStreams[tileIndex] == null) {
{ tileOutStreams[tileIndex] = createOutStream(new File(outTileDir, getNameForTile(tileIndex)));
tileOutStreams[tileIndex] = createOutStream( new File( outTileDir, getNameForTile( tileIndex ) ) );
} }
return tileOutStreams[tileIndex]; return tileOutStreams[tileIndex];
} }
protected String getNameForTile( int tileIndex ) protected String getNameForTile(int tileIndex) {
{ throw new IllegalArgumentException("getNameForTile not implemented");
throw new IllegalArgumentException( "getNameForTile not implemented" );
} }
protected void closeTileOutStreams() throws Exception protected void closeTileOutStreams() throws Exception {
{ if (tileOutStreams == null) {
if ( tileOutStreams == null )
{
return; return;
} }
for( int tileIndex=0; tileIndex<tileOutStreams.length; tileIndex++ ) for (int tileIndex = 0; tileIndex < tileOutStreams.length; tileIndex++) {
{ if (tileOutStreams[tileIndex] != null) tileOutStreams[tileIndex].close();
if ( tileOutStreams[tileIndex] != null ) tileOutStreams[tileIndex].close();
tileOutStreams[tileIndex] = null; tileOutStreams[tileIndex] = null;
} }
} }
@ -145,27 +123,36 @@ public abstract class MapCreatorBase implements WayListener, NodeListener, Relat
// interface dummys // interface dummys
@Override @Override
public void nodeFileStart( File nodefile ) throws Exception {} public void nodeFileStart(File nodefile) throws Exception {
}
@Override @Override
public void nextNode( NodeData n ) throws Exception {} public void nextNode(NodeData n) throws Exception {
}
@Override @Override
public void nodeFileEnd( File nodefile ) throws Exception {} public void nodeFileEnd(File nodefile) throws Exception {
}
@Override @Override
public boolean wayFileStart( File wayfile ) throws Exception { return true; } public boolean wayFileStart(File wayfile) throws Exception {
return true;
}
@Override @Override
public void nextWay( WayData data ) throws Exception {} public void nextWay(WayData data) throws Exception {
}
@Override @Override
public void wayFileEnd( File wayfile ) throws Exception {} public void wayFileEnd(File wayfile) throws Exception {
}
@Override @Override
public void nextRelation( RelationData data ) throws Exception {} public void nextRelation(RelationData data) throws Exception {
}
@Override @Override
public void nextRestriction( RelationData data, long fromWid, long toWid, long viaNid ) throws Exception {} public void nextRestriction(RelationData data, long fromWid, long toWid, long viaNid) throws Exception {
}
} }

View File

@ -4,78 +4,69 @@ 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"); System.out.println("*** NodeCutter: Cut big node-tiles into 5x5 tiles");
if (args.length != 2) if (args.length != 2) {
{ System.out.println("usage: java NodeCutter <node-tiles-in> <node-tiles-out>");
System.out.println("usage: java NodeCutter <node-tiles-in> <node-tiles-out>" );
return; return;
} }
new NodeCutter().process( new File( args[0] ), new File( args[1] ) ); new NodeCutter().process(new File(args[0]), new File(args[1]));
} }
public void init( File nodeTilesOut ) public void init(File nodeTilesOut) {
{
this.outTileDir = nodeTilesOut; this.outTileDir = nodeTilesOut;
} }
public void process( File nodeTilesIn, File nodeTilesOut ) throws Exception public void process(File nodeTilesIn, File nodeTilesOut) throws Exception {
{ init(nodeTilesOut);
init( nodeTilesOut );
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tlf" ); new NodeIterator(this, true).processDir(nodeTilesIn, ".tlf");
} }
@Override @Override
public void nodeFileStart( File nodefile ) throws Exception public void nodeFileStart(File nodefile) throws Exception {
{
lonoffset = -1; lonoffset = -1;
latoffset = -1; latoffset = -1;
} }
@Override @Override
public void nextNode( NodeData n ) throws Exception public void nextNode(NodeData n) throws Exception {
{ n.writeTo(getOutStreamForTile(getTileIndex(n.ilon, n.ilat)));
n.writeTo( getOutStreamForTile( getTileIndex( n.ilon, n.ilat ) ) );
} }
@Override @Override
public void nodeFileEnd( File nodeFile ) throws Exception public void nodeFileEnd(File nodeFile) throws Exception {
{
closeTileOutStreams(); closeTileOutStreams();
} }
private int getTileIndex( int ilon, int ilat ) private int getTileIndex(int ilon, int ilat) {
{ int lonoff = (ilon / 45000000) * 45;
int lonoff = (ilon / 45000000 ) * 45; int latoff = (ilat / 30000000) * 30;
int latoff = (ilat / 30000000 ) * 30; if (lonoffset == -1) lonoffset = lonoff;
if ( lonoffset == -1 ) lonoffset = lonoff; if (latoffset == -1) latoffset = latoff;
if ( latoffset == -1 ) latoffset = latoff; if (lonoff != lonoffset || latoff != latoffset)
if ( lonoff != lonoffset || latoff != latoffset ) throw new IllegalArgumentException("inconsistent node: " + ilon + " " + ilat);
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
int lon = (ilon / 5000000) % 9; int lon = (ilon / 5000000) % 9;
int lat = (ilat / 5000000) % 6; int lat = (ilat / 5000000) % 6;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat ); if (lon < 0 || lon > 8 || lat < 0 || lat > 5)
return lon*6 + lat; throw new IllegalArgumentException("illegal pos: " + ilon + "," + ilat);
return lon * 6 + lat;
} }
protected String getNameForTile( int tileIndex ) protected String getNameForTile(int tileIndex) {
{ int lon = (tileIndex / 6) * 5 + lonoffset - 180;
int lon = (tileIndex / 6 ) * 5 + lonoffset - 180; int lat = (tileIndex % 6) * 5 + latoffset - 90;
int lat = (tileIndex % 6 ) * 5 + latoffset - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon; String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat; String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".n5d"; return slon + "_" + slat + ".n5d";

View File

@ -8,39 +8,42 @@ import btools.util.DiffCoderDataOutputStream;
* *
* @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; nid = id;
ilat = (int)( ( lat + 90. )*1000000. + 0.5); ilat = (int) ((lat + 90.) * 1000000. + 0.5);
ilon = (int)( ( lon + 180. )*1000000. + 0.5); ilon = (int) ((lon + 180.) * 1000000. + 0.5);
} }
public NodeData( DiffCoderDataInputStream dis ) throws Exception public NodeData(DiffCoderDataInputStream dis) throws Exception {
{ nid = dis.readDiffed(0);
nid = dis.readDiffed( 0 ); ilon = (int) dis.readDiffed(1);
ilon = (int)dis.readDiffed( 1 ); ilat = (int) dis.readDiffed(2);
ilat = (int)dis.readDiffed( 2 );
int mode = dis.readByte(); int mode = dis.readByte();
if ( ( mode & 1 ) != 0 ) { int dlen = dis.readShort(); description = new byte[dlen]; dis.readFully( description ); } if ((mode & 1) != 0) {
if ( ( mode & 2 ) != 0 ) selev = dis.readShort(); int dlen = dis.readShort();
description = new byte[dlen];
dis.readFully(description);
}
if ((mode & 2) != 0) selev = dis.readShort();
} }
public void writeTo( DiffCoderDataOutputStream dos ) throws Exception 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) {
if ( ( mode & 1 ) != 0 ) { dos.writeShort( description.length ); dos.write( description ); } dos.writeShort(description.length);
if ( ( mode & 2 ) != 0 ) dos.writeShort( selev ); dos.write(description);
}
if ((mode & 2) != 0) dos.writeShort(selev);
} }
} }

View File

@ -10,83 +10,71 @@ 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"); System.out.println("*** NodeFilter: Filter way related nodes");
if (args.length != 3) if (args.length != 3) {
{ System.out.println("usage: java NodeFilter <node-tiles-in> <way-file-in> <node-tiles-out>");
System.out.println("usage: java NodeFilter <node-tiles-in> <way-file-in> <node-tiles-out>" );
return; 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 public void init() throws Exception {
{ nodebitmap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap(512) : new TinyDenseLongMap();
nodebitmap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap( 512 ) : new TinyDenseLongMap();
} }
public void process( File nodeTilesIn, File wayFileIn, File nodeTilesOut ) throws Exception public void process(File nodeTilesIn, File wayFileIn, File nodeTilesOut) throws Exception {
{
init(); init();
this.nodeTilesOut = nodeTilesOut; this.nodeTilesOut = nodeTilesOut;
// read the wayfile into a bitmap of used nodes // read the wayfile into a bitmap of used nodes
new WayIterator( this, false ).processFile( wayFileIn ); new WayIterator(this, false).processFile(wayFileIn);
// finally filter all node files // finally filter all node files
new NodeIterator( this, true ).processDir( nodeTilesIn, ".tls" ); new NodeIterator(this, true).processDir(nodeTilesIn, ".tls");
} }
@Override @Override
public void nextWay( WayData data ) throws Exception public void nextWay(WayData data) throws Exception {
{
int nnodes = data.nodes.size(); int nnodes = data.nodes.size();
for (int i=0; i<nnodes; i++ ) for (int i = 0; i < nnodes; i++) {
{ nodebitmap.put(data.nodes.get(i), 0);
nodebitmap.put( data.nodes.get(i), 0 );
} }
} }
@Override @Override
public void nodeFileStart( File nodefile ) throws Exception public void nodeFileStart(File nodefile) throws Exception {
{
String filename = nodefile.getName(); String filename = nodefile.getName();
File outfile = new File( nodeTilesOut, filename ); File outfile = new File(nodeTilesOut, filename);
nodesOutStream = new DiffCoderDataOutputStream( new BufferedOutputStream ( new FileOutputStream( outfile ) ) ); nodesOutStream = new DiffCoderDataOutputStream(new BufferedOutputStream(new FileOutputStream(outfile)));
} }
@Override @Override
public void nextNode( NodeData n ) throws Exception public void nextNode(NodeData n) throws Exception {
{ if (isRelevant(n)) {
if ( isRelevant( n ) ) n.writeTo(nodesOutStream);
{
n.writeTo( nodesOutStream );
} }
} }
public boolean isRelevant( NodeData n ) public boolean isRelevant(NodeData n) {
{
// check if node passes bitmap // check if node passes bitmap
return nodebitmap.getInt( n.nid ) == 0; // 0 -> bit set, -1 -> unset return nodebitmap.getInt(n.nid) == 0; // 0 -> bit set, -1 -> unset
} }
@Override @Override
public void nodeFileEnd( File nodeFile ) throws Exception public void nodeFileEnd(File nodeFile) throws Exception {
{
nodesOutStream.close(); nodesOutStream.close();
} }
} }

View File

@ -13,58 +13,46 @@ import btools.util.DiffCoderDataInputStream;
* *
* @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; listener = nodeListener;
delete = deleteAfterReading; delete = deleteAfterReading;
} }
public void processDir( File indir, String inSuffix ) throws Exception public void processDir(File indir, String inSuffix) throws Exception {
{ if (!indir.isDirectory()) {
if ( !indir.isDirectory() ) throw new IllegalArgumentException("not a directory: " + indir);
{
throw new IllegalArgumentException( "not a directory: " + indir );
} }
File[] af = sortBySizeAsc( indir.listFiles() ); File[] af = sortBySizeAsc(indir.listFiles());
for( int i=0; i<af.length; i++ ) for (int i = 0; i < af.length; i++) {
{
File nodefile = af[i]; File nodefile = af[i];
if ( nodefile.getName().endsWith( inSuffix ) ) if (nodefile.getName().endsWith(inSuffix)) {
{ processFile(nodefile);
processFile( nodefile );
} }
} }
} }
public void processFile(File nodefile) throws Exception public void processFile(File nodefile) throws Exception {
{ System.out.println("*** NodeIterator reading: " + nodefile);
System.out.println( "*** NodeIterator reading: " + nodefile );
listener.nodeFileStart( nodefile ); listener.nodeFileStart(nodefile);
DiffCoderDataInputStream di = new DiffCoderDataInputStream( new BufferedInputStream ( new FileInputStream( nodefile ) ) ); DiffCoderDataInputStream di = new DiffCoderDataInputStream(new BufferedInputStream(new FileInputStream(nodefile)));
try try {
{ for (; ; ) {
for(;;) NodeData n = new NodeData(di);
{ listener.nextNode(n);
NodeData n = new NodeData( di );
listener.nextNode( n );
} }
} } catch (EOFException eof) {
catch( EOFException eof )
{
di.close(); di.close();
} }
listener.nodeFileEnd( nodefile ); listener.nodeFileEnd(nodefile);
if ( delete && "true".equals( System.getProperty( "deletetmpfiles" ) )) if (delete && "true".equals(System.getProperty("deletetmpfiles"))) {
{
nodefile.delete(); nodefile.delete();
} }
} }

View File

@ -7,11 +7,10 @@ import java.io.File;
* *
* @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

@ -18,8 +18,7 @@ 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;
@ -34,25 +33,23 @@ public class OsmCutter extends MapCreatorBase
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"); System.out.println("*** OsmCutter: cut an osm map in node-tiles + a way file");
if (args.length != 6 && args.length != 7) if (args.length != 6 && args.length != 7) {
{
System.out.println("usage: bzip2 -dc <map> | java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile>"); System.out.println("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> "); System.out.println("or : java OsmCutter <lookup-file> <out-tile-dir> <out-way-file> <out-rel-file> <out-res-file> <filter-profile> <inputfile> ");
return; return;
} }
new OsmCutter().process( new OsmCutter().process(
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])
, args.length > 6 ? new File( args[6] ) : null , args.length > 6 ? new File(args[6]) : null
); );
} }
private BExpressionContextWay _expctxWay; private BExpressionContextWay _expctxWay;
@ -61,50 +58,46 @@ public class OsmCutter extends MapCreatorBase
// private BExpressionContextWay _expctxWayStat; // private BExpressionContextWay _expctxWayStat;
// private BExpressionContextNode _expctxNodeStat; // private BExpressionContextNode _expctxNodeStat;
public void process (File lookupFile, File outTileDir, File wayFile, File relFile, File resFile, File profileFile, File mapFile ) throws Exception public void process(File lookupFile, File outTileDir, File wayFile, File relFile, File resFile, File profileFile, File mapFile) throws Exception {
{ if (!lookupFile.exists()) {
if ( !lookupFile.exists() ) throw new IllegalArgumentException("lookup-file: " + lookupFile + " does not exist");
{
throw new IllegalArgumentException( "lookup-file: " + lookupFile + " does not exist" );
} }
BExpressionMetaData meta = new BExpressionMetaData(); BExpressionMetaData meta = new BExpressionMetaData();
_expctxWay = new BExpressionContextWay( meta ); _expctxWay = new BExpressionContextWay(meta);
_expctxNode = new BExpressionContextNode( meta ); _expctxNode = new BExpressionContextNode(meta);
meta.readMetaData( lookupFile ); meta.readMetaData(lookupFile);
_expctxWay.parseFile( profileFile, "global" ); _expctxWay.parseFile(profileFile, "global");
// _expctxWayStat = new BExpressionContextWay( null ); // _expctxWayStat = new BExpressionContextWay( null );
// _expctxNodeStat = new BExpressionContextNode( null ); // _expctxNodeStat = new BExpressionContextNode( null );
this.outTileDir = outTileDir; this.outTileDir = outTileDir;
if ( !outTileDir.isDirectory() ) throw new RuntimeException( "out tile directory " + outTileDir + " does not exist" ); if (!outTileDir.isDirectory())
throw new RuntimeException("out tile directory " + outTileDir + " does not exist");
wayDos = wayFile == null ? null : new DataOutputStream( new BufferedOutputStream( new FileOutputStream( wayFile ) ) ); wayDos = wayFile == null ? null : new DataOutputStream(new BufferedOutputStream(new FileOutputStream(wayFile)));
cyclewayDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( relFile ) ) ); cyclewayDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(relFile)));
if ( resFile != null ) if (resFile != null) {
{ restrictionsDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(resFile)));
restrictionsDos = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( resFile ) ) );
} }
// read the osm map into memory // read the osm map into memory
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
new OsmParser().readMap( mapFile, this, this, this ); new OsmParser().readMap(mapFile, this, this, this);
long t1 = System.currentTimeMillis(); long t1 = System.currentTimeMillis();
System.out.println( "parsing time (ms) =" + (t1-t0) ); System.out.println("parsing time (ms) =" + (t1 - t0));
// close all files // close all files
closeTileOutStreams(); closeTileOutStreams();
if ( wayDos != null ) if (wayDos != null) {
{
wayDos.close(); wayDos.close();
} }
cyclewayDos.close(); cyclewayDos.close();
if ( restrictionsDos != null ) if (restrictionsDos != null) {
{
restrictionsDos.close(); restrictionsDos.close();
} }
@ -113,177 +106,151 @@ public class OsmCutter extends MapCreatorBase
// System.out.println( "-------- node-statistics -------- " ); // System.out.println( "-------- node-statistics -------- " );
// _expctxNodeStat.dumpStatistics(); // _expctxNodeStat.dumpStatistics();
System.out.println( statsLine() ); System.out.println(statsLine());
} }
private void checkStats() private void checkStats() {
{ if ((++recordCnt % 100000) == 0) System.out.println(statsLine());
if ( (++recordCnt % 100000) == 0 ) System.out.println( statsLine() );
} }
private String statsLine() private String statsLine() {
{
return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed; return "records read: " + recordCnt + " nodes=" + nodesParsed + " ways=" + waysParsed + " rels=" + relsParsed + " changesets=" + changesetsParsed;
} }
@Override @Override
public void nextNode( NodeData n ) throws Exception public void nextNode(NodeData n) throws Exception {
{
nodesParsed++; nodesParsed++;
checkStats(); checkStats();
if ( n.getTagsOrNull() != null ) if (n.getTagsOrNull() != null) {
{
int[] lookupData = _expctxNode.createNewLookupData(); int[] lookupData = _expctxNode.createNewLookupData();
for( Map.Entry<String,String> e : n.getTagsOrNull().entrySet() ) for (Map.Entry<String, String> e : n.getTagsOrNull().entrySet()) {
{ _expctxNode.addLookupValue(e.getKey(), e.getValue(), lookupData);
_expctxNode.addLookupValue( e.getKey(), e.getValue(), lookupData );
// _expctxNodeStat.addLookupValue( key, value, null ); // _expctxNodeStat.addLookupValue( key, value, null );
} }
n.description = _expctxNode.encode(lookupData); n.description = _expctxNode.encode(lookupData);
} }
// write node to file // write node to file
int tileIndex = getTileIndex( n.ilon, n.ilat ); int tileIndex = getTileIndex(n.ilon, n.ilat);
if ( tileIndex >= 0 ) if (tileIndex >= 0) {
{ n.writeTo(getOutStreamForTile(tileIndex));
n.writeTo( getOutStreamForTile( tileIndex ) ); if (wayCutter != null) {
if ( wayCutter != null ) wayCutter.nextNode(n);
{
wayCutter.nextNode( n );
} }
} }
} }
private void generatePseudoTags( HashMap<String,String> map ) private void generatePseudoTags(HashMap<String, String> map) {
{
// add pseudo.tags for concrete:lanes and concrete:plates // add pseudo.tags for concrete:lanes and concrete:plates
String concrete = null; String concrete = null;
for( Map.Entry<String,String> e : map.entrySet() ) for (Map.Entry<String, String> e : map.entrySet()) {
{
String key = e.getKey(); String key = e.getKey();
if ( "concrete".equals( key ) ) if ("concrete".equals(key)) {
{
return; return;
} }
if ( "surface".equals( key ) ) if ("surface".equals(key)) {
{
String value = e.getValue(); String value = e.getValue();
if ( value.startsWith( "concrete:" ) ) if (value.startsWith("concrete:")) {
{ concrete = value.substring("concrete:".length());
concrete = value.substring( "concrete:".length() );
} }
} }
} }
if ( concrete != null ) if (concrete != null) {
{ map.put("concrete", concrete);
map.put( "concrete", concrete );
} }
} }
@Override @Override
public void nextWay( WayData w ) throws Exception public void nextWay(WayData w) throws Exception {
{
waysParsed++; waysParsed++;
checkStats(); checkStats();
// encode tags // encode tags
if ( w.getTagsOrNull() == null ) return; if (w.getTagsOrNull() == null) return;
generatePseudoTags( w.getTagsOrNull() ); generatePseudoTags(w.getTagsOrNull());
int[] lookupData = _expctxWay.createNewLookupData(); int[] lookupData = _expctxWay.createNewLookupData();
for( String key : w.getTagsOrNull().keySet() ) for (String key : w.getTagsOrNull().keySet()) {
{ String value = w.getTag(key);
String value = w.getTag( key ); _expctxWay.addLookupValue(key, value.replace(' ', '_'), lookupData);
_expctxWay.addLookupValue( key, value.replace( ' ', '_' ), lookupData );
// _expctxWayStat.addLookupValue( key, value, null ); // _expctxWayStat.addLookupValue( key, value, null );
} }
w.description = _expctxWay.encode(lookupData); w.description = _expctxWay.encode(lookupData);
if ( w.description == null ) return; if (w.description == null) return;
// filter according to profile // filter according to profile
_expctxWay.evaluate( false, w.description ); _expctxWay.evaluate(false, w.description);
boolean ok = _expctxWay.getCostfactor() < 10000.; boolean ok = _expctxWay.getCostfactor() < 10000.;
_expctxWay.evaluate( true, w.description ); _expctxWay.evaluate(true, w.description);
ok |= _expctxWay.getCostfactor() < 10000.; ok |= _expctxWay.getCostfactor() < 10000.;
if ( !ok ) return; if (!ok) return;
if ( wayDos != null ) if (wayDos != null) {
{ w.writeTo(wayDos);
w.writeTo( wayDos );
} }
if ( wayCutter != null ) if (wayCutter != null) {
{ wayCutter.nextWay(w);
wayCutter.nextWay( w );
} }
if ( nodeFilter != null ) if (nodeFilter != null) {
{ nodeFilter.nextWay(w);
nodeFilter.nextWay( w );
} }
} }
@Override @Override
public void nextRelation( RelationData r ) throws Exception public void nextRelation(RelationData r) throws Exception {
{
relsParsed++; relsParsed++;
checkStats(); checkStats();
String route = r.getTag( "route" ); String route = r.getTag("route");
// filter out non-cycle relations // filter out non-cycle relations
if ( route == null ) if (route == null) {
{
return; return;
} }
String network = r.getTag( "network" ); String network = r.getTag("network");
if ( network == null ) network = ""; if (network == null) network = "";
String state = r.getTag( "state" ); String state = r.getTag("state");
if ( state == null ) state = ""; if (state == null) state = "";
writeId( cyclewayDos, r.rid ); writeId(cyclewayDos, r.rid);
cyclewayDos.writeUTF( route ); cyclewayDos.writeUTF(route);
cyclewayDos.writeUTF( network ); cyclewayDos.writeUTF(network);
cyclewayDos.writeUTF( state ); cyclewayDos.writeUTF(state);
for ( int i=0; i<r.ways.size();i++ ) for (int i = 0; i < r.ways.size(); i++) {
{
long wid = r.ways.get(i); long wid = r.ways.get(i);
writeId( cyclewayDos, wid ); writeId(cyclewayDos, wid);
} }
writeId( cyclewayDos, -1 ); writeId(cyclewayDos, -1);
} }
@Override @Override
public void nextRestriction( RelationData r, long fromWid, long toWid, long viaNid ) throws Exception public void nextRestriction(RelationData r, long fromWid, long toWid, long viaNid) throws Exception {
{ String type = r.getTag("type");
String type = r.getTag( "type" ); if (type == null || !"restriction".equals(type)) {
if ( type == null || !"restriction".equals( type ) )
{
return; return;
} }
short exceptions = 0; short exceptions = 0;
String except = r.getTag( "except" ); String except = r.getTag("except");
if ( except != null ) if (except != null) {
{ exceptions |= toBit("bicycle", 0, except);
exceptions |= toBit( "bicycle" , 0, except ); exceptions |= toBit("motorcar", 1, except);
exceptions |= toBit( "motorcar" , 1, except ); exceptions |= toBit("agricultural", 2, except);
exceptions |= toBit( "agricultural" , 2, except ); exceptions |= toBit("forestry", 2, except);
exceptions |= toBit( "forestry" , 2, except ); exceptions |= toBit("psv", 3, except);
exceptions |= toBit( "psv" , 3, except ); exceptions |= toBit("hgv", 4, except);
exceptions |= toBit( "hgv" , 4, except );
} }
for( String restrictionKey : r.getTagsOrNull().keySet() ) for (String restrictionKey : r.getTagsOrNull().keySet()) {
{ if (!(restrictionKey.equals("restriction") || restrictionKey.startsWith("restriction:"))) {
if ( !( restrictionKey.equals( "restriction" ) || restrictionKey.startsWith( "restriction:" ) ) )
{
continue; continue;
} }
String restriction = r.getTag( restrictionKey ); String restriction = r.getTag(restrictionKey);
RestrictionData res = new RestrictionData(); RestrictionData res = new RestrictionData();
res.restrictionKey = restrictionKey; res.restrictionKey = restrictionKey;
@ -293,38 +260,32 @@ public class OsmCutter extends MapCreatorBase
res.toWid = toWid; res.toWid = toWid;
res.viaNid = viaNid; res.viaNid = viaNid;
if ( restrictionsDos != null ) if (restrictionsDos != null) {
{ res.writeTo(restrictionsDos);
res.writeTo( restrictionsDos );
} }
if ( restrictionCutter != null ) if (restrictionCutter != null) {
{ restrictionCutter.nextRestriction(res);
restrictionCutter.nextRestriction( res );
} }
} }
} }
private static short toBit( String tag, int bitpos, String s ) private static short toBit(String tag, int bitpos, String s) {
{ return (short) (s.indexOf(tag) < 0 ? 0 : 1 << bitpos);
return (short) ( s.indexOf( tag ) < 0 ? 0 : 1 << bitpos );
} }
private int getTileIndex( int ilon, int ilat ) private int getTileIndex(int ilon, int ilat) {
{ int lon = ilon / 45000000;
int lon = ilon / 45000000; int lat = ilat / 30000000;
int lat = ilat / 30000000; if (lon < 0 || lon > 7 || lat < 0 || lat > 5) {
if ( lon < 0 || lon > 7 || lat < 0 || lat > 5 ) System.out.println("warning: ignoring illegal pos: " + ilon + "," + ilat);
{ return -1;
System.out.println( "warning: ignoring illegal pos: " + ilon + "," + ilat ); }
return -1; return lon * 6 + lat;
}
return lon*6 + lat;
} }
protected String getNameForTile( int tileIndex ) protected String getNameForTile(int tileIndex) {
{ int lon = (tileIndex / 6) * 45 - 180;
int lon = (tileIndex / 6 ) * 45 - 180; int lat = (tileIndex % 6) * 30 - 90;
int lat = (tileIndex % 6 ) * 30 - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon; String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat; String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".ntl"; 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

@ -6,15 +6,14 @@
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;
@ -24,94 +23,67 @@ public class OsmLinkP
protected OsmLinkP next; protected OsmLinkP next;
public OsmLinkP( OsmNodeP source, OsmNodeP target ) public OsmLinkP(OsmNodeP source, OsmNodeP target) {
{
sourceNode = source; sourceNode = source;
targetNode = target; targetNode = target;
} }
protected OsmLinkP() protected OsmLinkP() {
{
} }
public final boolean counterLinkWritten( ) public final boolean counterLinkWritten() {
{ return descriptionBitmap == null;
return descriptionBitmap == null;
} }
/** /**
* Set the relevant next-pointer for the given source * Set the relevant next-pointer for the given source
*/ */
public void setNext( OsmLinkP link, OsmNodeP source ) public void setNext(OsmLinkP link, OsmNodeP source) {
{ if (sourceNode == source) {
if ( sourceNode == source ) next = link;
{ } else if (targetNode == source) {
next = link; previous = link;
} } else {
else if ( targetNode == source ) throw new IllegalArgumentException("internal error: setNext: unknown source");
{ }
previous = link;
}
else
{
throw new IllegalArgumentException( "internal error: setNext: unknown source" );
}
} }
/** /**
* Get the relevant next-pointer for the given source * Get the relevant next-pointer for the given source
*/ */
public OsmLinkP getNext( OsmNodeP source ) public OsmLinkP getNext(OsmNodeP source) {
{ if (sourceNode == source) {
if ( sourceNode == source )
{
return next; return next;
} } else if (targetNode == source) {
else if ( targetNode == source )
{
return previous; return previous;
} } else {
else throw new IllegalArgumentException("internal error: gextNext: unknown source");
{
throw new IllegalArgumentException( "internal error: gextNext: unknown source" );
} }
} }
/** /**
* Get the relevant target-node for the given source * Get the relevant target-node for the given source
*/ */
public OsmNodeP getTarget( OsmNodeP source ) public OsmNodeP getTarget(OsmNodeP source) {
{ if (sourceNode == source) {
if ( sourceNode == source )
{
return targetNode; return targetNode;
} } else if (targetNode == source) {
else if ( targetNode == source )
{
return sourceNode; return sourceNode;
} } else {
else throw new IllegalArgumentException("internal error: getTarget: unknown source");
{
throw new IllegalArgumentException( "internal error: getTarget: unknown source" );
} }
} }
/** /**
* Check if reverse link for the given source * Check if reverse link for the given source
*/ */
public boolean isReverse( OsmNodeP source ) public boolean isReverse(OsmNodeP source) {
{ if (sourceNode == source) {
if ( sourceNode == source )
{
return false; return false;
} } else if (targetNode == source) {
else if ( targetNode == source )
{
return true; return true;
} } else {
else throw new IllegalArgumentException("internal error: isReverse: unknown source");
{
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

@ -6,45 +6,38 @@
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 ) public OsmNodePT(OsmNodeP n) {
{ ilat = n.ilat;
ilat = n.ilat; ilon = n.ilon;
ilon = n.ilon; selev = n.selev;
selev = n.selev; bits = n.bits;
bits = n.bits; }
}
public OsmNodePT( byte[] descriptionBits ) public OsmNodePT(byte[] descriptionBits) {
{ this.descriptionBits = descriptionBits;
this.descriptionBits = descriptionBits; }
}
@Override @Override
public final byte[] getNodeDecsription() public final byte[] getNodeDecsription() {
{ return descriptionBits;
return descriptionBits; }
}
@Override @Override
public final RestrictionData getFirstRestriction() public final RestrictionData getFirstRestriction() {
{ return firstRestriction;
return firstRestriction; }
}
@Override @Override
public boolean isTransferNode() public boolean isTransferNode() {
{ return false; // always have descriptionBits so never transfernode
return false; // always have descriptionBits so never transfernode }
}
} }

View File

@ -11,225 +11,189 @@ import java.util.zip.GZIPInputStream;
* *
* @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.nListener = nListener;
this.wListener = wListener; this.wListener = wListener;
this.rListener = rListener; this.rListener = rListener;
if ( mapFile == null ) if (mapFile == null) {
{
_br = new BufferedReader(new InputStreamReader(System.in)); _br = new BufferedReader(new InputStreamReader(System.in));
} } else {
else if (mapFile.getName().endsWith(".gz")) {
{ _br = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(mapFile))));
if ( mapFile.getName().endsWith( ".gz" ) ) } else {
{ _br = new BufferedReader(new InputStreamReader(new FileInputStream(mapFile)));
_br = new BufferedReader(new InputStreamReader( new GZIPInputStream( new FileInputStream( mapFile ) ) ) );
}
else
{
_br = new BufferedReader(new InputStreamReader( new FileInputStream( mapFile ) ) );
} }
} }
for(;;) for (; ; ) {
{
String line = _br.readLine(); String line = _br.readLine();
if ( line == null ) break; if (line == null) break;
if ( checkNode( line ) ) continue; if (checkNode(line)) continue;
if ( checkWay( line ) ) continue; if (checkWay(line)) continue;
if ( checkRelation( line ) ) continue; if (checkRelation(line)) continue;
if ( checkChangeset( line ) ) continue; if (checkChangeset(line)) continue;
} }
if ( mapFile != null ) if (mapFile != null) {
{
_br.close(); _br.close();
} }
} }
private boolean checkNode( String line ) throws Exception private boolean checkNode(String line) throws Exception {
{ int idx0 = line.indexOf("<node id=\"");
int idx0 = line.indexOf( "<node id=\"" ); if (idx0 < 0) return false;
if ( idx0 < 0 ) return false;
idx0 += 10; idx0 += 10;
int idx1 = line.indexOf( '"', idx0 ); int idx1 = line.indexOf('"', idx0);
long nodeId = Long.parseLong( line.substring( idx0, idx1 ) ); long nodeId = Long.parseLong(line.substring(idx0, idx1));
int idx2 = line.indexOf( " lat=\"" ); int idx2 = line.indexOf(" lat=\"");
if ( idx2 < 0 ) return false; if (idx2 < 0) return false;
idx2 += 6; idx2 += 6;
int idx3 = line.indexOf( '"', idx2 ); int idx3 = line.indexOf('"', idx2);
double lat = Double.parseDouble( line.substring( idx2, idx3 ) ); double lat = Double.parseDouble(line.substring(idx2, idx3));
int idx4 = line.indexOf( " lon=\"" ); int idx4 = line.indexOf(" lon=\"");
if ( idx4 < 0 ) return false; if (idx4 < 0) return false;
idx4 += 6; idx4 += 6;
int idx5 = line.indexOf( '"', idx4 ); int idx5 = line.indexOf('"', idx4);
double lon = Double.parseDouble( line.substring( idx4, idx5 ) ); double lon = Double.parseDouble(line.substring(idx4, idx5));
NodeData n = new NodeData( nodeId, lon, lat ); NodeData n = new NodeData(nodeId, lon, lat);
if ( !line.endsWith( "/>" ) ) if (!line.endsWith("/>")) {
{
// read additional tags // read additional tags
for(;;) for (; ; ) {
{
String l2 = _br.readLine(); String l2 = _br.readLine();
if ( l2 == null ) return false; if (l2 == null) return false;
int i2; int i2;
if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 ) if ((i2 = l2.indexOf("<tag k=\"")) >= 0) { // property-tag
{ // property-tag
i2 += 8; i2 += 8;
int ri2 = l2.indexOf( '"', i2 ); int ri2 = l2.indexOf('"', i2);
String key = l2.substring( i2, ri2 ); String key = l2.substring(i2, ri2);
i2 = l2.indexOf( " v=\"", ri2 ); i2 = l2.indexOf(" v=\"", ri2);
if ( i2 >= 0 ) if (i2 >= 0) {
{
i2 += 4; i2 += 4;
int ri3 = l2.indexOf( '"', i2 ); int ri3 = l2.indexOf('"', i2);
String value = l2.substring( i2, ri3 ); String value = l2.substring(i2, ri3);
n.putTag( key, value ); n.putTag(key, value);
} }
} } else if (l2.indexOf("</node>") >= 0) { // end-tag
else if ( l2.indexOf( "</node>" ) >= 0 ) break;
{ // end-tag
break;
} }
} }
} }
nListener.nextNode( n ); nListener.nextNode(n);
return true; return true;
} }
private boolean checkWay( String line ) throws Exception private boolean checkWay(String line) throws Exception {
{ int idx0 = line.indexOf("<way id=\"");
int idx0 = line.indexOf( "<way id=\"" ); if (idx0 < 0) return false;
if ( idx0 < 0 ) return false;
idx0 += 9; idx0 += 9;
int idx1 = line.indexOf( '"', idx0 ); int idx1 = line.indexOf('"', idx0);
long id = Long.parseLong( line.substring( idx0, idx1 ) ); long id = Long.parseLong(line.substring(idx0, idx1));
WayData w = new WayData( id ); WayData w = new WayData(id);
// read the nodes // read the nodes
for(;;) for (; ; ) {
{
String l2 = _br.readLine(); String l2 = _br.readLine();
if ( l2 == null ) return false; if (l2 == null) return false;
int i2; int i2;
if ( (i2 = l2.indexOf( "<nd ref=\"" )) >= 0 ) if ((i2 = l2.indexOf("<nd ref=\"")) >= 0) { // node reference
{ // node reference
i2 += 9; i2 += 9;
int ri2 = l2.indexOf( '"', i2 ); int ri2 = l2.indexOf('"', i2);
long nid = Long.parseLong( l2.substring( i2, ri2 ) ); long nid = Long.parseLong(l2.substring(i2, ri2));
w.nodes.add( nid ); w.nodes.add(nid);
} } else if ((i2 = l2.indexOf("<tag k=\"")) >= 0) { // property-tag
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8; i2 += 8;
int ri2 = l2.indexOf( '"', i2 ); int ri2 = l2.indexOf('"', i2);
String key = l2.substring( i2, ri2 ); String key = l2.substring(i2, ri2);
i2 = l2.indexOf( " v=\"", ri2 ); i2 = l2.indexOf(" v=\"", ri2);
if ( i2 >= 0 ) if (i2 >= 0) {
{
i2 += 4; i2 += 4;
int ri3 = l2.indexOf( '"', i2 ); int ri3 = l2.indexOf('"', i2);
String value = l2.substring( i2, ri3 ); String value = l2.substring(i2, ri3);
w.putTag( key, value ); w.putTag(key, value);
} }
} } else if (l2.indexOf("</way>") >= 0) { // end-tag
else if ( l2.indexOf( "</way>" ) >= 0 )
{ // end-tag
break; break;
} }
} }
wListener.nextWay( w ); wListener.nextWay(w);
return true; return true;
} }
private boolean checkChangeset( String line ) throws Exception private boolean checkChangeset(String line) throws Exception {
{ int idx0 = line.indexOf("<changeset id=\"");
int idx0 = line.indexOf( "<changeset id=\"" ); if (idx0 < 0) return false;
if ( idx0 < 0 ) return false;
if ( !line.endsWith( "/>" ) ) if (!line.endsWith("/>")) {
{ int loopcheck = 0;
int loopcheck = 0; for (; ; ) {
for(;;) String l2 = _br.readLine();
{ if (l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000) break;
String l2 = _br.readLine(); }
if ( l2.indexOf("</changeset>") >= 0 || ++loopcheck > 10000 ) break;
}
} }
return true; return true;
} }
private boolean checkRelation( String line ) throws Exception private boolean checkRelation(String line) throws Exception {
{ int idx0 = line.indexOf("<relation id=\"");
int idx0 = line.indexOf( "<relation id=\"" ); if (idx0 < 0) return false;
if ( idx0 < 0 ) return false;
idx0 += 14; idx0 += 14;
int idx1 = line.indexOf( '"', idx0 ); int idx1 = line.indexOf('"', idx0);
long rid = Long.parseLong( line.substring( idx0, idx1 ) ); long rid = Long.parseLong(line.substring(idx0, idx1));
RelationData r = new RelationData( rid ); RelationData r = new RelationData(rid);
// read the nodes // read the nodes
for(;;) for (; ; ) {
{
String l2 = _br.readLine(); String l2 = _br.readLine();
if ( l2 == null ) return false; if (l2 == null) return false;
int i2; int i2;
if ( (i2 = l2.indexOf( "<member type=\"way\" ref=\"" )) >= 0 ) if ((i2 = l2.indexOf("<member type=\"way\" ref=\"")) >= 0) { // node reference
{ // node reference
i2 += 24; i2 += 24;
int ri2 = l2.indexOf( '"', i2 ); int ri2 = l2.indexOf('"', i2);
long wid = Long.parseLong( l2.substring( i2, ri2 ) ); long wid = Long.parseLong(l2.substring(i2, ri2));
r.ways.add( wid ); r.ways.add(wid);
} } else if ((i2 = l2.indexOf("<tag k=\"")) >= 0) { // property-tag
else if ( (i2 = l2.indexOf( "<tag k=\"" )) >= 0 )
{ // property-tag
i2 += 8; i2 += 8;
int ri2 = l2.indexOf( '"', i2 ); int ri2 = l2.indexOf('"', i2);
String key = l2.substring( i2, ri2 ); String key = l2.substring(i2, ri2);
i2 = l2.indexOf( " v=\"", ri2 ); i2 = l2.indexOf(" v=\"", ri2);
if ( i2 >= 0 ) if (i2 >= 0) {
{
i2 += 4; i2 += 4;
int ri3 = l2.indexOf( '"', i2 ); int ri3 = l2.indexOf('"', i2);
String value = l2.substring( i2, ri3 ); String value = l2.substring(i2, ri3);
r.putTag( key, value ); r.putTag(key, value);
} }
} } else if (l2.indexOf("</relation>") >= 0) { // end-tag
else if ( l2.indexOf( "</relation>" ) >= 0 )
{ // end-tag
break; break;
} }
} }
rListener.nextRelation( r ); rListener.nextRelation(r);
return true; 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;
@ -42,14 +41,12 @@ public class OsmTrafficMap
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;
@ -57,224 +54,189 @@ public class OsmTrafficMap
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 ); map = new FrozenLongMap<OsmTrafficElement>(map);
System.out.println( "read traffic-elements: " + trafficElements ); 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

@ -14,14 +14,13 @@ 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;
@ -35,140 +34,116 @@ public class PosUnifier extends MapCreatorBase
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");
System.out.println( "*** PosUnifier: Unify position values and enhance elevation" ); if (args.length != 5) {
if ( args.length != 5 ) System.out.println("usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <srtm-data-dir>");
{
System.out.println( "usage: java PosUnifier <node-tiles-in> <node-tiles-out> <bordernids-in> <bordernodes-out> <srtm-data-dir>" );
return; return;
} }
new PosUnifier().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ), args[4] ); 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 public void process(File nodeTilesIn, File nodeTilesOut, File bordernidsinfile, File bordernodesoutfile, String srtmdir) throws Exception {
{
this.nodeTilesOut = nodeTilesOut; this.nodeTilesOut = nodeTilesOut;
this.srtmdir = srtmdir; this.srtmdir = srtmdir;
// read border nids set // read border nids set
DataInputStream dis = createInStream( bordernidsinfile ); DataInputStream dis = createInStream(bordernidsinfile);
borderNids = new CompactLongSet(); borderNids = new CompactLongSet();
try try {
{ for (; ; ) {
for ( ;; ) long nid = readId(dis);
{ if (!borderNids.contains(nid))
long nid = readId( dis ); borderNids.fastAdd(nid);
if ( !borderNids.contains( nid ) )
borderNids.fastAdd( nid );
} }
} } catch (EOFException eof) {
catch (EOFException eof)
{
dis.close(); dis.close();
} }
borderNids = new FrozenLongSet( borderNids ); borderNids = new FrozenLongSet(borderNids);
// process all files // process all files
borderNodesOut = createOutStream( bordernodesoutfile ); borderNodesOut = createOutStream(bordernodesoutfile);
new NodeIterator( this, true ).processDir( nodeTilesIn, ".n5d" ); new NodeIterator(this, true).processDir(nodeTilesIn, ".n5d");
borderNodesOut.close(); borderNodesOut.close();
} }
@Override @Override
public void nodeFileStart( File nodefile ) throws Exception public void nodeFileStart(File nodefile) throws Exception {
{
resetSrtm(); resetSrtm();
nodesOutStream = createOutStream( fileFromTemplate( nodefile, nodeTilesOut, "u5d" ) ); nodesOutStream = createOutStream(fileFromTemplate(nodefile, nodeTilesOut, "u5d"));
positionSets = new CompactLongSet[2500]; positionSets = new CompactLongSet[2500];
} }
@Override @Override
public void nextNode( NodeData n ) throws Exception public void nextNode(NodeData n) throws Exception {
{ SrtmRaster srtm = srtmForNode(n.ilon, n.ilat);
SrtmRaster srtm = srtmForNode( n.ilon, n.ilat ); n.selev = srtm == null ? Short.MIN_VALUE : srtm.getElevation(n.ilon, n.ilat);
n.selev = srtm == null ? Short.MIN_VALUE : srtm.getElevation( n.ilon, n.ilat );
findUniquePos( n ); findUniquePos(n);
n.writeTo( nodesOutStream ); n.writeTo(nodesOutStream);
if ( borderNids.contains( n.nid ) ) if (borderNids.contains(n.nid)) {
{ n.writeTo(borderNodesOut);
n.writeTo( borderNodesOut );
} }
} }
@Override @Override
public void nodeFileEnd( File nodeFile ) throws Exception public void nodeFileEnd(File nodeFile) throws Exception {
{
nodesOutStream.close(); nodesOutStream.close();
} }
private boolean checkAdd( int lon, int lat ) private boolean checkAdd(int lon, int lat) {
{ int slot = ((lon % 5000000) / 100000) * 50 + ((lat % 5000000) / 100000);
int slot = ((lon%5000000)/100000)*50 + ((lat%5000000)/100000); long id = ((long) lon) << 32 | lat;
long id = ( (long) lon ) << 32 | lat;
CompactLongSet set = positionSets[slot]; CompactLongSet set = positionSets[slot];
if ( set == null ) if (set == null) {
{
positionSets[slot] = set = new CompactLongSet(); positionSets[slot] = set = new CompactLongSet();
} }
if ( !set.contains( id ) ) if (!set.contains(id)) {
{ set.fastAdd(id);
set.fastAdd( id );
return true; return true;
} }
return false; return false;
} }
private void findUniquePos(NodeData n) {
if (!checkAdd(n.ilon, n.ilat)) {
private void findUniquePos( NodeData n ) _findUniquePos(n);
{
if ( !checkAdd( n.ilon, n.ilat ) )
{
_findUniquePos( n );
} }
} }
private void _findUniquePos( NodeData n ) private void _findUniquePos(NodeData n) {
{
// fix the position for uniqueness // fix the position for uniqueness
int lonmod = n.ilon % 1000000; int lonmod = n.ilon % 1000000;
int londelta = lonmod < 500000 ? 1 : -1; int londelta = lonmod < 500000 ? 1 : -1;
int latmod = n.ilat % 1000000; int latmod = n.ilat % 1000000;
int latdelta = latmod < 500000 ? 1 : -1; int latdelta = latmod < 500000 ? 1 : -1;
for ( int latsteps = 0; latsteps < 100; latsteps++ ) for (int latsteps = 0; latsteps < 100; latsteps++) {
{ for (int lonsteps = 0; lonsteps <= latsteps; lonsteps++) {
for ( int lonsteps = 0; lonsteps <= latsteps; lonsteps++ )
{
int lon = n.ilon + lonsteps * londelta; int lon = n.ilon + lonsteps * londelta;
int lat = n.ilat + latsteps * latdelta; int lat = n.ilat + latsteps * latdelta;
if ( checkAdd( lon, lat ) ) if (checkAdd(lon, lat)) {
{
n.ilon = lon; n.ilon = lon;
n.ilat = lat; n.ilat = lat;
return; return;
} }
} }
} }
System.out.println( "*** WARNING: cannot unify position for: " + n.ilon + " " + n.ilat ); System.out.println("*** WARNING: cannot unify position for: " + n.ilon + " " + n.ilat);
} }
/** /**
* get the srtm data set for a position srtm coords are * get the srtm data set for a position srtm coords are
* srtm_<srtmLon>_<srtmLat> where srtmLon = 180 + lon, srtmLat = 60 - lat * srtm_<srtmLon>_<srtmLat> where srtmLon = 180 + lon, srtmLat = 60 - lat
*/ */
private SrtmRaster srtmForNode( int ilon, int ilat ) throws Exception private SrtmRaster srtmForNode(int ilon, int ilat) throws Exception {
{ int srtmLonIdx = (ilon + 5000000) / 5000000;
int srtmLonIdx = ( ilon + 5000000 ) / 5000000; int srtmLatIdx = (654999999 - ilat) / 5000000 - 100; // ugly negative rounding...
int srtmLatIdx = ( 654999999 - ilat ) / 5000000 - 100; // ugly negative rounding...
if ( srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx ) if (srtmLonIdx == lastSrtmLonIdx && srtmLatIdx == lastSrtmLatIdx) {
{
return lastSrtmRaster; return lastSrtmRaster;
} }
lastSrtmLonIdx = srtmLonIdx; lastSrtmLonIdx = srtmLonIdx;
@ -176,50 +151,40 @@ public class PosUnifier extends MapCreatorBase
String slonidx = "0" + srtmLonIdx; String slonidx = "0" + srtmLonIdx;
String slatidx = "0" + srtmLatIdx; String slatidx = "0" + srtmLatIdx;
String filename = "srtm_" + slonidx.substring( slonidx.length()-2 ) + "_" + slatidx.substring( slatidx.length()-2 ); String filename = "srtm_" + slonidx.substring(slonidx.length() - 2) + "_" + slatidx.substring(slatidx.length() - 2);
lastSrtmRaster = srtmmap.get( filename ); lastSrtmRaster = srtmmap.get(filename);
if ( lastSrtmRaster == null && !srtmmap.containsKey( filename ) ) if (lastSrtmRaster == null && !srtmmap.containsKey(filename)) {
{ File f = new File(new File(srtmdir), filename + ".bef");
File f = new File( new File( srtmdir ), filename + ".bef" ); System.out.println("checking: " + f + " ilon=" + ilon + " ilat=" + ilat);
System.out.println( "checking: " + f + " ilon=" + ilon + " ilat=" + ilat ); if (f.exists()) {
if ( f.exists() ) System.out.println("*** reading: " + f);
{ try {
System.out.println( "*** reading: " + f ); InputStream isc = new BufferedInputStream(new FileInputStream(f));
try lastSrtmRaster = new RasterCoder().decodeRaster(isc);
{
InputStream isc = new BufferedInputStream( new FileInputStream( f ) );
lastSrtmRaster = new RasterCoder().decodeRaster( isc );
isc.close(); isc.close();
} catch (Exception e) {
System.out.println("**** ERROR reading " + f + " ****");
} }
catch (Exception e) srtmmap.put(filename, lastSrtmRaster);
{
System.out.println( "**** ERROR reading " + f + " ****" );
}
srtmmap.put( filename, lastSrtmRaster );
return lastSrtmRaster; return lastSrtmRaster;
} }
f = new File( new File( srtmdir ), filename + ".zip" ); f = new File(new File(srtmdir), filename + ".zip");
System.out.println( "reading: " + f + " ilon=" + ilon + " ilat=" + ilat ); System.out.println("reading: " + f + " ilon=" + ilon + " ilat=" + ilat);
if ( f.exists() ) if (f.exists()) {
{ try {
try lastSrtmRaster = new SrtmData(f).getRaster();
{ } catch (Exception e) {
lastSrtmRaster = new SrtmData( f ).getRaster(); System.out.println("**** ERROR reading " + f + " ****");
}
catch (Exception e)
{
System.out.println( "**** ERROR reading " + f + " ****" );
} }
} }
srtmmap.put( filename, lastSrtmRaster ); srtmmap.put(filename, lastSrtmRaster);
} }
return lastSrtmRaster; return lastSrtmRaster;
} }
private void resetSrtm() private void resetSrtm() {
{
srtmmap = new HashMap<String, SrtmRaster>(); srtmmap = new HashMap<String, SrtmRaster>();
lastSrtmLonIdx = -1; lastSrtmLonIdx = -1;
lastSrtmLatIdx = -1; lastSrtmLatIdx = -1;

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();
@ -50,74 +48,61 @@ public class RasterCoder
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

@ -7,20 +7,17 @@ import btools.util.LongList;
* *
* @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; rid = id;
ways = new LongList( 16 ); ways = new LongList(16);
} }
public RelationData( long id, LongList ways ) public RelationData(long id, LongList ways) {
{
rid = id; rid = id;
this.ways = ways; this.ways = ways;
} }

View File

@ -6,9 +6,8 @@ package btools.mapcreator;
* *
* @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 (; ; ) {
for(;;) long rid = readId(dis);
{
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;
@ -36,119 +35,93 @@ public class RestrictionData extends MapCreatorBase
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() public boolean isPositive() {
{ return restriction.startsWith("only_");
return restriction.startsWith( "only_" );
} }
public boolean isValid() public boolean isValid() {
{ boolean valid = fromLon != 0 && toLon != 0 && (restriction.startsWith("only_") || restriction.startsWith("no_"));
boolean valid = fromLon != 0 && toLon != 0 && ( restriction.startsWith( "only_" ) || restriction.startsWith( "no_" ) ); if ((!valid) || badWayMatch || !(checkGeometry())) {
if ( (!valid) || badWayMatch || !(checkGeometry()) ) synchronized (badTRs) {
{ 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

@ -2,7 +2,7 @@ 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
@ -23,104 +23,82 @@ 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 ) ) ); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
try try {
{ for (; ; ) {
for ( ;; )
{
ZipEntry ze = zis.getNextEntry(); ZipEntry ze = zis.getNextEntry();
if ( ze.getName().endsWith( ".asc" ) ) if (ze.getName().endsWith(".asc")) {
{ readFromStream(zis);
readFromStream( zis );
return; return;
} }
} }
} } finally {
finally
{
zis.close(); zis.close();
} }
} }
public SrtmRaster getRaster() public SrtmRaster getRaster() {
{
return raster; return raster;
} }
private String secondToken( String s ) private String secondToken(String s) {
{ StringTokenizer tk = new StringTokenizer(s, " ");
StringTokenizer tk = new StringTokenizer( s, " " );
tk.nextToken(); tk.nextToken();
return tk.nextToken(); return tk.nextToken();
} }
public void readFromStream( InputStream is ) throws Exception public void readFromStream(InputStream is) throws Exception {
{ BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedReader br = new BufferedReader( new InputStreamReader( is ) );
int linenr = 0; int linenr = 0;
for ( ;; ) for (; ; ) {
{
linenr++; linenr++;
if ( linenr <= 6 ) if (linenr <= 6) {
{
String line = br.readLine(); String line = br.readLine();
if ( linenr == 1 ) if (linenr == 1)
raster.ncols = Integer.parseInt( secondToken( line ) ); raster.ncols = Integer.parseInt(secondToken(line));
else if ( linenr == 2 ) else if (linenr == 2)
raster.nrows = Integer.parseInt( secondToken( line ) ); raster.nrows = Integer.parseInt(secondToken(line));
else if ( linenr == 3 ) else if (linenr == 3)
raster.xllcorner = Double.parseDouble( secondToken( line ) ); raster.xllcorner = Double.parseDouble(secondToken(line));
else if ( linenr == 4 ) else if (linenr == 4)
raster.yllcorner = Double.parseDouble( secondToken( line ) ); raster.yllcorner = Double.parseDouble(secondToken(line));
else if ( linenr == 5 ) else if (linenr == 5)
raster.cellsize = Double.parseDouble( secondToken( line ) ); raster.cellsize = Double.parseDouble(secondToken(line));
else if ( linenr == 6 ) else if (linenr == 6) {
{
// nodata ignored here ( < -250 assumed nodata... ) // nodata ignored here ( < -250 assumed nodata... )
// raster.noDataValue = Short.parseShort( secondToken( line ) ); // raster.noDataValue = Short.parseShort( secondToken( line ) );
raster.eval_array = new short[raster.ncols * raster.nrows]; raster.eval_array = new short[raster.ncols * raster.nrows];
} }
} } else {
else
{
int row = 0; int row = 0;
int col = 0; int col = 0;
int n = 0; int n = 0;
boolean negative = false; boolean negative = false;
for ( ;; ) for (; ; ) {
{
int c = br.read(); int c = br.read();
if ( c < 0 ) if (c < 0)
break; break;
if ( c == ' ' ) if (c == ' ') {
{ if (negative)
if ( negative )
n = -n; n = -n;
short val = n < -250 ? Short.MIN_VALUE : (short) (n); short val = n < -250 ? Short.MIN_VALUE : (short) (n);
raster.eval_array[row * raster.ncols + col] = val; raster.eval_array[row * raster.ncols + col] = val;
if ( ++col == raster.ncols ) if (++col == raster.ncols) {
{
col = 0; col = 0;
++row; ++row;
} }
n = 0; n = 0;
negative = false; negative = false;
} } else if (c >= '0' && c <= '9') {
else if ( c >= '0' && c <= '9' ) n = 10 * n + (c - '0');
{ } else if (c == '-') {
n = 10 * n + ( c - '0' );
}
else if ( c == '-' )
{
negative = true; negative = true;
} }
} }
@ -130,63 +108,56 @@ public class SrtmData
br.close(); br.close();
} }
public static void main( String[] args ) throws Exception public static void main(String[] args) throws Exception {
{
String fromDir = args[0]; String fromDir = args[0];
String toDir = args[1]; String toDir = args[1];
File[] files = new File( fromDir ).listFiles(); File[] files = new File(fromDir).listFiles();
for( File f : files ) for (File f : files) {
{ if (!f.getName().endsWith(".zip")) {
if ( !f.getName().endsWith( ".zip" ) )
{
continue; continue;
} }
System.out.println( "*** reading: " + f ); System.out.println("*** reading: " + f);
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
SrtmRaster raster = new SrtmData( f ).getRaster(); SrtmRaster raster = new SrtmData(f).getRaster();
long t1 = System.currentTimeMillis(); long t1 = System.currentTimeMillis();
String name = f.getName(); String name = f.getName();
long zipTime = t1-t0; long zipTime = t1 - t0;
File fbef = new File( new File( toDir ), name.substring( 0, name.length()-3 ) + "bef" ); File fbef = new File(new File(toDir), name.substring(0, name.length() - 3) + "bef");
System.out.println( "recoding: " + f + " to " + fbef ); System.out.println("recoding: " + f + " to " + fbef);
OutputStream osbef = new BufferedOutputStream( new FileOutputStream( fbef ) ); OutputStream osbef = new BufferedOutputStream(new FileOutputStream(fbef));
new RasterCoder().encodeRaster( raster, osbef ); new RasterCoder().encodeRaster(raster, osbef);
osbef.close(); osbef.close();
System.out.println( "*** re-reading: " + fbef ); System.out.println("*** re-reading: " + fbef);
long t2 = System.currentTimeMillis(); long t2 = System.currentTimeMillis();
InputStream isc = new BufferedInputStream( new FileInputStream( fbef ) ); InputStream isc = new BufferedInputStream(new FileInputStream(fbef));
SrtmRaster raster2 = new RasterCoder().decodeRaster( isc ); SrtmRaster raster2 = new RasterCoder().decodeRaster(isc);
isc.close(); isc.close();
long t3 = System.currentTimeMillis(); long t3 = System.currentTimeMillis();
long befTime = t3-t2; long befTime = t3 - t2;
System.out.println( "*** zip-time: " + zipTime + "*** bef-time: " + befTime ); System.out.println("*** zip-time: " + zipTime + "*** bef-time: " + befTime);
String s1 = raster.toString(); String s1 = raster.toString();
String s2 = raster2.toString(); String s2 = raster2.toString();
if ( !s1.equals( s2 ) ) if (!s1.equals(s2)) {
{ throw new IllegalArgumentException("missmatch: " + s1 + "<--->" + s2);
throw new IllegalArgumentException( "missmatch: " + s1 + "<--->" + s2 );
} }
int cols = raster.ncols; int cols = raster.ncols;
int rows = raster.nrows; int rows = raster.nrows;
for( int c = 0; c < cols; c++ ) for (int c = 0; c < cols; c++) {
{ for (int r = 0; r < rows; r++) {
for( int r = 0; r < rows; r++ )
{
int idx = r * cols + c; int idx = r * cols + c;
if ( raster.eval_array[idx] != raster2.eval_array[idx] ) if (raster.eval_array[idx] != raster2.eval_array[idx]) {
{ throw new IllegalArgumentException("missmatch: at " + c + "," + r + ": " + 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

@ -7,103 +7,89 @@ 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"); System.out.println("*** WayCutter: Soft-Cut way-data into tiles");
if (args.length != 3) if (args.length != 3) {
{ System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out>");
System.out.println("usage: java WayCutter <node-tiles-in> <way-file-in> <way-tiles-out>" );
return; return;
} }
new WayCutter().process( new File( args[0] ), new File( args[1] ), new File( args[2] ) ); 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 public void process(File nodeTilesIn, File wayFileIn, File wayTilesOut) throws Exception {
{ init(wayTilesOut);
init( wayTilesOut );
new NodeIterator( this, false ).processDir( nodeTilesIn, ".tlf" ); new NodeIterator(this, false).processDir(nodeTilesIn, ".tlf");
// *** finally process the way-file, cutting into pieces // *** finally process the way-file, cutting into pieces
new WayIterator( this, true ).processFile( wayFileIn ); new WayIterator(this, true).processFile(wayFileIn);
finish(); finish();
} }
public void init( File wayTilesOut ) throws Exception public void init(File wayTilesOut) throws Exception {
{
this.outTileDir = wayTilesOut; this.outTileDir = wayTilesOut;
// *** read all nodes into tileIndexMap // *** read all nodes into tileIndexMap
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap(); tileIndexMap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap() : new TinyDenseLongMap();
} }
public void finish() throws Exception public void finish() throws Exception {
{
closeTileOutStreams(); closeTileOutStreams();
} }
@Override @Override
public void nextNode( NodeData n ) throws Exception public void nextNode(NodeData n) throws Exception {
{ tileIndexMap.put(n.nid, getTileIndex(n.ilon, n.ilat));
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) );
} }
@Override @Override
public void nextWay( WayData data ) throws Exception public void nextWay(WayData data) throws Exception {
{
long waytileset = 0; long waytileset = 0;
int nnodes = data.nodes.size(); int nnodes = data.nodes.size();
// determine the tile-index for each node // determine the tile-index for each node
for (int i=0; i<nnodes; i++ ) for (int i = 0; i < nnodes; i++) {
{ int tileIndex = tileIndexMap.getInt(data.nodes.get(i));
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) ); if (tileIndex != -1) {
if ( tileIndex != -1 ) waytileset |= (1L << tileIndex);
{
waytileset |= ( 1L << tileIndex );
} }
} }
// now write way to all tiles hit // now write way to all tiles hit
for( int tileIndex=0; tileIndex<54; tileIndex++ ) for (int tileIndex = 0; tileIndex < 54; tileIndex++) {
{ if ((waytileset & (1L << tileIndex)) == 0) {
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{
continue; continue;
} }
data.writeTo( getOutStreamForTile( tileIndex ) ); data.writeTo(getOutStreamForTile(tileIndex));
} }
} }
public int getTileIndexForNid( long nid ) public int getTileIndexForNid(long nid) {
{ return tileIndexMap.getInt(nid);
return tileIndexMap.getInt( nid );
} }
private int getTileIndex( int ilon, int ilat ) private int getTileIndex(int ilon, int ilat) {
{ int lon = ilon / 45000000;
int lon = ilon / 45000000; int lat = ilat / 30000000;
int lat = ilat / 30000000; if (lon < 0 || lon > 7 || lat < 0 || lat > 5)
if ( lon < 0 || lon > 7 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat ); throw new IllegalArgumentException("illegal pos: " + ilon + "," + ilat);
return lon*6 + lat; return lon * 6 + lat;
} }
public String getNameForTile( int tileIndex ) public String getNameForTile(int tileIndex) {
{ int lon = (tileIndex / 6) * 45 - 180;
int lon = (tileIndex / 6 ) * 45 - 180; int lat = (tileIndex % 6) * 30 - 90;
int lat = (tileIndex % 6 ) * 30 - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon; String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat; String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".wtl"; return slon + "_" + slat + ".wtl";

View File

@ -12,14 +12,13 @@ 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;
@ -31,180 +30,151 @@ public class WayCutter5 extends MapCreatorBase
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"); System.out.println("*** WayCutter5: Soft-Cut way-data into tiles");
if (args.length != 4) if (args.length != 4) {
{ System.out.println("usage: java WayCutter5 <node-tiles-in> <way-tiles-in> <way-tiles-out> <border-nids-out>");
System.out.println("usage: java WayCutter5 <node-tiles-in> <way-tiles-in> <way-tiles-out> <border-nids-out>" );
return; return;
} }
new WayCutter5().process( new File( args[0] ), new File( args[1] ), new File( args[2] ), new File( args[3] ) ); 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 public void process(File nodeTilesIn, File wayTilesIn, File wayTilesOut, File borderNidsOut) throws Exception {
{
this.nodeTilesIn = nodeTilesIn; this.nodeTilesIn = nodeTilesIn;
this.outTileDir = wayTilesOut; this.outTileDir = wayTilesOut;
borderNidsOutStream = createOutStream( borderNidsOut ); borderNidsOutStream = createOutStream(borderNidsOut);
new WayIterator( this, true ).processDir( wayTilesIn, ".wtl" ); new WayIterator(this, true).processDir(wayTilesIn, ".wtl");
borderNidsOutStream.close(); borderNidsOutStream.close();
} }
@Override @Override
public boolean wayFileStart( File wayfile ) throws Exception public boolean wayFileStart(File wayfile) throws Exception {
{
// read corresponding node-file into tileIndexMap // read corresponding node-file into tileIndexMap
String name = wayfile.getName(); String name = wayfile.getName();
String nodefilename = name.substring( 0, name.length()-3 ) + "ntl"; String nodefilename = name.substring(0, name.length() - 3) + "ntl";
File nodefile = new File( nodeTilesIn, nodefilename ); File nodefile = new File(nodeTilesIn, nodefilename);
tileIndexMap = Boolean.getBoolean( "useDenseMaps" ) ? new DenseLongMap() : new TinyDenseLongMap(); tileIndexMap = Boolean.getBoolean("useDenseMaps") ? new DenseLongMap() : new TinyDenseLongMap();
lonoffset = -1; lonoffset = -1;
latoffset = -1; latoffset = -1;
if ( nodeCutter != null ) if (nodeCutter != null) {
{ nodeCutter.nodeFileStart(null);
nodeCutter.nodeFileStart( null );
} }
new NodeIterator( this, nodeCutter != null ).processFile( nodefile ); new NodeIterator(this, nodeCutter != null).processFile(nodefile);
if ( restrictionCutter5 != null ) if (restrictionCutter5 != null) {
{ String resfilename = name.substring(0, name.length() - 3) + "rtl";
String resfilename = name.substring( 0, name.length()-3 ) + "rtl"; File resfile = new File("restrictions", resfilename);
File resfile = new File( "restrictions", resfilename );
if ( resfile.exists() ) if (resfile.exists()) {
{
// read restrictions for nodes in nodesMap // read restrictions for nodes in nodesMap
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( resfile ) ) ); DataInputStream di = new DataInputStream(new BufferedInputStream(new FileInputStream(resfile)));
int ntr = 0; int ntr = 0;
try try {
{ for (; ; ) {
for(;;) RestrictionData res = new RestrictionData(di);
{ restrictionCutter5.nextRestriction(res);
RestrictionData res = new RestrictionData( di );
restrictionCutter5.nextRestriction( res );
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");
} }
} }
return true; return true;
} }
@Override @Override
public void nextNode( NodeData n ) throws Exception public void nextNode(NodeData n) throws Exception {
{ if (nodeFilter != null) {
if ( nodeFilter != null ) if (!nodeFilter.isRelevant(n)) {
{
if ( !nodeFilter.isRelevant( n ) )
{
return; return;
} }
} }
if ( nodeCutter != null ) if (nodeCutter != null) {
{ nodeCutter.nextNode(n);
nodeCutter.nextNode( n );
} }
tileIndexMap.put( n.nid, getTileIndex( n.ilon, n.ilat ) ); tileIndexMap.put(n.nid, getTileIndex(n.ilon, n.ilat));
} }
@Override @Override
public void nextWay( WayData data ) throws Exception public void nextWay(WayData data) throws Exception {
{
long waytileset = 0; long waytileset = 0;
int nnodes = data.nodes.size(); int nnodes = data.nodes.size();
int[] tiForNode = new int[nnodes]; int[] tiForNode = new int[nnodes];
// determine the tile-index for each node // determine the tile-index for each node
for (int i=0; i<nnodes; i++ ) for (int i = 0; i < nnodes; i++) {
{ int tileIndex = tileIndexMap.getInt(data.nodes.get(i));
int tileIndex = tileIndexMap.getInt( data.nodes.get(i) ); if (tileIndex != -1) {
if ( tileIndex != -1 ) waytileset |= (1L << tileIndex);
{
waytileset |= ( 1L << tileIndex );
} }
tiForNode[i] = tileIndex; tiForNode[i] = tileIndex;
} }
if ( relMerger != null ) if (relMerger != null) {
{ relMerger.nextWay(data);
relMerger.nextWay( data );
} }
// now write way to all tiles hit // now write way to all tiles hit
for( int tileIndex=0; tileIndex<54; tileIndex++ ) for (int tileIndex = 0; tileIndex < 54; tileIndex++) {
{ if ((waytileset & (1L << tileIndex)) == 0) {
if ( ( waytileset & ( 1L << tileIndex ) ) == 0 )
{
continue; continue;
} }
data.writeTo( getOutStreamForTile( tileIndex ) ); data.writeTo(getOutStreamForTile(tileIndex));
} }
// and write edge nodes to the border-nid file // and write edge nodes to the border-nid file
for( int i=0; i < nnodes; i++ ) for (int i = 0; i < nnodes; i++) {
{
int ti = tiForNode[i]; int ti = tiForNode[i];
if ( ti != -1 ) if (ti != -1) {
{ if ((i > 0 && tiForNode[i - 1] != ti) || (i + 1 < nnodes && tiForNode[i + 1] != ti)) {
if ( ( i > 0 && tiForNode[i-1] != ti ) || (i+1 < nnodes && tiForNode[i+1] != ti ) ) writeId(borderNidsOutStream, data.nodes.get(i));
{
writeId( borderNidsOutStream, data.nodes.get(i) );
} }
} }
} }
} }
@Override @Override
public void wayFileEnd( File wayFile ) throws Exception public void wayFileEnd(File wayFile) throws Exception {
{
closeTileOutStreams(); closeTileOutStreams();
if ( nodeCutter != null ) if (nodeCutter != null) {
{ nodeCutter.nodeFileEnd(null);
nodeCutter.nodeFileEnd( null );
} }
if ( restrictionCutter5 != null ) if (restrictionCutter5 != null) {
{
restrictionCutter5.finish(); restrictionCutter5.finish();
} }
} }
public int getTileIndexForNid( long nid ) public int getTileIndexForNid(long nid) {
{ return tileIndexMap.getInt(nid);
return tileIndexMap.getInt( nid );
} }
private int getTileIndex( int ilon, int ilat ) private int getTileIndex(int ilon, int ilat) {
{ int lonoff = (ilon / 45000000) * 45;
int lonoff = (ilon / 45000000 ) * 45; int latoff = (ilat / 30000000) * 30;
int latoff = (ilat / 30000000 ) * 30; if (lonoffset == -1) lonoffset = lonoff;
if ( lonoffset == -1 ) lonoffset = lonoff; if (latoffset == -1) latoffset = latoff;
if ( latoffset == -1 ) latoffset = latoff; if (lonoff != lonoffset || latoff != latoffset)
if ( lonoff != lonoffset || latoff != latoffset ) throw new IllegalArgumentException("inconsistent node: " + ilon + " " + ilat);
throw new IllegalArgumentException( "inconsistent node: " + ilon + " " + ilat );
int lon = (ilon / 5000000) % 9; int lon = (ilon / 5000000) % 9;
int lat = (ilat / 5000000) % 6; int lat = (ilat / 5000000) % 6;
if ( lon < 0 || lon > 8 || lat < 0 || lat > 5 ) throw new IllegalArgumentException( "illegal pos: " + ilon + "," + ilat ); if (lon < 0 || lon > 8 || lat < 0 || lat > 5)
return lon*6 + lat; throw new IllegalArgumentException("illegal pos: " + ilon + "," + ilat);
return lon * 6 + lat;
} }
protected String getNameForTile( int tileIndex ) protected String getNameForTile(int tileIndex) {
{ int lon = (tileIndex / 6) * 5 + lonoffset - 180;
int lon = (tileIndex / 6 ) * 5 + lonoffset - 180; int lat = (tileIndex % 6) * 5 + latoffset - 90;
int lat = (tileIndex % 6 ) * 5 + latoffset - 90;
String slon = lon < 0 ? "W" + (-lon) : "E" + lon; String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
String slat = lat < 0 ? "S" + (-lat) : "N" + lat; String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
return slon + "_" + slat + ".wt5"; return slon + "_" + slat + ".wt5";

View File

@ -10,46 +10,42 @@ import btools.util.LongList;
* *
* @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; wid = id;
nodes = new LongList( 16 ); nodes = new LongList(16);
} }
public WayData( long id, LongList nodes ) public WayData(long id, LongList nodes) {
{
wid = id; wid = id;
this.nodes = nodes; this.nodes = nodes;
} }
public WayData( DataInputStream di ) throws Exception public WayData(DataInputStream di) throws Exception {
{ nodes = new LongList(16);
nodes = new LongList( 16 ); wid = readId(di);
wid = readId( di) ; int dlen = di.readByte();
int dlen = di.readByte(); description = new byte[dlen]; di.readFully( description ); description = new byte[dlen];
for (;;) di.readFully(description);
{ for (; ; ) {
long nid = readId( di ); long nid = readId(di);
if ( nid == -1 ) break; if (nid == -1) break;
nodes.add( nid ); nodes.add(nid);
} }
} }
public void writeTo( DataOutputStream dos ) throws Exception public void writeTo(DataOutputStream dos) throws Exception {
{ writeId(dos, wid);
writeId( dos, wid ); dos.writeByte(description.length);
dos.writeByte( description.length ); dos.write( description ); dos.write(description);
int size = nodes.size(); int size = nodes.size();
for( int i=0; i < size; i++ ) for (int i = 0; i < size; i++) {
{ writeId(dos, nodes.get(i));
writeId( dos, nodes.get( i ) );
} }
writeId( dos, -1 ); // stopbyte writeId(dos, -1); // stopbyte
} }
} }

View File

@ -12,68 +12,54 @@ import java.io.FileInputStream;
* *
* @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; listener = wayListener;
delete = deleteAfterReading; delete = deleteAfterReading;
} }
public WayIterator( WayListener wayListener, boolean deleteAfterReading, boolean descendingSize ) public WayIterator(WayListener wayListener, boolean deleteAfterReading, boolean descendingSize) {
{ this(wayListener, deleteAfterReading);
this( wayListener, deleteAfterReading );
this.descendingSize = descendingSize; this.descendingSize = descendingSize;
} }
public void processDir( File indir, String inSuffix ) throws Exception public void processDir(File indir, String inSuffix) throws Exception {
{ if (!indir.isDirectory()) {
if ( !indir.isDirectory() ) throw new IllegalArgumentException("not a directory: " + indir);
{
throw new IllegalArgumentException( "not a directory: " + indir );
} }
File[] af = sortBySizeAsc( indir.listFiles() ); File[] af = sortBySizeAsc(indir.listFiles());
for( int i=0; i<af.length; i++ ) for (int i = 0; i < af.length; i++) {
{ File wayfile = descendingSize ? af[af.length - 1 - i] : af[i];
File wayfile = descendingSize ? af[af.length -1 - i] : af[i]; if (wayfile.getName().endsWith(inSuffix)) {
if ( wayfile.getName().endsWith( inSuffix ) ) processFile(wayfile);
{
processFile( wayfile );
} }
} }
} }
public void processFile(File wayfile) throws Exception public void processFile(File wayfile) throws Exception {
{ System.out.println("*** WayIterator reading: " + wayfile);
System.out.println( "*** WayIterator reading: " + wayfile );
if ( !listener.wayFileStart( wayfile ) ) if (!listener.wayFileStart(wayfile)) {
{
return; return;
} }
DataInputStream di = new DataInputStream( new BufferedInputStream ( new FileInputStream( wayfile ) ) ); DataInputStream di = new DataInputStream(new BufferedInputStream(new FileInputStream(wayfile)));
try try {
{ for (; ; ) {
for(;;) WayData w = new WayData(di);
{ listener.nextWay(w);
WayData w = new WayData( di );
listener.nextWay( w );
} }
} } catch (EOFException eof) {
catch( EOFException eof )
{
di.close(); di.close();
} }
listener.wayFileEnd( wayfile ); listener.wayFileEnd(wayfile);
if ( delete && "true".equals( System.getProperty( "deletetmpfiles" ) )) if (delete && "true".equals(System.getProperty("deletetmpfiles"))) {
{
wayfile.delete(); 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,46 +69,36 @@ 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;
@ -117,35 +106,30 @@ public class WayLinker extends MapCreatorBase implements Runnable
} }
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( 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] ); args[6]), args[7]);
System.out.println( "dumping bad TRs" ); 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;
@ -155,23 +139,22 @@ public class WayLinker extends MapCreatorBase implements Runnable
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,47 +163,39 @@ 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
@ -228,66 +203,52 @@ public class WayLinker extends MapCreatorBase implements Runnable
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; return false;
} }
} } else {
else if (!tc.setCurrentMasterSize(filesize)) {
{
if ( !tc.setCurrentMasterSize( filesize ) )
{
return false; return false;
} }
} }
File trafficFile = fileFromTemplate(wayfile, trafficTilesIn, "trf");
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;
} }
} }
@ -395,55 +341,49 @@ public class WayLinker extends MapCreatorBase implements Runnable
} }
} }
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

@ -7,11 +7,10 @@ import java.io.File;
* *
* @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

@ -5,50 +5,49 @@ 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.net.URL;
import java.io.File; 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,57 +14,51 @@ 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;
@ -72,55 +66,48 @@ public final class DirectWeaver extends ByteDataWriter
// 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,8 +11,7 @@ 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;
@ -22,37 +21,35 @@ public final class MatchedWaypoint
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;
@ -49,154 +48,122 @@ public final class NodesCache
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 );
} }
} }
@ -241,57 +200,47 @@ public final class NodesCache
* *
* @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

@ -6,8 +6,7 @@
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

@ -6,15 +6,13 @@
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;
@ -30,12 +28,10 @@ public class OsmLink
private OsmLinkHolder reverselinkholder = null; private OsmLinkHolder reverselinkholder = null;
private OsmLinkHolder firstlinkholder = null; private OsmLinkHolder firstlinkholder = null;
protected OsmLink() protected OsmLink() {
{
} }
public OsmLink( OsmNode source, OsmNode target ) public OsmLink(OsmNode source, OsmNode target) {
{
n1 = source; n1 = source;
n2 = target; n2 = target;
} }
@ -43,8 +39,7 @@ public class OsmLink
/** /**
* Get the relevant target-node for the given source * Get the relevant target-node for the given source
*/ */
public final OsmNode getTarget( OsmNode source ) public final OsmNode getTarget(OsmNode source) {
{
return n2 != source && n2 != null ? n2 : n1; return n2 != source && n2 != null ? n2 : n1;
/* if ( n2 != null && n2 != source ) /* if ( n2 != null && n2 != source )
{ {
@ -64,8 +59,7 @@ public class OsmLink
/** /**
* Get the relevant next-pointer for the given source * Get the relevant next-pointer for the given source
*/ */
public final OsmLink getNext( OsmNode source ) public final OsmLink getNext(OsmNode source) {
{
return n2 != source && n2 != null ? next : previous; return n2 != source && n2 != null ? next : previous;
/* if ( n2 != null && n2 != source ) /* if ( n2 != null && n2 != source )
{ {
@ -84,69 +78,49 @@ public class OsmLink
/** /**
* Reset this link for the given direction * Reset this link for the given direction
*/ */
protected final OsmLink clear( OsmNode source ) protected final OsmLink clear(OsmNode source) {
{
OsmLink n; OsmLink n;
if ( n2 != null && n2 != source ) if (n2 != null && n2 != source) {
{ n = next;
n = next; next = null;
next = null; n2 = null;
n2 = null; firstlinkholder = null;
firstlinkholder = null; } else if (n1 != null && n1 != source) {
}
else if ( n1 != null && n1 != source )
{
n = previous; n = previous;
previous = null; previous = null;
n1 = null; n1 = null;
reverselinkholder = null; reverselinkholder = null;
} else {
throw new IllegalArgumentException("internal error: setNext: unknown source");
} }
else if (n1 == null && n2 == null) {
{
throw new IllegalArgumentException( "internal error: setNext: unknown source" );
}
if ( n1 == null && n2 == null )
{
descriptionBitmap = null; descriptionBitmap = null;
geometry = null; geometry = null;
} }
return n; return n;
} }
public final void setFirstLinkHolder( OsmLinkHolder holder, OsmNode source ) public final void setFirstLinkHolder(OsmLinkHolder holder, OsmNode source) {
{ if (n2 != null && n2 != source) {
if ( n2 != null && n2 != source ) firstlinkholder = holder;
{ } else if (n1 != null && n1 != source) {
firstlinkholder = holder; reverselinkholder = holder;
} } else {
else if ( n1 != null && n1 != source ) throw new IllegalArgumentException("internal error: setFirstLinkHolder: unknown source");
{ }
reverselinkholder = holder;
}
else
{
throw new IllegalArgumentException( "internal error: setFirstLinkHolder: unknown source" );
}
} }
public final OsmLinkHolder getFirstLinkHolder( OsmNode source ) public final OsmLinkHolder getFirstLinkHolder(OsmNode source) {
{ if (n2 != null && n2 != source) {
if ( n2 != null && n2 != source )
{
return firstlinkholder; return firstlinkholder;
} } else if (n1 != null && n1 != source) {
else if ( n1 != null && n1 != source )
{
return reverselinkholder; return reverselinkholder;
} } else {
else throw new IllegalArgumentException("internal error: getFirstLinkHolder: unknown source");
{
throw new IllegalArgumentException( "internal error: getFirstLinkHolder: unknown source" );
} }
} }
public final boolean isReverse( OsmNode source ) public final boolean isReverse(OsmNode source) {
{
return n1 != source && n1 != null; return n1 != source && n1 != null;
/* if ( n2 != null && n2 != source ) /* if ( n2 != null && n2 != source )
{ {
@ -162,21 +136,20 @@ public class OsmLink
} */ } */
} }
public final boolean isBidirectional() public final boolean isBidirectional() {
{
return n1 != null && n2 != null; return n1 != null && n2 != null;
} }
public final boolean isLinkUnused() public final boolean isLinkUnused() {
{
return n1 == null && n2 == null; return n1 == null && n2 == null;
} }
public final void addLinkHolder( OsmLinkHolder holder, OsmNode source ) public final void addLinkHolder(OsmLinkHolder holder, OsmNode source) {
{ OsmLinkHolder firstHolder = getFirstLinkHolder(source);
OsmLinkHolder firstHolder = getFirstLinkHolder( source ); if (firstHolder != null) {
if ( firstHolder != null ) { holder.setNextForLink( firstHolder ); } holder.setNextForLink(firstHolder);
setFirstLinkHolder( holder, source ); }
setFirstLinkHolder(holder, source);
} }
} }

View File

@ -5,9 +5,8 @@
*/ */
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
*/ */
@ -37,8 +36,7 @@ public class OsmNode extends OsmLink implements OsmPos
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,145 +99,121 @@ 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;
@ -259,56 +221,45 @@ public class OsmNode extends OsmLink implements OsmPos
} }
} }
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

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

View File

@ -6,8 +6,7 @@
package btools.mapaccess; package btools.mapaccess;
public interface OsmPos public interface OsmPos {
{
public int getILat(); public int getILat();
public int getILon(); public int getILon();
@ -16,7 +15,7 @@ public interface OsmPos
public double getElev(); public double getElev();
public int calcDistance( OsmPos p ); public int calcDistance(OsmPos p);
public long getIdFromPos(); public long getIdFromPos();

View File

@ -6,10 +6,7 @@
package btools.mapaccess; package btools.mapaccess;
public final class OsmTransferNode {
public final class OsmTransferNode
{
public OsmTransferNode next; public OsmTransferNode next;
public int ilon; public int ilon;

View File

@ -14,8 +14,7 @@ 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;
@ -27,16 +26,15 @@ final public class PhysicalFile
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 // calculate MD5 of old file
String md5 = getMD5( fo ); String md5 = getMD5(fo);
String md5New = getMD5( fn ); String md5New = getMD5(fn);
System.out.println( "name=" + name + " md5=" + md5 ); System.out.println("name=" + name + " md5=" + md5);
File specificNewDiffs = new File( newDiffDir, basename ); 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));
@ -122,8 +109,7 @@ final public class Rd5DiffManager
} }
} }
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