147 lines
4.9 KiB
C++
147 lines
4.9 KiB
C++
#include <mbgl/map/vector_tile.hpp>
|
|
#include <mbgl/geometry/pbf_geometry.hpp>
|
|
#include <mbgl/style/filter_expression_private.hpp>
|
|
#include <mbgl/util/pbf.hpp>
|
|
|
|
#include <type_traits>
|
|
#include <ostream>
|
|
|
|
using namespace mbgl;
|
|
|
|
VectorTileFeature::VectorTileFeature(pbf feature_pbf, const VectorTileLayer& layer) {
|
|
while (feature_pbf.next()) {
|
|
if (feature_pbf.tag == 1) { // id
|
|
id = feature_pbf.varint<uint64_t>();
|
|
} else if (feature_pbf.tag == 2) { // tags
|
|
// tags are packed varints. They should have an even length.
|
|
pbf tags = feature_pbf.message();
|
|
while (tags) {
|
|
uint32_t tag_key = tags.varint();
|
|
|
|
if (layer.keys.size() <= tag_key) {
|
|
throw std::runtime_error("feature referenced out of range key");
|
|
}
|
|
|
|
if (tags) {
|
|
uint32_t tag_val = tags.varint();
|
|
if (layer.values.size() <= tag_val) {
|
|
throw std::runtime_error("feature referenced out of range value");
|
|
}
|
|
|
|
properties.emplace(layer.keys[tag_key], layer.values[tag_val]);
|
|
} else {
|
|
throw std::runtime_error("uneven number of feature tag ids");
|
|
}
|
|
}
|
|
} else if (feature_pbf.tag == 3) { // type
|
|
type = (GeometryFeatureType)feature_pbf.varint();
|
|
} else if (feature_pbf.tag == 4) { // geometry
|
|
geometry_pbf = feature_pbf.message();
|
|
} else {
|
|
feature_pbf.skip();
|
|
}
|
|
}
|
|
}
|
|
|
|
mapbox::util::optional<Value> VectorTileFeature::getValue(const std::string& key) const {
|
|
auto it = properties.find(key);
|
|
if (it != properties.end()) {
|
|
return it->second;
|
|
}
|
|
return mapbox::util::optional<Value>();
|
|
}
|
|
|
|
GeometryCollection VectorTileFeature::getGeometries() const {
|
|
GeometryCollection result;
|
|
pbf geom_pbf = geometry_pbf;
|
|
|
|
while (geom_pbf.next(4)) { // geometry
|
|
pbf current_geometry_pbf = geom_pbf.message();
|
|
PBFGeometry current_geometry(current_geometry_pbf);
|
|
PBFGeometry::command cmd;
|
|
int32_t x, y;
|
|
|
|
if (type == GeometryFeatureType::Point) {
|
|
if ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
|
|
GeometryPoint point(x, y);
|
|
result.emplace_back(GeometryPoint(x, y));
|
|
}
|
|
} else if (type == GeometryFeatureType::LineString) {
|
|
GeometryLine line;
|
|
while ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
|
|
if (cmd == PBFGeometry::move_to) {
|
|
if (!line.empty()) {
|
|
result.push_back(line);
|
|
line.clear();
|
|
}
|
|
}
|
|
line.emplace_back(x, y);
|
|
}
|
|
if (line.size()) {
|
|
result.push_back(line);
|
|
}
|
|
} else if (type == GeometryFeatureType::Polygon) {
|
|
GeometryLine line;
|
|
while ((cmd = current_geometry.next(x, y)) != PBFGeometry::end) {
|
|
if (cmd == PBFGeometry::move_to) {
|
|
if (line.size()) {
|
|
result.push_back(line);
|
|
line.clear();
|
|
}
|
|
}
|
|
line.emplace_back(x, y);
|
|
}
|
|
|
|
if (line.size()) {
|
|
result.push_back(line);
|
|
line.clear();
|
|
}
|
|
} else {
|
|
throw std::runtime_error("unrecognized geometry type");
|
|
}
|
|
}
|
|
|
|
return std::move(result);
|
|
}
|
|
|
|
VectorTile::VectorTile(pbf tile_pbf) {
|
|
while (tile_pbf.next()) {
|
|
if (tile_pbf.tag == 3) { // layer
|
|
util::ptr<VectorTileLayer> layer = std::make_shared<VectorTileLayer>(tile_pbf.message());
|
|
layers.emplace(layer->name, layer);
|
|
} else {
|
|
tile_pbf.skip();
|
|
}
|
|
}
|
|
}
|
|
|
|
const util::ptr<const GeometryTileLayer> VectorTile::getLayer(const std::string& name) const {
|
|
auto layer_it = layers.find(name);
|
|
if (layer_it != layers.end()) {
|
|
return layer_it->second;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
VectorTileLayer::VectorTileLayer(pbf layer_pbf) {
|
|
while (layer_pbf.next()) {
|
|
if (layer_pbf.tag == 1) { // name
|
|
name = layer_pbf.string();
|
|
} else if (layer_pbf.tag == 2) { // feature
|
|
features.push_back(layer_pbf.message());
|
|
} else if (layer_pbf.tag == 3) { // keys
|
|
keys.emplace_back(layer_pbf.string());
|
|
} else if (layer_pbf.tag == 4) { // values
|
|
values.emplace_back(std::move(parseValue(layer_pbf.message())));
|
|
} else if (layer_pbf.tag == 5) { // extent
|
|
extent = layer_pbf.varint();
|
|
} else {
|
|
layer_pbf.skip();
|
|
}
|
|
}
|
|
}
|
|
|
|
const util::ptr<const GeometryTileFeature> VectorTileLayer::feature(std::size_t i) const {
|
|
return std::make_shared<VectorTileFeature>(features.at(i), *this);
|
|
}
|