summaryrefslogtreecommitdiff
path: root/src/mbgl/tile/vector_tile_data.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/tile/vector_tile_data.cpp')
-rw-r--r--src/mbgl/tile/vector_tile_data.cpp218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp
new file mode 100644
index 0000000000..fd15dd939d
--- /dev/null
+++ b/src/mbgl/tile/vector_tile_data.cpp
@@ -0,0 +1,218 @@
+#include <mbgl/tile/vector_tile_data.hpp>
+
+namespace mbgl {
+
+class VectorTileLayer;
+
+Value parseValue(protozero::pbf_reader data) {
+ while (data.next()) {
+ switch (data.tag()) {
+ case 1: // string_value
+ return data.get_string();
+ case 2: // float_value
+ return static_cast<double>(data.get_float());
+ case 3: // double_value
+ return data.get_double();
+ case 4: // int_value
+ return data.get_int64();
+ case 5: // uint_value
+ return data.get_uint64();
+ case 6: // sint_value
+ return data.get_sint64();
+ case 7: // bool_value
+ return data.get_bool();
+ default:
+ data.skip();
+ break;
+ }
+ }
+ return false;
+}
+
+VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf,
+ const VectorTileLayer& layer_)
+ : layer(layer_) {
+ 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<FeatureType>(feature_pbf.get_enum());
+ break;
+ case 4: // geometry
+ geometry_iter = feature_pbf.get_packed_uint32();
+ break;
+ default:
+ feature_pbf.skip();
+ break;
+ }
+ }
+}
+
+optional<Value> VectorTileFeature::getValue(const std::string& key) const {
+ auto keyIter = layer.keysMap.find(key);
+ if (keyIter == layer.keysMap.end()) {
+ return optional<Value>();
+ }
+
+ auto start_itr = tags_iter.first;
+ const auto& end_itr = tags_iter.second;
+ while (start_itr != end_itr) {
+ uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
+
+ if (layer.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");
+ }
+
+ uint32_t tag_val = static_cast<uint32_t>(*start_itr++);
+ ;
+ if (layer.values.size() <= tag_val) {
+ throw std::runtime_error("feature referenced out of range value");
+ }
+
+ if (tag_key == keyIter->second) {
+ return layer.values[tag_val];
+ }
+ }
+
+ return optional<Value>();
+}
+
+std::unordered_map<std::string, Value> VectorTileFeature::getProperties() const {
+ std::unordered_map<std::string, Value> properties;
+ auto start_itr = tags_iter.first;
+ const auto& end_itr = tags_iter.second;
+ while (start_itr != end_itr) {
+ uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
+ if (start_itr == end_itr) {
+ throw std::runtime_error("uneven number of feature tag ids");
+ }
+ uint32_t tag_val = static_cast<uint32_t>(*start_itr++);
+ properties[layer.keys.at(tag_key)] = layer.values.at(tag_val);
+ }
+ return properties;
+}
+
+optional<FeatureIdentifier> 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) / layer.extent;
+
+ GeometryCollection lines;
+
+ lines.emplace_back();
+ GeometryCoordinates* line = &lines.back();
+
+ auto g_itr = geometry_iter;
+ while (g_itr.first != g_itr.second) {
+ if (length == 0) {
+ uint32_t cmd_length = static_cast<uint32_t>(*g_itr.first++);
+ cmd = cmd_length & 0x7;
+ length = cmd_length >> 3;
+ }
+
+ --length;
+
+ if (cmd == 1 || cmd == 2) {
+ x += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr.first++));
+ y += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr.first++));
+
+ 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 (layer.version >= 2 || type != FeatureType::Polygon) {
+ return lines;
+ }
+
+ return fixupPolygons(lines);
+}
+
+VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) : data(std::move(data_)) {
+}
+
+util::ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const {
+ if (!parsed) {
+ parsed = true;
+ protozero::pbf_reader tile_pbf(*data);
+ while (tile_pbf.next(3)) {
+ util::ptr<VectorTileLayer> layer =
+ std::make_shared<VectorTileLayer>(tile_pbf.get_message());
+ layers.emplace(layer->name, layer);
+ }
+ }
+
+ auto layer_it = layers.find(name);
+ if (layer_it != layers.end()) {
+ return layer_it->second;
+ }
+
+ return nullptr;
+}
+
+VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
+ 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 = keysMap.emplace(layer_pbf.get_string(), keysMap.size());
+ keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
+ } break;
+ case 4: // values
+ values.emplace_back(parseValue(layer_pbf.get_message()));
+ break;
+ case 5: // extent
+ extent = layer_pbf.get_uint32();
+ break;
+ case 15: // version
+ version = layer_pbf.get_uint32();
+ break;
+ default:
+ layer_pbf.skip();
+ break;
+ }
+ }
+}
+
+util::ptr<const GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
+ return std::make_shared<VectorTileFeature>(features.at(i), *this);
+}
+
+std::string VectorTileLayer::getName() const {
+ return name;
+}
+
+} // namespace mbgl