262 lines
6.3 KiB
Java
262 lines
6.3 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 = Short.MIN_VALUE;
|
|
|
|
/**
|
|
* 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) Math.max(1.0, Math.round(CheapRuler.distance(ilon, ilat, p.getILon(), p.getILat())));
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|