C/C++通过shapelib开源库读取shapefile文件

shapelib下载

链接: http://download.osgeo.org/shapelib/

shapelib编译

作者使用的是deepin操作系统(linux),下载的是shapelib-1.5.0.tar.gz压缩包,解压后会有一个源码目录shapelib-1.5.0。进入源码路径即CMakeList.txt所在路径。
命令行分别输入:

./configure
mkdir build
cd build
cmake ..

然后在build路径下就会生成libshp.so,通过源码路径下的shapefil.h就可以调用libshp.so库
如果不想使用库,希望把源码和你的项目编译到一起可以直接将CMakeLists.txt中lib_SRC 所包含的源码文件添加到你的项目中进行编译即可
在这里插入图片描述

C++使用二次封装

作者在C++项目中使用到了这个库对其进行了二次封装,该项目读取的是.dbf文件和.shp文件
read_shapefile.h

#ifndef __READ_SHAPEFILE_H__
#define __READ_SHAPEFILE_H__
#include "shapefil.h"
#include <unistd.h>
#include <memory>
#include <iostream>
#include <vector>
#include <assert.h>
#include <bits/stdc++.h>
using namespace std;
class ReadShapeFile;
#define SUCCESS (0)
#define FAILURE (-1)
using SpReadShapeFile = std::shared_ptr<ReadShapeFile>;

typedef struct {
    double x;
    double y;
    double z;
} Point3D;
using Point3DS = vector<Point3D>;
#define SHAPEFILE_DBF_TITLE_SIZE (50) // dbf文件标题长度
class ReadShapeFile
{
public:
  static SpReadShapeFile createSpReadShapeFile(const string &file_name)
  { // file_name中应为路径和文件前缀
      if(access((file_name + ".dbf").c_str(), F_OK) != 0)return NULL;
      SpReadShapeFile ptr(new ReadShapeFile(file_name));
      return ptr;
  }
  ~ReadShapeFile();
  /**
   * @brief 获取DBF文件的记录数目和字段数目
   *
   * @param [out] record 记录数
   * @param [out] field 字段数
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetDBFRecordAndField(int32_t &record, int32_t &field);
  /**
   * @brief 获取SHP文件的记录数
   *
   * @param [out] record 记录数
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetSHPRecord(int32_t &record);
  /**
   * @brief 如果不知道DBF文件类型可以通过该方法获取目前支持int;double;string
   *
   * @param [in] field 字段
   * @param [out] data_type 该字段的数据类型
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetDBFDataType(const int32_t field, DBFFieldType &data_type) const;
  /**
   * @brief 获取DBF中int类型的字段
   *
   * @param [in] record 记录
   * @param [in] field 字段
   * @param [out] data
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetDBFIntData(const int32_t record, const int32_t field,
                    int32_t &data) const;
  /**
   * @brief 获取DBF中double类型的字段
   *
   * @param [in] record 记录
   * @param [in] field 字段
   * @param [out] data
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetDBFDoubleData(const int32_t record, const int32_t field,
                      double &data) const;
  /**
   * @brief 获取DBF中string类型的字段
   *
   * @param [in] record 记录
   * @param [in] field 字段
   * @param [out] data
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetDBFStringData(const int32_t record, const int32_t field,
                       string &data) const;
  /**
   * @brief 获取SHP文件中的点信息
   *
   * @param [in] record 记录
   * @param [out] data 点集合可能是一个或者多个
   * @return int 成功——SUCCESS 失败——FAILURE
   */
  int GetSHP3DPoints(const int32_t record, Point3DS &data) const;

private:
  ReadShapeFile(const string &file_name);

private:
  string file_name_;
  DBFHandle h_dbf_;
  SHPHandle h_shp_;

};

#endif //__READ_SHAPEFILE_H__

read_shapefile.cpp

#include "readshapfile.h"

ReadShapeFile::ReadShapeFile(const string &file_name)
    : file_name_(file_name), h_dbf_(NULL), h_shp_(NULL)
{
    h_dbf_ = DBFOpen((file_name + ".dbf").c_str(), "r");
    h_shp_ = SHPOpen((file_name + ".shp").c_str(), "r");
}
ReadShapeFile::~ReadShapeFile()
{
    if (h_dbf_ != NULL) {
        DBFClose(h_dbf_);
    }
    if (h_shp_ != NULL) {
        SHPClose(h_shp_);
    }
}
int ReadShapeFile::GetDBFRecordAndField(int32_t &record, int32_t &field)
{
    if(h_dbf_ == NULL) return FAILURE;
    record = h_dbf_->nRecords;
    field = h_dbf_->nFields;
    return SUCCESS;
}
int ReadShapeFile::GetSHPRecord(int32_t &record)
{
    if(h_shp_ == NULL) return FAILURE;
    record = h_shp_->nRecords;
    return SUCCESS;
}

int ReadShapeFile::GetDBFDataType(const int32_t field,
                                  DBFFieldType &data_type) const
{
    if(h_dbf_ == NULL) return FAILURE;
    if(field > h_dbf_->nFields) return FAILURE;
     char title[SHAPEFILE_DBF_TITLE_SIZE] = "";
    // int32_t len;      //字段长度 单位:bit
    // int32_t decimals; //小数位数
    // DBFFieldType data_type = DBFGetFieldInfo(h_dbf_, field, title, &len,
    // &decimals);
    data_type = DBFGetFieldInfo(h_dbf_, field, title, NULL, NULL);
    cout << title;
    return SUCCESS;
}
int ReadShapeFile::GetDBFIntData(const int32_t record, const int32_t field,
                                 int32_t &data) const
{
    if(h_dbf_ == NULL) return FAILURE;
    if(record > h_dbf_->nRecords || field > h_dbf_->nFields) return FAILURE;
    data = DBFReadIntegerAttribute(h_dbf_, record, field);
    return SUCCESS;
}
int ReadShapeFile::GetDBFDoubleData(const int32_t record, const int32_t field,
                                   double &data) const
{
    if(h_dbf_ == NULL) return FAILURE;
    if(record > h_dbf_->nRecords || field > h_dbf_->nFields) return FAILURE;
    data = DBFReadDoubleAttribute(h_dbf_, record, field);
    return SUCCESS;
}
int ReadShapeFile::GetDBFStringData(const int32_t record, const int32_t field,
                                    string &data) const
{
    if(h_dbf_ == NULL) return FAILURE;
    if(record > h_dbf_->nRecords || field > h_dbf_->nFields) return FAILURE;
    data = DBFReadStringAttribute(h_dbf_, record, field);
    return SUCCESS;
}
int ReadShapeFile::GetSHP3DPoints(const int32_t record,
                                  Point3DS &data) const
{
    if(h_shp_ == NULL) return FAILURE;
    if(record > h_shp_->nRecords) return FAILURE;
    SHPObject *shp_obj = SHPReadObject(h_shp_, record);
    if(shp_obj == NULL) return FAILURE;
    Point3DS.clear();
    for (int i = 0; i < shp_obj->nVertices; ++i) {
        Point3D point = {(shp_obj->padfX[i]),
                          (shp_obj->padfY[i]),
                          (shp_obj->padfZ[i])};
        data.emplace_back(std::move(point));
    }
    return SUCCESS;
}

main.cpp

#include<iostream>
#include "readshapfile.h"
using namespace std;

int main()
{
    auto fp =ReadShapeFile::createSpReadShapeFile("file_name");
    if(fp==NULL) return ;
    int32_t record, field;
    fp->GetDBFRecordAndField(record, field);
    int32_t shp_record;
    fp->GetSHPRecord(shp_record);
    int32_t int_data;
    double double_data;
    string string_data;
    Point3DS points;
    for(int i=0;i<record;++i)
    {
        for(int j= 0; j< field; ++j){
            DBFFieldType type;
            fp->GetDBFDataType(j,type);
            switch(type){
                case FTString:
                    fp->GetDBFStringData(i,j,string_data);
                    cout<<"  string: "<<string_data<<endl;
                    break;
                case FTInteger:
                    fp->GetDBFIntData(i,j,int_data);
                    cout<<"  int: "<<int_data<<endl;
                    break;
                case FTDouble:
                    fp->GetDBFDoubleData(i,j,double_data);
                    cout<<"  double: "<<double_data<<endl;
                    break;
                default:
                    break;
            }
        }
    }
    for(int i=0;i<shp_record;++i){
        fp->GetSHP3DPoints(i,points);
        for(auto &point:points){
            cout<<"xyz["<<point.x<<","<<point.y<<","<<point.z<<"] " <<endl;
        }
    }
}

以上均作者通过查阅资料和自己理解摸索出来的,如有问题望各位及时指出,谢谢!

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐