1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-30 22:51:16 +01:00
This commit is contained in:
Martin Tůma 2020-09-18 20:56:00 +02:00
parent 0e026d6a96
commit d738ad7b5a
11 changed files with 1016 additions and 188 deletions

View File

@ -1,35 +1,6 @@
#include "bitstream.h"
bool BitStream1::read(int bits, quint32 &val)
{
val = 0;
for (int pos = 0; pos < bits; ) {
if (!_remaining) {
if (!_length || !_file.readUInt8(_hdl, _data))
return false;
_remaining = 8;
_length--;
}
quint32 get = bits - pos;
if (get >= _remaining) {
val |= _data << pos;
pos += _remaining;
_remaining = 0;
} else {
quint32 mask = (1<<get) - 1;
val |= (_data & mask)<<pos;
_data >>= get;
_remaining -= get;
break;
}
}
return true;
}
bool BitStream1::flush()
{
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
@ -41,7 +12,7 @@ bool BitStream1::flush()
return true;
}
bool BitStream4::flush()
bool BitStream4F::flush()
{
if (_length && !_file.seek(_hdl, _file.pos(_hdl) + _length))
return false;
@ -96,7 +67,14 @@ bool BitStream4R::readBytes(int bytes, quint32 &val)
Q_ASSERT(!b);
}
return read(bytes * 8, val);
val = 0;
for (int i = 0; i < bytes; i++) {
if (!read(8, b))
return false;
val |= (b << (i * 8));
}
return true;
}
bool BitStream4R::readVUInt32(quint32 &val)
@ -139,7 +117,7 @@ bool BitStream4R::readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits)
return false;
if (!(b & 1)) {
val1 = b >> 3 & 0x1f;
val1 = b >> 3;
val2 = b >> 1 & 3;
val2Bits = 2;
} else {
@ -188,14 +166,33 @@ bool BitStream4R::skip(quint32 bytes)
return true;
}
void BitStream4R::resize(quint32 length)
void BitStream4R::resize(quint32 bytes)
{
quint32 ab = (32 - _used)/8;
quint32 ab = (32 - (_used + _unused) + 7)/8;
if (ab < length)
_length = length - ab;
if (ab <= bytes)
_length = bytes - ab;
else {
_length = 0;
_used += length * 8;
_unused += (ab - bytes) * 8;
}
}
void BitStream4R::save(State &state)
{
state.pos = _file.pos(_hdl);
state.length = _length;
state.used = _used;
state.unused = _unused;
state.data = _data;
}
bool BitStream4R::restore(const State &state)
{
_length = state.length;
_used = state.used;
_unused = state.unused;
_data = state.data;
return _file.seek(_hdl, state.pos);
}

View File

@ -8,7 +8,7 @@ public:
BitStream1(const SubFile &file, SubFile::Handle &hdl, quint32 length)
: _file(file), _hdl(hdl), _length(length), _remaining(0) {}
bool read(int bits, quint32 &val);
template<typename T> bool read(int bits, T &val);
bool flush();
quint64 bitsAvailable() const {return (quint64)_length * 8 + _remaining;}
@ -25,7 +25,6 @@ public:
: _file(file), _hdl(hdl), _length(length), _used(32), _unused(0),
_data(0) {}
bool flush();
quint64 bitsAvailable() const
{return (quint64)_length * 8 + (32 - _used) - _unused;}
@ -42,10 +41,19 @@ public:
: BitStream4(file, hdl, length) {}
bool read(int bits, quint32 &val);
bool flush();
};
class BitStream4R : public BitStream4 {
public:
struct State {
quint32 pos;
quint32 length;
quint32 used;
quint32 unused;
quint32 data;
};
BitStream4R(const SubFile &file, SubFile::Handle &hdl, quint32 length);
template<typename T> bool read(int bits, T &val);
@ -54,9 +62,42 @@ public:
bool readVuint32SM(quint32 &val1, quint32 &val2, quint32 &val2Bits);
bool skip(quint32 bytes);
void resize(quint32 length);
void resize(quint32 bytes);
void save(State &state);
bool restore(const State &state);
};
template<typename T>
bool BitStream1::read(int bits, T &val)
{
val = 0;
for (int pos = 0; pos < bits; ) {
if (!_remaining) {
if (!_length || !_file.readUInt8(_hdl, _data))
return false;
_remaining = 8;
_length--;
}
quint32 get = bits - pos;
if (get >= _remaining) {
val |= _data << pos;
pos += _remaining;
_remaining = 0;
} else {
quint32 mask = (1<<get) - 1;
val |= (_data & mask)<<pos;
_data >>= get;
_remaining -= get;
break;
}
}
return true;
}
template<typename T>
bool BitStream4R::read(int bits, T &val)
{

View File

@ -28,3 +28,14 @@ bool HuffmanStreamR::init()
return true;
}
bool HuffmanStreamR::init(int lonSign, int latSign, quint32 data,
quint32 dataSize)
{
_lonSign = lonSign;
_latSign = latSign;
_symbolData = data;
_symbolDataSize = dataSize;
return true;
}

View File

@ -11,6 +11,8 @@ public:
: _bs(bitstream), _table(table), _symbolDataSize(0), _symbolData(0),
_lonSign(0), _latSign(0) {}
bool read(int bits, quint32 &val);
bool readSymbol(quint32 &symbol);
bool readNext(qint32 &lonDelta, qint32 &latDelta)
{
if (!(readDelta(_lonSign, lonDelta) && readDelta(_latSign, latDelta)))
@ -52,7 +54,31 @@ bool HuffmanStream<BitStream>::sign(int &val)
}
template <class BitStream>
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
bool HuffmanStream<BitStream>::read(int bits, quint32 &val)
{
if (_symbolDataSize < (quint32)bits) {
quint32 next;
quint8 nextSize = qMin((quint64)(32 - _symbolDataSize),
_bs.bitsAvailable());
if (!_bs.read(nextSize, next))
return false;
_symbolData = (_symbolData << nextSize) | next;
_symbolDataSize += nextSize;
}
if (_symbolDataSize < (quint32)bits)
return false;
val = (_symbolData << (32-_symbolDataSize)) >> (32 - bits);
_symbolDataSize -= bits;
return true;
}
template <class BitStream>
bool HuffmanStream<BitStream>::readSymbol(quint32 &symbol)
{
quint8 size;
quint32 next;
@ -65,10 +91,19 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
_symbolDataSize += nextSize;
symbol = _table.symbol(_symbolData << (32 - _symbolDataSize), size);
if (size > _symbolDataSize)
return false;
if (size <= _symbolDataSize)
_symbolDataSize -= size;
else
_symbolDataSize -= size;
return true;
}
template <class BitStream>
bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &delta)
{
quint32 symbol;
if (!readSymbol(symbol))
return false;
if (symbol && !sign) {
@ -79,7 +114,7 @@ bool HuffmanStream<BitStream>::readDelta(int sign, qint32 &symbol)
_symbolDataSize--;
}
}
symbol = sign * symbol;
delta = sign * symbol;
return true;
}
@ -100,6 +135,7 @@ public:
: HuffmanStream(bitstream, table) {}
bool init();
bool init(int lonSign, int latSign, quint32 data, quint32 dataSize);
};
#endif // HUFFMANSTREAM_H

View File

@ -2,10 +2,11 @@
#include "huffmanstream.h"
#include "subdiv.h"
#include "nodfile.h"
#include "lblfile.h"
#include "netfile.h"
bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
static bool readAdjCounts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
{
quint32 val, cnt, bits;
if (!bs.read(4, val))
@ -17,7 +18,6 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
if (cnt == 5) {
if (!bs.read(8, cnt))
return false;
Q_ASSERT(cnt > 4);
}
if (cnt < 2)
@ -30,14 +30,25 @@ bool adjCnts(BitStream4R &bs, QVector<quint16> &cnts, quint16 &mask)
return true;
}
bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
static bool skipShape(BitStream4R &bs)
{
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
return bs.skip(v1);
}
static bool skipAdjShapes(BitStream4R &bs, const QVector<quint16> &cnts,
quint16 mask, bool firstIsShape)
{
if (firstIsShape && !skipShape(bs))
return false;
for (int i = 0; i < cnts.size(); i++) {
if (cnts.at(i) & mask) {
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
if (!bs.skip(v1))
if (!skipShape(bs))
return false;
}
}
@ -45,7 +56,7 @@ bool skipNodes(BitStream4R &bs, const QVector<quint16> &cnts, quint16 mask)
return true;
}
bool seekToLevel(BitStream4R &bs, quint8 level)
static bool seekToLevel(BitStream4R &bs, quint8 level)
{
quint32 v1, v2, v2b;
@ -55,7 +66,6 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
if (!bs.skip(v1))
return false;
Q_ASSERT(!(v2 & 2));
if (v2 & 2)
return false;
if (v2 & 1)
@ -65,7 +75,7 @@ bool seekToLevel(BitStream4R &bs, quint8 level)
return true;
}
bool seekToLine(BitStream4R &bs, quint8 line)
static bool seekToLine(BitStream4R &bs, quint8 line)
{
quint32 v1, v2, v2b;
@ -75,7 +85,6 @@ bool seekToLine(BitStream4R &bs, quint8 line)
if (!bs.skip(v1))
return false;
Q_ASSERT(!(v2 & 2));
if (v2 & 2)
return false;
}
@ -83,15 +92,295 @@ bool seekToLine(BitStream4R &bs, quint8 line)
return true;
}
static bool readLine(BitStream4R &bs, const SubDiv *subdiv,
const HuffmanTable &table, IMG::Poly &poly)
{
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
bs.resize(v1);
quint32 lon, lat;
if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
return false;
if (2 < v2b)
lon |= (v2 >> 2) << (0x12U - v2b);
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon, 32-subdiv->bits()),
LS(subdiv->lat(), 8) + LS((qint16)lat, 32-subdiv->bits()));
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
HuffmanStreamR stream(bs, table);
if (!stream.init())
return false;
qint32 lonDelta, latDelta;
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += LS(lonDelta, 32-subdiv->bits());
if (pos.rx() < 0 && subdiv->lon() >= 0)
pos.rx() = 0x7fffffff;
pos.ry() += LS(latDelta, 32-subdiv->bits());
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
}
return stream.atEnd();
}
static bool readNodeGeometry(NODFile *nod, SubFile::Handle &nodHdl,
NODFile::AdjacencyInfo &adj, IMG::Poly &poly, quint16 cnt = 0xFFFF)
{
for (int i = 0; i <= cnt; i++) {
int ret = nod->nextNode(nodHdl, adj);
if (ret < 0)
return false;
else if (ret > 0)
return (cnt == 0xFFFF);
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
toWGS32(adj.nodeInfo.pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
}
return true;
}
static bool skipNodes(NODFile *nod, SubFile::Handle &nodHdl,
NODFile::AdjacencyInfo &adj, int cnt)
{
for (int i = 0; i < cnt; i++)
if (nod->nextNode(nodHdl, adj))
return false;
return true;
}
static bool readShape(NODFile *nod, SubFile::Handle &nodHdl,
NODFile::AdjacencyInfo &adj, BitStream4R &bs, const HuffmanTable &table,
const SubDiv *subdiv, quint32 shift, IMG::Poly &poly, quint16 cnt = 0xFFFF,
bool check = false)
{
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
BitStream4R::State state;
bs.save(state);
bs.resize(v1);
quint32 flags;
if (!bs.read(8, flags))
return false;
flags |= (v2 << 8);
bool hasCoordinatesAdjustBit = flags & (1 << (v2b + 7));
bool useEosBit = flags & (1 << (v2b + 5));
bool startWithStream = flags & (1 << (v2b + 6));
quint32 extraBits;
int lonSign, latSign;
if ((flags >> (v2b + 4) & 1) == 0) {
extraBits = v2b + 4;
lonSign = 0;
} else {
extraBits = v2b + 3;
lonSign = 1;
if ((flags >> (v2b + 3) & 1) != 0) {
lonSign = -1;
}
}
extraBits -= 1;
if ((flags >> extraBits & 1) == 0) {
latSign = 0;
} else {
extraBits -= 1;
latSign = -1;
if ((flags >> extraBits & 1) == 0) {
latSign = 1;
}
}
if (nod->nextNode(nodHdl, adj))
return false;
QPoint pos(adj.nodeInfo.pos);
quint16 nodes = 0;
if (!startWithStream) {
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
toWGS32(adj.nodeInfo.pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
while (!(adj.flags & 1)) {
int ret = nod->nextNode(nodHdl, adj);
if (ret < 0)
return false;
else if (ret > 0)
break;
nodes++;
c = Coordinates(toWGS32(adj.nodeInfo.pos.x()),
toWGS32(adj.nodeInfo.pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
pos = adj.nodeInfo.pos;
}
}
HuffmanStreamR stream(bs, table);
if (!stream.init(lonSign, latSign, flags, extraBits))
return false;
qint32 lonDelta, latDelta;
QVector<QPoint> deltas;
quint32 adjustBit = 0;
quint32 stepsCnt = 0;
quint32 steps = 0;
quint32 eos = 0;
while (true) {
if ((stepsCnt == steps) && !useEosBit) {
if (!stream.readSymbol(steps))
break;
if (!steps)
break;
}
if (!stream.readNext(lonDelta, latDelta))
break;
if (hasCoordinatesAdjustBit && !stream.read(1, adjustBit))
return false;
stepsCnt++;
if (useEosBit) {
if (!stream.read(1, eos))
return false;
} else {
if (steps == stepsCnt)
eos = 1;
}
if (!startWithStream) {
pos.rx() += LS(lonDelta, 32-subdiv->bits()-shift);
pos.ry() += LS(latDelta, 32-subdiv->bits()-shift);
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
} else {
deltas.append(QPoint(lonDelta, latDelta));
poly.points.append(QPointF());
}
if (startWithStream && eos) {
for (int i = deltas.size() - 1, j = 0; i >= 0; i--, j++) {
pos.rx() -= LS(deltas.at(i).x(), 32-subdiv->bits()-shift);
pos.ry() -= LS(deltas.at(i).y(), 32-subdiv->bits()-shift);
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points[poly.points.size() - 1 - j] = QPointF(c.lon(), c.lat());
poly.boundingRect = poly.boundingRect.united(c);
}
pos = adj.nodeInfo.pos;
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
stepsCnt = 0;
steps = 0;
startWithStream = false;
if (adj.flags & 1)
eos = 0;
}
if (eos) {
if (nodes >= cnt)
break;
do {
int ret = nod->nextNode(nodHdl, adj);
if (ret < 0)
return false;
else if (ret > 0)
break;
nodes++;
if (check && nodes == cnt) {
if (!(bs.restore(state) && bs.skip(v1)
&& bs.readVuint32SM(v1, v2, v2b)))
return false;
if (5 < v2b)
v2 >>= v2b - 2;
if (v2 & 1)
break;
}
Coordinates c(toWGS32(adj.nodeInfo.pos.x()),
toWGS32(adj.nodeInfo.pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
pos = adj.nodeInfo.pos;
} while (!(adj.flags & 1) && nodes < cnt);
if (nodes == cnt)
break;
steps = 0;
stepsCnt = 0;
eos = 0;
}
}
return true;
}
bool NETFile::linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
Handle &lblHdl, Label &label)
{
if (!seek(hdl, offset))
return false;
BitStream1 bs(*this, hdl, size);
quint32 flags, b, labelPtr = 0;
if (!bs.read(8, flags))
return false;
for (int i = 0; i < 3; i++) {
if (!bs.read(8, b))
return false;
labelPtr |= (b << (i * 8));
}
if (lbl && (labelPtr & 0x3FFFFF)) {
if (labelPtr & 0x400000) {
quint32 lblOff;
if (lblOffset(hdl, labelPtr & 0x3FFFFF, lblOff) && lblOff)
label = lbl->label(lblHdl, lblOff);
} else
label = lbl->label(lblHdl, labelPtr & 0x3FFFFF);
}
return true;
}
bool NETFile::init(Handle &hdl)
{
quint8 multiplier;
quint16 hdrLen;
if (!(seek(hdl, _gmpOffset) && readUInt16(hdl, hdrLen)
&& seek(hdl, _gmpOffset + 0x15) && readUInt32(hdl, _offset)
&& readUInt32(hdl, _size) && readUInt8(hdl, multiplier)))
&& readUInt32(hdl, _size) && readUInt8(hdl, _shift)))
return false;
if (hdrLen >= 0x47) {
@ -105,20 +394,25 @@ bool NETFile::init(Handle &hdl)
return false;
}
_multiplier = 1<<multiplier;
_init = true;
return true;
}
bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
Handle &nodHdl, const NODFile::BlockInfo blockInfo, quint8 linkId,
quint8 lineId, const HuffmanTable &table, QList<IMG::Poly> *lines)
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
const HuffmanTable &table, QList<IMG::Poly> *lines)
{
if (!_multiplier && !init(hdl))
if (!_init && !init(hdl))
return false;
// TODO
if (!subdiv->level())
Q_ASSERT(_tableId == table.id());
if (_tableId != table.id())
return false;
IMG::Poly poly;
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
return false;
NODFile::LinkInfo linkInfo;
@ -126,95 +420,89 @@ bool NETFile::link(const SubDiv *subdiv, Handle &hdl, NODFile *nod,
return false;
quint32 linkOffset = _linksOffset + (linkInfo.linkOffset << _linksShift);
Q_ASSERT(linkOffset <= _linksOffset + _linksSize);
if (linkOffset > _linksOffset + _linksSize)
return false;
if (!seek(hdl, linkOffset))
return false;
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
QVector<quint16> ca;
quint16 mask = 0;
quint32 size;
quint8 s68 = (linkInfo.flags >> 0x12) & 1;
quint8 s69 = (linkInfo.flags >> 0x11) & 1;
quint8 s6a = (linkInfo.flags >> 0x13) & 1;
if (s6a == 1) {
QVector<quint16> ca;
quint16 mask;
if (!seek(hdl, linkOffset))
return false;
BitStream4R bs(*this, hdl, linkOffset - _linksOffset);
quint32 size;
if (s69 == 0 || s6a == 1) {
if (!bs.readVUInt32(size))
return false;
if (s69 == 0) {
if (!adjCnts(bs, ca, mask))
return false;
}
if (s68 == 1) {
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
return false;
Q_ASSERT(v1);
if (!bs.skip(v1))
return false;
}
if (!skipNodes(bs, ca, mask))
}
if (s69 == 0) {
if (!readAdjCounts(bs, ca, mask))
return false;
}
if (!subdiv->level()) {
NODFile::AdjacencyInfo adj(nod, blockInfo, linkId, linkInfo);
if (s69 == 1) {
if (s68 == 1) {
if (!readShape(nod, nodHdl, adj, bs, table, subdiv, shift, poly))
return false;
} else {
if (!readNodeGeometry(nod, nodHdl, adj, poly))
return false;
}
} else {
quint16 mask2 = mask + 0xffff;
for (int i = 0; i <= ca.size(); i++) {
quint16 step = (i < ca.size()) ? ca.at(i) & mask2 : 0xFFFF;
bool shape = (i > 0) ? ca.at(i-1) & mask : (s68 == 1);
if (i == lineId) {
if (shape) {
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
if (!readShape(nod, nodHdl, adj, bs, table, subdiv,
shift, poly, step, check))
return false;
} else {
if (!readNodeGeometry(nod, nodHdl, adj, poly, step))
return false;
}
break;
}
if (shape && !skipShape(bs))
return false;
if (!skipNodes(nod, nodHdl, adj, step))
return false;
}
}
} else {
if (!skipAdjShapes(bs, ca, mask, s68 == 1))
return false;
if (!seekToLevel(bs, subdiv->level()))
return false;
if (!seekToLine(bs, lineId))
return false;
quint32 v1, v2, v2b;
if (!bs.readVuint32SM(v1, v2, v2b))
if (!readLine(bs, subdiv, table, poly))
return false;
bs.resize(v1);
quint32 lon, lat;
if (!(bs.read(0x12 - v2b, lon) && bs.read(16, lat)))
return false;
if (2 < v2b)
lon |= (v2 >> 2) << (0x12U - v2b);
QPoint pos = QPoint(LS(subdiv->lon(), 8) + LS((qint16)lon,
32-subdiv->bits()), LS(subdiv->lat(), 8) + LS((qint16)lat,
32-subdiv->bits()));
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
IMG::Poly poly;
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
return false;
poly.boundingRect = RectC(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
Q_ASSERT(_tableId == table.id());
HuffmanStreamR stream(bs, table);
if (!stream.init())
return false;
qint32 lonDelta, latDelta;
while (stream.readNext(lonDelta, latDelta)) {
pos.rx() += LS(lonDelta, 32-subdiv->bits());
if (pos.rx() < 0 && subdiv->lon() >= 0)
pos.rx() = 0x7fffffff;
pos.ry() += LS(latDelta, 32-subdiv->bits());
Coordinates c(toWGS32(pos.x()), toWGS32(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
poly.boundingRect = poly.boundingRect.united(c);
}
lines->append(poly);
}
linkLabel(hdl, linkOffset, _linksSize - (linkOffset - _linksOffset), lbl,
lblHdl, poly.label);
lines->append(poly);
return true;
}
bool NETFile::lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset)
{
if (!_multiplier && !init(hdl))
if (!_init && !init(hdl))
return false;
if (!(seek(hdl, _offset + netOffset * _multiplier)
if (!(seek(hdl, _offset + (netOffset << _shift))
&& readUInt24(hdl, lblOffset)))
return false;

View File

@ -14,24 +14,29 @@ class NETFile : public SubFile
{
public:
NETFile(IMG *img) : SubFile(img), _offset(0), _size(0), _linksOffset(0),
_linksSize(0), _multiplier(0), _linksShift(0) {}
_linksSize(0), _shift(0), _linksShift(0), _init(false) {}
NETFile(const QString &path) : SubFile(path), _offset(0), _size(0),
_linksOffset(0), _linksSize(0), _multiplier(0), _linksShift(0) {}
_linksOffset(0), _linksSize(0), _shift(0), _linksShift(0),
_init(false) {}
NETFile(SubFile *gmp, quint32 offset) : SubFile(gmp, offset),
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _multiplier(0),
_linksShift(0) {}
_offset(0), _size(0), _linksOffset(0), _linksSize(0), _shift(0),
_linksShift(0), _init(false) {}
bool lblOffset(Handle &hdl, quint32 netOffset, quint32 &lblOffset);
bool link(const SubDiv *subdiv, Handle &hdl, NODFile *nod, Handle &nodHdl,
bool link(const SubDiv *subdiv, quint32 shift, Handle &hdl, NODFile *nod,
Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
const NODFile::BlockInfo blockInfo, quint8 linkId, quint8 lineId,
const HuffmanTable &table, QList<IMG::Poly> *lines);
private:
bool init(Handle &hdl);
bool linkLabel(Handle &hdl, quint32 offset, quint32 size, LBLFile *lbl,
Handle &lblHdl, Label &label);
quint32 _offset, _size, _linksOffset, _linksSize;
quint8 _multiplier, _linksShift;
quint8 _shift, _linksShift;
quint8 _tableId;
bool _init;
};
#endif // NETFILE_H

View File

@ -1,6 +1,81 @@
#include "bitstream.h"
#include "nodfile.h"
#define ARRAY_SIZE(array) \
(sizeof(array) / sizeof(array[0]))
static const struct {
quint8 lon;
quint8 lat;
} LLBITS[] = {
{0xc, 0xc}, {0x8, 0x10}, {0x10, 0x8}, {0x10, 0x10}, {0xc, 0x14},
{0x14, 0xc}, {0x14, 0x14}
};
union NodeShift {
qint32 offset;
quint8 id;
};
static bool adjDistInfo(BitStream1 &bs, bool extraBit, quint8 &flags)
{
quint32 data, cnt;
if (!bs.read(extraBit | 8, data))
return false;
data <<= !extraBit;
flags |= (quint8)data & 1;
data >>= 1;
for (cnt = 0; (data >> cnt) & 1; cnt++) {
if (cnt == 4)
break;
}
if (!bs.read(cnt * 4, data))
return false;
return true;
}
static bool adjNodeInfo(BitStream1 &bs, bool extraBit, NodeShift &shift,
quint8 &flags)
{
quint32 data;
if (!bs.read(9, data))
return false;
data <<= !extraBit;
if (data & 1)
shift.id = data >> 1;
else {
quint32 bits = (data >> 1) & 7;
quint32 data2;
flags |= 2;
if (!bs.read(bits + extraBit + 1, data2))
return false;
data = data2 << (6 - extraBit) | data >> 4;
bits = 0x19 - bits;
shift.offset = ((qint32)(data << bits) >> bits);
}
return true;
}
static bool skipOptAdjData(BitStream1 &bs)
{
// TODO
Q_UNUSED(bs);
Q_ASSERT(false);
return false;
}
bool NODFile::init(Handle &hdl)
{
quint16 hdrLen;
@ -9,9 +84,10 @@ bool NODFile::init(Handle &hdl)
return false;
if (hdrLen >= 0x7b) {
if (!(seek(hdl, _gmpOffset + 0x21) && readUInt8(hdl, _blockShift)
&& readUInt8(hdl, _nodeShift)))
if (!(seek(hdl, _gmpOffset + 0x1d) && readUInt32(hdl, _flags)
&& readUInt8(hdl, _blockShift) && readUInt8(hdl, _nodeShift)))
return false;
if (!(seek(hdl, _gmpOffset + 0x67) && readUInt32(hdl, _blockOffset)
&& readUInt32(hdl, _blockSize) && readUInt16(hdl, _blockRecordSize)
&& readUInt32(hdl, _indexOffset) && readUInt32(hdl, _indexSize)
@ -38,42 +114,49 @@ quint32 NODFile::indexIdSize(Handle &hdl)
return 0;
}
bool NODFile::blockInfo(Handle &hdl, quint32 blockIndexId,
bool NODFile::readBlock(Handle &hdl, quint32 blockOffset,
BlockInfo &blockInfo) const
{
quint32 blockOffset;
quint32 offset = _indexRecordSize * blockIndexId + _indexOffset;
quint32 offsetSize = (_indexFlags & 3) + 1;
blockInfo.offset = blockOffset;
Q_ASSERT(offset <= _indexOffset + _indexSize);
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
return false;
blockInfo.offset = (blockOffset << _blockShift) + _blockOffset;
if (!(seek(hdl, blockInfo.offset) && readUInt16(hdl, blockInfo.h0)
&& readUInt32(hdl, blockInfo.h2) && readUInt32(hdl, blockInfo.h6)
&& readUInt32(hdl, blockInfo.ha) && readUInt16(hdl, blockInfo.he)
&& readUInt8(hdl, blockInfo.h10) && readUInt8(hdl, blockInfo.h11)
&& readUInt8(hdl, blockInfo.h12)))
if (!(seek(hdl, blockInfo.offset + _blockOffset)
&& readUInt16(hdl, blockInfo.hdr.s0) && readUInt32(hdl, blockInfo.hdr.s2)
&& readUInt32(hdl, blockInfo.hdr.s6) && readUInt32(hdl, blockInfo.hdr.sa)
&& readUInt16(hdl, blockInfo.hdr.se) && readUInt8(hdl, blockInfo.hdr.s10)
&& readUInt8(hdl, blockInfo.hdr.s11) && readUInt8(hdl, blockInfo.hdr.s12)))
return false;
return true;
}
bool NODFile::blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const
{
quint32 blockOffset;
quint32 offset = _indexRecordSize * blockId + _indexOffset;
quint32 offsetSize = (_indexFlags & 3) + 1;
if (offset > _indexOffset + _indexSize)
return false;
if (!(seek(hdl, offset) && readVUInt32(hdl, offsetSize, blockOffset)))
return false;
return readBlock(hdl, blockOffset << _blockShift, blockInfo);
}
bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
LinkInfo &linkInfo) const
{
Q_ASSERT(linkId < blockInfo.h10);
if (linkId >= blockInfo.hdr.s10)
return false;
quint32 infoOffset = ((blockInfo.he * linkId) >> 3) + 0x13
+ ((blockInfo.h0 >> 0xb) & 1) + blockInfo.offset;
quint32 s1 = ((blockInfo.h0 >> 2) & 0x1f) + 8;
quint32 s2 = (blockInfo.h0 >> 7) & 0xf;
quint32 skip = (blockInfo.he * linkId) & 7;
quint32 infoOffset = ((blockInfo.hdr.se * linkId) >> 3) + 0x13
+ ((blockInfo.hdr.s0 >> 0xb) & 1) + blockInfo.offset + _blockOffset;
quint32 s1 = ((blockInfo.hdr.s0 >> 2) & 0x1f) + 8;
quint32 s2 = (blockInfo.hdr.s0 >> 7) & 0xf;
quint32 skip = (blockInfo.hdr.se * linkId) & 7;
Q_ASSERT(infoOffset <= _blockOffset + _blockSize);
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
return false;
if (!seek(hdl, infoOffset))
return false;
@ -90,20 +173,340 @@ bool NODFile::linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
} else {
if (!bs.read(s1 - s2, linkInfo.linkOffset))
return false;
linkInfo.linkOffset += blockInfo.ha;
linkInfo.linkOffset += blockInfo.hdr.sa;
}
if (!bs.read(s2, linkInfo.nodeOffset))
return false;
linkInfo.nodeOffset = (blockInfo.offset - linkInfo.nodeOffset)
>> _nodeShift;
return true;
}
bool NODFile::nodeInfo(Handle &hdl, const BlockInfo &blockInfo,
quint32 nodeOffset, NodeInfo &nodeInfo) const
{
quint32 infoOffset = (nodeOffset << _nodeShift) + _blockOffset;
if (infoOffset > _blockOffset + _blockSize || infoOffset < blockInfo.offset)
return false;
if (!seek(hdl, infoOffset))
return false;
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
if (!bs.read(8, nodeInfo.flags))
return false;
if ((nodeInfo.flags & 7) >= ARRAY_SIZE(LLBITS))
return false;
quint8 lonBits = LLBITS[nodeInfo.flags & 7].lon;
quint8 latBits = LLBITS[nodeInfo.flags & 7].lat;
quint8 maxBits = ((_flags >> 10) & 7) | 0x18;
quint32 lon, lat;
if (!(bs.read(lonBits, lon) && bs.read(latBits, lat)))
return false;
quint8 lonShift = 0x20 - lonBits;
quint8 latShift = 0x20 - latBits;
quint8 shift = 0x20 - maxBits;
QPoint pos((((int)(lon << lonShift) >> lonShift) << shift)
+ blockInfo.hdr.s2, (((int)(lat << latShift) >> latShift) << shift)
+ blockInfo.hdr.s6);
nodeInfo.bytes = ((lonBits + latBits) >> 3) + 1;
if ((maxBits < 0x1c) && (nodeInfo.flags & 8)) {
quint8 extraBits = 0x1c - maxBits;
quint32 extraLon, extraLat;
if (!(bs.read(extraBits, extraLon) && bs.read(extraBits, extraLat)))
return false;
pos.setX(pos.x() | extraLon << 4); pos.setY(pos.y() | extraLat << 4);
nodeInfo.bytes++;
}
// TODO?: extra bits
nodeInfo.pos = pos;
nodeInfo.flags &= 0xf8;
return true;
}
bool NODFile::nodeOffset(Handle &hdl, const BlockInfo &blockInfo,
quint8 nodeId, quint32 &nodeOffset) const
{
if (nodeId >= blockInfo.hdr.s11)
return false;
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3)
+ 0x13 + nodeId * 3 + _blockOffset + blockInfo.offset
+ ((blockInfo.hdr.s0 >> 0xb) & 1);
if (!(seek(hdl, offset) && readUInt24(hdl, nodeOffset)))
return false;
return true;
}
bool NODFile::nodeBlock(Handle &hdl, quint32 nodeOffset,
BlockInfo &blockInfo) const
{
int low = 0;
int high = _indexSize / _indexRecordSize - 1;
quint32 offsetSize = (_indexFlags & 3) + 1;
while (low <= high) {
quint32 m = ((low + high) / 2);
quint32 offset = _indexRecordSize * m + _indexOffset;
quint32 blockOffset, prevBlockOffset;
if (m > 0) {
if (!(seek(hdl, offset - _indexRecordSize)
&& readVUInt32(hdl, offsetSize, prevBlockOffset)
&& readVUInt32(hdl, offsetSize, blockOffset)))
return false;
} else {
if (!(seek(hdl, offset)
&& readVUInt32(hdl, offsetSize, blockOffset)))
return false;
prevBlockOffset = 0;
}
prevBlockOffset <<= _blockShift;
blockOffset <<= _blockShift;
if (blockOffset < nodeOffset)
low = m + 1;
else {
if (prevBlockOffset <= nodeOffset)
return readBlock(hdl, blockOffset, blockInfo);
else
high = m - 1;
}
}
return false;
}
bool NODFile::absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
{
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
+ adj.nodeInfo.bytes;
if (!seek(hdl, infoOffset))
return false;
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
quint8 linkId = adj.blockInfo.hdr.s10;
quint32 m2p = 2;
quint32 skip = 8;
quint32 flags;
quint32 nextOffset;
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
bool linkIdValid = true;
bool firstLoop = true;
do {
adj.flags = 0;
if (!bs.read(8, flags))
return false;
if (firstLoop) {
skip >>= (flags >> 5) & 1;
flags |= 0x20;
}
firstLoop = false;
quint32 f4 = flags & 0x10;
quint32 f4sn = (f4 >> 4) ^ 1;
quint32 m1 = (flags >> 5) & f4sn;
quint32 m2 = (f4 >> 3) | (f4sn & (flags >> 6));
if (m1) {
if (!bs.read(8, linkId))
return false;
linkIdValid = true;
}
if ((m2 != m2p) || (flags & 0x10) || m1) {
quint32 data;
if (!bs.read(skip, data))
return false;
}
if (!(flags & 0x10)) {
if (!adjDistInfo(bs, (m2 == 1 && linkIdValid), adj.flags))
return false;
NodeShift shift;
if (!adjNodeInfo(bs, extraBit, shift, adj.flags))
return false;
if (adj.flags & 2)
nextOffset = adj.nodeOffset + shift.offset;
else if (!nodeOffset(adj.extHdl, adj.blockInfo, shift.id, nextOffset))
return false;
m2p = m2;
}
if (flags & 0x8) {
quint32 data;
if (!bs.read(8, data))
return false;
if (!(data & 0xe0)) {
if (!bs.read(8, data))
return false;
}
}
if ((_flags & 0x18) && !skipOptAdjData(bs))
return false;
if ((m2 == 1) && linkIdValid) {
LinkInfo li;
if (adj.linkId == 0xFFFFFFFF) {
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
return false;
} else
li.linkOffset = 0xFFFFFFFF;
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
adj.nodeOffset = nextOffset;
if (!(adj.flags & 2)) {
adj.linkId = 0xFFFFFFFF;
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
adj.blockInfo);
} else {
adj.linkId = linkId;
return true;
}
}
linkIdValid = false;
}
} while (!(flags & 0x80));
adj.nodeOffset = 0xFFFFFFFF;
return true;
}
bool NODFile::relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const
{
quint32 infoOffset = (adj.nodeOffset << _nodeShift) + _blockOffset
+ adj.nodeInfo.bytes;
if (!seek(hdl, infoOffset))
return false;
BitStream1 bs(*this, hdl, _blockOffset + _blockSize - infoOffset);
quint32 linkId = adj.blockInfo.hdr.s10;
quint32 skip = 8;
quint32 flagsBits = 8;
quint32 flags;
quint32 nextOffset;
bool extraBit = (adj.nodeInfo.flags >> 6) & 1;
bool linkIdValid = true;
bool firstLoop = true;
do {
adj.flags = 0;
if (!bs.read(flagsBits, flags))
return false;
flags <<= (8U - flagsBits);
if (firstLoop) {
skip >>= (flags >> 5) & 1;
flags = ((flags >> 1) & 0x20) | (flags & 0xffffffdf);
}
firstLoop = false;
flagsBits >>= (flags >> 3) & 1;
quint32 m = (((flags & 0x70) == 0x30) << 1) | ((flags >> 6) & 1);
if (!m) {
adj.nodeOffset = 0xFFFFFFFF;
return true;
}
if ((flags & 0x60) == 0x60) {
if (!bs.read(8, linkId))
return false;
linkIdValid = true;
}
if (((flags & 0x70) == 0x70)) {
quint32 data;
if (!bs.read(skip, data))
return false;
}
if ((flags & 0x50) == 0x50) {
if (!adjDistInfo(bs, false, adj.flags))
return false;
adj.flags |= 1;
}
if ((flags >> 6) & 1) {
NodeShift shift;
if (!adjNodeInfo(bs, extraBit, shift, adj.flags))
return false;
if (adj.flags & 2)
nextOffset = adj.nodeOffset + shift.offset;
else if (!nodeOffset(adj.extHdl, adj.blockInfo, shift.id, nextOffset))
return false;
}
if ((_flags & 0x18) && !skipOptAdjData(bs))
return false;
if (((m == 1) && linkIdValid)) {
LinkInfo li;
if (adj.linkId == 0xFFFFFFFF) {
if (!linkInfo(adj.extHdl, adj.blockInfo, linkId, li))
return false;
} else
li.linkOffset = 0xFFFFFFFF;
if ((adj.linkOffset == li.linkOffset) || (adj.linkId == linkId)) {
adj.nodeOffset = nextOffset;
if (!(adj.flags & 2)) {
adj.linkId = 0xFFFFFFFF;
return nodeBlock(hdl, adj.nodeOffset << _nodeShift,
adj.blockInfo);
} else {
adj.linkId = linkId;
return true;
}
}
linkIdValid = false;
}
} while (!(flags & 0x80));
adj.nodeOffset = 0xFFFFFFFF;
return true;
}
int NODFile::nextNode(Handle &hdl, AdjacencyInfo &adjInfo)
{
if (adjInfo.nodeOffset == 0xFFFFFFFF)
return 1;
if (!nodeInfo(hdl, adjInfo.blockInfo, adjInfo.nodeOffset,
adjInfo.nodeInfo))
return -1;
if (!adjacencyInfo(hdl, adjInfo))
return -1;
return 0;
}
bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
quint32 &type) const
{
quint32 offset = ((blockInfo.h10 * blockInfo.he + 7) >> 3) + 0x13 +
blockInfo.offset + ((blockInfo.h0 >> 0xb) & 1) + (quint32)blockInfo.h11
* 3;
quint32 offset = ((blockInfo.hdr.s10 * blockInfo.hdr.se + 7) >> 3) + 0x13
+ blockInfo.offset + _blockOffset + ((blockInfo.hdr.s0 >> 0xb) & 1)
+ blockInfo.hdr.s11 * 3;
quint32 low = 0;
quint32 high = blockInfo.h12 - 1;
quint32 high = blockInfo.hdr.s12 - 1;
quint32 pos;
quint16 val;
@ -142,7 +545,7 @@ bool NODFile::linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
}
}
type *= 256;
type <<= 8;
return true;
}

View File

@ -7,23 +7,53 @@
class NODFile : public SubFile
{
public:
struct BlockInfo {
struct BlockInfo
{
quint32 offset;
quint16 h0;
quint32 h2;
quint32 h6;
quint32 ha;
quint16 he;
quint8 h10; // links count
quint8 h11;
quint8 h12;
struct
{
quint32 s2; // node lon base
quint32 s6; // node lat base
quint32 sa;
quint16 s0; // flags
quint16 se; // link info bit size
quint8 s10; // links count
quint8 s11; // nodes count
quint8 s12; // link types count
} hdr;
};
struct LinkInfo {
struct LinkInfo
{
quint32 linkOffset;
quint32 nodeOffset;
quint32 flags;
};
struct NodeInfo
{
QPoint pos;
quint8 flags;
quint8 bytes;
};
struct AdjacencyInfo
{
AdjacencyInfo(const SubFile *file, const BlockInfo &blockInfo,
quint32 linkId, const LinkInfo &linkInfo) : extHdl(file),
blockInfo(blockInfo), nodeOffset(linkInfo.nodeOffset),
linkOffset(linkInfo.linkOffset), linkId(linkId)
{}
Handle extHdl;
struct BlockInfo blockInfo;
struct NodeInfo nodeInfo;
quint32 nodeOffset;
quint32 linkOffset;
quint32 linkId;
quint8 flags;
};
NODFile(IMG *img) : SubFile(img), _indexOffset(0), _indexSize(0),
_indexFlags(0), _blockOffset(0), _blockSize(0), _indexRecordSize(0),
_blockRecordSize(0), _blockShift(0), _nodeShift(0) {}
@ -36,19 +66,33 @@ public:
_nodeShift(0) {}
quint32 indexIdSize(Handle &hdl);
bool blockInfo(Handle &hdl, quint32 blockIndexId,
BlockInfo &blockInfo) const;
bool blockInfo(Handle &hdl, quint32 blockId, BlockInfo &blockInfo) const;
bool linkInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 linkId,
LinkInfo &linkInfo) const;
bool linkType(Handle &hdl, const BlockInfo &blockInfo, quint8 linkId,
quint32 &type) const;
int nextNode(Handle &hdl, AdjacencyInfo &adjInfo);
private:
bool init(Handle &hdl);
bool nodeInfo(Handle &hdl, const BlockInfo &blockInfo, quint32 nodeOffset,
NodeInfo &nodeInfo) const;
bool nodeOffset(Handle &hdl, const BlockInfo &blockInfo, quint8 nodeId,
quint32 &nodeOffset) const;
bool absAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
bool relAdjInfo(Handle &hdl, AdjacencyInfo &adj) const;
bool adjacencyInfo(Handle &hdl, AdjacencyInfo &adj) const
{
return (adj.nodeInfo.flags & 0x20) ? absAdjInfo(hdl, adj)
: relAdjInfo(hdl, adj);
}
bool nodeBlock(Handle &hdl, quint32 nodeOffset, BlockInfo &blockInfo) const;
bool readBlock(Handle &hdl, quint32 blockOffset, BlockInfo &blockInfo) const;
quint32 _indexOffset, _indexSize, _indexFlags, _blockOffset, _blockSize;
quint16 _indexRecordSize, _blockRecordSize;
quint8 _blockShift, _nodeShift;
quint32 _flags;
};
#endif // NETFILE_H

View File

@ -424,8 +424,9 @@ bool RGNFile::extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
return true;
}
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
Handle &netHdl, NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const
bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, quint32 shift,
NETFile *net, Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl,
Handle &lblHdl, QList<IMG::Poly> *lines) const
{
quint32 size, blockIndexIdSize, blockIndexId;
quint8 flags;
@ -494,8 +495,8 @@ bool RGNFile::links(Handle &hdl, const SubDiv *subdiv, NETFile *net,
lineId = 0;
}
net->link(subdiv, netHdl, nod, nodHdl, blockInfo, linkId, lineId,
_huffmanTable, lines);
net->link(subdiv, shift, netHdl, nod, nodHdl, lbl, lblHdl,
blockInfo, linkId, lineId, _huffmanTable, lines);
}
Q_ASSERT(entryStart + size == pos(hdl));

View File

@ -46,8 +46,9 @@ public:
QList<IMG::Poly> *polys) const;
bool extPointObjects(Handle &hdl, const SubDiv *subdiv, LBLFile *lbl,
Handle &lblHdl, QList<IMG::Point> *points) const;
bool links(Handle &hdl, const SubDiv *subdiv, NETFile *net, Handle &netHdl,
NODFile *nod, Handle &nodHdl, QList<IMG::Poly> *lines) const;
bool links(Handle &hdl, const SubDiv *subdiv, quint32 shift, NETFile *net,
Handle &netHdl, NODFile *nod, Handle &nodHdl, LBLFile *lbl, Handle &lblHdl,
QList<IMG::Poly> *lines) const;
bool subdivInit(Handle &hdl, SubDiv *subdiv) const;

View File

@ -149,7 +149,8 @@ void VectorTile::polys(const RectC &rect, int bits, bool baseMap,
lblHdl, &p);
_rgn->extPolyObjects(rgnHdl, subdiv, shift, RGNFile::Line, _lbl,
lblHdl, &l);
_rgn->links(rgnHdl, subdiv, _net, netHdl, _nod, nodHdl, &l);
_rgn->links(rgnHdl, subdiv, shift, _net, netHdl, _nod, nodHdl, _lbl,
lblHdl, &l);
copyPolys(rect, &p, polygons);
copyPolys(rect, &l, lines);