Compare commits

...

5 Commits

14 changed files with 415 additions and 241 deletions

View File

@ -1,4 +1,4 @@
version: 3.2.{build} version: 4.0.{build}
configuration: configuration:
- Release - Release
@ -14,20 +14,18 @@ environment:
install: install:
- cmd: |- - cmd: |-
set PATH=%QTDIR%\bin;%VCPKGDIR%\tools\protobuf;%PATH% set PATH=%QTDIR%\bin;%PATH%
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat
vcpkg install pkgconf:x64-windows-static-md-release
vcpkg install protobuf:x64-windows-static-md-release
vcpkg install zlib:x64-windows-static-md-release vcpkg install zlib:x64-windows-static-md-release
copy /y %VCPKGDIR%\lib\zlib.lib %VCPKGDIR%\lib\zlibstatic.lib copy /y %VCPKGDIR%\lib\zlib.lib %VCPKGDIR%\lib\zlibstatic.lib
build_script: build_script:
- cmd: |- - cmd: |-
qmake USE_PKGCONFIG=true pbfplugin.pro qmake ZLIB=%VCPKGDIR% pbfplugin.pro
nmake release nmake release
artifacts: artifacts:
- path: release\pbf3.dll - path: release\pbf4.dll
cache: cache:
- C:\tools\vcpkg\installed\ - C:\tools\vcpkg\installed\

View File

@ -12,10 +12,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install protobuf compiler
run: |
sudo apt-get update
sudo apt-get install protobuf-compiler
- name: set up JDK 11 - name: set up JDK 11
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
@ -41,10 +37,8 @@ jobs:
version: '6.4.0' version: '6.4.0'
target: 'android' target: 'android'
arch: 'android_arm64_v8a' arch: 'android_arm64_v8a'
- name: Install Android Google Protocol Buffers
run: git clone https://github.com/tumic0/android_protobuf.git
- name: Configure build - name: Configure build
run: qmake pbfplugin.pro PROTOBUF=android_protobuf run: qmake pbfplugin.pro
- name: Build project - name: Build project
run: make -j2 run: make -j2
- name: Upload artifacts - name: Upload artifacts

View File

@ -15,7 +15,7 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install qtbase5-dev qtbase5-dev-tools qt5-qmake libprotobuf-dev protobuf-compiler zlib1g-dev sudo apt-get install qtbase5-dev qtbase5-dev-tools qt5-qmake zlib1g-dev
- name: Configure build - name: Configure build
run: qmake pbfplugin.pro run: qmake pbfplugin.pro
- name: Build project - name: Build project

View File

@ -6,36 +6,22 @@ on:
- master - master
jobs: jobs:
qt5: build:
name: QtPBFImagePlugin Qt5 build name: QtPBFImagePlugin
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- name: Set environment variables
run: echo "PATH=/opt/homebrew/opt/qt@5/bin:/opt/homebrew/opt/protobuf@21/bin:$PATH" >> $GITHUB_ENV
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install dependencies - name: Install Qt
run: | uses: jurplel/install-qt-action@v4
brew update with:
brew install qt@5 protobuf@21 version: '6.8.1'
- name: Configure build - name: Configure build
run: qmake PROTOBUF=/opt/homebrew/opt/protobuf@21 pbfplugin.pro run: qmake pbfplugin.pro QMAKE_APPLE_DEVICE_ARCHS="x86_64h arm64"
- name: Build project
run: make -j3
qt6:
name: QtPBFImagePlugin Qt6 build
runs-on: macos-latest
steps:
- name: Set environment variables
run: echo "PATH=/opt/homebrew/opt/qt@6/bin:/opt/homebrew/opt/protobuf@21/bin:$PATH" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: |
brew update
brew install qt@6 protobuf@21
- name: Configure build
run: qmake PROTOBUF=/opt/homebrew/opt/protobuf@21 pbfplugin.pro
- name: Build project - name: Build project
run: make -j3 run: make -j3
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
path: libpbf.dylib
name: libpbf.dylib

View File

@ -68,25 +68,19 @@ repository.
## Build ## Build
### Requirements ### Requirements
* Qt5 >= 5.11 or Qt6 * Qt5 >= 5.11 or Qt6
* Google Protocol Buffers (protobuf-lite)
* Zlib * Zlib
### Build steps ### Build steps
#### Linux #### Linux, OS X and Android
```shell ```shell
qmake pbfplugin.pro qmake pbfplugin.pro
make make
``` ```
#### Windows #### Windows
```shell ```shell
qmake PROTOBUF=path/to/protobuf ZLIB=path/to/zlib pbfplugin.pro qmake ZLIB=path/to/zlib pbfplugin.pro
nmake nmake
``` ```
#### OS X
```shell
qmake PROTOBUF=path/to/protobuf pbfplugin.pro
make
```
## Install ## Install
Copy the plugin to the system Qt image plugins path to make it work. You may Copy the plugin to the system Qt image plugins path to make it work. You may

View File

@ -2,13 +2,10 @@ TARGET = pbf
TEMPLATE = lib TEMPLATE = lib
CONFIG += plugin CONFIG += plugin
QT += gui QT += gui
VERSION = 3.3 VERSION = 4.0
PROTOS = protobuf/vector_tile.proto
include(protobuf/vector_tile.pri)
INCLUDEPATH += ./protobuf
HEADERS += src/pbfhandler.h \ HEADERS += src/pbfhandler.h \
src/data.h \
src/pbfplugin.h \ src/pbfplugin.h \
src/gzip.h \ src/gzip.h \
src/pbf.h \ src/pbf.h \
@ -23,6 +20,7 @@ HEADERS += src/pbfhandler.h \
src/textitem.h \ src/textitem.h \
src/sprites.h src/sprites.h
SOURCES += src/pbfplugin.cpp \ SOURCES += src/pbfplugin.cpp \
src/data.cpp \
src/pbfhandler.cpp \ src/pbfhandler.cpp \
src/gzip.cpp \ src/gzip.cpp \
src/pbf.cpp \ src/pbf.cpp \
@ -39,45 +37,25 @@ RESOURCES += pbfplugin.qrc
DEFINES += QT_NO_DEPRECATED_WARNINGS DEFINES += QT_NO_DEPRECATED_WARNINGS
equals(USE_PKGCONFIG, "true") {
CONFIG += link_pkgconfig
PKGCONFIG += protobuf-lite zlib
}
unix:!macx:!android { unix:!macx:!android {
!equals(USE_PKGCONFIG, "true") { LIBS += -lz
LIBS += -lprotobuf-lite \
-lz
}
target.path += $$[QT_INSTALL_PLUGINS]/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats
INSTALLS += target INSTALLS += target
} }
win32 { win32 {
!equals(USE_PKGCONFIG, "true") { INCLUDEPATH += $$ZLIB/include
INCLUDEPATH += $$PROTOBUF/include \ LIBS += $$ZLIB/lib/zlibstatic.lib
$$ZLIB/include
LIBS += $$PROTOBUF/lib/libprotobuf-lite.lib \
$$ZLIB/lib/zlibstatic.lib
}
QMAKE_TARGET_PRODUCT = QtPBFImagePlugin QMAKE_TARGET_PRODUCT = QtPBFImagePlugin
QMAKE_TARGET_DESCRIPTION = Qt $$QT_VERSION MVT/PBF image plugin QMAKE_TARGET_DESCRIPTION = Qt $$QT_VERSION MVT/PBF image plugin
QMAKE_TARGET_COPYRIGHT = Copyright (c) 2018-2025 Martin Tuma QMAKE_TARGET_COPYRIGHT = Copyright (c) 2018-2025 Martin Tuma
} }
macx { macx {
!equals(USE_PKGCONFIG, "true") { LIBS += -lz
INCLUDEPATH += $$PROTOBUF/include
LIBS += $$PROTOBUF/lib/libprotobuf-lite.a \
-lz
}
} }
android { android {
!equals(USE_PKGCONFIG, "true") { LIBS += -lz
INCLUDEPATH += $$PROTOBUF/include
LIBS += $$PROTOBUF/$$ANDROID_TARGET_ARCH/libprotobuf-lite.a \
-lz
}
top_builddir=$$shadowed($$PWD) top_builddir=$$shadowed($$PWD)
DESTDIR = $$top_builddir/plugins DESTDIR = $$top_builddir/plugins

View File

@ -1,17 +0,0 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
protobuf_decl.name = protobuf headers
protobuf_decl.input = PROTOS
protobuf_decl.output = ${QMAKE_FILE_IN_PATH}/${QMAKE_FILE_BASE}.pb.h
protobuf_decl.commands = protoc --cpp_out=${QMAKE_FILE_IN_PATH} --proto_path=${QMAKE_FILE_IN_PATH} ${QMAKE_FILE_NAME}
protobuf_decl.variable_out = HEADERS
QMAKE_EXTRA_COMPILERS += protobuf_decl
protobuf_impl.name = protobuf sources
protobuf_impl.input = PROTOS
protobuf_impl.output = ${QMAKE_FILE_IN_PATH}/${QMAKE_FILE_BASE}.pb.cc
protobuf_impl.depends = ${QMAKE_FILE_IN_PATH}/${QMAKE_FILE_BASE}.pb.h
protobuf_impl.commands = $$escape_expand(\n)
protobuf_impl.variable_out = SOURCES
QMAKE_EXTRA_COMPILERS += protobuf_impl

View File

@ -1,78 +0,0 @@
package vector_tile;
option optimize_for = LITE_RUNTIME;
message Tile {
// GeomType is described in section 4.3.4 of the specification
enum GeomType {
UNKNOWN = 0;
POINT = 1;
LINESTRING = 2;
POLYGON = 3;
}
// Variant type encoding
// The use of values is described in section 4.1 of the specification
message Value {
// Exactly one of these values must be present in a valid message
optional string string_value = 1;
optional float float_value = 2;
optional double double_value = 3;
optional int64 int_value = 4;
optional uint64 uint_value = 5;
optional sint64 sint_value = 6;
optional bool bool_value = 7;
extensions 8 to max;
}
// Features are described in section 4.2 of the specification
message Feature {
optional uint64 id = 1 [ default = 0 ];
// Tags of this feature are encoded as repeated pairs of
// integers.
// A detailed description of tags is located in sections
// 4.2 and 4.4 of the specification
repeated uint32 tags = 2 [ packed = true ];
// The type of geometry stored in this feature.
optional GeomType type = 3 [ default = UNKNOWN ];
// Contains a stream of commands and parameters (vertices).
// A detailed description on geometry encoding is located in
// section 4.3 of the specification.
repeated uint32 geometry = 4 [ packed = true ];
}
// Layers are described in section 4.1 of the specification
message Layer {
// Any compliant implementation must first read the version
// number encoded in this message and choose the correct
// implementation for this version number before proceeding to
// decode other parts of this message.
required uint32 version = 15 [ default = 1 ];
required string name = 1;
// The actual features in this tile.
repeated Feature features = 2;
// Dictionary encoding for keys
repeated string keys = 3;
// Dictionary encoding for values
repeated Value values = 4;
// Although this is an "optional" field it is required by the specification.
// See https://github.com/mapbox/vector-tile-spec/issues/47
optional uint32 extent = 5 [ default = 4096 ];
extensions 16 to max;
}
repeated Layer layers = 3;
extensions 16 to 8191;
}

301
src/data.cpp Normal file
View File

@ -0,0 +1,301 @@
#include "data.h"
#define TYPE(tag) (tag & 0x07)
#define FIELD(tag) (tag >> 3)
struct CTX
{
CTX(const QByteArray &ba)
: bp(ba.constData()), be(bp + ba.size()) {}
const char *bp;
const char *be;
quint64 tag;
};
static inline qint64 zigzag64decode(quint64 value)
{
return static_cast<qint64>((value >> 1u) ^ static_cast<quint64>(
-static_cast<qint64>(value & 1u)));
}
template<typename T>
static bool varint(CTX &ctx, T &val)
{
val = 0;
uint shift = 0;
const char *end = qMin(ctx.be, ctx.bp + sizeof(val));
while (ctx.bp < end) {
val |= ((quint8)*ctx.bp & 0x7F) << shift;
shift += 7;
if (!((quint8)*ctx.bp++ & 0x80))
return true;
}
return false;
}
static bool str(CTX &ctx, QByteArray &val)
{
quint64 len;
if (!varint(ctx, len))
return false;
if (ctx.bp + len > ctx.be)
return false;
val = QByteArray::fromRawData(ctx.bp, len);
ctx.bp += len;
return true;
}
static bool dbl(CTX &ctx, double &val)
{
if (ctx.bp + sizeof(val) > ctx.be)
return false;
memcpy(&val, ctx.bp, sizeof(val));
return true;
}
static bool flt(CTX &ctx, float &val)
{
if (ctx.bp + sizeof(val) > ctx.be)
return false;
memcpy(&val, ctx.bp, sizeof(val));
return true;
}
static bool packed(CTX &ctx, QVector<quint32> &vals)
{
quint32 v;
if (TYPE(ctx.tag) == 2) {
quint64 len;
if (!varint(ctx, len))
return false;
const char *ee = ctx.bp + len;
if (ee > ctx.be)
return false;
while (ctx.bp < ee) {
if (!varint(ctx, v))
return false;
vals.append(v);
}
return (ctx.bp == ee);
} else if (TYPE(ctx.tag) == 0) {
if (!varint(ctx, v))
return false;
vals.append(v);
return true;
} else
return false;
}
static bool skip(CTX &ctx)
{
quint64 len = 0;
switch (TYPE(ctx.tag)) {
case 0:
return varint(ctx, len);
case 1:
len = 8;
break;
case 2:
if (!varint(ctx, len))
return false;
break;
case 5:
len = 4;
break;
default:
return false;
}
if (ctx.bp + len > ctx.be)
return false;
ctx.bp += len;
return true;
}
static bool value(CTX &ctx, QVariant &val)
{
QByteArray ba;
quint64 len, num;
double dnum;
float fnum;
if (!varint(ctx, len))
return false;
const char *ee = ctx.bp + len;
if (ee > ctx.be)
return false;
while (ctx.bp < ee) {
if (!varint(ctx, ctx.tag))
return false;
switch (FIELD(ctx.tag)) {
case 1:
if (!str(ctx, ba))
return false;
val = QVariant(ba);
break;
case 2:
if (!flt(ctx, fnum))
return false;
val = QVariant(fnum);
break;
case 3:
if (!dbl(ctx, dnum))
return false;
val = QVariant(dnum);
break;
case 4:
if (!varint(ctx, num))
return false;
val = QVariant(static_cast<qint64>(num));
break;
case 5:
if (!varint(ctx, num))
return false;
val = QVariant(num);
break;
case 6:
if (!varint(ctx, num))
return false;
val = QVariant(zigzag64decode(num));
break;
case 7:
if (!varint(ctx, num))
return false;
val = QVariant(num ? true : false);
break;
default:
if (!skip(ctx))
return false;
}
}
return (ctx.bp == ee);
}
static bool feature(CTX &ctx, Data::Feature &f)
{
quint64 len;
quint8 e;
if (!varint(ctx, len))
return false;
const char *ee = ctx.bp + len;
if (ee > ctx.be)
return false;
while (ctx.bp < ee) {
if (!varint(ctx, ctx.tag))
return false;
switch (FIELD(ctx.tag)) {
case 1:
if (!varint(ctx, f.id))
return false;
break;
case 2:
if (!packed(ctx, f.tags))
return false;
break;
case 3:
if (!varint(ctx, e))
return false;
if (e > Data::GeomType::POLYGON)
return false;
f.type = (Data::GeomType)e;
break;
case 4:
if (!packed(ctx, f.geometry))
return false;
break;
default:
if (!skip(ctx))
return false;
}
}
return (ctx.bp == ee);
}
static bool layer(CTX &ctx, Data::Layer &l)
{
if (ctx.tag == 0x1a) {
quint64 len;
if (!varint(ctx, len))
return false;
const char *ee = ctx.bp + len;
if (ee > ctx.be)
return false;
while (ctx.bp < ee) {
if (!varint(ctx, ctx.tag))
return false;
switch (FIELD(ctx.tag)) {
case 1:
if (!str(ctx, l.name))
return false;
break;
case 2:
l.features.append(Data::Feature());
if (!feature(ctx, l.features.last()))
return false;
break;
case 3:
l.keys.append(QByteArray());
if (!str(ctx, l.keys.last()))
return false;
break;
case 4:
l.values.append(QVariant());
if (!value(ctx, l.values.last()))
return false;
break;
case 5:
if (!varint(ctx, l.extent))
return false;
break;
case 15:
if (!varint(ctx, l.version))
return false;
break;
default:
if (!skip(ctx))
return false;
}
}
return (ctx.bp == ee);
} else
return skip(ctx);
}
bool Data::load(const QByteArray &ba)
{
CTX ctx(ba);
while (ctx.bp < ctx.be) {
if (!varint(ctx, ctx.tag))
return false;
_layers.append(Layer());
if (!layer(ctx, _layers.last()))
return false;
}
return (ctx.bp == ctx.be);
}

43
src/data.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef DATA_H
#define DATA_H
#include <QByteArray>
#include <QVector>
#include <QVariant>
class Data
{
public:
enum GeomType {
UNKNOWN = 0,
POINT = 1,
LINESTRING = 2,
POLYGON = 3
};
struct Feature
{
quint64 id;
QVector<quint32> tags;
GeomType type;
QVector<quint32> geometry;
};
struct Layer
{
quint32 version;
QByteArray name;
QVector<Feature> features;
QVector<QByteArray> keys;
QVector<QVariant> values;
quint32 extent;
};
bool load(const QByteArray &ba);
const QVector<Layer> &layers() const {return _layers;}
private:
QVector<Layer> _layers;
};
#endif // DATA_H

View File

@ -4,7 +4,6 @@
#define LINE_TO 2 #define LINE_TO 2
#define CLOSE_PATH 7 #define CLOSE_PATH 7
static inline qint32 zigzag32decode(quint32 value) static inline qint32 zigzag32decode(quint32 value)
{ {
return static_cast<qint32>((value >> 1u) ^ static_cast<quint32>( return static_cast<qint32>((value >> 1u) ^ static_cast<quint32>(
@ -16,26 +15,6 @@ static inline QPoint parameters(quint32 v1, quint32 v2)
return QPoint(zigzag32decode(v1), zigzag32decode(v2)); return QPoint(zigzag32decode(v1), zigzag32decode(v2));
} }
static QVariant value(const vector_tile::Tile_Value &val)
{
if (val.has_bool_value())
return QVariant(val.bool_value());
else if (val.has_int_value())
return QVariant((qlonglong)val.int_value());
else if (val.has_sint_value())
return QVariant((qlonglong)val.sint_value());
else if (val.has_uint_value())
return QVariant((qulonglong)val.uint_value());
else if (val.has_float_value())
return QVariant(val.float_value());
else if (val.has_double_value())
return QVariant(val.double_value());
else if (val.has_string_value())
return QVariant(QByteArray::fromStdString(val.string_value()));
else
return QVariant();
}
const QVariant *PBF::Feature::value(const QByteArray &key) const const QVariant *PBF::Feature::value(const QByteArray &key) const
{ {
const KeyHash &keys(_layer->keys()); const KeyHash &keys(_layer->keys());
@ -43,10 +22,10 @@ const QVariant *PBF::Feature::value(const QByteArray &key) const
if (it == keys.constEnd()) if (it == keys.constEnd())
return 0; return 0;
google::protobuf::uint32 index = *it; quint32 index = *it;
for (int i = 0; i < _data->tags_size(); i = i + 2) for (int i = 0; i < _data->tags.size(); i = i + 2)
if (_data->tags(i) == index) if (_data->tags.at(i) == index)
return &(_layer->values().at(_data->tags(i+1))); return &(_layer->values().at(_data->tags.at(i+1)));
return 0; return 0;
} }
@ -56,15 +35,15 @@ QPainterPath PBF::Feature::path(const QSizeF &factor) const
QPoint cursor; QPoint cursor;
QPainterPath path; QPainterPath path;
for (int i = 0; i < _data->geometry_size(); i++) { for (int i = 0; i < _data->geometry.size(); i++) {
quint32 g = _data->geometry(i); quint32 g = _data->geometry.at(i);
unsigned cmdId = g & 0x7; unsigned cmdId = g & 0x7;
unsigned cmdCount = g >> 3; unsigned cmdCount = g >> 3;
if (cmdId == MOVE_TO) { if (cmdId == MOVE_TO) {
for (unsigned j = 0; j < cmdCount; j++) { for (unsigned j = 0; j < cmdCount; j++) {
QPoint offset = parameters(_data->geometry(i+1), QPoint offset = parameters(_data->geometry.at(i+1),
_data->geometry(i+2)); _data->geometry.at(i+2));
i += 2; i += 2;
cursor += offset; cursor += offset;
path.moveTo(QPointF(cursor.x() * factor.width(), path.moveTo(QPointF(cursor.x() * factor.width(),
@ -72,8 +51,8 @@ QPainterPath PBF::Feature::path(const QSizeF &factor) const
} }
} else if (cmdId == LINE_TO) { } else if (cmdId == LINE_TO) {
for (unsigned j = 0; j < cmdCount; j++) { for (unsigned j = 0; j < cmdCount; j++) {
QPoint offset = parameters(_data->geometry(i+1), QPoint offset = parameters(_data->geometry.at(i+1),
_data->geometry(i+2)); _data->geometry.at(i+2));
i += 2; i += 2;
cursor += offset; cursor += offset;
path.lineTo(QPointF(cursor.x() * factor.width(), path.lineTo(QPointF(cursor.x() * factor.width(),
@ -88,27 +67,23 @@ QPainterPath PBF::Feature::path(const QSizeF &factor) const
return path; return path;
} }
PBF::Layer::Layer(const vector_tile::Tile_Layer *data) : _data(data) PBF::Layer::Layer(const Data::Layer *layer) : _data(layer)
{ {
_keys.reserve(data->keys_size()); _keys.reserve(layer->keys.size());
for (int i = 0; i < data->keys_size(); i++) for (int i = 0; i < layer->keys.size(); i++)
_keys.insert(QByteArray::fromStdString(data->keys(i)), i); _keys.insert(layer->keys.at(i), i);
_values.reserve(data->values_size());
for (int i = 0; i < data->values_size(); i++)
_values.append(value(data->values(i)));
_features.reserve(data->features_size()); _features.reserve(layer->features.size());
for (int i = 0; i < data->features_size(); i++) for (int i = 0; i < layer->features.size(); i++)
_features.append(Feature(&(data->features(i)), this)); _features.append(Feature(&(layer->features.at(i)), this));
std::sort(_features.begin(), _features.end()); std::sort(_features.begin(), _features.end());
} }
PBF::PBF(const vector_tile::Tile &tile) PBF::PBF(const Data &data)
{ {
for (int i = 0; i < tile.layers_size(); i++) { for (int i = 0; i < data.layers().size(); i++) {
const vector_tile::Tile_Layer &layer = tile.layers(i); const Data::Layer &layer = data.layers().at(i);
_layers.insert(QByteArray::fromStdString(layer.name()), _layers.insert(layer.name, new Layer(&layer));
new Layer(&layer));
} }
} }

View File

@ -5,10 +5,10 @@
#include <QVector> #include <QVector>
#include <QHash> #include <QHash>
#include <QPainterPath> #include <QPainterPath>
#include "vector_tile.pb.h" #include "data.h"
typedef QHash<QByteArray, google::protobuf::uint32> KeyHash; typedef QHash<QByteArray, quint32> KeyHash;
class PBF class PBF
{ {
@ -19,17 +19,17 @@ public:
{ {
public: public:
Feature() : _data(0), _layer(0) {} Feature() : _data(0), _layer(0) {}
Feature(const vector_tile::Tile_Feature *data, const Layer *layer) Feature(const Data::Feature *data, const Layer *layer)
: _data(data), _layer(layer) {} : _data(data), _layer(layer) {}
const QVariant *value(const QByteArray &key) const; const QVariant *value(const QByteArray &key) const;
vector_tile::Tile_GeomType type() const {return _data->type();} Data::GeomType type() const {return _data->type;}
QPainterPath path(const QSizeF &factor) const; QPainterPath path(const QSizeF &factor) const;
friend bool operator<(const Feature &f1, const Feature &f2); friend bool operator<(const Feature &f1, const Feature &f2);
private: private:
const vector_tile::Tile_Feature *_data; const Data::Feature *_data;
const Layer *_layer; const Layer *_layer;
}; };
@ -37,22 +37,21 @@ public:
{ {
public: public:
Layer(const vector_tile::Tile_Layer *data); Layer(const Data::Layer *layer);
const QVector<Feature> &features() const {return _features;} const QVector<Feature> &features() const {return _features;}
const QVector<QVariant> &values() const {return _values;} const QVector<QVariant> &values() const {return _data->values;}
const KeyHash &keys() const {return _keys;} const KeyHash &keys() const {return _keys;}
const vector_tile::Tile_Layer *data() const {return _data;} const Data::Layer *data() const {return _data;}
private: private:
const vector_tile::Tile_Layer *_data; const Data::Layer *_data;
QVector<Feature> _features; QVector<Feature> _features;
QVector<QVariant> _values;
KeyHash _keys; KeyHash _keys;
}; };
PBF(const vector_tile::Tile &tile); PBF(const Data &data);
~PBF(); ~PBF();
const QHash<QByteArray, Layer*> &layers() const {return _layers;} const QHash<QByteArray, Layer*> &layers() const {return _layers;}
@ -62,6 +61,6 @@ private:
}; };
inline bool operator<(const PBF::Feature &f1, const PBF::Feature &f2) inline bool operator<(const PBF::Feature &f1, const PBF::Feature &f2)
{return f1._data->id() < f2._data->id();} {return f1._data->id < f2._data->id;}
#endif // PBF_H #endif // PBF_H

View File

@ -3,6 +3,7 @@
#include <QtEndian> #include <QtEndian>
#include <QDebug> #include <QDebug>
#include "gzip.h" #include "gzip.h"
#include "data.h"
#include "tile.h" #include "tile.h"
#include "style.h" #include "style.h"
#include "pbfhandler.h" #include "pbfhandler.h"
@ -73,8 +74,8 @@ bool PBFHandler::read(QImage *image)
} }
} else if (isPlainPBF(magic)) } else if (isPlainPBF(magic))
ba = device()->readAll(); ba = device()->readAll();
vector_tile::Tile data; Data data;
if (!data.ParseFromArray(ba.constData(), ba.size())) { if (!data.load(ba)) {
qCritical() << "Invalid PBF data"; qCritical() << "Invalid PBF data";
return false; return false;
} }

View File

@ -14,16 +14,16 @@
#include "style.h" #include "style.h"
static vector_tile::Tile_GeomType geometryType(const QString &str) static Data::GeomType geometryType(const QString &str)
{ {
if (str == "Point") if (str == "Point")
return vector_tile::Tile_GeomType_POINT; return Data::GeomType::POINT;
else if (str == "LineString") else if (str == "LineString")
return vector_tile::Tile_GeomType_LINESTRING; return Data::GeomType::LINESTRING;
else if (str == "Polygon") else if (str == "Polygon")
return vector_tile::Tile_GeomType_POLYGON; return Data::GeomType::POLYGON;
else else
return vector_tile::Tile_GeomType_UNKNOWN; return Data::GeomType::UNKNOWN;
} }
static QVariant variant(const QJsonValue &val) static QVariant variant(const QJsonValue &val)
@ -680,15 +680,15 @@ void Style::drawFeature(const PBF::Feature &feature, const Layer &layer,
void Style::drawLayer(const PBF::Layer &pbfLayer, const Layer &styleLayer, void Style::drawLayer(const PBF::Layer &pbfLayer, const Layer &styleLayer,
Tile &tile) Tile &tile)
{ {
if (pbfLayer.data()->version() > 2) if (pbfLayer.data()->version > 2)
return; return;
if (!styleLayer.isVisible()) if (!styleLayer.isVisible())
return; return;
QSizeF factor(tile.size().width() / tile.scale().x() / QSizeF factor(tile.size().width() / tile.scale().x() /
(qreal)pbfLayer.data()->extent(), tile.size().height() / tile.scale().y() (qreal)pbfLayer.data()->extent, tile.size().height() / tile.scale().y()
/ (qreal)pbfLayer.data()->extent()); / (qreal)pbfLayer.data()->extent);
tile.painter().save(); tile.painter().save();
setupLayer(tile, styleLayer); setupLayer(tile, styleLayer);