314 lines
6.7 KiB
Java
314 lines
6.7 KiB
Java
/**
|
|
* Container for an osm node
|
|
*
|
|
* @author ab
|
|
*/
|
|
package btools.mapaccess;
|
|
|
|
import btools.codec.MicroCache;
|
|
import btools.codec.MicroCache2;
|
|
import btools.util.ByteArrayUnifier;
|
|
import btools.util.CheapRuler;
|
|
import btools.util.IByteArrayUnifier;
|
|
|
|
public class OsmNode extends OsmLink implements OsmPos
|
|
{
|
|
/**
|
|
* The latitude
|
|
*/
|
|
public int ilat;
|
|
|
|
/**
|
|
* The longitude
|
|
*/
|
|
public int ilon;
|
|
|
|
/**
|
|
* The elevation
|
|
*/
|
|
public short selev;
|
|
|
|
/**
|
|
* The node-tags, if any
|
|
*/
|
|
public byte[] nodeDescription;
|
|
|
|
public TurnRestriction firstRestriction;
|
|
|
|
public int visitID;
|
|
|
|
public void addTurnRestriction( TurnRestriction tr )
|
|
{
|
|
tr.next = firstRestriction;
|
|
firstRestriction = tr;
|
|
}
|
|
|
|
/**
|
|
* The links to other nodes
|
|
*/
|
|
public OsmLink firstlink;
|
|
|
|
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 );
|
|
}
|
|
|
|
|
|
// interface OsmPos
|
|
public final int getILat()
|
|
{
|
|
return ilat;
|
|
}
|
|
|
|
public final int getILon()
|
|
{
|
|
return ilon;
|
|
}
|
|
|
|
public final short getSElev()
|
|
{
|
|
return selev;
|
|
}
|
|
|
|
public final double getElev()
|
|
{
|
|
return selev / 4.;
|
|
}
|
|
|
|
public final void addLink( OsmLink link, boolean isReverse, OsmNode tn )
|
|
{
|
|
if ( link == firstlink )
|
|
{
|
|
throw new IllegalArgumentException( "UUUUPS" );
|
|
}
|
|
|
|
if ( isReverse )
|
|
{
|
|
link.n1 = tn;
|
|
link.n2 = this;
|
|
link.next = tn.firstlink;
|
|
link.previous = firstlink;
|
|
tn.firstlink = link;
|
|
firstlink = link;
|
|
}
|
|
else
|
|
{
|
|
link.n1 = this;
|
|
link.n2 = tn;
|
|
link.next = firstlink;
|
|
link.previous = tn.firstlink;
|
|
tn.firstlink = link;
|
|
firstlink = link;
|
|
}
|
|
}
|
|
|
|
public final int calcDistance( OsmPos p )
|
|
{
|
|
return (int)(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat()) + 1.0 );
|
|
}
|
|
|
|
public String toString()
|
|
{
|
|
return "n_" + (ilon-180000000) + "_" + (ilat-90000000);
|
|
}
|
|
|
|
public final void parseNodeBody( MicroCache mc, OsmNodesMap hollowNodes, IByteArrayUnifier expCtxWay )
|
|
{
|
|
if ( mc instanceof MicroCache2 )
|
|
{
|
|
parseNodeBody2( (MicroCache2) mc, hollowNodes, expCtxWay );
|
|
}
|
|
else
|
|
throw new IllegalArgumentException( "unknown cache version: " + mc.getClass() );
|
|
}
|
|
|
|
public final void parseNodeBody2( MicroCache2 mc, OsmNodesMap hollowNodes, IByteArrayUnifier expCtxWay )
|
|
{
|
|
ByteArrayUnifier abUnifier = hollowNodes.getByteArrayUnifier();
|
|
|
|
// read turn restrictions
|
|
while( mc.readBoolean() )
|
|
{
|
|
TurnRestriction tr = new TurnRestriction();
|
|
tr.exceptions = mc.readShort();
|
|
tr.isPositive = mc.readBoolean();
|
|
tr.fromLon = mc.readInt();
|
|
tr.fromLat = mc.readInt();
|
|
tr.toLon = mc.readInt();
|
|
tr.toLat = mc.readInt();
|
|
addTurnRestriction( tr );
|
|
}
|
|
|
|
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, expCtxWay );
|
|
}
|
|
byte[] geometry = mc.readDataUntil( endPointer );
|
|
|
|
addLink( linklon, linklat, description, geometry, hollowNodes, isReverse );
|
|
}
|
|
hollowNodes.remove( this );
|
|
}
|
|
|
|
public void addLink( int linklon, int linklat, byte[] description, byte[] geometry, OsmNodesMap hollowNodes, boolean isReverse )
|
|
{
|
|
if ( linklon == ilon && linklat == ilat )
|
|
{
|
|
return; // skip self-ref
|
|
}
|
|
|
|
OsmNode tn = null; // find the target node
|
|
OsmLink link = null;
|
|
|
|
// ...in our known links
|
|
for ( OsmLink l = firstlink; l != null; l = l.getNext( this ) )
|
|
{
|
|
OsmNode t = l.getTarget( this );
|
|
if ( t.ilon == linklon && t.ilat == linklat )
|
|
{
|
|
tn = t;
|
|
if ( isReverse || ( l.descriptionBitmap == null && !l.isReverse( this ) ) )
|
|
{
|
|
link = l; // the correct one that needs our data
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
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 = new OsmNode( linklon, linklat );
|
|
tn.setHollow();
|
|
hollowNodes.put( tn );
|
|
addLink( link = tn, isReverse, tn ); // technical inheritance: link instance in node
|
|
}
|
|
}
|
|
if ( link == null )
|
|
{
|
|
addLink( link = new OsmLink(), isReverse, tn );
|
|
}
|
|
if ( !isReverse )
|
|
{
|
|
link.descriptionBitmap = description;
|
|
link.geometry = geometry;
|
|
}
|
|
}
|
|
|
|
|
|
public final boolean isHollow()
|
|
{
|
|
return selev == -12345;
|
|
}
|
|
|
|
public final void setHollow()
|
|
{
|
|
selev = -12345;
|
|
}
|
|
|
|
public final long getIdFromPos()
|
|
{
|
|
return ( (long) ilon ) << 32 | ilat;
|
|
}
|
|
|
|
public void vanish()
|
|
{
|
|
if ( !isHollow() )
|
|
{
|
|
OsmLink l = firstlink;
|
|
while( l != null )
|
|
{
|
|
OsmNode target = l.getTarget( this );
|
|
OsmLink nextLink = l.getNext( this );
|
|
if ( !target.isHollow() )
|
|
{
|
|
unlinkLink( l );
|
|
if ( !l.isLinkUnused() )
|
|
{
|
|
target.unlinkLink( l );
|
|
}
|
|
}
|
|
l = nextLink;
|
|
}
|
|
}
|
|
}
|
|
|
|
public final void unlinkLink( OsmLink link )
|
|
{
|
|
OsmLink n = link.clear( this );
|
|
|
|
if ( link == firstlink )
|
|
{
|
|
firstlink = n;
|
|
return;
|
|
}
|
|
OsmLink l = firstlink;
|
|
while( l != null )
|
|
{
|
|
// if ( l.isReverse( this ) )
|
|
if ( l.n1 != this && l.n1 != null ) // isReverse inline
|
|
{
|
|
OsmLink nl = l.previous;
|
|
if ( nl == link )
|
|
{
|
|
l.previous = n;
|
|
return;
|
|
}
|
|
l = nl;
|
|
}
|
|
else if ( l.n2 != this && l.n2 != null )
|
|
{
|
|
OsmLink nl = l.next;
|
|
if ( nl == link )
|
|
{
|
|
l.next = n;
|
|
return;
|
|
}
|
|
l = nl;
|
|
}
|
|
else
|
|
{
|
|
throw new IllegalArgumentException( "unlinkLink: unknown source" );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public final boolean equals( Object o )
|
|
{
|
|
return ((OsmNode)o).ilon == ilon && ((OsmNode)o).ilat == ilat;
|
|
}
|
|
|
|
@Override
|
|
public final int hashCode()
|
|
{
|
|
return ilon + ilat;
|
|
}
|
|
}
|