1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 06:43:22 +02:00

Added support for GPI speed/red light cameras

This commit is contained in:
Martin Tůma 2019-11-10 16:46:31 +01:00
parent 6d6dc9f316
commit db7e60bdfb
8 changed files with 145 additions and 42 deletions

View File

@ -21,6 +21,7 @@ INCLUDEPATH += ./src
HEADERS += src/common/config.h \
src/GUI/graphicsscene.h \
src/GUI/popup.h \
src/common/garmin.h \
src/common/staticassert.h \
src/common/coordinates.h \
src/common/range.h \
@ -178,7 +179,6 @@ HEADERS += src/common/config.h \
src/map/IMG/lblfile.h \
src/map/IMG/vectortile.h \
src/map/IMG/subdiv.h \
src/map/IMG/units.h \
src/map/IMG/style.h \
src/map/IMG/netfile.h \
src/GUI/limitedcombobox.h \

18
src/common/garmin.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef GARMIN_H
#define GARMIN_H
#include <QtGlobal>
inline double toWGS32(qint32 v)
{
return (double)(((double)v / (double)(1<<31)) * (double)180);
}
inline double toWGS24(qint32 coord)
{
return (coord < 0x800000)
? (double)coord * 360.0 / (double)(1<<24)
: (double)(coord - 0x1000000) * 360.0 / (double)(1<<24);
}
#endif // GARMIN_H

View File

@ -10,6 +10,7 @@
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QTemporaryDir>
#endif // QT_VERSION >= 5
#include "common/garmin.h"
#include "gpiparser.h"
@ -112,9 +113,15 @@ qint64 CryptDevice::readData(char *data, qint64 maxSize)
return ts;
}
static inline double toWGS(qint32 v)
static qint32 readInt24(QDataStream &stream)
{
return (double)(((double)v / (double)(1U<<31)) * (double)180);
unsigned char data[3];
quint32 val;
stream.readRawData((char*)data, sizeof(data));
val = data[0] | ((quint32)data[1]) << 8 | ((quint32)data[2]) << 16;
return (val > 0x7FFFFF) ? (val & 0x7FFFFF) - 0x800000 : val;
}
static quint16 nextHeaderType(QDataStream &stream)
@ -415,6 +422,85 @@ static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint,
}
#endif // QT_VERSION >= 5
static int speed(quint8 flags)
{
switch (flags >> 4) {
case 0x8:
return 40;
case 0x9:
return 30;
case 0xA:
return 50;
case 0xB:
return 70;
case 0xC:
return 80;
case 0xD:
return 90;
case 0xE:
return 100;
default:
return 0;
}
}
static quint32 readCamera(QDataStream &stream, QVector<Waypoint> &waypoints,
QList<Area> &polygons)
{
RecordHeader rh;
quint8 flags, type, s7, rs;
qint32 top, right, bottom, left;
rs = readRecordHeader(stream, rh);
top = readInt24(stream);
right = readInt24(stream);
bottom = readInt24(stream);
left = readInt24(stream);
stream >> flags >> type >> s7;
if (s7) {
int skip = s7 + 2 + s7/4;
stream.skipRawData(skip);
qint32 lat = readInt24(stream);
qint32 lon = readInt24(stream);
stream.skipRawData(rh.size - 12 - 3 - skip - 6);
waypoints.append(Coordinates(toWGS24(lon), toWGS24(lat)));
} else
stream.skipRawData(rh.size - 15);
Area area;
Polygon polygon;
QVector<Coordinates> v(4);
v[0] = Coordinates(toWGS24(left), toWGS24(top));
v[1] = Coordinates(toWGS24(right), toWGS24(top));
v[2] = Coordinates(toWGS24(right), toWGS24(bottom));
v[3] = Coordinates(toWGS24(left), toWGS24(bottom));
polygon.append(v);
area.append(polygon);
switch (type) {
case 8:
area.setDescription(QString("%1&nbsp;mi/h")
.arg(speed(flags)));
break;
case 9:
area.setDescription(QString("%1&nbsp;km/h")
.arg(speed(flags)));
break;
case 10:
case 11:
area.setDescription("Red light camera");
break;
}
polygons.append(area);
return rs + rh.size;
}
static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
{
@ -431,7 +517,7 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
ds = 10 + s3;
ds += readTranslatedObjects(stream, codec, obj);
waypoints.append(Waypoint(Coordinates(toWGS(lon), toWGS(lat))));
waypoints.append(Waypoint(Coordinates(toWGS32(lon), toWGS32(lat))));
if (!obj.isEmpty())
waypoints.last().setName(obj.first().str());
@ -466,7 +552,8 @@ static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
}
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
int &imgId)
{
RecordHeader rh;
quint32 ds, s5;
@ -485,8 +572,11 @@ static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
ds += readPOI(stream, codec, waypoints, fileName, imgId);
break;
case 8:
ds += readSpatialIndex(stream, codec, waypoints, fileName,
imgId);
ds += readSpatialIndex(stream, codec, waypoints, polygons,
fileName, imgId);
break;
case 19:
ds += readCamera(stream, waypoints, polygons);
break;
default:
ds += skipRecord(stream);
@ -501,7 +591,8 @@ static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
}
static void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
int &imgId)
{
RecordHeader rh;
QList<TranslatedString> obj;
@ -509,7 +600,7 @@ static void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
readRecordHeader(stream, rh);
ds = readTranslatedObjects(stream, codec, obj);
ds += readSpatialIndex(stream, codec, waypoints, fileName, imgId);
ds += readSpatialIndex(stream, codec, waypoints, polygons, fileName, imgId);
if (rh.flags & 0x8) {
while (stream.status() == QDataStream::Ok && ds < rh.size) {
switch(nextHeaderType(stream)) {
@ -526,12 +617,14 @@ static void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
}
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
int &imgId)
{
while (stream.status() == QDataStream::Ok) {
switch (nextHeaderType(stream)) {
case 0x09: // POI database
readPOIDatabase(stream, codec, waypoints, fileName, imgId);
readPOIDatabase(stream, codec, waypoints, polygons, fileName,
imgId);
break;
case 0xffff: // EOF
skipRecord(stream);
@ -631,7 +724,9 @@ bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
CryptDevice dev(stream.device(), 0xf870b5, ebs);
QDataStream cryptStream(&dev);
cryptStream.setByteOrder(QDataStream::LittleEndian);
return readData(cryptStream, codec, waypoints, file->fileName(), imgId);
return readData(cryptStream, codec, waypoints, polygons, file->fileName(),
imgId);
} else
return readData(stream, codec, waypoints, file->fileName(), imgId);
return readData(stream, codec, waypoints, polygons, file->fileName(),
imgId);
}

View File

@ -18,7 +18,8 @@ private:
bool readFileHeader(QDataStream &stream, quint32 &ebs);
bool readGPIHeader(QDataStream &stream, QTextCodec **codec);
bool readData(QDataStream &stream, QTextCodec *codec,
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId);
QVector<Waypoint> &waypoints, QList<Area> &polygons,
const QString &fileName, int &imgId);
QString _errorString;
};

View File

@ -1,5 +1,5 @@
#include "common/rectc.h"
#include "units.h"
#include "common/garmin.h"
#include "lblfile.h"
#include "netfile.h"
#include "rgnfile.h"
@ -193,7 +193,7 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
RectC br(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
@ -204,7 +204,7 @@ bool RGNFile::polyObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits());
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
}
@ -259,7 +259,7 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
QPoint pos(subdiv->lon() + ((qint32)lon<<(24-subdiv->bits())),
subdiv->lat() + ((qint32)lat<<(24-subdiv->bits())));
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
RectC br(c, c);
poly.points.append(QPointF(c.lon(), c.lat()));
@ -269,7 +269,7 @@ bool RGNFile::extPolyObjects(const RectC &rect, Handle &hdl,
pos.rx() += lonDelta<<(24-subdiv->bits());
pos.ry() += latDelta<<(24-subdiv->bits());
Coordinates c(toWGS84(pos.x()), toWGS84(pos.y()));
Coordinates c(toWGS24(pos.x()), toWGS24(pos.y()));
poly.points.append(QPointF(c.lon(), c.lat()));
br = br.united(c);
}
@ -321,8 +321,8 @@ bool RGNFile::pointObjects(const RectC &rect, Handle &hdl, const SubDiv *subdiv,
qint16 lonOffset = lon<<(24-subdiv->bits());
qint16 latOffset = lat<<(24-subdiv->bits());
point.coordinates = Coordinates(toWGS84(subdiv->lon() + lonOffset),
toWGS84(subdiv->lat() + latOffset));
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
toWGS24(subdiv->lat() + latOffset));
if (!rect.contains(point.coordinates))
continue;
@ -367,8 +367,8 @@ bool RGNFile::extPointObjects(const RectC &rect, Handle &hdl,
qint16 lonOffset = lon<<(24-subdiv->bits());
qint16 latOffset = lat<<(24-subdiv->bits());
point.coordinates = Coordinates(toWGS84(subdiv->lon() + lonOffset),
toWGS84(subdiv->lat() + latOffset));
point.coordinates = Coordinates(toWGS24(subdiv->lon() + lonOffset),
toWGS24(subdiv->lat() + latOffset));
if (subtype & 0x20) {
if (!readUInt24(hdl, labelPtr))

View File

@ -3,7 +3,7 @@
#include <QtGlobal>
#include "common/coordinates.h"
#include "units.h"
#include "common/garmin.h"
class SubDiv {
public:
@ -51,7 +51,7 @@ private:
#ifndef QT_NO_DEBUG
inline QDebug operator<<(QDebug dbg, const SubDiv &subdiv)
{
Coordinates c(toWGS84(subdiv.lon()), toWGS84(subdiv.lat()));
Coordinates c(toWGS24(subdiv.lon()), toWGS24(subdiv.lat()));
dbg.nospace() << "SubDiv(" << c << ", " << subdiv.offset()
<< ", " << subdiv.end() << ", " << subdiv.objects() << ")";
return dbg.space();

View File

@ -1,5 +1,5 @@
#include "common/garmin.h"
#include "subdiv.h"
#include "units.h"
#include "trefile.h"
@ -52,8 +52,8 @@ bool TREFile::init()
if (!(seek(hdl, _gmpOffset + 0x15) && readInt24(hdl, north)
&& readInt24(hdl, east) && readInt24(hdl, south) && readInt24(hdl, west)))
return false;
_bounds = RectC(Coordinates(toWGS84(west), toWGS84(north)),
Coordinates(toWGS84(east), toWGS84(south)));
_bounds = RectC(Coordinates(toWGS24(west), toWGS24(north)),
Coordinates(toWGS24(east), toWGS24(south)));
// Levels & subdivs info
quint32 levelsOffset, levelsSize, subdivSize;
@ -150,9 +150,9 @@ bool TREFile::load(int idx)
sl.append(s);
double min[2], max[2];
RectC bounds(Coordinates(toWGS84(lon - width),
toWGS84(lat + height + 1)), Coordinates(toWGS84(lon + width + 1),
toWGS84(lat - height)));
RectC bounds(Coordinates(toWGS24(lon - width),
toWGS24(lat + height + 1)), Coordinates(toWGS24(lon + width + 1),
toWGS24(lat - height)));
min[0] = bounds.left();
min[1] = bounds.bottom();

View File

@ -1,11 +0,0 @@
#ifndef UNITS_H
#define UNITS_H
inline double toWGS84(qint32 coord)
{
return (coord < 0x800000)
? (double)coord * 360.0 / (double)(1<<24)
: (double)(coord - 0x1000000) * 360.0 / (double)(1<<24);
}
#endif // UNITS_H