summaryrefslogtreecommitdiff
path: root/src/mbgl/map/vector_tile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/map/vector_tile.cpp')
-rw-r--r--src/mbgl/map/vector_tile.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp
new file mode 100644
index 0000000000..ac7134fb0c
--- /dev/null
+++ b/src/mbgl/map/vector_tile.cpp
@@ -0,0 +1,214 @@
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/style/filter_expression_private.hpp>
+
+#include <algorithm>
+#include <iostream>
+
+using namespace mbgl;
+
+
+std::ostream& mbgl::operator<<(std::ostream& os, const FeatureType& type) {
+ switch (type) {
+ case FeatureType::Unknown: return os << "Unknown";
+ case FeatureType::Point: return os << "Point";
+ case FeatureType::LineString: return os << "LineString";
+ case FeatureType::Polygon: return os << "Polygon";
+ default: return os << "Invalid";
+ }
+}
+
+VectorTileFeature::VectorTileFeature(pbf feature, const VectorTileLayer& layer) {
+ while (feature.next()) {
+ if (feature.tag == 1) { // id
+ id = feature.varint<uint64_t>();
+ } else if (feature.tag == 2) { // tags
+ // tags are packed varints. They should have an even length.
+ pbf tags = feature.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.tag == 3) { // type
+ type = (FeatureType)feature.varint();
+ } else if (feature.tag == 4) { // geometry
+ geometry = feature.message();
+ } else {
+ feature.skip();
+ }
+ }
+}
+
+
+std::ostream& mbgl::operator<<(std::ostream& os, const VectorTileFeature& feature) {
+ os << "Feature(" << feature.id << "): " << feature.type << std::endl;
+ for (const auto& prop : feature.properties) {
+ os << " - " << prop.first << ": " << prop.second << std::endl;
+ }
+ return os;
+}
+
+
+VectorTile::VectorTile() {}
+
+
+VectorTile::VectorTile(pbf tile) {
+ while (tile.next()) {
+ if (tile.tag == 3) { // layer
+ VectorTileLayer layer(tile.message());
+ layers.emplace(layer.name, std::forward<VectorTileLayer>(layer));
+ } else {
+ tile.skip();
+ }
+ }
+}
+
+VectorTile& VectorTile::operator=(VectorTile && other) {
+ if (this != &other) {
+ layers.swap(other.layers);
+ }
+ return *this;
+}
+
+VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) {
+ std::vector<std::string> stacks;
+
+ while (layer.next()) {
+ if (layer.tag == 1) { // name
+ name = layer.string();
+ } else if (layer.tag == 3) { // keys
+ keys.emplace_back(layer.string());
+ key_index.emplace(keys.back(), keys.size() - 1);
+ } else if (layer.tag == 4) { // values
+ values.emplace_back(std::move(parseValue(layer.message())));
+ } else if (layer.tag == 5) { // extent
+ extent = layer.varint();
+ } else {
+ layer.skip();
+ }
+ }
+}
+
+FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer_, const FilterExpression &filterExpression_)
+ : layer(layer_),
+ filterExpression(filterExpression_) {
+}
+
+FilteredVectorTileLayer::iterator FilteredVectorTileLayer::begin() const {
+ return iterator(*this, layer.data);
+}
+
+FilteredVectorTileLayer::iterator FilteredVectorTileLayer::end() const {
+ return iterator(*this, pbf(layer.data.end, 0));
+}
+
+FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& parent_, const pbf& data_)
+ : parent(parent_),
+ feature(pbf()),
+ data(data_) {
+ operator++();
+}
+
+VectorTileTagExtractor::VectorTileTagExtractor(const VectorTileLayer &layer) : layer_(layer) {}
+
+
+void VectorTileTagExtractor::setTags(const pbf &pbf) {
+ tags_ = pbf;
+}
+
+mapbox::util::optional<Value> VectorTileTagExtractor::getValue(const std::string &key) const {
+ if (key == "$type") {
+ return Value(uint64_t(type_));
+ }
+
+ mapbox::util::optional<Value> value;
+
+ auto field_it = layer_.key_index.find(key);
+ if (field_it != layer_.key_index.end()) {
+ const uint32_t filter_key = field_it->second;
+
+ // Now loop through all the key/value pair tags.
+ // tags are packed varints. They should have an even length.
+ pbf tags_pbf = tags_;
+ uint32_t tag_key, tag_val;
+ while (tags_pbf) {
+ tag_key = tags_pbf.varint();
+ if (!tags_pbf) {
+ // This should not happen; otherwise the vector tile is invalid.
+ fprintf(stderr, "[WARNING] uneven number of feature tag ids\n");
+ return value;
+ }
+ // Note: We need to run this command in all cases, even if the keys don't match.
+ tag_val = tags_pbf.varint();
+
+ if (tag_key == filter_key) {
+ if (layer_.values.size() > tag_val) {
+ value = layer_.values[tag_val];
+ } else {
+ fprintf(stderr, "[WARNING] feature references out of range value\n");
+ break;
+ }
+ }
+ }
+ }
+
+ return value;
+}
+
+void VectorTileTagExtractor::setType(FeatureType type) {
+ type_ = type;
+}
+
+template bool mbgl::evaluate(const FilterExpression&, const VectorTileTagExtractor&);
+
+void FilteredVectorTileLayer::iterator::operator++() {
+ valid = false;
+
+ const FilterExpression &expression = parent.filterExpression;
+
+ while (data.next(2)) { // feature
+ feature = data.message();
+ pbf feature_pbf = feature;
+
+ VectorTileTagExtractor extractor(parent.layer);
+
+ // Retrieve the basic information
+ while (feature_pbf.next()) {
+ if (feature_pbf.tag == 2) { // tags
+ extractor.setTags(feature_pbf.message());
+ } else if (feature_pbf.tag == 3) { // geometry type
+ extractor.setType(FeatureType(feature_pbf.varint()));
+ } else {
+ feature_pbf.skip();
+ }
+ }
+
+ if (evaluate(expression, extractor)) {
+ valid = true;
+ return; // data loop
+ } else {
+ valid = false;
+ }
+ }
+}
+
+bool FilteredVectorTileLayer::iterator::operator!=(const iterator& other) const {
+ return !(data.data == other.data.data && data.end == other.data.end && valid == other.valid);
+}
+
+const pbf& FilteredVectorTileLayer::iterator:: operator*() const {
+ return feature;
+}