MapBox 矢量数据规格(MVT) C++ 编解码示例

     开发准备:

    1)开发环境: CLion 2022.3 

    2)MapBox 矢量数据规格定义可参见 github MapBox官网 。

   


    开发步骤:

    第一步:根据文件 vector_tile.proto 生成c++基础代码。 

    本示例使用的是 2.1 规格。代码生成指令示例如下:

protoc --cpp_out=./cpp_out --proto_path=./  ./vector_tile.proto

   生成过程中会提示如下警告,忽略就可以了

[libprotobuf WARNING google/protobuf/compiler/parser.cc:562] No syntax specified for the proto file: vector_tile.proto. Please use 'syntax = "proto2";' or 'syntax = "proto3";' to specify a syntax version. (Defaulted to proto2 syntax.)

    第二步:生成CLion C++ 工程

    1)生成基本工程

    2)将vector_tile.pb.h和vector_tile.pb.cc文件拷贝到同main.cpp同级目录

    3)CMakeList.txt中增加protobuf的头文件路径以及lib路径

link_directories(/home/ubuntu/sdk/protobuf/lib)

target_include_directories(${PROJECT_NAME} PUBLIC /home/ubuntu/sdk/protobuf/include)

target_link_libraries(${PROJECT_NAME} protobuf pthread)

    第三步:实现点类型mvt文件的读写

   1、MVT编码示例代码

int test_pb_encode(const std::string &file_name) {

    shared_ptr<vector_tile::Tile> tile_value = make_shared<vector_tile::Tile>();
    ::vector_tile::Tile_Layer *new_layer = tile_value->add_layers();
    new_layer->set_version(2); //版本号为2
    new_layer->set_name("point layer"); //
    new_layer->set_extent(4096); //extent 4096
    new_layer->add_keys("type"); //第一个属性字段名称
    new_layer->add_keys("sub_type"); //第二个属性字段名称
    ::vector_tile::Tile_Value *value_type = new_layer->add_values();
    value_type->set_int_value(3); //第一个属性值
    ::vector_tile::Tile_Value *value_subtype = new_layer->add_values();
    value_subtype->set_int_value(5); //第二个属性值
    ::vector_tile::Tile_Value *value_subtype2 = new_layer->add_values();
    value_subtype2->set_int_value(7); //第三个属性值

    //增加第一个Feature
    {
        ::vector_tile::Tile_Feature *new_featue = new_layer->add_features();
        new_featue->set_id(0); //id为0
        new_featue->set_type(::vector_tile::Tile_GeomType::Tile_GeomType_POINT);
        new_featue->add_tags(0); //第一个属性字段名
        new_featue->add_tags(0); //第一个value 3
        new_featue->add_tags(1); //第二个属性字段名
        new_featue->add_tags(1); //第二个value 5

        MapboxMvtUtil::AddPointGeometry(std::array<int, 2>{116, 25}, new_featue);
    }

    //增加第二个Feature
    {
        ::vector_tile::Tile_Feature *new_featue = new_layer->add_features();
        new_featue->set_id(1); //id为1
        new_featue->set_type(::vector_tile::Tile_GeomType::Tile_GeomType_POINT);
        new_featue->add_tags(0); //第一个属性字段名
        new_featue->add_tags(0); //第一个value 3
        new_featue->add_tags(1); //第二个属性字段名
        new_featue->add_tags(2); //第三个value 7

        MapboxMvtUtil::AddPointGeometry(std::array<int, 2>{1258, 492}, new_featue);
    }

    //序列化tile到文件中
    string result = tile_value->SerializeAsString();

    ofstream info_output(file_name, ios::out | ios::binary | ios::trunc);
    info_output << result;
    info_output.close();

    return 0;
}

      2、MVT解码示例

int test_pb_decode(const std::string &file_name) {
    string file_content;
    if (read_file_content(file_name, file_content) != 0) {
        std::cerr << "read file " << file_name << " content error." << std::endl;
        return 1;
    }

    //解析数据
    shared_ptr<vector_tile::Tile> tile_value = make_shared<vector_tile::Tile>();
    tile_value->ParseFromString(file_content);

    //遍历内容
    int layer_size = tile_value->layers_size();
    for (int i = 0; i < layer_size; i++) {
        const auto &layer = tile_value->layers(i);
        std::cout << " one layer info ...................." << std::endl;
        std::cout << "layer version:" << layer.version() << std::endl;
        std::cout << "layer name:" << layer.name() << std::endl;

        //获得图层的keys
        auto &layer_key_values = layer.keys();
        std::cout << "layer key count:" << layer_key_values.size() << std::endl;

        //获得图层的values
        auto &layer_value_values = layer.values();
        std::cout << "layer value count:" << layer_value_values.size() << std::endl;

        //解析图层中的Feature
        std::cout << "layer feature count:" << layer.features_size() << std::endl;
        for (int j = 0; j < layer.features_size(); j++) {
            const ::vector_tile::Tile_Feature &feature = layer.features(j);
            std::cout << "feature " << feature.id() << " info ... ..." << std::endl;
            std::cout << "feature type " << feature.type() << std::endl;

            //解析feature的属性字段及取值
            int prop_count = feature.tags_size() / 2;
            for (int k = 0; k < prop_count; k++) {
                int key_index = k * 2;
                int value_index = k * 2 + 1;
                int key_tag_value = feature.tags(key_index);
                int value_tag_value = feature.tags(value_index);

                string key_value = layer_key_values.Get(key_tag_value);
                const ::vector_tile::Tile_Value &value_value = layer_value_values.Get(value_tag_value);

                std::cout << "key: " << key_value << ", value: " << value_value.int_value() << std::endl;
            }

            //获取数据的几何信息
            switch (feature.type()) {
                case ::vector_tile::Tile_GeomType::Tile_GeomType_POINT: {
                    std::array<int, 2> loc_values;
                    MapboxMvtUtil::ParsePointGeometry(feature, loc_values);
                    std::cout << "point pos: " << loc_values[0] << "," << loc_values[1] << std::endl;
                }
                    break;
                default:
                    break;
            }
        }
    }
    return 0;
}

   3、main函数实现如下

  

int main() {
    std::string file_name = "/media/ubuntu/study/data/test.mvt";

    test_pb_encode(file_name);

    test_pb_decode(file_name);

    return 0;
}

       搞定! 

猜你喜欢

转载自blog.csdn.net/bluebird888/article/details/127307232