brouter/brouter-mapaccess/src/main/java/btools/mapaccess/DirectWeaver.java
2023-04-29 19:04:52 +02:00

199 lines
6.9 KiB
Java

package btools.mapaccess;
import btools.codec.DataBuffers;
import btools.codec.NoisyDiffCoder;
import btools.codec.StatCoderContext;
import btools.codec.TagValueCoder;
import btools.codec.TagValueValidator;
import btools.codec.TagValueWrapper;
import btools.codec.WaypointMatcher;
import btools.util.ByteDataWriter;
/**
* DirectWeaver does the same decoding as MicroCache2, but decodes directly
* into the instance-graph, not into the intermediate nodes-cache
*/
public final class DirectWeaver extends ByteDataWriter {
private long id64Base;
public DirectWeaver(StatCoderContext bc, DataBuffers dataBuffers, int lonIdx, int latIdx, int divisor, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes) {
super(null);
int cellsize = 1000000 / divisor;
id64Base = ((long) (lonIdx * cellsize)) << 32 | (latIdx * cellsize);
TagValueCoder wayTagCoder = new TagValueCoder(bc, dataBuffers, wayValidator);
TagValueCoder nodeTagCoder = new TagValueCoder(bc, dataBuffers, null);
NoisyDiffCoder nodeIdxDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder nodeEleDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLonDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder extLatDiff = new NoisyDiffCoder(bc);
NoisyDiffCoder transEleDiff = new NoisyDiffCoder(bc);
int size = bc.decodeNoisyNumber(5);
int[] faid = size > dataBuffers.ibuf2.length ? new int[size] : dataBuffers.ibuf2;
bc.decodeSortedArray(faid, 0, size, 29, 0);
OsmNode[] nodes = new OsmNode[size];
for (int n = 0; n < size; n++) {
long id = expandId(faid[n]);
int ilon = (int) (id >> 32);
int ilat = (int) (id & 0xffffffff);
OsmNode node = hollowNodes.get(ilon, ilat);
if (node == null) {
node = new OsmNode(ilon, ilat);
} else {
node.visitID = 1;
hollowNodes.remove(node);
}
nodes[n] = node;
}
int netdatasize = bc.decodeNoisyNumber(10); // (not needed for direct weaving)
ab = dataBuffers.bbuf1;
aboffset = 0;
int selev = 0;
for (int n = 0; n < size; n++) { // loop over nodes
OsmNode node = nodes[n];
int ilon = node.ilon;
int ilat = node.ilat;
// future escapes (turn restrictions?)
short trExceptions = 0;
for (; ; ) {
int featureId = bc.decodeVarBits();
if (featureId == 0) break;
int bitsize = bc.decodeNoisyNumber(5);
if (featureId == 2) { // exceptions to turn-restriction
trExceptions = (short) bc.decodeBounded(1023);
} else if (featureId == 1) { // turn-restriction
TurnRestriction tr = new TurnRestriction();
tr.exceptions = trExceptions;
trExceptions = 0;
tr.isPositive = bc.decodeBit();
tr.fromLon = ilon + bc.decodeNoisyDiff(10);
tr.fromLat = ilat + bc.decodeNoisyDiff(10);
tr.toLon = ilon + bc.decodeNoisyDiff(10);
tr.toLat = ilat + bc.decodeNoisyDiff(10);
node.addTurnRestriction(tr);
} else {
for (int i = 0; i < bitsize; i++) bc.decodeBit(); // unknown feature, just skip
}
}
selev += nodeEleDiff.decodeSignedValue();
node.selev = (short) selev;
TagValueWrapper nodeTags = nodeTagCoder.decodeTagValueSet();
node.nodeDescription = nodeTags == null ? null : nodeTags.data; // TODO: unified?
int links = bc.decodeNoisyNumber(1);
for (int li = 0; li < links; li++) {
int nodeIdx = n + nodeIdxDiff.decodeSignedValue();
int dlon_remaining;
int dlat_remaining;
boolean isReverse = false;
if (nodeIdx != n) { // internal (forward-) link
dlon_remaining = nodes[nodeIdx].ilon - ilon;
dlat_remaining = nodes[nodeIdx].ilat - ilat;
} else {
isReverse = bc.decodeBit();
dlon_remaining = extLonDiff.decodeSignedValue();
dlat_remaining = extLatDiff.decodeSignedValue();
}
TagValueWrapper wayTags = wayTagCoder.decodeTagValueSet();
int linklon = ilon + dlon_remaining;
int linklat = ilat + dlat_remaining;
aboffset = 0;
if (!isReverse) { // write geometry for forward links only
WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher;
int ilontarget = ilon + dlon_remaining;
int ilattarget = ilat + dlat_remaining;
if (matcher != null) {
if (!matcher.start(ilon, ilat, ilontarget, ilattarget)) {
matcher = null;
}
}
int transcount = bc.decodeVarBits();
int count = transcount + 1;
for (int i = 0; i < transcount; i++) {
int dlon = bc.decodePredictedValue(dlon_remaining / count);
int dlat = bc.decodePredictedValue(dlat_remaining / count);
dlon_remaining -= dlon;
dlat_remaining -= dlat;
count--;
int elediff = transEleDiff.decodeSignedValue();
if (wayTags != null) {
writeVarLengthSigned(dlon);
writeVarLengthSigned(dlat);
writeVarLengthSigned(elediff);
}
if (matcher != null)
matcher.transferNode(ilontarget - dlon_remaining, ilattarget - dlat_remaining);
}
if (matcher != null) matcher.end();
}
if (wayTags != null) {
byte[] geometry = null;
if (aboffset > 0) {
geometry = new byte[aboffset];
System.arraycopy(ab, 0, geometry, 0, aboffset);
}
if (nodeIdx != n) { // valid internal (forward-) link
OsmNode node2 = nodes[nodeIdx];
OsmLink link = node.isLinkUnused() ? node : (node2.isLinkUnused() ? node2 : null);
if (link == null) {
link = new OsmLink();
}
link.descriptionBitmap = wayTags.data;
link.geometry = geometry;
node.addLink(link, isReverse, node2);
} else { // weave external link
node.addLink(linklon, linklat, wayTags.data, geometry, hollowNodes, isReverse);
node.visitID = 1;
}
}
} // ... loop over links
} // ... loop over nodes
hollowNodes.cleanupAndCount(nodes);
}
private static final long[] id32_00 = new long[1024];
private static final long[] id32_10 = new long[1024];
private static final long[] id32_20 = new long[1024];
static {
for (int i = 0; i < 1024; i++) {
id32_00[i] = _expandId(i);
id32_10[i] = _expandId(i << 10);
id32_20[i] = _expandId(i << 20);
}
}
private static long _expandId(int id32) {
int dlon = 0;
int dlat = 0;
for (int bm = 1; bm < 0x8000; bm <<= 1) {
if ((id32 & 1) != 0) dlon |= bm;
if ((id32 & 2) != 0) dlat |= bm;
id32 >>= 2;
}
return ((long) dlon) << 32 | dlat;
}
public long expandId(int id32) {
return id64Base + id32_00[id32 & 1023] + id32_10[(id32 >> 10) & 1023] + id32_20[(id32 >> 20) & 1023];
}
}