开发准备:
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;
}
搞定!