301 lines
8.1 KiB
Java
301 lines
8.1 KiB
Java
/**
|
|
* Container for an osm node (pre-pocessor version)
|
|
*
|
|
* @author ab
|
|
*/
|
|
package btools.mapcreator;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
|
|
import btools.codec.MicroCache;
|
|
import btools.codec.MicroCache2;
|
|
|
|
public class OsmNodeP extends OsmLinkP {
|
|
/**
|
|
* The latitude
|
|
*/
|
|
public int ilat;
|
|
|
|
/**
|
|
* The longitude
|
|
*/
|
|
public int ilon;
|
|
|
|
/**
|
|
* The elevation
|
|
*/
|
|
public short selev;
|
|
|
|
public final static int NO_BRIDGE_BIT = 1;
|
|
public final static int NO_TUNNEL_BIT = 2;
|
|
public final static int BORDER_BIT = 4;
|
|
public final static int TRAFFIC_BIT = 8;
|
|
public final static int ANY_WAY_BIT = 16;
|
|
public final static int MULTI_WAY_BIT = 32;
|
|
public final static int DP_SURVIVOR_BIT = 64;
|
|
|
|
public byte bits = 0;
|
|
|
|
// interface OsmPos
|
|
public int getILat() {
|
|
return ilat;
|
|
}
|
|
|
|
public int getILon() {
|
|
return ilon;
|
|
}
|
|
|
|
public short getSElev() {
|
|
// if all bridge or all tunnel, elevation=no-data
|
|
return (bits & NO_BRIDGE_BIT) == 0 || (bits & NO_TUNNEL_BIT) == 0 ? Short.MIN_VALUE : selev;
|
|
}
|
|
|
|
public double getElev() {
|
|
return selev / 4.;
|
|
}
|
|
|
|
// populate and return the inherited link, if available,
|
|
// else create a new one
|
|
public OsmLinkP createLink(OsmNodeP source) {
|
|
if (sourceNode == null && targetNode == null) {
|
|
// inherited instance is available, use this
|
|
sourceNode = source;
|
|
targetNode = this;
|
|
source.addLink(this);
|
|
return this;
|
|
}
|
|
OsmLinkP link = new OsmLinkP(source, this);
|
|
addLink(link);
|
|
source.addLink(link);
|
|
return link;
|
|
}
|
|
|
|
// memory-squeezing-hack: OsmLinkP's "previous" also used as firstlink..
|
|
|
|
public void addLink(OsmLinkP link) {
|
|
link.setNext(previous, this);
|
|
previous = link;
|
|
}
|
|
|
|
public OsmLinkP getFirstLink() {
|
|
return sourceNode == null && targetNode == null ? previous : this;
|
|
}
|
|
|
|
public byte[] getNodeDecsription() {
|
|
return null;
|
|
}
|
|
|
|
public RestrictionData getFirstRestriction() {
|
|
return null;
|
|
}
|
|
|
|
public void writeNodeData(MicroCache mc, OsmTrafficMap trafficMap) throws IOException {
|
|
boolean valid = true;
|
|
if (mc instanceof MicroCache2) {
|
|
valid = writeNodeData2((MicroCache2) mc, trafficMap);
|
|
} else
|
|
throw new IllegalArgumentException("unknown cache version: " + mc.getClass());
|
|
if (valid) {
|
|
mc.finishNode(getIdFromPos());
|
|
} else {
|
|
mc.discardNode();
|
|
}
|
|
}
|
|
|
|
public void checkDuplicateTargets() {
|
|
HashMap<OsmNodeP, OsmLinkP> targets = new HashMap<>();
|
|
|
|
for (OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext(this)) {
|
|
OsmLinkP link = link0;
|
|
OsmNodeP origin = this;
|
|
OsmNodeP target = null;
|
|
|
|
// first pass just to see if that link is consistent
|
|
while (link != null) {
|
|
target = link.getTarget(origin);
|
|
if (!target.isTransferNode()) {
|
|
break;
|
|
}
|
|
// next link is the one (of two), does does'nt point back
|
|
for (link = target.getFirstLink(); link != null; link = link.getNext(target)) {
|
|
if (link.getTarget(target) != origin)
|
|
break;
|
|
}
|
|
origin = target;
|
|
}
|
|
if (link == null) continue;
|
|
OsmLinkP oldLink = targets.put(target, link0);
|
|
if (oldLink != null) {
|
|
unifyLink(oldLink);
|
|
unifyLink(link0);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void unifyLink(OsmLinkP link) {
|
|
if (link.isReverse(this)) return;
|
|
OsmNodeP target = link.getTarget(this);
|
|
if (target.isTransferNode()) {
|
|
target.incWayCount();
|
|
}
|
|
}
|
|
|
|
public boolean writeNodeData2(MicroCache2 mc, OsmTrafficMap trafficMap) throws IOException {
|
|
boolean hasLinks = false;
|
|
|
|
// write turn restrictions
|
|
RestrictionData r = getFirstRestriction();
|
|
while (r != null) {
|
|
if (r.isValid() && r.fromLon != 0 && r.toLon != 0) {
|
|
mc.writeBoolean(true); // restriction follows
|
|
mc.writeShort(r.exceptions);
|
|
mc.writeBoolean(r.isPositive());
|
|
mc.writeInt(r.fromLon);
|
|
mc.writeInt(r.fromLat);
|
|
mc.writeInt(r.toLon);
|
|
mc.writeInt(r.toLat);
|
|
}
|
|
r = r.next;
|
|
}
|
|
mc.writeBoolean(false); // end restritions
|
|
|
|
mc.writeShort(getSElev());
|
|
mc.writeVarBytes(getNodeDecsription());
|
|
|
|
// buffer internal reverse links
|
|
ArrayList<OsmNodeP> internalReverse = new ArrayList<>();
|
|
|
|
for (OsmLinkP link0 = getFirstLink(); link0 != null; link0 = link0.getNext(this)) {
|
|
OsmLinkP link = link0;
|
|
OsmNodeP origin = this;
|
|
OsmNodeP target = null;
|
|
|
|
ArrayList<OsmNodeP> linkNodes = new ArrayList<>();
|
|
linkNodes.add(this);
|
|
|
|
// first pass just to see if that link is consistent
|
|
while (link != null) {
|
|
target = link.getTarget(origin);
|
|
linkNodes.add(target);
|
|
|
|
if (!target.isTransferNode()) {
|
|
break;
|
|
}
|
|
// next link is the one (of two), does does'nt point back
|
|
for (link = target.getFirstLink(); link != null; link = link.getNext(target)) {
|
|
if (link.getTarget(target) != origin)
|
|
break;
|
|
}
|
|
|
|
if (link != null && link.descriptionBitmap != link0.descriptionBitmap) {
|
|
throw new IllegalArgumentException("assertion failed: description change along transfer nodes");
|
|
}
|
|
|
|
origin = target;
|
|
}
|
|
if (link == null)
|
|
continue; // dead end
|
|
if (target == this)
|
|
continue; // self-ref
|
|
hasLinks = true;
|
|
|
|
// internal reverse links later
|
|
boolean isReverse = link0.isReverse(this);
|
|
if (isReverse) {
|
|
if (mc.isInternal(target.ilon, target.ilat)) {
|
|
internalReverse.add(target);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// add traffic simulation, if present
|
|
byte[] description = link0.descriptionBitmap;
|
|
if (trafficMap != null) {
|
|
description = trafficMap.addTrafficClass(linkNodes, description);
|
|
}
|
|
|
|
// write link data
|
|
int sizeoffset = mc.writeSizePlaceHolder();
|
|
mc.writeVarLengthSigned(target.ilon - ilon);
|
|
mc.writeVarLengthSigned(target.ilat - ilat);
|
|
mc.writeModeAndDesc(isReverse, description);
|
|
if (!isReverse && linkNodes.size() > 2) { // write geometry for forward links only
|
|
DPFilter.doDPFilter(linkNodes);
|
|
origin = this;
|
|
for (int i = 1; i < linkNodes.size() - 1; i++) {
|
|
OsmNodeP tranferNode = linkNodes.get(i);
|
|
if ((tranferNode.bits & OsmNodeP.DP_SURVIVOR_BIT) != 0) {
|
|
mc.writeVarLengthSigned(tranferNode.ilon - origin.ilon);
|
|
mc.writeVarLengthSigned(tranferNode.ilat - origin.ilat);
|
|
mc.writeVarLengthSigned(tranferNode.getSElev() - origin.getSElev());
|
|
origin = tranferNode;
|
|
}
|
|
}
|
|
}
|
|
mc.injectSize(sizeoffset);
|
|
}
|
|
|
|
while (internalReverse.size() > 0) {
|
|
int nextIdx = 0;
|
|
if (internalReverse.size() > 1) {
|
|
int max32 = Integer.MIN_VALUE;
|
|
for (int i = 0; i < internalReverse.size(); i++) {
|
|
int id32 = mc.shrinkId(internalReverse.get(i).getIdFromPos());
|
|
if (id32 > max32) {
|
|
max32 = id32;
|
|
nextIdx = i;
|
|
}
|
|
}
|
|
}
|
|
OsmNodeP target = internalReverse.remove(nextIdx);
|
|
int sizeoffset = mc.writeSizePlaceHolder();
|
|
mc.writeVarLengthSigned(target.ilon - ilon);
|
|
mc.writeVarLengthSigned(target.ilat - ilat);
|
|
mc.writeModeAndDesc(true, null);
|
|
mc.injectSize(sizeoffset);
|
|
}
|
|
return hasLinks;
|
|
}
|
|
|
|
public String toString2() {
|
|
return (ilon - 180000000) + "_" + (ilat - 90000000) + "_" + (selev / 4);
|
|
}
|
|
|
|
public long getIdFromPos() {
|
|
return ((long) ilon) << 32 | ilat;
|
|
}
|
|
|
|
public boolean isBorderNode() {
|
|
return (bits & BORDER_BIT) != 0;
|
|
}
|
|
|
|
public boolean hasTraffic() {
|
|
return (bits & TRAFFIC_BIT) != 0;
|
|
}
|
|
|
|
/**
|
|
* Not really count the ways, just detect if more than one
|
|
*/
|
|
public void incWayCount() {
|
|
if ((bits & ANY_WAY_BIT) != 0) {
|
|
bits |= MULTI_WAY_BIT;
|
|
}
|
|
bits |= ANY_WAY_BIT;
|
|
}
|
|
|
|
public boolean isTransferNode() {
|
|
return (bits & BORDER_BIT) == 0 && (bits & MULTI_WAY_BIT) == 0 && _linkCnt() == 2;
|
|
}
|
|
|
|
private int _linkCnt() {
|
|
int cnt = 0;
|
|
|
|
for (OsmLinkP link = getFirstLink(); link != null; link = link.getNext(this)) {
|
|
cnt++;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
}
|