diff options
Diffstat (limited to 'src/map/vector_tile.cpp')
-rw-r--r-- | src/map/vector_tile.cpp | 199 |
1 files changed, 123 insertions, 76 deletions
diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 24f03e1a97..54a971cd87 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -102,7 +102,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { } } -FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression) +FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression) : layer(layer), filterExpression(filterExpression) { } @@ -122,120 +122,167 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren operator++(); } -bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf) { - if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) { - return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf); - } else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) { - return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf); - } else if (filterExpression.is<std::true_type>()) { - return true; - } else { - return false; - } +//bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const FilterExpression &filterExpression, const pbf &tags_pbf) { +// if (filterExpression.empty()) { +// return true; +// } +// +// +// +// +// if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) { +// return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf); +// } else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) { +// return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf); +// } else if (filterExpression.is<std::true_type>()) { +// return true; +// } else { +// return false; +// } +// return true; +//} + +// +//bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { +// auto field_it = parent.layer.key_index.find(filter.field); +// if (field_it != parent.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 = const_tags_pbf; +// while (tags_pbf) { +// uint32_t tag_key = tags_pbf.varint(); +// if (!tags_pbf) { +// // This should not happen; otherwise the vector tile +// // is invalid. +// throw std::runtime_error("uneven number of feature tag ids"); +// } +// uint32_t tag_val = tags_pbf.varint(); +// +// if (tag_key == filter_key) { +// if (parent.layer.values.size() > tag_val) { +// const Value &value = parent.layer.values[tag_val]; +// return filter.compare(value); +// } else { +// throw std::runtime_error("feature references out of range value"); +// } +// } +// } +// } +// +// // The feature doesn't contain the field that we're looking to compare. +// // Depending on the filter, this may still be okay. +// return filter.isMissingFieldOkay(); +//} +// +//bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { +// if (expression.op == ExpressionOperator::Or) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (matchesFilterExpression(filterExpression, tags_pbf)) { +// return true; +// } +// } +// return false; +// } else if (expression.op == ExpressionOperator::And) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (!matchesFilterExpression(filterExpression, tags_pbf)) { +// return false; +// } +// } +// return true; +// } else { +// return false; +// } +//} +// + +VectorTileTagExtractor::VectorTileTagExtractor(const VectorTileLayer &layer) : layer_(layer) {} + + +void VectorTileTagExtractor::setTags(const pbf &pbf) { + tags_ = pbf; } +std::forward_list<Value> VectorTileTagExtractor::getValues(const std::string &key) const { + std::forward_list<Value> values; -bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { - auto field_it = parent.layer.key_index.find(filter.field); - if (field_it != parent.layer.key_index.end()) { + auto field_it = layer_.key_index.find(key); + if (field_it != layer_.key_index.end()) { + auto it = values.before_begin(); 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 = const_tags_pbf; + pbf tags_pbf = tags_; + uint32_t tag_key, tag_val; while (tags_pbf) { - uint32_t tag_key = tags_pbf.varint(); + tag_key = tags_pbf.varint(); if (!tags_pbf) { - // This should not happen; otherwise the vector tile - // is invalid. - throw std::runtime_error("uneven number of feature tag ids"); + // This should not happen; otherwise the vector tile is invalid. + fprintf(stderr, "[WARNING] uneven number of feature tag ids\n"); + return values; } - uint32_t tag_val = tags_pbf.varint(); + // 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 (parent.layer.values.size() > tag_val) { - const Value &value = parent.layer.values[tag_val]; - return filter.compare(value); + if (layer_.values.size() > tag_val) { + it = values.emplace_after(it, layer_.values[tag_val]); } else { - throw std::runtime_error("feature references out of range value"); + fprintf(stderr, "[WARNING] feature references out of range value\n"); + break; } } } } - // The feature doesn't contain the field that we're looking to compare. - // Depending on the filter, this may still be okay. - return filter.isMissingFieldOkay(); + return values; } -bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { - if (expression.op == ExpressionOperator::Or) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (matchesFilterExpression(filterExpression, tags_pbf)) { - return true; - } - } - return false; - } else if (expression.op == ExpressionOperator::And) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (!matchesFilterExpression(filterExpression, tags_pbf)) { - return false; - } - } - return true; - } else { - return false; - } +void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) { + type_ = type; } - +FilterExpression::GeometryType VectorTileTagExtractor::getType() const { + return type_; +} void FilteredVectorTileLayer::iterator::operator++() { valid = false; - const PropertyFilterExpression &expression = parent.filterExpression; + const FilterExpression &expression = parent.filterExpression; while (data.next(2)) { // feature feature = data.message(); pbf feature_pbf = feature; - BucketType type = BucketType::None; - bool matched = false; // Treat the absence of any expression filters as a match. - if (!expression.valid() || expression.is<std::true_type>()) { + if (expression.empty()) { matched = true; } - while (feature_pbf.next()) { - if (feature_pbf.tag == 2) { // tags - if (matched) { - // There is no filter, so we want to parse the entire layer anyway. - feature_pbf.skip(); - } else { - // We only want to parse some features. - const pbf tags_pbf = feature_pbf.message(); - matched = matchesFilterExpression(expression, tags_pbf); - if (!matched) { - break; // feature_pbf loop early + if (!matched) { + 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 + switch (FeatureType(feature_pbf.varint())) { + case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break; + case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::Line); break; + case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break; + default: break; } + } else { + feature_pbf.skip(); } - } else if (feature_pbf.tag == 3) { // geometry type - switch (feature_pbf.varint()) { - case 1 /* Point */: type = BucketType::Icon; break; - case 2 /* LineString */: type = BucketType::Line; break; - case 3 /* Polygon */: type = BucketType::Fill; break; - default: type = BucketType::None; break; - } - - // TODO: Parse feature type -// if (type != parent.bucket_desc.feature_type) { -// matched = false; -// break; // feature_pbf loop early -// } - } else { - feature_pbf.skip(); } + + matched = expression.compare(extractor); } if (matched) { |