From 4bfc5592239d96d6d352ddbbb906dde0ea4012be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 21 Jun 2017 11:03:00 -0700 Subject: [core] add benchmark for vector tile parsing --- src/mbgl/tile/vector_tile_data.cpp | 247 +++++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 src/mbgl/tile/vector_tile_data.cpp (limited to 'src/mbgl/tile/vector_tile_data.cpp') diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp new file mode 100644 index 0000000000..5eb199f482 --- /dev/null +++ b/src/mbgl/tile/vector_tile_data.cpp @@ -0,0 +1,247 @@ +#include +#include + +namespace mbgl { + +Value parseValue(protozero::pbf_reader data) { + Value value; + while (data.next()) { + switch (data.tag()) { + case 1: // string_value + value = data.get_string(); + break; + case 2: // float_value + value = static_cast(data.get_float()); + break; + case 3: // double_value + value = data.get_double(); + break; + case 4: // int_value + value = data.get_int64(); + break; + case 5: // uint_value + value = data.get_uint64(); + break; + case 6: // sint_value + value = data.get_sint64(); + break; + case 7: // bool_value + value = data.get_bool(); + break; + default: + data.skip(); + break; + } + } + return value; +} + +VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, std::shared_ptr layerData_) + : layerData(std::move(layerData_)) { + while (feature_pbf.next()) { + switch (feature_pbf.tag()) { + case 1: // id + id = { feature_pbf.get_uint64() }; + break; + case 2: // tags + tags_iter = feature_pbf.get_packed_uint32(); + break; + case 3: // type + type = static_cast(feature_pbf.get_enum()); + break; + case 4: // geometry + geometry_iter = feature_pbf.get_packed_uint32(); + break; + default: + feature_pbf.skip(); + break; + } + } +} + +optional VectorTileFeature::getValue(const std::string& key) const { + auto keyIter = layerData->keysMap.find(key); + if (keyIter == layerData->keysMap.end()) { + return optional(); + } + + auto start_itr = tags_iter.begin(); + const auto & end_itr = tags_iter.end(); + while (start_itr != end_itr) { + auto tag_key = static_cast(*start_itr++); + + if (layerData->keysMap.size() <= tag_key) { + throw std::runtime_error("feature referenced out of range key"); + } + + if (start_itr == end_itr) { + throw std::runtime_error("uneven number of feature tag ids"); + } + + auto tag_val = static_cast(*start_itr++);; + if (layerData->values.size() <= tag_val) { + throw std::runtime_error("feature referenced out of range value"); + } + + if (tag_key == keyIter->second) { + return layerData->values[tag_val]; + } + } + + return optional(); +} + +std::unordered_map VectorTileFeature::getProperties() const { + std::unordered_map properties; + auto start_itr = tags_iter.begin(); + const auto & end_itr = tags_iter.end(); + while (start_itr != end_itr) { + auto tag_key = static_cast(*start_itr++); + if (start_itr == end_itr) { + throw std::runtime_error("uneven number of feature tag ids"); + } + auto tag_val = static_cast(*start_itr++); + properties[layerData->keys.at(tag_key)] = layerData->values.at(tag_val); + } + return properties; +} + +optional VectorTileFeature::getID() const { + return id; +} + +GeometryCollection VectorTileFeature::getGeometries() const { + uint8_t cmd = 1; + uint32_t length = 0; + int32_t x = 0; + int32_t y = 0; + const float scale = float(util::EXTENT) / layerData->extent; + + GeometryCollection lines; + + lines.emplace_back(); + GeometryCoordinates* line = &lines.back(); + + auto g_itr = geometry_iter.begin(); + while (g_itr != geometry_iter.end()) { + if (length == 0) { + auto cmd_length = static_cast(*g_itr++); + cmd = cmd_length & 0x7; + length = cmd_length >> 3; + } + + --length; + + if (cmd == 1 || cmd == 2) { + x += protozero::decode_zigzag32(static_cast(*g_itr++)); + y += protozero::decode_zigzag32(static_cast(*g_itr++)); + + if (cmd == 1 && !line->empty()) { // moveTo + lines.emplace_back(); + line = &lines.back(); + } + + line->emplace_back(::round(x * scale), ::round(y * scale)); + + } else if (cmd == 7) { // closePolygon + if (!line->empty()) { + line->push_back((*line)[0]); + } + + } else { + throw std::runtime_error("unknown command"); + } + } + + if (layerData->version >= 2 || type != FeatureType::Polygon) { + return lines; + } + + return fixupPolygons(lines); +} + +VectorTileData::VectorTileData(std::shared_ptr data_) + : data(std::move(data_)) { +} + +const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const { + if (!parsed) { + parse(); + } + + auto it = layers.find(name); + if (it != layers.end()) { + return &it->second; + } + return nullptr; +} + +std::vector VectorTileData::layerNames() const { + if (!parsed) { + parse(); + } + + std::vector names; + names.reserve(layers.size()); + for (auto const& layer : layers) { + names.emplace_back(layer.first); + } + return names; +} + +void VectorTileData::parse() const { + parsed = true; + layers.clear(); + protozero::pbf_reader tile_pbf(*data); + while (tile_pbf.next(3)) { + VectorTileLayer layer(tile_pbf.get_message(), data); + layers.emplace(layer.name, std::move(layer)); + } +} + +VectorTileLayerData::VectorTileLayerData(std::shared_ptr pbfData) : + data(std::move(pbfData)) +{} + +VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf, std::shared_ptr pbfData) + : data(std::make_shared(std::move(pbfData))) +{ + while (layer_pbf.next()) { + switch (layer_pbf.tag()) { + case 1: // name + name = layer_pbf.get_string(); + break; + case 2: // feature + features.push_back(layer_pbf.get_message()); + break; + case 3: // keys + { + auto iter = data->keysMap.emplace(layer_pbf.get_string(), data->keysMap.size()); + data->keys.emplace_back(std::reference_wrapper(iter.first->first)); + } + break; + case 4: // values + data->values.emplace_back(parseValue(layer_pbf.get_message())); + break; + case 5: // extent + data->extent = layer_pbf.get_uint32(); + break; + case 15: // version + data->version = layer_pbf.get_uint32(); + break; + default: + layer_pbf.skip(); + break; + } + } +} + +std::unique_ptr VectorTileLayer::getFeature(std::size_t i) const { + return std::make_unique(features.at(i), data); +} + +std::string VectorTileLayer::getName() const { + return name; +} + +} // namespace mbgl -- cgit v1.2.1