#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { // Note: This destructor is seemingly empty, but we need to declare it anyway // because this object has a std::unique_ptr<> of a forward-declare type in // its header file. TileParser::~TileParser() = default; TileParser::TileParser(const std::string& rawData_, VectorTileData& tile_, const util::ptr& style_, GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, SpriteAtlas& spriteAtlas_, const util::ptr& sprite_) : vectorTile(pbf((const uint8_t *)rawData_.data(), rawData_.size())), tile(tile_), style(style_), glyphAtlas(glyphAtlas_), glyphStore(glyphStore_), spriteAtlas(spriteAtlas_), sprite(sprite_), collision(util::make_unique(tile.id.z, 4096, tile.source.tile_size, tile.depth)) { assert(style); assert(sprite); assert(collision); } void TileParser::parse() { parseStyleLayers(style->layers); } bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; } void TileParser::parseStyleLayers(util::ptr group) { if (!group) { return; } for (const util::ptr &layer_desc : group->layers) { // Cancel early when parsing. if (obsolete()) { return; } if (layer_desc->isBackground()) { // background is a special, fake bucket continue; } if (layer_desc->bucket) { // This is a singular layer. Check if this bucket already exists. If not, // parse this bucket. auto bucket_it = tile.buckets.find(layer_desc->bucket->name); if (bucket_it == tile.buckets.end()) { // We need to create this bucket since it doesn't exist yet. std::unique_ptr bucket = createBucket(*layer_desc->bucket); if (bucket) { // Bucket creation might fail because the data tile may not // contain any data that falls into this bucket. tile.buckets[layer_desc->bucket->name] = std::move(bucket); } } } else { fprintf(stderr, "[WARNING] layer '%s' does not have buckets\n", layer_desc->id.c_str()); } } } template struct PropertyEvaluator { typedef T result_type; PropertyEvaluator(float z_) : z(z_) {} template ::value, int>::type = 0> T operator()(const P &value) const { return value; } T operator()(const Function &value) const { return mapbox::util::apply_visitor(FunctionEvaluator(z), value); } template ::value, int>::type = 0> T operator()(const P &) const { return T(); } private: const float z; }; template void applyLayoutProperty(PropertyKey key, const ClassProperties &classProperties, T &target, const float z) { auto it = classProperties.properties.find(key); if (it != classProperties.properties.end()) { const PropertyEvaluator evaluator(z); target = mapbox::util::apply_visitor(evaluator, it->second); } } std::unique_ptr parseStyleLayoutFill(const StyleBucket &/*bucket*/, const float /*z*/) { // no-op; Fill buckets don't currently have any applicable layout properties auto fillPtr = util::make_unique(); return fillPtr; } std::unique_ptr parseStyleLayoutLine(const StyleBucket &bucket_desc, const float z) { auto linePtr = util::make_unique(); auto &line = *linePtr; applyLayoutProperty(PropertyKey::LineCap, bucket_desc.layout, line.cap, z); applyLayoutProperty(PropertyKey::LineJoin, bucket_desc.layout, line.join, z); applyLayoutProperty(PropertyKey::LineMiterLimit, bucket_desc.layout, line.miter_limit, z); applyLayoutProperty(PropertyKey::LineRoundLimit, bucket_desc.layout, line.round_limit, z); return linePtr; } std::unique_ptr parseStyleLayoutSymbol(const StyleBucket &bucket_desc, const float z) { auto symbolPtr = util::make_unique(); auto &symbol = *symbolPtr; applyLayoutProperty(PropertyKey::SymbolPlacement, bucket_desc.layout, symbol.placement, z); if (symbol.placement == PlacementType::Line) { symbol.icon.rotation_alignment = RotationAlignmentType::Map; symbol.text.rotation_alignment = RotationAlignmentType::Map; }; applyLayoutProperty(PropertyKey::SymbolMinDistance, bucket_desc.layout, symbol.min_distance, z); applyLayoutProperty(PropertyKey::SymbolAvoidEdges, bucket_desc.layout, symbol.avoid_edges, z); applyLayoutProperty(PropertyKey::IconAllowOverlap, bucket_desc.layout, symbol.icon.allow_overlap, z); applyLayoutProperty(PropertyKey::IconIgnorePlacement, bucket_desc.layout, symbol.icon.ignore_placement, z); applyLayoutProperty(PropertyKey::IconOptional, bucket_desc.layout, symbol.icon.optional, z); applyLayoutProperty(PropertyKey::IconRotationAlignment, bucket_desc.layout, symbol.icon.rotation_alignment, z); applyLayoutProperty(PropertyKey::IconMaxSize, bucket_desc.layout, symbol.icon.max_size, z); applyLayoutProperty(PropertyKey::IconImage, bucket_desc.layout, symbol.icon.image, z); applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, symbol.icon.padding, z); applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, symbol.icon.rotate, z); applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, symbol.icon.keep_upright, z); applyLayoutProperty(PropertyKey::IconOffset, bucket_desc.layout, symbol.icon.offset, z); applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, symbol.text.rotation_alignment, z); applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, symbol.text.field, z); applyLayoutProperty(PropertyKey::TextFont, bucket_desc.layout, symbol.text.font, z); applyLayoutProperty(PropertyKey::TextMaxSize, bucket_desc.layout, symbol.text.max_size, z); applyLayoutProperty(PropertyKey::TextMaxWidth, bucket_desc.layout, symbol.text.max_width, z); applyLayoutProperty(PropertyKey::TextLineHeight, bucket_desc.layout, symbol.text.line_height, z); applyLayoutProperty(PropertyKey::TextLetterSpacing, bucket_desc.layout, symbol.text.letter_spacing, z); applyLayoutProperty(PropertyKey::TextMaxAngle, bucket_desc.layout, symbol.text.max_angle, z); applyLayoutProperty(PropertyKey::TextRotate, bucket_desc.layout, symbol.text.rotate, z); applyLayoutProperty(PropertyKey::TextPadding, bucket_desc.layout, symbol.text.padding, z); applyLayoutProperty(PropertyKey::TextIgnorePlacement, bucket_desc.layout, symbol.text.ignore_placement, z); applyLayoutProperty(PropertyKey::TextOptional, bucket_desc.layout, symbol.text.optional, z); applyLayoutProperty(PropertyKey::TextJustify, bucket_desc.layout, symbol.text.justify, z); applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, symbol.text.anchor, z); applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, symbol.text.keep_upright, z); applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, symbol.text.transform, z); applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, symbol.text.offset, z); applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, symbol.text.allow_overlap, z); return symbolPtr; } std::unique_ptr TileParser::createBucket(const StyleBucket &bucketDesc) { // Skip this bucket if we are to not render this if (tile.id.z < std::floor(bucketDesc.min_zoom) && std::floor(bucketDesc.min_zoom) < tile.source.max_zoom) return nullptr; if (tile.id.z >= std::ceil(bucketDesc.max_zoom)) return nullptr; if (bucketDesc.visibility == mbgl::VisibilityType::None) return nullptr; auto layer_it = vectorTile.layers.find(bucketDesc.source_layer); if (layer_it != vectorTile.layers.end()) { const VectorTileLayer &layer = layer_it->second; if (bucketDesc.type == StyleLayerType::Fill) { return createFillBucket(layer, bucketDesc); } else if (bucketDesc.type == StyleLayerType::Line) { return createLineBucket(layer, bucketDesc); } else if (bucketDesc.type == StyleLayerType::Symbol) { return createSymbolBucket(layer, bucketDesc); } else if (bucketDesc.type == StyleLayerType::Raster) { return nullptr; } else { fprintf(stderr, "[WARNING] unknown bucket render type for layer '%s' (source layer '%s')\n", bucketDesc.name.c_str(), bucketDesc.source_layer.c_str()); } } else { // The layer specified in the bucket does not exist. Do nothing. if (debug::tileParseWarnings) { fprintf(stderr, "[WARNING] layer '%s' does not exist in tile %d/%d/%d\n", bucketDesc.source_layer.c_str(), tile.id.z, tile.id.x, tile.id.y); } } return nullptr; } template void TileParser::addBucketGeometries(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) { FilteredVectorTileLayer filtered_layer(layer, filter); for (pbf feature : filtered_layer) { if (obsolete()) return; while (feature.next(4)) { // geometry pbf geometry_pbf = feature.message(); if (geometry_pbf) { bucket->addGeometry(geometry_pbf); } else if (debug::tileParseWarnings) { fprintf(stderr, "[WARNING] geometry is empty\n"); } } } } std::unique_ptr TileParser::createFillBucket(const VectorTileLayer &layer, const StyleBucket &bucket_desc) { auto fill = parseStyleLayoutFill(bucket_desc, tile.id.z); auto bucket = util::make_unique(std::move(fill), tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer); addBucketGeometries(bucket, layer, bucket_desc.filter); return obsolete() ? nullptr : std::move(bucket); } std::unique_ptr TileParser::createLineBucket(const VectorTileLayer &layer, const StyleBucket &bucket_desc) { auto line = parseStyleLayoutLine(bucket_desc, tile.id.z); auto bucket = util::make_unique(std::move(line), tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer); addBucketGeometries(bucket, layer, bucket_desc.filter); return obsolete() ? nullptr : std::move(bucket); } std::unique_ptr TileParser::createSymbolBucket(const VectorTileLayer &layer, const StyleBucket &bucket_desc) { auto symbol = parseStyleLayoutSymbol(bucket_desc, tile.id.z); auto bucket = util::make_unique(std::move(symbol), *collision); bucket->addFeatures( layer, bucket_desc.filter, tile.id, spriteAtlas, *sprite, glyphAtlas, glyphStore); return obsolete() ? nullptr : std::move(bucket); } }