diff --git a/include/llmr/map/tile_data.hpp b/include/llmr/map/tile_data.hpp index fbaa4c0f0..f9ad8b3a4 100644 --- a/include/llmr/map/tile_data.hpp +++ b/include/llmr/map/tile_data.hpp @@ -65,10 +65,10 @@ public: void parseStyleLayers(const VectorTile& tile, const std::vector& layers); std::shared_ptr createBucket(const VectorTile& tile, const BucketDescription& bucket_desc); template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const BucketDescription& bucket_desc); - std::shared_ptr createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); - std::shared_ptr createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); - std::shared_ptr createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); - std::shared_ptr createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc); + std::shared_ptr createFillBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc); + std::shared_ptr createLineBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc); + std::shared_ptr createPointBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc); + std::shared_ptr createTextBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc); void cancel(); diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index 4f78d9d98..98f2a1ca3 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -33,6 +33,27 @@ struct Coordinate { } }; +enum class FeatureType { + Unknown = 0, + Point = 1, + LineString = 2, + Polygon = 3 +}; + +std::ostream& operator<<(std::ostream&, const FeatureType& type); + +class VectorTileFeature { +public: + VectorTileFeature(pbf feature, const VectorTileLayer& layer); + + uint64_t id = 0; + FeatureType type = FeatureType::Unknown; + std::map properties; + pbf geometry; +}; + +std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature); + /* * Allows iterating over the features of a VectorTileLayer using a * BucketDescription as filter. Only features matching the descriptions will diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 919d3db68..c935d5061 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -12,7 +12,8 @@ enum class BucketType { None = 0, Fill = 1, Line = 2, - Point = 3 + Point = 3, + Text = 4 }; enum class CapType { diff --git a/src/map/tile_data.cpp b/src/map/tile_data.cpp index d06a0becc..5ca0e817a 100644 --- a/src/map/tile_data.cpp +++ b/src/map/tile_data.cpp @@ -14,6 +14,7 @@ #include #include +#include using namespace llmr; @@ -85,7 +86,7 @@ bool TileData::parse() { double parse_time_start = platform::time(); VectorTile tile(pbf((const uint8_t *)data.data(), data.size())); parseStyleLayers(tile, style.layers); - double parse_time = (platform::time() - parse_time_start) * 1000.0; + // double parse_time = (platform::time() - parse_time_start) * 1000.0; if (state == State::obsolete) { // fprintf(stderr, "[%p] parsing [%d/%d/%d] cancelled after %8.3fms\n", this, id.z, id.x, id.y, parse_time); } else { @@ -148,11 +149,13 @@ std::shared_ptr TileData::createBucket(const VectorTile& tile, const Buc if (layer_it != tile.layers.end()) { const VectorTileLayer& layer = layer_it->second; if (bucket_desc.type == BucketType::Fill) { - return createFillBucket(layer, bucket_desc); + return createFillBucket(tile, layer, bucket_desc); } else if (bucket_desc.type == BucketType::Line) { - return createLineBucket(layer, bucket_desc); + return createLineBucket(tile, layer, bucket_desc); } else if (bucket_desc.type == BucketType::Point) { - return createPointBucket(layer, bucket_desc); + return createPointBucket(tile, layer, bucket_desc); + } else if (bucket_desc.type == BucketType::Text) { + return createTextBucket(tile, layer, bucket_desc); } else { // TODO: create other bucket types. } @@ -178,26 +181,52 @@ void TileData::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, c } } -std::shared_ptr TileData::createFillBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { +std::shared_ptr TileData::createFillBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc) { std::shared_ptr bucket = std::make_shared(fillVertexBuffer, triangleElementsBuffer, lineElementsBuffer, bucket_desc); addBucketFeatures(bucket, layer, bucket_desc); return state == State::obsolete ? nullptr : bucket; } -std::shared_ptr TileData::createLineBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { +std::shared_ptr TileData::createLineBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc) { std::shared_ptr bucket = std::make_shared(lineVertexBuffer, triangleElementsBuffer, pointElementsBuffer, bucket_desc); addBucketFeatures(bucket, layer, bucket_desc); return state == State::obsolete ? nullptr : bucket; } -std::shared_ptr TileData::createPointBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { +std::shared_ptr TileData::createPointBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc) { std::shared_ptr bucket = std::make_shared(pointVertexBuffer, bucket_desc); addBucketFeatures(bucket, layer, bucket_desc); return state == State::obsolete ? nullptr : bucket; } -std::shared_ptr TileData::createTextBucket(const VectorTileLayer& layer, const BucketDescription& bucket_desc) { +std::shared_ptr TileData::createTextBucket(const VectorTile& tile, const VectorTileLayer& layer, const BucketDescription& bucket_desc) { + // Determine the correct text stack. + if (!layer.shaping.size()) { + return nullptr; + } + + // TODO: currently hardcoded to use the first font stack. + const std::map>& stack = layer.shaping.begin()->second; + + std::vector faces; + for (const std::string& face : layer.faces) { + auto it = tile.faces.find(face); + if (it == tile.faces.end()) { + // This layer references an unknown face. + return nullptr; + } + faces.push_back(&it->second); + } + std::shared_ptr bucket = std::make_shared(textVertexBuffer, triangleElementsBuffer, bucket_desc); - addBucketFeatures(bucket, layer, bucket_desc); - return state == State::obsolete ? nullptr : bucket; + + FilteredVectorTileLayer filtered_layer(layer, bucket_desc); + for (pbf feature_pbf : filtered_layer) { + if (state == State::obsolete) return nullptr; + + const VectorTileFeature feature(feature_pbf, layer); + std::cerr << feature; + } + + return bucket; } diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index fb6340532..e4df0d359 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -6,6 +6,68 @@ using namespace llmr; + +std::ostream& llmr::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(); + } 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) { + // TODO: Throw correct exception + fprintf(stderr, "feature referenced out of range key\n"); + break; + } + + if (tags) { + uint32_t tag_val = tags.varint(); + if (layer.values.size() <= tag_val) { + // TODO: Throw correct exception + fprintf(stderr, "feature referenced out of range value\n"); + break; + } + + properties.emplace(layer.keys[tag_key], layer.values[tag_val]); + } else { + // TODO: Throw correct exception + fprintf(stderr, "uneven number of feature tag ids\n"); + break; + } + } + } else if (feature.tag == 3) { // type + type = (FeatureType)feature.varint(); + } else if (feature.tag == 4) { // geometry + geometry = feature.message(); + } else { + feature.skip(); + } + } +} + + +std::ostream& llmr::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() {}