1 #include "common/rectc.h"
2 #include "common/garmin.h"
3 #include "common/hash.h"
4 #include "deltastream.h"
5 #include "huffmanstream.h"
12 using namespace Garmin
;
15 #define MASK(bits) ((1U << (bits)) - 1U)
17 static quint64
pointId(const QPoint
&pos
, quint32 type
, const QString
&label
)
19 quint64 hash
= qHash(pos
) ^ qHash(label
);
20 quint64 id
= ((quint64
)type
)<<40 | (hash
& 0xFFFFFFFFFF);
22 // Increase rendering priorities for some special items
23 if (!Style::isCountry(type
) && !Style::isMarina(type
))
29 static double d2m(quint32 val
, quint32 flags
)
31 return (flags
& 1) ? val
/ 10.0 : val
;
39 bool RGNFile::readRasterInfo(Handle
&hdl
, const LBLFile
*lbl
, quint32 size
,
40 MapData::Poly
*poly
) const
43 quint32 top
, right
, bottom
, left
;
45 if (!(lbl
&& lbl
->imageIdSize()))
47 if (size
< lbl
->imageIdSize() + 16U)
50 if (!(readVUInt32(hdl
, lbl
->imageIdSize(), id
)
51 && readUInt32(hdl
, top
) && readUInt32(hdl
, right
)
52 && readUInt32(hdl
, bottom
) && readUInt32(hdl
, left
)))
55 poly
->raster
= Raster(lbl
, id
, QRect(QPoint(left
, top
), QPoint(right
,
61 bool RGNFile::readDepthInfo(Handle
&hdl
, quint8 flags
, quint32 size
,
62 MapData::Point
*point
) const
65 quint32 units
= (flags
>> 3) & 3;
70 units
= (flags
>> 5) & 2;
71 } else if (size
== 1) {
72 if (!readUInt8(hdl
, val
))
74 depth
= val
| ((quint32
)flags
& 7) << 8;
75 } else if (size
< 4) {
76 Q_ASSERT(!(flags
& 4));
77 if (!readVUInt32(hdl
, size
, val
))
79 depth
= val
| ((quint32
)flags
& 3) << (size
* 8);
83 point
->label
= QString::number(d2m(depth
, units
));
88 bool RGNFile::readObstructionInfo(Handle
&hdl
, quint8 flags
, quint32 size
,
89 MapData::Point
*point
) const
91 quint32 val
, rb
= size
;
92 quint32 units
= (flags
>> 3) & 3;
97 if ((flags
& 7) == 7) {
98 if (!readUInt8(hdl
, val
))
102 if (!readVUInt32(hdl
, rb
, val
))
105 point
->label
= QString::number(d2m(val
, units
));
110 bool RGNFile::readLabel(Handle
&hdl
, const LBLFile
*lbl
, Handle
&lblHdl
,
111 quint8 flags
, quint32 size
, MapData::Point
*point
) const
118 point
->label
= lbl
->label(lblHdl
, this, hdl
, size
);
119 point
->classLabel
= true;
124 bool RGNFile::readClassFields(Handle
&hdl
, SegmentType segmentType
,
125 void *object
, const LBLFile
*lbl
, Handle
&lblHdl
) const
129 MapData::Poly
*poly
= (segmentType
== Polygon
)
130 ? (MapData::Poly
*) object
: 0;
131 MapData::Point
*point
= (segmentType
== Point
)
132 ? (MapData::Point
*) object
: 0;
134 if (!readByte(hdl
, &flags
))
137 switch (flags
>> 5) {
148 if (!readVUInt32(hdl
, rs
))
153 quint32 off
= pos(hdl
);
155 if (poly
&& Style::isRaster(poly
->type
))
156 readRasterInfo(hdl
, lbl
, rs
, poly
);
157 if (point
&& Style::isDepthPoint(point
->type
))
158 readDepthInfo(hdl
, flags
, rs
, point
);
159 if (point
&& Style::isObstructionPoint(point
->type
))
160 readObstructionInfo(hdl
, flags
, rs
, point
);
161 if (point
&& !Style::isMarinePoint(point
->type
))
162 readLabel(hdl
, lbl
, lblHdl
, flags
, rs
, point
);
164 return seek(hdl
, off
+ rs
);
167 bool RGNFile::skipLclFields(Handle
&hdl
, const quint32 flags
[3]) const
169 quint32 bitfield
= 0xFFFFFFFF;
171 if (flags
[0] & 0x20000000)
172 if (!readVBitfield32(hdl
, bitfield
))
175 for (int i
= 0, j
= 0; i
< 29; i
++) {
176 if ((flags
[0] >> i
) & 1) {
178 quint32 m
= flags
[(j
>> 4) + 1] >> ((j
* 2) & 0x1e) & 3;
182 if (!readVUInt32(hdl
, skip
))
186 if (!seek(hdl
, pos(hdl
) + skip
))
197 bool RGNFile::skipGblFields(Handle
&hdl
, quint32 flags
) const
202 cnt
= cnt
+ (flags
& 3);
204 } while (flags
!= 0);
206 return seek(hdl
, pos(hdl
) + cnt
);
209 bool RGNFile::load(Handle
&hdl
)
213 if (!(seek(hdl
, _gmpOffset
) && readUInt16(hdl
, hdrLen
)
214 && seek(hdl
, _gmpOffset
+ 0x15) && readUInt32(hdl
, _base
.offset
)
215 && readUInt32(hdl
, _base
.size
)))
218 if (hdrLen
>= 0x71) {
219 if (!(readUInt32(hdl
, _polygons
.offset
) && readUInt32(hdl
, _polygons
.size
)
220 && seek(hdl
, _gmpOffset
+ 0x29) && readUInt32(hdl
, _polygonsGblFlags
)
221 && readUInt32(hdl
, _polygonsLclFlags
[0])
222 && readUInt32(hdl
, _polygonsLclFlags
[1])
223 && readUInt32(hdl
, _polygonsLclFlags
[2])
224 && readUInt32(hdl
, _lines
.offset
) && readUInt32(hdl
, _lines
.size
)
225 && seek(hdl
, _gmpOffset
+ 0x45) && readUInt32(hdl
, _linesGblFlags
)
226 && readUInt32(hdl
, _linesLclFlags
[0])
227 && readUInt32(hdl
, _linesLclFlags
[1])
228 && readUInt32(hdl
, _linesLclFlags
[2])
229 && readUInt32(hdl
, _points
.offset
) && readUInt32(hdl
, _points
.size
)
230 && seek(hdl
, _gmpOffset
+ 0x61) && readUInt32(hdl
, _pointsGblFlags
)
231 && readUInt32(hdl
, _pointsLclFlags
[0])
232 && readUInt32(hdl
, _pointsLclFlags
[1])
233 && readUInt32(hdl
, _pointsLclFlags
[2])))
237 if (hdrLen
>= 0x7D) {
239 if (!(seek(hdl
, _gmpOffset
+ 0x71) && readUInt32(hdl
, _dict
.offset
)
240 && readUInt32(hdl
, _dict
.size
) && readUInt32(hdl
, info
)))
243 if (_dict
.size
&& _dict
.offset
&& (info
& 0x1E)) {
244 _huffmanTable
= new HuffmanTable(((info
>> 1) & 0xF) - 1);
245 if (!_huffmanTable
->load(this, hdl
))
253 void RGNFile::clear()
255 delete _huffmanTable
;
259 bool RGNFile::polyObjects(Handle
&hdl
, const SubDiv
*subdiv
,
260 SegmentType segmentType
, const LBLFile
*lbl
, Handle
&lblHdl
, NETFile
*net
,
261 Handle
&netHdl
, QList
<MapData::Poly
> *polys
) const
263 const SubDiv::Segment
&segment
= (segmentType
== Line
)
264 ? subdiv
->lines() : subdiv
->polygons();
266 if (!segment
.isValid())
268 if (!seek(hdl
, segment
.offset()))
272 quint8 type
, len8
, bitstreamInfo
;
276 while (pos(hdl
) < segment
.end()) {
279 if (!(readByte(hdl
, &type
) && readUInt24(hdl
, labelPtr
)
280 && readInt16(hdl
, lon
) && readInt16(hdl
, lat
)))
283 if (!readUInt16(hdl
, len
))
286 if (!readByte(hdl
, &len8
))
290 if (!readByte(hdl
, &bitstreamInfo
))
293 poly
.type
= (segmentType
== Polygon
)
294 ? ((quint32
)(type
& 0x7F)) << 8 : ((quint32
)(type
& 0x3F)) << 8;
295 if (segmentType
== Line
&& type
& 0x40)
299 QPoint
pos(subdiv
->lon() + LS(lon
, 24-subdiv
->bits()),
300 subdiv
->lat() + LS(lat
, 24-subdiv
->bits()));
301 Coordinates
c(toWGS24(pos
.x()), toWGS24(pos
.y()));
302 poly
.boundingRect
= RectC(c
, c
);
303 poly
.points
.append(QPointF(c
.lon(), c
.lat()));
305 qint32 lonDelta
, latDelta
;
306 DeltaStream
stream(*this, hdl
, len
);
307 if (!stream
.init(bitstreamInfo
, labelPtr
& 0x400000, false))
309 while (stream
.readNext(lonDelta
, latDelta
)) {
310 if (!(lonDelta
|| latDelta
))
312 pos
.rx() += LS(lonDelta
, (24-subdiv
->bits()));
313 if (pos
.rx() >= 0x800000 && subdiv
->lon() >= 0)
315 pos
.ry() += LS(latDelta
, (24-subdiv
->bits()));
317 Coordinates
c(toWGS24(pos
.x()), toWGS24(pos
.y()));
318 poly
.points
.append(QPointF(c
.lon(), c
.lat()));
319 poly
.boundingRect
= poly
.boundingRect
.united(c
);
321 if (!(stream
.atEnd() && stream
.flush()))
324 if (lbl
&& (labelPtr
& 0x3FFFFF)) {
325 if (labelPtr
& 0x800000) {
327 if (net
&& net
->lblOffset(netHdl
, labelPtr
& 0x3FFFFF, lblOff
)
329 poly
.label
= lbl
->label(lblHdl
, lblOff
, false, true,
330 Style::isContourLine(poly
.type
));
332 poly
.label
= lbl
->label(lblHdl
, labelPtr
& 0x3FFFFF, false,
333 true, Style::isContourLine(poly
.type
));
342 bool RGNFile::extPolyObjects(Handle
&hdl
, const SubDiv
*subdiv
, quint32 shift
,
343 SegmentType segmentType
, const LBLFile
*lbl
, Handle
&lblHdl
,
344 QList
<MapData::Poly
> *polys
) const
346 quint32 labelPtr
, len
;
347 quint8 type
, subtype
;
349 const SubDiv::Segment
&segment
= (segmentType
== Line
)
350 ? subdiv
->extLines() : subdiv
->extPolygons();
353 if (!segment
.isValid())
355 if (!seek(hdl
, segment
.offset()))
358 while (pos(hdl
) < segment
.end()) {
362 if (!(readByte(hdl
, &type
) && readByte(hdl
, &subtype
)
363 && readInt16(hdl
, lon
) && readInt16(hdl
, lat
)
364 && readVUInt32(hdl
, len
)))
366 Q_ASSERT(SubFile::pos(hdl
) + len
<= segment
.end());
368 poly
.type
= 0x10000 | (quint16(type
)<<8) | (subtype
& 0x1F);
372 pos
= QPoint(LS(subdiv
->lon(), 8) + LS(lon
, 32-subdiv
->bits()),
373 LS(subdiv
->lat(), 8) + LS(lat
, (32-subdiv
->bits())));
375 qint32 lonDelta
, latDelta
;
376 BitStream4F
bs(*this, hdl
, len
);
377 HuffmanDeltaStreamF
stream(bs
, *_huffmanTable
);
378 if (!stream
.init(segmentType
== Line
))
382 if (!stream
.readOffset(lonDelta
, latDelta
))
384 pos
= QPoint(pos
.x() | LS(lonDelta
, 32-subdiv
->bits()-shift
),
385 pos
.y() | LS(latDelta
, 32-subdiv
->bits()-shift
));
387 Coordinates
c(toWGS32(pos
.x()), toWGS32(pos
.y()));
388 poly
.boundingRect
= RectC(c
, c
);
389 poly
.points
.append(QPointF(c
.lon(), c
.lat()));
391 while (stream
.readNext(lonDelta
, latDelta
)) {
392 if (!(lonDelta
| latDelta
))
395 pos
.rx() += LS(lonDelta
, 32-subdiv
->bits()-shift
);
396 pos
.ry() += LS(latDelta
, 32-subdiv
->bits()-shift
);
398 Coordinates
c(toWGS32(pos
.x()), toWGS32(pos
.y()));
399 poly
.points
.append(QPointF(c
.lon(), c
.lat()));
400 poly
.boundingRect
= poly
.boundingRect
.united(c
);
403 if (!(stream
.atEnd() && bs
.flush()))
406 pos
= QPoint(subdiv
->lon() + LS(lon
, 24-subdiv
->bits()),
407 subdiv
->lat() + LS(lat
, 24-subdiv
->bits()));
408 Coordinates
c(toWGS24(pos
.x()), toWGS24(pos
.y()));
409 poly
.boundingRect
= RectC(c
, c
);
410 poly
.points
.append(QPointF(c
.lon(), c
.lat()));
412 quint8 bitstreamInfo
;
413 if (!readByte(hdl
, &bitstreamInfo
))
416 qint32 lonDelta
, latDelta
;
417 DeltaStream
stream(*this, hdl
, len
- 1);
418 if (!stream
.init(bitstreamInfo
, false, true))
420 while (stream
.readNext(lonDelta
, latDelta
)) {
421 if (!(lonDelta
|| latDelta
))
423 pos
.rx() += LS(lonDelta
, 24-subdiv
->bits());
424 if (pos
.rx() >= 0x800000 && subdiv
->lon() >= 0)
426 pos
.ry() += LS(latDelta
, 24-subdiv
->bits());
428 Coordinates
c(toWGS24(pos
.x()), toWGS24(pos
.y()));
429 poly
.points
.append(QPointF(c
.lon(), c
.lat()));
430 poly
.boundingRect
= poly
.boundingRect
.united(c
);
432 if (!(stream
.atEnd() && stream
.flush()))
436 if (subtype
& 0x20 && !readUInt24(hdl
, labelPtr
))
438 if (subtype
& 0x80 && !readClassFields(hdl
, segmentType
, &poly
, lbl
,
441 if (subtype
& 0x40 && !skipLclFields(hdl
, segmentType
== Line
442 ? _linesLclFlags
: _polygonsLclFlags
))
444 quint32 gblFlags
= (segmentType
== Line
)
445 ? _linesGblFlags
: _polygonsGblFlags
;
446 if (gblFlags
&& !skipGblFields(hdl
, gblFlags
))
449 if (lbl
&& (labelPtr
& 0x3FFFFF))
450 poly
.label
= lbl
->label(lblHdl
, labelPtr
& 0x3FFFFF, false, true,
451 Style::isContourLine(poly
.type
));
459 bool RGNFile::pointObjects(Handle
&hdl
, const SubDiv
*subdiv
,
460 SegmentType segmentType
, const LBLFile
*lbl
, Handle
&lblHdl
,
461 QList
<MapData::Point
> *points
) const
463 const SubDiv::Segment
&segment
= (segmentType
== IndexedPoint
)
464 ? subdiv
->idxPoints() : subdiv
->points();
467 if (!segment
.isValid())
469 if (!seek(hdl
, segment
.offset()))
472 while (pos(hdl
) < segment
.end()) {
473 MapData::Point point
;
474 quint8 type
, subtype
;
478 if (!(readByte(hdl
, &type
) && readUInt24(hdl
, labelPtr
)
479 && readInt16(hdl
, lon
) && readInt16(hdl
, lat
)))
481 if (labelPtr
& 0x800000) {
482 if (!readByte(hdl
, &subtype
))
487 QPoint
pos(subdiv
->lon() + LS(lon
, 24-subdiv
->bits()),
488 subdiv
->lat() + LS(lat
, 24-subdiv
->bits()));
490 point
.type
= (quint16
)type
<<8 | subtype
;
491 point
.coordinates
= Coordinates(toWGS24(pos
.x()), toWGS24(pos
.y()));
492 if (lbl
&& (labelPtr
& 0x3FFFFF))
493 point
.label
= lbl
->label(lblHdl
, labelPtr
& 0x3FFFFF,
494 labelPtr
& 0x400000, !(Style::isCountry(point
.type
)
495 || Style::isState(point
.type
)), Style::isSpot(point
.type
));
496 point
.id
= pointId(pos
, point
.type
, point
.label
.text());
498 points
->append(point
);
504 bool RGNFile::extPointObjects(Handle
&hdl
, const SubDiv
*subdiv
,
505 const LBLFile
*lbl
, Handle
&lblHdl
, QList
<MapData::Point
> *points
) const
507 const SubDiv::Segment
&segment
= subdiv
->extPoints();
510 if (!segment
.isValid())
512 if (!seek(hdl
, segment
.offset()))
515 while (pos(hdl
) < segment
.end()) {
516 MapData::Point point
;
518 quint8 type
, subtype
;
519 quint32 labelPtr
= 0;
521 if (!(readByte(hdl
, &type
) && readByte(hdl
, &subtype
)
522 && readInt16(hdl
, lon
) && readInt16(hdl
, lat
)))
525 point
.type
= 0x10000 | (((quint32
)type
)<<8) | (subtype
& 0x1F);
527 if (subtype
& 0x20 && !readUInt24(hdl
, labelPtr
))
529 if (subtype
& 0x80 && !readClassFields(hdl
, Point
, &point
, lbl
, lblHdl
))
531 if (subtype
& 0x40 && !skipLclFields(hdl
, _pointsLclFlags
))
533 if (_pointsGblFlags
&& !skipGblFields(hdl
, _pointsGblFlags
))
536 QPoint
p(subdiv
->lon() + LS(lon
, 24-subdiv
->bits()),
537 subdiv
->lat() + LS(lat
, 24-subdiv
->bits()));
539 // Discard NT points breaking style draw order logic (and causing huge
540 // performance drawback)
541 if (point
.type
== 0x11400)
544 point
.coordinates
= Coordinates(toWGS24(p
.x()), toWGS24(p
.y()));
545 if (lbl
&& (labelPtr
& 0x3FFFFF))
546 point
.label
= lbl
->label(lblHdl
, labelPtr
& 0x3FFFFF);
547 point
.id
= pointId(p
, point
.type
, point
.label
.text());
549 points
->append(point
);
555 bool RGNFile::links(Handle
&hdl
, const SubDiv
*subdiv
, quint32 shift
,
556 const NETFile
*net
, Handle
&netHdl
, const NODFile
*nod
, Handle
&nodHdl
,
557 Handle
&nodHdl2
, const LBLFile
*lbl
, Handle
&lblHdl
,
558 QList
<MapData::Poly
> *lines
) const
560 quint32 size
, blockIndexId
;
562 const SubDiv::Segment
&segment
= subdiv
->roadReferences();
566 if (!segment
.isValid())
568 if (!seek(hdl
, segment
.offset()))
571 while (pos(hdl
) < segment
.end()) {
572 if (!readVUInt32(hdl
, size
))
575 quint32 entryStart
= pos(hdl
);
577 if (!(readByte(hdl
, &flags
) && readVUInt32(hdl
, nod
->indexIdSize(),
582 for (int i
= 0; i
< 3; i
++)
583 bits
[i
] = 0x4000a08 >> (((flags
>> (2*i
) & 3) << 3) ^ 0x10);
584 quint8 byteSize
= bs(bits
[0] + bits
[1] + bits
[2]);
587 if (!readVUInt32(hdl
, byteSize
, counts
))
590 quint16 b8
= bits
[0] ? (MASK(bits
[0]) & counts
) + 1 : 0;
591 quint16 b10
= bits
[1] ? (MASK(bits
[1]) & (counts
>> bits
[0])) + 1 : 0;
592 quint16 b16
= bits
[2] ? (MASK(bits
[2]) & (counts
>> (bits
[0] + bits
[1])))
595 NODFile::BlockInfo blockInfo
;
596 if (!nod
->blockInfo(nodHdl
, blockIndexId
, blockInfo
))
599 quint8 linkId
, lineId
;
600 for (int i
= 0; i
< b8
+ b10
+ b16
; i
++) {
601 if (!b8
|| b8
<= i
) {
603 if (!readUInt16(hdl
, v16
))
606 if (!b16
|| b8
+ b16
<= i
) {
607 int shift
= ((i
- (b8
+ b16
)) * 10) & 7;
608 linkId
= (quint8
)(v16
>> shift
);
609 lineId
= (((v16
>> shift
) >> 8) & 3) + 1;
611 if (shift
< 6 && i
< b8
+ b10
+ b16
- 1)
612 seek(hdl
, pos(hdl
) - 1);
614 linkId
= (quint8
)v16
;
616 Q_ASSERT(lineId
> 4);
619 if (!readByte(hdl
, &linkId
))
624 net
->link(subdiv
, shift
, netHdl
, nod
, nodHdl
, nodHdl2
, lbl
, lblHdl
,
625 blockInfo
, linkId
, lineId
, lines
);
628 if (entryStart
+ size
!= pos(hdl
))
635 bool RGNFile::segments(Handle
&hdl
, SubDiv
*subdiv
, SubDiv::Segment seg
[5]) const
637 if (subdiv
->offset() == subdiv
->end() || !(subdiv
->objects() & 0x1F))
640 quint32 offset
= _base
.offset
+ subdiv
->offset();
641 if (!seek(hdl
, offset
))
645 for (int i
= 0; i
< 5; i
++)
646 if (subdiv
->objects() & (1<<i
))
649 quint32 start
= offset
+ 2 * (no
- 1);
653 for (int i
= 0; i
< 5; i
++) {
654 if (subdiv
->objects() & (1<<i
)) {
657 if (!readUInt16(hdl
, po
) || !po
)
660 seg
[lt
] = SubDiv::Segment(ls
, start
);
668 seg
[lt
] = SubDiv::Segment(ls
,
669 subdiv
->end() ? _base
.offset
+ subdiv
->end() : _base
.offset
+ _base
.size
);
674 bool RGNFile::subdivInit(Handle
&hdl
, SubDiv
*subdiv
) const
676 SubDiv::Segment std
[5], extPoints
, extLines
, extPolygons
;
678 if (!segments(hdl
, subdiv
, std
))
681 if (subdiv
->extPointsOffset() != subdiv
->extPointsEnd()) {
682 quint32 start
= _points
.offset
+ subdiv
->extPointsOffset();
683 quint32 end
= subdiv
->extPointsEnd()
684 ? _points
.offset
+ subdiv
->extPointsEnd()
685 : _points
.offset
+ _points
.size
;
686 extPoints
= SubDiv::Segment(start
, end
);
688 if (subdiv
->extPolygonsOffset() != subdiv
->extPolygonsEnd()) {
689 quint32 start
= _polygons
.offset
+ subdiv
->extPolygonsOffset();
690 quint32 end
= subdiv
->extPolygonsEnd()
691 ? _polygons
.offset
+ subdiv
->extPolygonsEnd()
692 : _polygons
.offset
+ _polygons
.size
;
693 extPolygons
= SubDiv::Segment(start
, end
);
695 if (subdiv
->extLinesOffset() != subdiv
->extLinesEnd()) {
696 quint32 start
= _lines
.offset
+ subdiv
->extLinesOffset();
697 quint32 end
= subdiv
->extLinesEnd()
698 ? _lines
.offset
+ subdiv
->extLinesEnd()
699 : _lines
.offset
+ _lines
.size
;
700 extLines
= SubDiv::Segment(start
, end
);
703 subdiv
->init(std
[Point
], std
[IndexedPoint
], std
[Line
], std
[Polygon
],
704 std
[RoadReference
], extPoints
, extLines
, extPolygons
);