statistical encoding
This commit is contained in:
parent
f8dee5b7d1
commit
ccf6641bad
41 changed files with 4543 additions and 1965 deletions
|
|
@ -17,5 +17,15 @@
|
|||
<artifactId>brouter-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.btools</groupId>
|
||||
<artifactId>brouter-codec</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.btools</groupId>
|
||||
<artifactId>brouter-expressions</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -1,271 +0,0 @@
|
|||
/**
|
||||
* cache for a single square
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import btools.util.ByteDataReader;
|
||||
import btools.util.Crc32;
|
||||
|
||||
final class MicroCache extends ByteDataReader
|
||||
{
|
||||
private int[] faid;
|
||||
private int[] fapos;
|
||||
private int size = 0;
|
||||
private int delcount = 0;
|
||||
private int delbytes = 0;
|
||||
private int p2size; // next power of 2 of size
|
||||
|
||||
// the object parsing position and length
|
||||
private int aboffsetEnd;
|
||||
|
||||
private int lonIdxBase;
|
||||
private int latIdxBase;
|
||||
|
||||
// cache control: a virgin cache can be
|
||||
// put to ghost state for later recovery
|
||||
boolean virgin = true;
|
||||
boolean ghost = false;
|
||||
|
||||
public MicroCache( OsmFile segfile, int lonIdx80, int latIdx80, byte[] iobuffer ) throws Exception
|
||||
{
|
||||
super( null );
|
||||
int lonDegree = lonIdx80/80;
|
||||
int latDegree = latIdx80/80;
|
||||
|
||||
lonIdxBase = (lonIdx80/5)*62500 + 31250;
|
||||
latIdxBase = (latIdx80/5)*62500 + 31250;
|
||||
|
||||
int subIdx = (latIdx80-80*latDegree)*80 + (lonIdx80-80*lonDegree);
|
||||
|
||||
{
|
||||
ab = iobuffer;
|
||||
int asize = segfile.getDataInputForSubIdx(subIdx, ab);
|
||||
|
||||
if ( asize == 0 )
|
||||
{
|
||||
ab = null;
|
||||
return;
|
||||
}
|
||||
if ( asize > iobuffer.length )
|
||||
{
|
||||
ab = new byte[asize];
|
||||
asize = segfile.getDataInputForSubIdx(subIdx, ab);
|
||||
}
|
||||
aboffset = 0;
|
||||
size = readInt();
|
||||
|
||||
// get net size
|
||||
int nbytes = 0;
|
||||
for(int i = 0; i<size; i++)
|
||||
{
|
||||
aboffset += 4;
|
||||
int bodySize = readVarLengthUnsigned();
|
||||
|
||||
aboffset += bodySize;
|
||||
nbytes += bodySize;
|
||||
}
|
||||
|
||||
int crc = Crc32.crc( ab, 0, aboffset );
|
||||
if ( crc != readInt() )
|
||||
{
|
||||
throw new IOException( "checkum error" );
|
||||
}
|
||||
|
||||
// new array with only net data
|
||||
byte[] nab = new byte[nbytes];
|
||||
aboffset = 4;
|
||||
int noffset = 0;
|
||||
faid = new int[size];
|
||||
fapos = new int[size];
|
||||
p2size = 0x40000000;
|
||||
while( p2size > size ) p2size >>= 1;
|
||||
|
||||
for(int i = 0; i<size; i++)
|
||||
{
|
||||
faid[i] = readInt() ^ 0x8000; // flip lat-sign for correct ordering
|
||||
|
||||
int bodySize = readVarLengthUnsigned();
|
||||
fapos[i] = noffset;
|
||||
System.arraycopy( ab, aboffset, nab, noffset, bodySize );
|
||||
aboffset += bodySize;
|
||||
noffset += bodySize;
|
||||
}
|
||||
|
||||
ab = nab;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
public int getDataSize()
|
||||
{
|
||||
return ab == null ? 0 : ab.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the internal reader (aboffset, ablength)
|
||||
* to the body data for the given id
|
||||
*
|
||||
* @return true if id was found
|
||||
*
|
||||
* Throws an exception if that id was already requested
|
||||
* as an early detector for identity problems
|
||||
*/
|
||||
private boolean getAndClear( long id64 )
|
||||
{
|
||||
if ( size == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int id = shrinkId( id64 );
|
||||
int[] a = faid;
|
||||
int offset = p2size;
|
||||
int n = 0;
|
||||
|
||||
|
||||
while ( offset> 0 )
|
||||
{
|
||||
int nn = n + offset;
|
||||
if ( nn < size && a[nn] <= id )
|
||||
{
|
||||
n = nn;
|
||||
}
|
||||
offset >>= 1;
|
||||
}
|
||||
if ( a[n] == id )
|
||||
{
|
||||
if ( ( fapos[n] & 0x80000000 ) == 0 )
|
||||
{
|
||||
aboffset = fapos[n];
|
||||
int ablength = ( n+1 < size ? fapos[n+1] & 0x7fffffff : ab.length ) - aboffset;
|
||||
aboffsetEnd = aboffset + ablength;
|
||||
fapos[n] |= 0x80000000; // mark deleted
|
||||
delbytes+= ablength;
|
||||
delcount++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException( "MicroCache: node already consumed: id=" + id );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a hollow node with it's body data
|
||||
*/
|
||||
public void fillNode( OsmNode node, OsmNodesMap nodesMap, DistanceChecker dc, boolean doCollect )
|
||||
{
|
||||
long id = node.getIdFromPos();
|
||||
if ( getAndClear( id ) )
|
||||
{
|
||||
node.parseNodeBody( this, nodesMap, dc );
|
||||
}
|
||||
|
||||
if ( doCollect && delcount > size / 2 ) // garbage collection
|
||||
{
|
||||
collect();
|
||||
}
|
||||
}
|
||||
|
||||
void collect()
|
||||
{
|
||||
if ( delcount > 0 )
|
||||
{
|
||||
virgin = false;
|
||||
|
||||
int nsize = size - delcount;
|
||||
if ( nsize == 0 )
|
||||
{
|
||||
faid = null;
|
||||
fapos = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] nfaid = new int[nsize];
|
||||
int[] nfapos = new int[nsize];
|
||||
int idx = 0;
|
||||
|
||||
byte[] nab = new byte[ab.length - delbytes];
|
||||
int nab_off = 0;
|
||||
for( int i=0; i<size; i++ )
|
||||
{
|
||||
int pos = fapos[i];
|
||||
if ( ( pos & 0x80000000 ) == 0 )
|
||||
{
|
||||
int ablength = ( i+1 < size ? fapos[i+1] & 0x7fffffff : ab.length ) - pos;
|
||||
System.arraycopy( ab, pos, nab, nab_off, ablength );
|
||||
nfaid[idx] = faid[i];
|
||||
nfapos[idx] = nab_off;
|
||||
nab_off += ablength;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
faid = nfaid;
|
||||
fapos = nfapos;
|
||||
ab = nab;
|
||||
}
|
||||
size = nsize;
|
||||
delcount = 0;
|
||||
delbytes = 0;
|
||||
p2size = 0x40000000;
|
||||
while( p2size > size ) p2size >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void unGhost()
|
||||
{
|
||||
ghost = false;
|
||||
delcount = 0;
|
||||
delbytes = 0;
|
||||
for( int i=0; i<size; i++ )
|
||||
{
|
||||
fapos[i] &= 0x7fffffff; // clear deleted flags
|
||||
}
|
||||
}
|
||||
|
||||
public List<OsmNode> getPositions( OsmNodesMap nodesMap )
|
||||
{
|
||||
ArrayList<OsmNode> positions = new ArrayList<OsmNode>();
|
||||
|
||||
for( int i=0; i<size; i++ )
|
||||
{
|
||||
int id32 = faid[i];
|
||||
long id64 = expandId( id32 );
|
||||
OsmNode n = new OsmNode( id64 );
|
||||
n.setHollow();
|
||||
nodesMap.put( n );
|
||||
positions.add( n );
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
private long expandId( int id32 )
|
||||
{
|
||||
int lon32 = lonIdxBase + (short)(id32 >> 16);
|
||||
int lat32 = latIdxBase + (short)((id32 & 0xffff) ^ 0x8000);
|
||||
return ((long)lon32)<<32 | lat32;
|
||||
}
|
||||
|
||||
private int shrinkId( long id64 )
|
||||
{
|
||||
int lon32 = (int)(id64 >> 32);
|
||||
int lat32 = (int)(id64 & 0xffffffff);
|
||||
return (lon32 - lonIdxBase)<<16 | ( ( (lat32 - latIdxBase) & 0xffff) ^ 0x8000);
|
||||
}
|
||||
|
||||
public boolean hasMoreData()
|
||||
{
|
||||
return aboffset < aboffsetEnd;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,291 +1,332 @@
|
|||
/**
|
||||
* Efficient cache or osmnodes
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public final class NodesCache
|
||||
{
|
||||
private File segmentDir;
|
||||
private File secondarySegmentsDir = null;
|
||||
|
||||
private OsmNodesMap nodesMap;
|
||||
private int lookupVersion;
|
||||
private int lookupMinorVersion;
|
||||
private boolean carMode;
|
||||
private boolean forceSecondaryData;
|
||||
private String currentFileName;
|
||||
|
||||
private HashMap<String,PhysicalFile> fileCache;
|
||||
private byte[] iobuffer;
|
||||
|
||||
private OsmFile[][] fileRows;
|
||||
private ArrayList<MicroCache> segmentList = new ArrayList<MicroCache>();
|
||||
|
||||
public DistanceChecker distanceChecker;
|
||||
|
||||
public boolean oom_carsubset_hint = false;
|
||||
public boolean first_file_access_failed = false;
|
||||
public String first_file_access_name;
|
||||
|
||||
private long cacheSum = 0;
|
||||
private boolean garbageCollectionEnabled = false;
|
||||
|
||||
|
||||
public NodesCache( String segmentDir, OsmNodesMap nodesMap, int lookupVersion, int minorVersion, boolean carMode, boolean forceSecondaryData, NodesCache oldCache )
|
||||
{
|
||||
this.segmentDir = new File( segmentDir );
|
||||
this.nodesMap = nodesMap;
|
||||
this.lookupVersion = lookupVersion;
|
||||
this.lookupMinorVersion = minorVersion;
|
||||
this.carMode = carMode;
|
||||
this.forceSecondaryData = forceSecondaryData;
|
||||
|
||||
first_file_access_failed = false;
|
||||
first_file_access_name = null;
|
||||
|
||||
if ( !this.segmentDir.isDirectory() ) throw new RuntimeException( "segment directory " + segmentDir + " does not exist" );
|
||||
|
||||
if ( oldCache != null )
|
||||
{
|
||||
fileCache = oldCache.fileCache;
|
||||
iobuffer = oldCache.iobuffer;
|
||||
oom_carsubset_hint = oldCache.oom_carsubset_hint;
|
||||
secondarySegmentsDir = oldCache.secondarySegmentsDir;
|
||||
|
||||
// re-use old, virgin caches
|
||||
fileRows = oldCache.fileRows;
|
||||
for( OsmFile[] fileRow : fileRows )
|
||||
{
|
||||
if ( fileRow == null ) continue;
|
||||
for( OsmFile osmf : fileRow )
|
||||
{
|
||||
cacheSum += osmf.setGhostState();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fileCache = new HashMap<String,PhysicalFile>(4);
|
||||
fileRows = new OsmFile[180][];
|
||||
iobuffer = new byte[65636];
|
||||
secondarySegmentsDir = StorageConfigHelper.getSecondarySegmentDir( segmentDir );
|
||||
}
|
||||
}
|
||||
|
||||
private File getFileFromSegmentDir( String filename )
|
||||
{
|
||||
if ( forceSecondaryData )
|
||||
{
|
||||
return new File( secondarySegmentsDir, filename );
|
||||
}
|
||||
|
||||
File f = new File( segmentDir, filename );
|
||||
if ( secondarySegmentsDir != null && !f.exists() )
|
||||
{
|
||||
File f2 = new File( secondarySegmentsDir, filename );
|
||||
if ( f2.exists() ) return f2;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
// if the cache sum exceeded a threshold,
|
||||
// clean all ghosts and enable garbage collection
|
||||
private void checkEnableCacheCleaning()
|
||||
{
|
||||
if ( cacheSum < 200000 || garbageCollectionEnabled ) return;
|
||||
|
||||
for( int i=0; i<fileRows.length; i++ )
|
||||
{
|
||||
OsmFile[] fileRow = fileRows[i];
|
||||
if ( fileRow == null ) continue;
|
||||
int nghosts = 0;
|
||||
for( OsmFile osmf : fileRow )
|
||||
{
|
||||
if ( osmf.ghost ) nghosts++;
|
||||
else osmf.cleanAll();
|
||||
}
|
||||
if ( nghosts == 0 ) continue;
|
||||
int j=0;
|
||||
OsmFile[] frow = new OsmFile[fileRow.length-nghosts];
|
||||
for( OsmFile osmf : fileRow )
|
||||
{
|
||||
if ( osmf.ghost ) continue;
|
||||
frow[j++] = osmf;
|
||||
}
|
||||
fileRows[i] = frow;
|
||||
}
|
||||
garbageCollectionEnabled = true;
|
||||
}
|
||||
|
||||
public int loadSegmentFor( int ilon, int ilat )
|
||||
{
|
||||
MicroCache mc = getSegmentFor( ilon, ilat );
|
||||
return mc == null ? 0 : mc.getSize();
|
||||
}
|
||||
|
||||
public MicroCache getSegmentFor( int ilon, int ilat )
|
||||
{
|
||||
try
|
||||
{
|
||||
int lonIdx80 = ilon/12500;
|
||||
int latIdx80 = ilat/12500;
|
||||
int lonDegree = lonIdx80/80;
|
||||
int latDegree = latIdx80/80;
|
||||
OsmFile osmf = null;
|
||||
OsmFile[] fileRow = fileRows[latDegree];
|
||||
int ndegrees = fileRow == null ? 0 : fileRow.length;
|
||||
for( int i=0; i<ndegrees; i++ )
|
||||
{
|
||||
if ( fileRow[i].lonDegree == lonDegree )
|
||||
{
|
||||
osmf = fileRow[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( osmf == null )
|
||||
{
|
||||
osmf = fileForSegment( lonDegree, latDegree );
|
||||
OsmFile[] newFileRow = new OsmFile[ndegrees+1];
|
||||
for( int i=0; i<ndegrees; i++ )
|
||||
{
|
||||
newFileRow[i] = fileRow[i];
|
||||
}
|
||||
newFileRow[ndegrees] = osmf;
|
||||
fileRows[latDegree] = newFileRow;
|
||||
}
|
||||
osmf.ghost = false;
|
||||
currentFileName = osmf.filename;
|
||||
if ( osmf.microCaches == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int subIdx = (latIdx80-80*latDegree)*80 + (lonIdx80-80*lonDegree);
|
||||
MicroCache segment = osmf.microCaches[subIdx];
|
||||
if ( segment == null )
|
||||
{
|
||||
// nodesMap.removeCompleteNodes();
|
||||
|
||||
checkEnableCacheCleaning();
|
||||
|
||||
segment = new MicroCache( osmf, lonIdx80, latIdx80, iobuffer );
|
||||
cacheSum += segment.getDataSize();
|
||||
osmf.microCaches[subIdx] = segment;
|
||||
segmentList.add( segment );
|
||||
}
|
||||
else if ( segment.ghost )
|
||||
{
|
||||
segment.unGhost();
|
||||
segmentList.add( segment );
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
catch( RuntimeException re )
|
||||
{
|
||||
throw re;
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
throw new RuntimeException( "error reading datafile " + currentFileName + ": " + e );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean obtainNonHollowNode( OsmNode node )
|
||||
{
|
||||
if ( !node.isHollow() ) return true;
|
||||
|
||||
MicroCache segment = getSegmentFor( node.ilon, node.ilat );
|
||||
if ( segment == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
segment.fillNode( node, nodesMap, distanceChecker, garbageCollectionEnabled );
|
||||
return !node.isHollow();
|
||||
}
|
||||
|
||||
private OsmFile fileForSegment( int lonDegree, int latDegree ) throws Exception
|
||||
{
|
||||
int lonMod5 = lonDegree % 5;
|
||||
int latMod5 = latDegree % 5;
|
||||
int tileIndex = lonMod5 * 5 + latMod5;
|
||||
|
||||
int lon = lonDegree - 180 - lonMod5;
|
||||
String slon = lon < 0 ? "W" + (-lon) : "E" + lon;
|
||||
int lat = latDegree - 90 - latMod5;
|
||||
|
||||
String slat = lat < 0 ? "S" + (-lat) : "N" + lat;
|
||||
String filenameBase = slon + "_" + slat;
|
||||
|
||||
currentFileName = filenameBase + ".rd5/cd5";
|
||||
|
||||
PhysicalFile ra = null;
|
||||
if ( !fileCache.containsKey( filenameBase ) )
|
||||
{
|
||||
File f = null;
|
||||
if ( carMode )
|
||||
{
|
||||
File carFile = getFileFromSegmentDir( "carsubset/" + filenameBase + ".cd5" );
|
||||
if ( carFile.exists() ) f = carFile;
|
||||
}
|
||||
if ( f == null )
|
||||
{
|
||||
File fullFile = getFileFromSegmentDir( filenameBase + ".rd5" );
|
||||
if ( fullFile.exists() ) f = fullFile;
|
||||
if ( carMode && f != null ) oom_carsubset_hint = true;
|
||||
}
|
||||
if ( f != null )
|
||||
{
|
||||
currentFileName = f.getName();
|
||||
ra = new PhysicalFile( f, iobuffer, lookupVersion, lookupMinorVersion );
|
||||
}
|
||||
fileCache.put( filenameBase, ra );
|
||||
}
|
||||
ra = fileCache.get( filenameBase );
|
||||
OsmFile osmf = new OsmFile( ra, tileIndex, iobuffer );
|
||||
osmf.lonDegree = lonDegree;
|
||||
osmf.latDegree = latDegree;
|
||||
|
||||
if ( first_file_access_name == null )
|
||||
{
|
||||
first_file_access_name = currentFileName;
|
||||
first_file_access_failed = osmf.filename == null;
|
||||
}
|
||||
|
||||
return osmf;
|
||||
}
|
||||
|
||||
public List<OsmNode> getAllNodes()
|
||||
{
|
||||
List<OsmNode> all = new ArrayList<OsmNode>();
|
||||
for( MicroCache segment : segmentList )
|
||||
{
|
||||
List<OsmNode> positions = segment.getPositions( nodesMap );
|
||||
all.addAll( positions );
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
|
||||
public void close()
|
||||
{
|
||||
for( PhysicalFile f: fileCache.values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( f != null ) f.ra.close();
|
||||
}
|
||||
catch( IOException ioe )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Efficient cache or osmnodes
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import btools.codec.DataBuffers;
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.WaypointMatcher;
|
||||
import btools.expressions.BExpressionContextWay;
|
||||
|
||||
public final class NodesCache
|
||||
{
|
||||
private File segmentDir;
|
||||
private File secondarySegmentsDir = null;
|
||||
|
||||
private OsmNodesMap nodesMap;
|
||||
private BExpressionContextWay expCtxWay;
|
||||
private int lookupVersion;
|
||||
private int lookupMinorVersion;
|
||||
private boolean carMode;
|
||||
private boolean forceSecondaryData;
|
||||
private String currentFileName;
|
||||
|
||||
private HashMap<String, PhysicalFile> fileCache;
|
||||
private DataBuffers dataBuffers;
|
||||
|
||||
private OsmFile[][] fileRows;
|
||||
private ArrayList<MicroCache> segmentList = new ArrayList<MicroCache>();
|
||||
|
||||
public DistanceChecker distanceChecker;
|
||||
|
||||
public WaypointMatcher waypointMatcher;
|
||||
|
||||
public boolean oom_carsubset_hint = false;
|
||||
public boolean first_file_access_failed = false;
|
||||
public String first_file_access_name;
|
||||
|
||||
private long cacheSum = 0;
|
||||
private boolean garbageCollectionEnabled = false;
|
||||
|
||||
public NodesCache( String segmentDir, OsmNodesMap nodesMap, BExpressionContextWay ctxWay, boolean carMode, boolean forceSecondaryData,
|
||||
NodesCache oldCache )
|
||||
{
|
||||
this.segmentDir = new File( segmentDir );
|
||||
this.nodesMap = nodesMap;
|
||||
this.expCtxWay = ctxWay;
|
||||
this.lookupVersion = ctxWay.meta.lookupVersion;
|
||||
this.lookupMinorVersion = ctxWay.meta.lookupMinorVersion;
|
||||
this.carMode = carMode;
|
||||
this.forceSecondaryData = forceSecondaryData;
|
||||
|
||||
first_file_access_failed = false;
|
||||
first_file_access_name = null;
|
||||
|
||||
if ( !this.segmentDir.isDirectory() )
|
||||
throw new RuntimeException( "segment directory " + segmentDir + " does not exist" );
|
||||
|
||||
if ( oldCache != null )
|
||||
{
|
||||
fileCache = oldCache.fileCache;
|
||||
dataBuffers = oldCache.dataBuffers;
|
||||
oom_carsubset_hint = oldCache.oom_carsubset_hint;
|
||||
secondarySegmentsDir = oldCache.secondarySegmentsDir;
|
||||
|
||||
// re-use old, virgin caches
|
||||
fileRows = oldCache.fileRows;
|
||||
for ( OsmFile[] fileRow : fileRows )
|
||||
{
|
||||
if ( fileRow == null )
|
||||
continue;
|
||||
for ( OsmFile osmf : fileRow )
|
||||
{
|
||||
cacheSum += osmf.setGhostState();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fileCache = new HashMap<String, PhysicalFile>( 4 );
|
||||
fileRows = new OsmFile[180][];
|
||||
dataBuffers = new DataBuffers();
|
||||
secondarySegmentsDir = StorageConfigHelper.getSecondarySegmentDir( segmentDir );
|
||||
}
|
||||
}
|
||||
|
||||
private File getFileFromSegmentDir( String filename )
|
||||
{
|
||||
if ( forceSecondaryData )
|
||||
{
|
||||
return new File( secondarySegmentsDir, filename );
|
||||
}
|
||||
|
||||
File f = new File( segmentDir, filename );
|
||||
if ( secondarySegmentsDir != null && !f.exists() )
|
||||
{
|
||||
File f2 = new File( secondarySegmentsDir, filename );
|
||||
if ( f2.exists() )
|
||||
return f2;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
// if the cache sum exceeded a threshold,
|
||||
// clean all ghosts and enable garbage collection
|
||||
private void checkEnableCacheCleaning()
|
||||
{
|
||||
if ( cacheSum < 500000 || garbageCollectionEnabled )
|
||||
return;
|
||||
|
||||
for ( int i = 0; i < fileRows.length; i++ )
|
||||
{
|
||||
OsmFile[] fileRow = fileRows[i];
|
||||
if ( fileRow == null )
|
||||
continue;
|
||||
int nghosts = 0;
|
||||
for ( OsmFile osmf : fileRow )
|
||||
{
|
||||
if ( osmf.ghost )
|
||||
nghosts++;
|
||||
else
|
||||
osmf.cleanAll();
|
||||
}
|
||||
if ( nghosts == 0 )
|
||||
continue;
|
||||
int j = 0;
|
||||
OsmFile[] frow = new OsmFile[fileRow.length - nghosts];
|
||||
for ( OsmFile osmf : fileRow )
|
||||
{
|
||||
if ( osmf.ghost )
|
||||
continue;
|
||||
frow[j++] = osmf;
|
||||
}
|
||||
fileRows[i] = frow;
|
||||
}
|
||||
garbageCollectionEnabled = true;
|
||||
}
|
||||
|
||||
public int loadSegmentFor( int ilon, int ilat )
|
||||
{
|
||||
MicroCache mc = getSegmentFor( ilon, ilat );
|
||||
return mc == null ? 0 : mc.getSize();
|
||||
}
|
||||
|
||||
public MicroCache getSegmentFor( int ilon, int ilat )
|
||||
{
|
||||
try
|
||||
{
|
||||
int lonDegree = ilon / 1000000;
|
||||
int latDegree = ilat / 1000000;
|
||||
OsmFile osmf = null;
|
||||
OsmFile[] fileRow = fileRows[latDegree];
|
||||
int ndegrees = fileRow == null ? 0 : fileRow.length;
|
||||
for ( int i = 0; i < ndegrees; i++ )
|
||||
{
|
||||
if ( fileRow[i].lonDegree == lonDegree )
|
||||
{
|
||||
osmf = fileRow[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( osmf == null )
|
||||
{
|
||||
osmf = fileForSegment( lonDegree, latDegree );
|
||||
OsmFile[] newFileRow = new OsmFile[ndegrees + 1];
|
||||
for ( int i = 0; i < ndegrees; i++ )
|
||||
{
|
||||
newFileRow[i] = fileRow[i];
|
||||
}
|
||||
newFileRow[ndegrees] = osmf;
|
||||
fileRows[latDegree] = newFileRow;
|
||||
}
|
||||
osmf.ghost = false;
|
||||
currentFileName = osmf.filename;
|
||||
|
||||
if ( !osmf.hasData() )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MicroCache segment = osmf.getMicroCache( ilon, ilat );
|
||||
if ( segment == null )
|
||||
{
|
||||
checkEnableCacheCleaning();
|
||||
segment = osmf.createMicroCache( ilon, ilat, dataBuffers, expCtxWay, waypointMatcher );
|
||||
|
||||
cacheSum += segment.getDataSize();
|
||||
if ( segment.getSize() > 0 )
|
||||
{
|
||||
segmentList.add( segment );
|
||||
}
|
||||
}
|
||||
else if ( segment.ghost )
|
||||
{
|
||||
segment.unGhost();
|
||||
if ( segment.getSize() > 0 )
|
||||
{
|
||||
segmentList.add( segment );
|
||||
}
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
catch (RuntimeException re)
|
||||
{
|
||||
throw re;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException( "error reading datafile " + currentFileName + ": ", e );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean obtainNonHollowNode( OsmNode node )
|
||||
{
|
||||
if ( !node.isHollow() )
|
||||
return true;
|
||||
|
||||
MicroCache segment = getSegmentFor( node.ilon, node.ilat );
|
||||
if ( segment == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long id = node.getIdFromPos();
|
||||
if ( segment.getAndClear( id ) )
|
||||
{
|
||||
node.parseNodeBody( segment, nodesMap, distanceChecker );
|
||||
}
|
||||
|
||||
if ( garbageCollectionEnabled ) // garbage collection
|
||||
{
|
||||
segment.collect( segment.getSize() >> 1 );
|
||||
}
|
||||
|
||||
return !node.isHollow();
|
||||
}
|
||||
|
||||
private OsmFile fileForSegment( int lonDegree, int latDegree ) throws Exception
|
||||
{
|
||||
int lonMod5 = lonDegree % 5;
|
||||
int latMod5 = latDegree % 5;
|
||||
|
||||
int lon = lonDegree - 180 - lonMod5;
|
||||
String slon = lon < 0 ? "W" + ( -lon ) : "E" + lon;
|
||||
int lat = latDegree - 90 - latMod5;
|
||||
|
||||
String slat = lat < 0 ? "S" + ( -lat ) : "N" + lat;
|
||||
String filenameBase = slon + "_" + slat;
|
||||
|
||||
currentFileName = filenameBase + ".rd5/cd5";
|
||||
|
||||
PhysicalFile ra = null;
|
||||
if ( !fileCache.containsKey( filenameBase ) )
|
||||
{
|
||||
File f = null;
|
||||
if ( carMode )
|
||||
{
|
||||
File carFile = getFileFromSegmentDir( "carsubset/" + filenameBase + ".cd5" );
|
||||
if ( carFile.exists() )
|
||||
f = carFile;
|
||||
}
|
||||
if ( f == null )
|
||||
{
|
||||
File fullFile = getFileFromSegmentDir( filenameBase + ".rd5" );
|
||||
if ( fullFile.exists() )
|
||||
f = fullFile;
|
||||
if ( carMode && f != null )
|
||||
oom_carsubset_hint = true;
|
||||
}
|
||||
if ( f != null )
|
||||
{
|
||||
currentFileName = f.getName();
|
||||
ra = new PhysicalFile( f, dataBuffers, lookupVersion, lookupMinorVersion );
|
||||
}
|
||||
fileCache.put( filenameBase, ra );
|
||||
}
|
||||
ra = fileCache.get( filenameBase );
|
||||
OsmFile osmf = new OsmFile( ra, lonDegree, latDegree, dataBuffers );
|
||||
|
||||
if ( first_file_access_name == null )
|
||||
{
|
||||
first_file_access_name = currentFileName;
|
||||
first_file_access_failed = osmf.filename == null;
|
||||
}
|
||||
|
||||
return osmf;
|
||||
}
|
||||
|
||||
public List<OsmNode> getAllNodes()
|
||||
{
|
||||
List<OsmNode> all = new ArrayList<OsmNode>();
|
||||
for ( MicroCache segment : segmentList )
|
||||
{
|
||||
ArrayList<OsmNode> positions = new ArrayList<OsmNode>();
|
||||
int size = segment.getSize();
|
||||
|
||||
for ( int i = 0; i < size; i++ )
|
||||
{
|
||||
long id = segment.getIdForIndex( i );
|
||||
OsmNode n = new OsmNode( id );
|
||||
n.setHollow();
|
||||
nodesMap.put( n );
|
||||
positions.add( n );
|
||||
}
|
||||
all.addAll( positions );
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
for ( PhysicalFile f : fileCache.values() )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( f != null )
|
||||
f.ra.close();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,124 +1,208 @@
|
|||
/**
|
||||
* cache for a single square
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import btools.util.ByteDataReader;
|
||||
import btools.util.Crc32;
|
||||
|
||||
final class OsmFile
|
||||
{
|
||||
private RandomAccessFile is = null;
|
||||
private long fileOffset;
|
||||
|
||||
private int[] posIdx;
|
||||
public MicroCache[] microCaches;
|
||||
|
||||
public int lonDegree;
|
||||
public int latDegree;
|
||||
|
||||
public String filename;
|
||||
|
||||
public boolean ghost = false;
|
||||
|
||||
public OsmFile( PhysicalFile rafile, int tileIndex, byte[] iobuffer ) throws Exception
|
||||
{
|
||||
if ( rafile != null )
|
||||
{
|
||||
filename = rafile.fileName;
|
||||
|
||||
long[] index = rafile.fileIndex;
|
||||
fileOffset = tileIndex > 0 ? index[ tileIndex-1 ] : 200L;
|
||||
if ( fileOffset == index[ tileIndex] ) return; // empty
|
||||
|
||||
is = rafile.ra;
|
||||
posIdx = new int[6400];
|
||||
microCaches = new MicroCache[6400];
|
||||
is.seek( fileOffset );
|
||||
is.readFully( iobuffer, 0, 25600 );
|
||||
|
||||
if ( rafile.fileHeaderCrcs != null )
|
||||
{
|
||||
int headerCrc = Crc32.crc( iobuffer, 0, 25600 );
|
||||
if ( rafile.fileHeaderCrcs[tileIndex] != headerCrc )
|
||||
{
|
||||
throw new IOException( "sub index checksum error" );
|
||||
}
|
||||
}
|
||||
|
||||
ByteDataReader dis = new ByteDataReader( iobuffer );
|
||||
for( int i=0; i<6400; i++ )
|
||||
{
|
||||
posIdx[i] = dis.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getPosIdx( int idx )
|
||||
{
|
||||
return idx == -1 ? 25600 : posIdx[idx];
|
||||
}
|
||||
|
||||
public int getDataInputForSubIdx( int subIdx, byte[] iobuffer ) throws Exception
|
||||
{
|
||||
int startPos = getPosIdx(subIdx-1);
|
||||
int endPos = getPosIdx(subIdx);
|
||||
int size = endPos-startPos;
|
||||
if ( size > 0 )
|
||||
{
|
||||
is.seek( fileOffset + startPos );
|
||||
if ( size <= iobuffer.length )
|
||||
{
|
||||
is.readFully( iobuffer, 0, size );
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// set this OsmFile to ghost-state:
|
||||
long setGhostState()
|
||||
{
|
||||
long sum = 0;
|
||||
ghost = true;
|
||||
int nc = microCaches == null ? 0 : microCaches.length;
|
||||
for( int i=0; i< nc; i++ )
|
||||
{
|
||||
MicroCache mc = microCaches[i];
|
||||
if ( mc == null ) continue;
|
||||
if ( mc.virgin )
|
||||
{
|
||||
mc.ghost = true;
|
||||
sum += mc.getDataSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
microCaches[i] = null;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void cleanAll()
|
||||
{
|
||||
int nc = microCaches == null ? 0 : microCaches.length;
|
||||
for( int i=0; i< nc; i++ )
|
||||
{
|
||||
MicroCache mc = microCaches[i];
|
||||
if ( mc == null ) continue;
|
||||
if ( mc.ghost )
|
||||
{
|
||||
microCaches[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
mc.collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* cache for a single square
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import btools.codec.DataBuffers;
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.MicroCache1;
|
||||
import btools.codec.MicroCache2;
|
||||
import btools.codec.TagValueValidator;
|
||||
import btools.codec.WaypointMatcher;
|
||||
import btools.util.ByteDataReader;
|
||||
import btools.util.Crc32;
|
||||
|
||||
final class OsmFile
|
||||
{
|
||||
private RandomAccessFile is = null;
|
||||
private long fileOffset;
|
||||
|
||||
private int[] posIdx;
|
||||
private MicroCache[] microCaches;
|
||||
|
||||
public int lonDegree;
|
||||
public int latDegree;
|
||||
|
||||
public String filename;
|
||||
|
||||
public boolean ghost = false;
|
||||
|
||||
private int divisor;
|
||||
private int cellsize;
|
||||
private int ncaches;
|
||||
private int indexsize;
|
||||
|
||||
public OsmFile( PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers ) throws Exception
|
||||
{
|
||||
this.lonDegree = lonDegree;
|
||||
this.latDegree = latDegree;
|
||||
int lonMod5 = lonDegree % 5;
|
||||
int latMod5 = latDegree % 5;
|
||||
int tileIndex = lonMod5 * 5 + latMod5;
|
||||
|
||||
if ( rafile != null )
|
||||
{
|
||||
divisor = rafile.divisor;
|
||||
|
||||
cellsize = 1000000 / divisor;
|
||||
ncaches = divisor * divisor;
|
||||
indexsize = ncaches * 4;
|
||||
|
||||
byte[] iobuffer = dataBuffers.iobuffer;
|
||||
filename = rafile.fileName;
|
||||
|
||||
long[] index = rafile.fileIndex;
|
||||
fileOffset = tileIndex > 0 ? index[tileIndex - 1] : 200L;
|
||||
if ( fileOffset == index[tileIndex] )
|
||||
return; // empty
|
||||
|
||||
is = rafile.ra;
|
||||
posIdx = new int[ncaches];
|
||||
microCaches = new MicroCache[ncaches];
|
||||
is.seek( fileOffset );
|
||||
is.readFully( iobuffer, 0, indexsize );
|
||||
|
||||
if ( rafile.fileHeaderCrcs != null )
|
||||
{
|
||||
int headerCrc = Crc32.crc( iobuffer, 0, indexsize );
|
||||
if ( rafile.fileHeaderCrcs[tileIndex] != headerCrc )
|
||||
{
|
||||
throw new IOException( "sub index checksum error" );
|
||||
}
|
||||
}
|
||||
|
||||
ByteDataReader dis = new ByteDataReader( iobuffer );
|
||||
for ( int i = 0; i < ncaches; i++ )
|
||||
{
|
||||
posIdx[i] = dis.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasData()
|
||||
{
|
||||
return microCaches != null;
|
||||
}
|
||||
|
||||
public MicroCache getMicroCache( int ilon, int ilat )
|
||||
{
|
||||
int lonIdx = ilon / cellsize;
|
||||
int latIdx = ilat / cellsize;
|
||||
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
|
||||
return microCaches[subIdx];
|
||||
}
|
||||
|
||||
public MicroCache createMicroCache( int ilon, int ilat, DataBuffers dataBuffers, TagValueValidator wayValidator, WaypointMatcher waypointMatcher )
|
||||
throws Exception
|
||||
{
|
||||
int lonIdx = ilon / cellsize;
|
||||
int latIdx = ilat / cellsize;
|
||||
MicroCache segment = createMicroCache( lonIdx, latIdx, dataBuffers, wayValidator, waypointMatcher, true );
|
||||
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
|
||||
microCaches[subIdx] = segment;
|
||||
return segment;
|
||||
}
|
||||
|
||||
private int getPosIdx( int idx )
|
||||
{
|
||||
return idx == -1 ? indexsize : posIdx[idx];
|
||||
}
|
||||
|
||||
public int getDataInputForSubIdx( int subIdx, byte[] iobuffer ) throws Exception
|
||||
{
|
||||
int startPos = getPosIdx( subIdx - 1 );
|
||||
int endPos = getPosIdx( subIdx );
|
||||
int size = endPos - startPos;
|
||||
if ( size > 0 )
|
||||
{
|
||||
is.seek( fileOffset + startPos );
|
||||
if ( size <= iobuffer.length )
|
||||
{
|
||||
is.readFully( iobuffer, 0, size );
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public MicroCache createMicroCache( int lonIdx, int latIdx, DataBuffers dataBuffers, TagValueValidator wayValidator,
|
||||
WaypointMatcher waypointMatcher, boolean reallyDecode ) throws Exception
|
||||
{
|
||||
int subIdx = ( latIdx - divisor * latDegree ) * divisor + ( lonIdx - divisor * lonDegree );
|
||||
|
||||
byte[] ab = dataBuffers.iobuffer;
|
||||
int asize = getDataInputForSubIdx( subIdx, ab );
|
||||
|
||||
if ( asize == 0 )
|
||||
{
|
||||
return MicroCache.emptyCache();
|
||||
}
|
||||
if ( asize > ab.length )
|
||||
{
|
||||
ab = new byte[asize];
|
||||
asize = getDataInputForSubIdx( subIdx, ab );
|
||||
}
|
||||
// hack: the checksum contains the information
|
||||
// which type of microcache we have
|
||||
|
||||
int crcData = Crc32.crc( ab, 0, asize - 4 );
|
||||
int crcFooter = new ByteDataReader( ab, asize - 4 ).readInt();
|
||||
if ( crcData == crcFooter )
|
||||
{
|
||||
return reallyDecode ? new MicroCache1( ab, lonIdx, latIdx ) : null;
|
||||
}
|
||||
if ( ( crcData ^ 2 ) == crcFooter )
|
||||
{
|
||||
return reallyDecode ? new MicroCache2( dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher ) : null;
|
||||
}
|
||||
throw new IOException( "checkum error" );
|
||||
}
|
||||
|
||||
// set this OsmFile to ghost-state:
|
||||
long setGhostState()
|
||||
{
|
||||
long sum = 0;
|
||||
ghost = true;
|
||||
int nc = microCaches == null ? 0 : microCaches.length;
|
||||
for ( int i = 0; i < nc; i++ )
|
||||
{
|
||||
MicroCache mc = microCaches[i];
|
||||
if ( mc == null )
|
||||
continue;
|
||||
if ( mc.virgin )
|
||||
{
|
||||
mc.ghost = true;
|
||||
sum += mc.getDataSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
microCaches[i] = null;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void cleanAll()
|
||||
{
|
||||
int nc = microCaches == null ? 0 : microCaches.length;
|
||||
for ( int i = 0; i < nc; i++ )
|
||||
{
|
||||
MicroCache mc = microCaches[i];
|
||||
if ( mc == null )
|
||||
continue;
|
||||
if ( mc.ghost )
|
||||
{
|
||||
microCaches[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
mc.collect( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import btools.util.ByteDataReader;
|
||||
|
||||
|
||||
public class OsmLink
|
||||
{
|
||||
|
|
@ -14,32 +16,77 @@ public class OsmLink
|
|||
*/
|
||||
public byte[] descriptionBitmap;
|
||||
|
||||
/**
|
||||
* The target is either the next link or the target node
|
||||
*/
|
||||
public OsmNode targetNode;
|
||||
|
||||
public OsmLink next;
|
||||
|
||||
public byte[] firsttransferBytes;
|
||||
public OsmLinkHolder firstlinkholder = null;
|
||||
|
||||
final public OsmTransferNode decodeFirsttransfer()
|
||||
public byte[] geometry;
|
||||
|
||||
public boolean counterLinkWritten;
|
||||
|
||||
public boolean hasNewGeometry; // preliminary
|
||||
|
||||
public byte state;
|
||||
|
||||
public void setGeometry( byte[] geometry )
|
||||
{
|
||||
return firsttransferBytes == null ? null : OsmTransferNode.decode( firsttransferBytes );
|
||||
this.geometry = geometry;
|
||||
hasNewGeometry = true;
|
||||
}
|
||||
|
||||
final public OsmTransferNode decodeFirsttransfer( OsmNode sourceNode )
|
||||
{
|
||||
if ( geometry == null ) return null;
|
||||
if ( hasNewGeometry )
|
||||
{
|
||||
OsmTransferNode firstTransferNode = null;
|
||||
OsmTransferNode lastTransferNode = null;
|
||||
OsmNode startnode = counterLinkWritten ? targetNode : sourceNode;
|
||||
ByteDataReader r = new ByteDataReader( geometry );
|
||||
int olon = startnode.ilon;
|
||||
int olat = startnode.ilat;
|
||||
int oselev = startnode.selev;
|
||||
while ( r.hasMoreData() )
|
||||
{
|
||||
OsmTransferNode trans = new OsmTransferNode();
|
||||
trans.ilon = olon + r.readVarLengthSigned();
|
||||
trans.ilat = olat + r.readVarLengthSigned();
|
||||
trans.descriptionBitmap = descriptionBitmap;
|
||||
trans.selev = (short)(oselev + r.readVarLengthSigned());
|
||||
olon = trans.ilon;
|
||||
olat = trans.ilat;
|
||||
oselev = trans.selev;
|
||||
if ( counterLinkWritten ) // reverse chaining
|
||||
{
|
||||
trans.next = firstTransferNode;
|
||||
firstTransferNode = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( lastTransferNode == null )
|
||||
{
|
||||
firstTransferNode = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTransferNode.next = trans;
|
||||
}
|
||||
lastTransferNode = trans;
|
||||
}
|
||||
}
|
||||
return firstTransferNode;
|
||||
}
|
||||
return OsmTransferNode.decode( geometry );
|
||||
}
|
||||
|
||||
final public void encodeFirsttransfer( OsmTransferNode firsttransfer )
|
||||
{
|
||||
if ( firsttransfer == null ) firsttransferBytes = null;
|
||||
else firsttransferBytes = OsmTransferNode.encode( firsttransfer );
|
||||
if ( firsttransfer == null ) geometry = null;
|
||||
else geometry = OsmTransferNode.encode( firsttransfer );
|
||||
}
|
||||
|
||||
public boolean counterLinkWritten;
|
||||
|
||||
public byte state;
|
||||
|
||||
public OsmLinkHolder firstlinkholder = null;
|
||||
|
||||
final public void addLinkHolder( OsmLinkHolder holder )
|
||||
{
|
||||
if ( firstlinkholder != null ) { holder.setNextForLink( firstlinkholder ); }
|
||||
|
|
|
|||
|
|
@ -1,363 +1,471 @@
|
|||
/**
|
||||
* Container for an osm node
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import btools.util.ByteArrayUnifier;
|
||||
|
||||
|
||||
|
||||
public class OsmNode implements OsmPos
|
||||
{
|
||||
public static final int EXTERNAL_BITMASK = 0x80; // old semantic
|
||||
public static final int SIGNLON_BITMASK = 0x80;
|
||||
public static final int SIGNLAT_BITMASK = 0x40;
|
||||
public static final int TRANSFERNODE_BITMASK = 0x20;
|
||||
public static final int WRITEDESC_BITMASK = 0x10;
|
||||
public static final int SKIPDETAILS_BITMASK = 0x08;
|
||||
public static final int NODEDESC_BITMASK = 0x04;
|
||||
public static final int RESERVED1_BITMASK = 0x02;
|
||||
public static final int RESERVED2_BITMASK = 0x01;
|
||||
|
||||
public OsmNode()
|
||||
{
|
||||
}
|
||||
|
||||
public OsmNode( int ilon, int ilat )
|
||||
{
|
||||
this.ilon = ilon;
|
||||
this.ilat = ilat;
|
||||
}
|
||||
|
||||
public OsmNode( long id )
|
||||
{
|
||||
ilon = (int)(id >> 32);
|
||||
ilat = (int)(id & 0xffffffff);
|
||||
}
|
||||
|
||||
/**
|
||||
* The latitude
|
||||
*/
|
||||
public int ilat;
|
||||
|
||||
/**
|
||||
* The longitude
|
||||
*/
|
||||
public int ilon;
|
||||
|
||||
/**
|
||||
* The elevation
|
||||
*/
|
||||
public short selev;
|
||||
|
||||
public byte[] nodeDescription;
|
||||
|
||||
// interface OsmPos
|
||||
public int getILat()
|
||||
{
|
||||
return ilat;
|
||||
}
|
||||
|
||||
public int getILon()
|
||||
{
|
||||
return ilon;
|
||||
}
|
||||
|
||||
public short getSElev()
|
||||
{
|
||||
return selev;
|
||||
}
|
||||
|
||||
public double getElev()
|
||||
{
|
||||
return selev / 4.;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The links to other nodes
|
||||
*/
|
||||
public OsmLink firstlink = null;
|
||||
|
||||
// preliminry in forward order to avoid regressions
|
||||
public void addLink( OsmLink link )
|
||||
{
|
||||
if ( firstlink == null )
|
||||
{
|
||||
firstlink = link;
|
||||
}
|
||||
else
|
||||
{
|
||||
OsmLink l = firstlink;
|
||||
while( l.next != null ) l = l.next;
|
||||
l.next = link;
|
||||
}
|
||||
}
|
||||
|
||||
private OsmLink getCompatibleLink( int ilon, int ilat, boolean counterLinkWritten, int state )
|
||||
{
|
||||
for( OsmLink l = firstlink; l != null; l = l.next )
|
||||
{
|
||||
if ( counterLinkWritten == l.counterLinkWritten && l.state == state )
|
||||
{
|
||||
OsmNode t = l.targetNode;
|
||||
if ( t.ilon == ilon && t.ilat == ilat )
|
||||
{
|
||||
l.state = 0;
|
||||
return l;
|
||||
}
|
||||
}
|
||||
}
|
||||
// second try ignoring counterLinkWritten
|
||||
// (border links are written in both directions)
|
||||
for( OsmLink l = firstlink; l != null; l = l.next )
|
||||
{
|
||||
if ( l.state == state )
|
||||
{
|
||||
OsmNode t = l.targetNode;
|
||||
if ( t.ilon == ilon && t.ilat == ilat )
|
||||
{
|
||||
l.state = 0;
|
||||
return l;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int calcDistance( OsmPos p )
|
||||
{
|
||||
double l = (ilat-90000000) * 0.00000001234134;
|
||||
double l2 = l*l;
|
||||
double l4 = l2*l2;
|
||||
double coslat = 1.- l2 + l4 / 6.;
|
||||
|
||||
double dlat = (ilat - p.getILat() )/1000000.;
|
||||
double dlon = (ilon - p.getILon() )/1000000. * coslat;
|
||||
double d = Math.sqrt( dlat*dlat + dlon*dlon ) * (6378000. / 57.3);
|
||||
return (int)(d + 1.0 );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "" + getIdFromPos();
|
||||
}
|
||||
|
||||
public void parseNodeBody( MicroCache is, OsmNodesMap hollowNodes, DistanceChecker dc )
|
||||
{
|
||||
ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier();
|
||||
|
||||
selev = is.readShort();
|
||||
|
||||
while( is.hasMoreData() )
|
||||
{
|
||||
int ilonref = ilon;
|
||||
int ilatref = ilat;
|
||||
|
||||
boolean counterLinkWritten = false;
|
||||
OsmTransferNode firstTransferNode = null;
|
||||
OsmTransferNode lastTransferNode = null;
|
||||
int linklon;
|
||||
int linklat;
|
||||
byte[] description = null;
|
||||
for(;;)
|
||||
{
|
||||
int bitField = is.readByte();
|
||||
int dlon = is.readVarLengthUnsigned();
|
||||
int dlat = is.readVarLengthUnsigned();
|
||||
if ( (bitField & SIGNLON_BITMASK) != 0 ) { dlon = -dlon;}
|
||||
if ( (bitField & SIGNLAT_BITMASK) != 0 ) { dlat = -dlat;}
|
||||
linklon = ilonref + dlon;
|
||||
linklat = ilatref + dlat;
|
||||
ilonref = linklon;
|
||||
ilatref = linklat;
|
||||
// read variable length or old 8 byte fixed, and ensure that 8 bytes is only fixed
|
||||
if ( (bitField & WRITEDESC_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
description = abUnifier.unify( ab );
|
||||
}
|
||||
if ( (bitField & NODEDESC_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
nodeDescription = abUnifier.unify( ab );
|
||||
}
|
||||
if ( (bitField & RESERVED1_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
}
|
||||
if ( (bitField & RESERVED2_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
}
|
||||
if ( (bitField & SKIPDETAILS_BITMASK ) != 0 )
|
||||
{
|
||||
counterLinkWritten = true;
|
||||
}
|
||||
|
||||
if ( description == null && !counterLinkWritten ) throw new IllegalArgumentException( "internal error: missing way description!" );
|
||||
|
||||
boolean isTransfer = (bitField & TRANSFERNODE_BITMASK ) != 0;
|
||||
if ( isTransfer )
|
||||
{
|
||||
OsmTransferNode trans = new OsmTransferNode();
|
||||
trans.ilon = linklon;
|
||||
trans.ilat = linklat;
|
||||
trans.descriptionBitmap = description;
|
||||
trans.selev = (short)(selev + is.readVarLengthSigned());
|
||||
if ( lastTransferNode == null )
|
||||
{
|
||||
firstTransferNode = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTransferNode.next = trans;
|
||||
}
|
||||
lastTransferNode = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// performance shortcut: ignore link if out of reach
|
||||
if ( dc != null && !counterLinkWritten )
|
||||
{
|
||||
if ( !dc.isWithinRadius( ilon, ilat, firstTransferNode, linklon, linklat ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( linklon == ilon && linklat == ilat )
|
||||
{
|
||||
continue; // skip self-ref
|
||||
}
|
||||
|
||||
// first check the known links for that target
|
||||
OsmLink link = getCompatibleLink( linklon, linklat, counterLinkWritten, 2 );
|
||||
if ( link == null ) // .. not found, then check the hollow nodes
|
||||
{
|
||||
long targetNodeId = ((long)linklon)<<32 | linklat;
|
||||
OsmNode tn = hollowNodes.get( targetNodeId ); // target node
|
||||
if ( tn == null ) // node not yet known, create a new hollow proxy
|
||||
{
|
||||
tn = new OsmNode(linklon, linklat);
|
||||
tn.setHollow();
|
||||
hollowNodes.put( tn );
|
||||
}
|
||||
link = new OsmLink();
|
||||
link.targetNode = tn;
|
||||
link.counterLinkWritten = counterLinkWritten;
|
||||
link.state = 1;
|
||||
addLink( link );
|
||||
}
|
||||
|
||||
// now we have a link with a target node -> get the reverse link
|
||||
OsmLink rlink = link.targetNode.getCompatibleLink( ilon, ilat, !counterLinkWritten, 1 );
|
||||
if ( rlink == null ) // .. not found, create it
|
||||
{
|
||||
rlink = new OsmLink();
|
||||
rlink.targetNode = this;
|
||||
rlink.counterLinkWritten = !counterLinkWritten;
|
||||
rlink.state = 2;
|
||||
link.targetNode.addLink( rlink );
|
||||
}
|
||||
|
||||
if ( !counterLinkWritten )
|
||||
{
|
||||
// we have the data for that link, so fill both the link ..
|
||||
link.descriptionBitmap = description;
|
||||
link.encodeFirsttransfer(firstTransferNode);
|
||||
|
||||
// .. and the reverse
|
||||
if ( rlink.counterLinkWritten )
|
||||
{
|
||||
rlink.descriptionBitmap = description; // default for no transfer-nodes
|
||||
OsmTransferNode previous = null;
|
||||
OsmTransferNode rtrans = null;
|
||||
for( OsmTransferNode trans = firstTransferNode; trans != null; trans = trans.next )
|
||||
{
|
||||
if ( previous == null )
|
||||
{
|
||||
rlink.descriptionBitmap = trans.descriptionBitmap;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous.descriptionBitmap = trans.descriptionBitmap;
|
||||
}
|
||||
rtrans = new OsmTransferNode();
|
||||
rtrans.ilon = trans.ilon;
|
||||
rtrans.ilat = trans.ilat;
|
||||
rtrans.selev = trans.selev;
|
||||
rtrans.next = previous;
|
||||
rtrans.descriptionBitmap = description;
|
||||
previous = rtrans;
|
||||
}
|
||||
rlink.encodeFirsttransfer(rtrans);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if ( dc == null )
|
||||
{
|
||||
hollowNodes.remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHollow()
|
||||
{
|
||||
return selev == -12345;
|
||||
}
|
||||
|
||||
public void setHollow()
|
||||
{
|
||||
selev = -12345;
|
||||
}
|
||||
|
||||
public long getIdFromPos()
|
||||
{
|
||||
return ((long)ilon)<<32 | ilat;
|
||||
}
|
||||
|
||||
public void unlinkLink( OsmLink link )
|
||||
{
|
||||
if ( link == firstlink )
|
||||
{
|
||||
firstlink = link.next;
|
||||
return;
|
||||
}
|
||||
for( OsmLink l = firstlink; l != null; l = l.next )
|
||||
{
|
||||
if ( l.next == link )
|
||||
{
|
||||
l.next = link.next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
if ( o instanceof OsmNode )
|
||||
{
|
||||
OsmNode n = (OsmNode)o;
|
||||
return n.ilon == ilon && n.ilat == ilat;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode( )
|
||||
{
|
||||
return ilon + ilat;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Container for an osm node
|
||||
*
|
||||
* @author ab
|
||||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import btools.codec.MicroCache;
|
||||
import btools.codec.MicroCache1;
|
||||
import btools.codec.MicroCache2;
|
||||
import btools.util.ByteArrayUnifier;
|
||||
|
||||
public class OsmNode implements OsmPos
|
||||
{
|
||||
public static final int EXTERNAL_BITMASK = 0x80; // old semantic
|
||||
public static final int SIGNLON_BITMASK = 0x80;
|
||||
public static final int SIGNLAT_BITMASK = 0x40;
|
||||
public static final int TRANSFERNODE_BITMASK = 0x20;
|
||||
public static final int WRITEDESC_BITMASK = 0x10;
|
||||
public static final int SKIPDETAILS_BITMASK = 0x08;
|
||||
public static final int NODEDESC_BITMASK = 0x04;
|
||||
public static final int RESERVED1_BITMASK = 0x02;
|
||||
public static final int RESERVED2_BITMASK = 0x01;
|
||||
|
||||
public OsmNode()
|
||||
{
|
||||
}
|
||||
|
||||
public OsmNode( int ilon, int ilat )
|
||||
{
|
||||
this.ilon = ilon;
|
||||
this.ilat = ilat;
|
||||
}
|
||||
|
||||
public OsmNode( long id )
|
||||
{
|
||||
ilon = (int) ( id >> 32 );
|
||||
ilat = (int) ( id & 0xffffffff );
|
||||
}
|
||||
|
||||
/**
|
||||
* The latitude
|
||||
*/
|
||||
public int ilat;
|
||||
|
||||
/**
|
||||
* The longitude
|
||||
*/
|
||||
public int ilon;
|
||||
|
||||
/**
|
||||
* The elevation
|
||||
*/
|
||||
public short selev;
|
||||
|
||||
public byte[] nodeDescription;
|
||||
|
||||
// interface OsmPos
|
||||
public int getILat()
|
||||
{
|
||||
return ilat;
|
||||
}
|
||||
|
||||
public int getILon()
|
||||
{
|
||||
return ilon;
|
||||
}
|
||||
|
||||
public short getSElev()
|
||||
{
|
||||
return selev;
|
||||
}
|
||||
|
||||
public double getElev()
|
||||
{
|
||||
return selev / 4.;
|
||||
}
|
||||
|
||||
/**
|
||||
* The links to other nodes
|
||||
*/
|
||||
public OsmLink firstlink = null;
|
||||
|
||||
// preliminry in forward order to avoid regressions
|
||||
public void addLink( OsmLink link )
|
||||
{
|
||||
if ( firstlink == null )
|
||||
{
|
||||
firstlink = link;
|
||||
}
|
||||
else
|
||||
{
|
||||
OsmLink l = firstlink;
|
||||
while (l.next != null)
|
||||
l = l.next;
|
||||
l.next = link;
|
||||
}
|
||||
}
|
||||
|
||||
private OsmLink getCompatibleLink( int ilon, int ilat, boolean counterLinkWritten, int state )
|
||||
{
|
||||
for ( OsmLink l = firstlink; l != null; l = l.next )
|
||||
{
|
||||
if ( counterLinkWritten == l.counterLinkWritten && l.state == state )
|
||||
{
|
||||
OsmNode t = l.targetNode;
|
||||
if ( t.ilon == ilon && t.ilat == ilat )
|
||||
{
|
||||
l.state = 0;
|
||||
return l;
|
||||
}
|
||||
}
|
||||
}
|
||||
// second try ignoring counterLinkWritten
|
||||
// (border links are written in both directions)
|
||||
for ( OsmLink l = firstlink; l != null; l = l.next )
|
||||
{
|
||||
if ( l.state == state )
|
||||
{
|
||||
OsmNode t = l.targetNode;
|
||||
if ( t.ilon == ilon && t.ilat == ilat )
|
||||
{
|
||||
l.state = 0;
|
||||
return l;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int calcDistance( OsmPos p )
|
||||
{
|
||||
double l = ( ilat - 90000000 ) * 0.00000001234134;
|
||||
double l2 = l * l;
|
||||
double l4 = l2 * l2;
|
||||
double coslat = 1. - l2 + l4 / 6.;
|
||||
|
||||
double dlat = ( ilat - p.getILat() ) / 1000000.;
|
||||
double dlon = ( ilon - p.getILon() ) / 1000000. * coslat;
|
||||
double d = Math.sqrt( dlat * dlat + dlon * dlon ) * ( 6378000. / 57.3 );
|
||||
return (int) ( d + 1.0 );
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "" + getIdFromPos();
|
||||
}
|
||||
|
||||
public void parseNodeBody( MicroCache mc, OsmNodesMap hollowNodes, DistanceChecker dc )
|
||||
{
|
||||
if ( mc instanceof MicroCache1 )
|
||||
{
|
||||
parseNodeBody1( (MicroCache1) mc, hollowNodes, dc );
|
||||
}
|
||||
else if ( mc instanceof MicroCache2 )
|
||||
{
|
||||
parseNodeBody2( (MicroCache2) mc, hollowNodes, dc );
|
||||
}
|
||||
else
|
||||
throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() );
|
||||
}
|
||||
|
||||
public void parseNodeBody2( MicroCache2 mc, OsmNodesMap hollowNodes, DistanceChecker dc )
|
||||
{
|
||||
ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier();
|
||||
|
||||
selev = mc.readShort();
|
||||
int nodeDescSize = mc.readVarLengthUnsigned();
|
||||
nodeDescription = nodeDescSize == 0 ? null : mc.readUnified( nodeDescSize, abUnifier );
|
||||
|
||||
while (mc.hasMoreData())
|
||||
{
|
||||
// read link data
|
||||
int endPointer = mc.getEndPointer();
|
||||
int linklon = ilon + mc.readVarLengthSigned();
|
||||
int linklat = ilat + mc.readVarLengthSigned();
|
||||
int sizecode = mc.readVarLengthUnsigned();
|
||||
boolean isReverse = ( sizecode & 1 ) != 0;
|
||||
byte[] description = null;
|
||||
int descSize = sizecode >> 1;
|
||||
if ( descSize > 0 )
|
||||
{
|
||||
description = mc.readUnified( descSize, abUnifier );
|
||||
}
|
||||
byte[] geometry = mc.readDataUntil( endPointer );
|
||||
|
||||
// preliminary hack: way-point-matching not here (done at decoding time)
|
||||
if ( dc != null )
|
||||
continue;
|
||||
|
||||
if ( linklon == ilon && linklat == ilat )
|
||||
{
|
||||
continue; // skip self-ref
|
||||
}
|
||||
|
||||
// first check the known links for that target
|
||||
OsmLink link = getCompatibleLink( linklon, linklat, isReverse, 2 );
|
||||
if ( link == null ) // .. not found, then check the hollow nodes
|
||||
{
|
||||
long targetNodeId = ( (long) linklon ) << 32 | linklat;
|
||||
OsmNode tn = hollowNodes.get( targetNodeId ); // target node
|
||||
if ( tn == null ) // node not yet known, create a new hollow proxy
|
||||
{
|
||||
tn = new OsmNode( linklon, linklat );
|
||||
tn.setHollow();
|
||||
hollowNodes.put( tn );
|
||||
}
|
||||
link = new OsmLink();
|
||||
link.targetNode = tn;
|
||||
link.counterLinkWritten = isReverse;
|
||||
link.state = 1;
|
||||
addLink( link );
|
||||
}
|
||||
|
||||
// now we have a link with a target node -> get the reverse link
|
||||
OsmLink rlink = link.targetNode.getCompatibleLink( ilon, ilat, !isReverse, 1 );
|
||||
if ( rlink == null ) // .. not found, create it
|
||||
{
|
||||
rlink = new OsmLink();
|
||||
rlink.targetNode = this;
|
||||
rlink.counterLinkWritten = !isReverse;
|
||||
rlink.state = 2;
|
||||
link.targetNode.addLink( rlink );
|
||||
}
|
||||
|
||||
if ( !isReverse )
|
||||
{
|
||||
// we have the data for that link, so fill both the link ..
|
||||
link.descriptionBitmap = description;
|
||||
link.setGeometry( geometry );
|
||||
|
||||
// .. and the reverse
|
||||
if ( rlink.counterLinkWritten )
|
||||
{
|
||||
rlink.descriptionBitmap = description;
|
||||
rlink.setGeometry( geometry );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if ( dc == null )
|
||||
{
|
||||
hollowNodes.remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
public void parseNodeBody1( MicroCache1 is, OsmNodesMap hollowNodes, DistanceChecker dc )
|
||||
{
|
||||
ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier();
|
||||
|
||||
selev = is.readShort();
|
||||
|
||||
while (is.hasMoreData())
|
||||
{
|
||||
int ilonref = ilon;
|
||||
int ilatref = ilat;
|
||||
|
||||
boolean counterLinkWritten = false;
|
||||
OsmTransferNode firstTransferNode = null;
|
||||
OsmTransferNode lastTransferNode = null;
|
||||
int linklon;
|
||||
int linklat;
|
||||
byte[] description = null;
|
||||
for ( ;; )
|
||||
{
|
||||
int bitField = is.readByte();
|
||||
int dlon = is.readVarLengthUnsigned();
|
||||
int dlat = is.readVarLengthUnsigned();
|
||||
if ( ( bitField & SIGNLON_BITMASK ) != 0 )
|
||||
{
|
||||
dlon = -dlon;
|
||||
}
|
||||
if ( ( bitField & SIGNLAT_BITMASK ) != 0 )
|
||||
{
|
||||
dlat = -dlat;
|
||||
}
|
||||
linklon = ilonref + dlon;
|
||||
linklat = ilatref + dlat;
|
||||
ilonref = linklon;
|
||||
ilatref = linklat;
|
||||
// read variable length or old 8 byte fixed, and ensure that 8 bytes is
|
||||
// only fixed
|
||||
if ( ( bitField & WRITEDESC_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
description = abUnifier.unify( ab );
|
||||
}
|
||||
if ( ( bitField & NODEDESC_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
nodeDescription = abUnifier.unify( ab );
|
||||
}
|
||||
if ( ( bitField & RESERVED1_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
}
|
||||
if ( ( bitField & RESERVED2_BITMASK ) != 0 )
|
||||
{
|
||||
byte[] ab = new byte[is.readByte()];
|
||||
is.readFully( ab );
|
||||
}
|
||||
if ( ( bitField & SKIPDETAILS_BITMASK ) != 0 )
|
||||
{
|
||||
counterLinkWritten = true;
|
||||
}
|
||||
|
||||
if ( description == null && !counterLinkWritten )
|
||||
throw new IllegalArgumentException( "internal error: missing way description!" );
|
||||
|
||||
boolean isTransfer = ( bitField & TRANSFERNODE_BITMASK ) != 0;
|
||||
if ( isTransfer )
|
||||
{
|
||||
OsmTransferNode trans = new OsmTransferNode();
|
||||
trans.ilon = linklon;
|
||||
trans.ilat = linklat;
|
||||
trans.descriptionBitmap = description;
|
||||
trans.selev = (short) ( selev + is.readVarLengthSigned() );
|
||||
if ( lastTransferNode == null )
|
||||
{
|
||||
firstTransferNode = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTransferNode.next = trans;
|
||||
}
|
||||
lastTransferNode = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// performance shortcut: ignore link if out of reach
|
||||
if ( dc != null && !counterLinkWritten )
|
||||
{
|
||||
if ( !dc.isWithinRadius( ilon, ilat, firstTransferNode, linklon, linklat ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( linklon == ilon && linklat == ilat )
|
||||
{
|
||||
continue; // skip self-ref
|
||||
}
|
||||
|
||||
// first check the known links for that target
|
||||
OsmLink link = getCompatibleLink( linklon, linklat, counterLinkWritten, 2 );
|
||||
if ( link == null ) // .. not found, then check the hollow nodes
|
||||
{
|
||||
long targetNodeId = ( (long) linklon ) << 32 | linklat;
|
||||
OsmNode tn = hollowNodes.get( targetNodeId ); // target node
|
||||
if ( tn == null ) // node not yet known, create a new hollow proxy
|
||||
{
|
||||
tn = new OsmNode( linklon, linklat );
|
||||
tn.setHollow();
|
||||
hollowNodes.put( tn );
|
||||
}
|
||||
link = new OsmLink();
|
||||
link.targetNode = tn;
|
||||
link.counterLinkWritten = counterLinkWritten;
|
||||
link.state = 1;
|
||||
addLink( link );
|
||||
}
|
||||
|
||||
// now we have a link with a target node -> get the reverse link
|
||||
OsmLink rlink = link.targetNode.getCompatibleLink( ilon, ilat, !counterLinkWritten, 1 );
|
||||
if ( rlink == null ) // .. not found, create it
|
||||
{
|
||||
rlink = new OsmLink();
|
||||
rlink.targetNode = this;
|
||||
rlink.counterLinkWritten = !counterLinkWritten;
|
||||
rlink.state = 2;
|
||||
link.targetNode.addLink( rlink );
|
||||
}
|
||||
|
||||
if ( !counterLinkWritten )
|
||||
{
|
||||
// we have the data for that link, so fill both the link ..
|
||||
link.descriptionBitmap = description;
|
||||
link.encodeFirsttransfer( firstTransferNode );
|
||||
|
||||
// .. and the reverse
|
||||
if ( rlink.counterLinkWritten )
|
||||
{
|
||||
rlink.descriptionBitmap = description; // default for no
|
||||
// transfer-nodes
|
||||
OsmTransferNode previous = null;
|
||||
OsmTransferNode rtrans = null;
|
||||
for ( OsmTransferNode trans = firstTransferNode; trans != null; trans = trans.next )
|
||||
{
|
||||
if ( previous == null )
|
||||
{
|
||||
rlink.descriptionBitmap = trans.descriptionBitmap;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous.descriptionBitmap = trans.descriptionBitmap;
|
||||
}
|
||||
rtrans = new OsmTransferNode();
|
||||
rtrans.ilon = trans.ilon;
|
||||
rtrans.ilat = trans.ilat;
|
||||
rtrans.selev = trans.selev;
|
||||
rtrans.next = previous;
|
||||
rtrans.descriptionBitmap = description;
|
||||
previous = rtrans;
|
||||
}
|
||||
rlink.encodeFirsttransfer( rtrans );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if ( dc == null )
|
||||
{
|
||||
hollowNodes.remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHollow()
|
||||
{
|
||||
return selev == -12345;
|
||||
}
|
||||
|
||||
public void setHollow()
|
||||
{
|
||||
selev = -12345;
|
||||
}
|
||||
|
||||
public long getIdFromPos()
|
||||
{
|
||||
return ( (long) ilon ) << 32 | ilat;
|
||||
}
|
||||
|
||||
public void unlinkLink( OsmLink link )
|
||||
{
|
||||
if ( link == firstlink )
|
||||
{
|
||||
firstlink = link.next;
|
||||
return;
|
||||
}
|
||||
for ( OsmLink l = firstlink; l != null; l = l.next )
|
||||
{
|
||||
if ( l.next == link )
|
||||
{
|
||||
l.next = link.next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object o )
|
||||
{
|
||||
if ( o instanceof OsmNode )
|
||||
{
|
||||
OsmNode n = (OsmNode) o;
|
||||
return n.ilon == ilon && n.ilat == ilat;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return ilon + ilat;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@
|
|||
*/
|
||||
package btools.mapaccess;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import btools.codec.DataBuffers;
|
||||
import btools.util.ByteDataReader;
|
||||
import btools.util.Crc32;
|
||||
|
||||
|
|
@ -21,6 +24,8 @@ final public class PhysicalFile
|
|||
|
||||
String fileName;
|
||||
|
||||
public int divisor = 80;
|
||||
|
||||
/**
|
||||
* Checks the integrity of the file using the build-in checksums
|
||||
*
|
||||
|
|
@ -28,39 +33,50 @@ final public class PhysicalFile
|
|||
*/
|
||||
public static String checkFileIntegrity( File f )
|
||||
{
|
||||
PhysicalFile pf = null;
|
||||
try
|
||||
{
|
||||
byte[] iobuffer = new byte[65636];
|
||||
pf = new PhysicalFile( f, new byte[65636], -1, -1 );
|
||||
for( int tileIndex=0; tileIndex<25; tileIndex++ )
|
||||
{
|
||||
OsmFile osmf = new OsmFile( pf, tileIndex, iobuffer );
|
||||
if ( osmf.microCaches != null )
|
||||
for( int lonIdx80=0; lonIdx80<80; lonIdx80++ )
|
||||
for( int latIdx80=0; latIdx80<80; latIdx80++ )
|
||||
new MicroCache( osmf, lonIdx80, latIdx80, iobuffer );
|
||||
}
|
||||
}
|
||||
catch( IllegalArgumentException iae )
|
||||
{
|
||||
return iae.getMessage();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
return e.toString();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( pf != null ) try{ pf.ra.close(); } catch( Exception ee ) {}
|
||||
}
|
||||
return null;
|
||||
PhysicalFile pf = null;
|
||||
try
|
||||
{
|
||||
DataBuffers dataBuffers = new DataBuffers();
|
||||
pf = new PhysicalFile( f, dataBuffers, -1, -1 );
|
||||
int div = pf.divisor;
|
||||
for ( int lonDegree = 0; lonDegree < 5; lonDegree++ ) // does'nt really matter..
|
||||
{
|
||||
for ( int latDegree = 0; latDegree < 5; latDegree++ ) // ..where on earth we are
|
||||
{
|
||||
OsmFile osmf = new OsmFile( pf, lonDegree, latDegree, dataBuffers );
|
||||
if ( osmf.hasData() )
|
||||
for ( int lonIdx = 0; lonIdx < div; lonIdx++ )
|
||||
for ( int latIdx = 0; latIdx < div; latIdx++ )
|
||||
osmf.createMicroCache( lonDegree * div + lonIdx, latDegree * div + latIdx, dataBuffers, null, null, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException iae)
|
||||
{
|
||||
return iae.getMessage();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.toString();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( pf != null )
|
||||
try
|
||||
{
|
||||
pf.ra.close();
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PhysicalFile( File f, byte[] iobuffer, int lookupVersion, int lookupMinorVersion ) throws Exception
|
||||
public PhysicalFile( File f, DataBuffers dataBuffers, int lookupVersion, int lookupMinorVersion ) throws Exception
|
||||
{
|
||||
fileName = f.getName();
|
||||
|
||||
byte[] iobuffer = dataBuffers.iobuffer;
|
||||
ra = new RandomAccessFile( f, "r" );
|
||||
ra.readFully( iobuffer, 0, 200 );
|
||||
fileIndexCrc = Crc32.crc( iobuffer, 0, 200 );
|
||||
|
|
@ -99,7 +115,17 @@ final public class PhysicalFile
|
|||
ra.readFully( iobuffer, 0, extraLen );
|
||||
dis = new ByteDataReader( iobuffer );
|
||||
creationTime = dis.readLong();
|
||||
if ( dis.readInt() != fileIndexCrc )
|
||||
|
||||
int crcData = dis.readInt();
|
||||
if ( crcData == fileIndexCrc )
|
||||
{
|
||||
divisor = 80; // old format
|
||||
}
|
||||
else if ( (crcData ^ 2) == fileIndexCrc )
|
||||
{
|
||||
divisor = 32; // new format
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException( "top index checksum error" );
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue