diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index 4d6af15d9..21a16177d 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -13,13 +13,23 @@ public: void parseBuckets(JSVal value, std::map& buckets); void parseLayers(JSVal value, std::vector& layers); void parseConstants(JSVal value); - void parseClasses(JSVal value, std::map& classes, std::map& buckets, std::vector& layers); + void parseClasses(JSVal value, std::map &classes, + const std::map &buckets, + const std::vector &layers); private: LayerDescription parseLayer(JSVal value); BucketDescription parseBucket(JSVal value); - std::pair parseClassDescription(JSVal value, std::map& buckets, std::vector& layers); - void parseClass(const std::string& name, JSVal value, ClassDescription& class_desc, std::map& buckets, std::vector& layers); + + std::pair + parseClassDescription(JSVal value, + const std::map &buckets, + const std::map &layerBuckets); + + void parseClass(const std::string &name, JSVal value, ClassDescription &class_desc, + const std::map &buckets, + const std::map &layerBuckets); + FillClass parseFillClass(JSVal value); LineClass parseLineClass(JSVal value); IconClass parseIconClass(JSVal value); diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 06936ded6..f4d94f51a 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -207,17 +207,39 @@ TranslateAnchor parseTranslateAnchor(JSVal anchor) { } } -void StyleParser::parseClasses(JSVal value, std::map& classes, std::map& buckets, std::vector& layers) { + +void collectLayerBuckets(std::map &layerBuckets, + const std::vector &layers) { + for (const auto& layer : layers) { + layerBuckets.emplace(layer.name, layer.bucket_name); + if (layer.child_layer.size()) { + collectLayerBuckets(layerBuckets, layer.child_layer); + } + } +} + +void StyleParser::parseClasses(JSVal value, + std::map &classes, + const std::map &buckets, + const std::vector &layers) { + + // Build a non-recursive mapping of layer => bucket. + std::map layerBuckets; + collectLayerBuckets(layerBuckets, layers); + if (value.IsArray()) { for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - classes.insert(std::forward>(parseClassDescription(value[i], buckets, layers))); + classes.emplace(parseClassDescription(value[i], buckets, layerBuckets)); } } else { throw Style::exception("classes must be an array"); } } -std::pair StyleParser::parseClassDescription(JSVal value, std::map& buckets, std::vector& style_layers) { +std::pair +StyleParser::parseClassDescription(JSVal value, + const std::map &buckets, + const std::map &layerBuckets) { ClassDescription klass; std::string klass_name; @@ -242,7 +264,7 @@ std::pair StyleParser::parseClassDescription(JSVa const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; - parseClass(name, itr->value, klass, buckets, style_layers); + parseClass(name, itr->value, klass, buckets, layerBuckets); } } else { throw Style::exception("class layer styles must be an object"); @@ -255,35 +277,44 @@ std::pair StyleParser::parseClassDescription(JSVa return { klass_name, std::forward(klass) }; } -void StyleParser::parseClass(const std::string& name, JSVal value, ClassDescription& class_desc, std::map& buckets, std::vector& layers) { - if (value.IsObject()) { - for (const auto& layer : layers) { - if (name == layer.name) { - if (layer.bucket_name == "background") { - // background buckets are fake - class_desc.background = parseBackgroundClass(value); - } else { - auto bucket_it = buckets.find(layer.bucket_name); - BucketType type = bucket_it->second.type; - if (type == BucketType::Fill) { - class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); - } else if (type == BucketType::Line) { - class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); - } else if (type == BucketType::Icon) { - class_desc.icon.insert({ name, std::forward(parseIconClass(value)) }); - } else if (type == BucketType::Text) { - class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); - } else if (type == BucketType::Raster) { - class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); - } else { - throw Style::exception("unknown class type name"); - } - } - } - } - } else { +void StyleParser::parseClass(const std::string &name, JSVal value, ClassDescription &class_desc, + const std::map &buckets, + const std::map &layerBuckets) { + if (!value.IsObject()) { throw Style::exception("style class must be an object"); } + + auto layer_bucket_it = layerBuckets.find(name); + if (layer_bucket_it == layerBuckets.end()) { + fprintf(stderr, "there is no layer associated with style '%s'\n", name.c_str()); + return; + } + + const std::string &bucket_name = layer_bucket_it->second; + if (bucket_name == "background") { + // background buckets are fake + class_desc.background = parseBackgroundClass(value); + } else { + auto bucket_it = buckets.find(bucket_name); + if (bucket_it == buckets.end()) { + return; + } + + BucketType type = bucket_it->second.type; + if (type == BucketType::Fill) { + class_desc.fill.insert({ name, std::forward(parseFillClass(value)) }); + } else if (type == BucketType::Line) { + class_desc.line.insert({ name, std::forward(parseLineClass(value)) }); + } else if (type == BucketType::Icon) { + class_desc.icon.insert({ name, std::forward(parseIconClass(value)) }); + } else if (type == BucketType::Text) { + class_desc.text.insert({ name, std::forward(parseTextClass(value)) }); + } else if (type == BucketType::Raster) { + class_desc.raster.insert({ name, std::forward(parseRasterClass(value)) }); + } else { + throw Style::exception("unknown class type name"); + } + } } bool StyleParser::parseBoolean(JSVal value) {