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

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;
        }
    }
}

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

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
读取 .dbf 文件可以使用 DBF 文件开源,例如 Dbasepp 或者 libdbf++。读取 .sbn、.shx、.sho、.abx 文件可以使用 ESRI Shapefile开源,例如 GDAL 或者 shapelib。 加水印需要先在要输出的文件中插入水印,可以使用开源的图像处理,例如 OpenCV。将水印作为图像,先读入要输出的文件,然后在图像上叠加水印,最后将加了水印的图像输出到文件中。 下面是一个简单的示例代码,仅供参考: ```c++ #include <iostream> #include <fstream> #include <vector> #include <string> #include "dbf.h" #include "shapefil.h" #include "opencv2/opencv.hpp" using namespace std; using namespace cv; int main() { // 读取.dbf文件 DBFHandle dbf = DBFOpen("data.dbf", "rb"); if (dbf == nullptr) { cerr << "Failed to open data.dbf." << endl; return -1; } int recordCount = DBFGetRecordCount(dbf); int fieldCount = DBFGetFieldCount(dbf); // 读取.shp文件 SHPHandle shp = SHPOpen("data.shp", "rb"); if (shp == nullptr) { cerr << "Failed to open data.shp." << endl; return -1; } int shapeType; int shapeCount; double minBound[4], maxBound[4]; SHPGetInfo(shp, &shapeCount, &shapeType, minBound, maxBound); // 读取水印图像 Mat watermark = imread("watermark.png", IMREAD_UNCHANGED); if (watermark.empty()) { cerr << "Failed to open watermark.png." << endl; return -1; } // 创建输出文件 SHPHandle outShp = SHPCreate("output.shp", shapeType); DBFHandle outDbf = DBFCreate("output.dbf"); // 复制.dbf文件的schema for (int i = 0; i < fieldCount; i++) { char fieldName[12]; int fieldType, fieldWidth, fieldDecimals; fieldType = DBFGetFieldInfo(dbf, i, fieldName, &fieldWidth, &fieldDecimals); DBFAddField(outDbf, fieldName, fieldType, fieldWidth, fieldDecimals); } // 复制.shp文件的geometry vector<SHPObject*> shapes; for (int i = 0; i < shapeCount; i++) { SHPObject* shape = SHPReadObject(shp, i); shapes.push_back(shape); } // 在每个geometry上加水印 for (int i = 0; i < shapeCount; i++) { SHPObject* shape = shapes[i]; // 读取geometry的bounding box double xMin = shape->dfXMin; double yMin = shape->dfYMin; double xMax = shape->dfXMax; double yMax = shape->dfYMax; // 在bounding box中心位置叠加水印 Point2d center((xMin + xMax) / 2, (yMin + yMax) / 2); Point2d topLeft(center.x - watermark.cols / 2, center.y - watermark.rows / 2); Point2d bottomRight(center.x + watermark.cols / 2, center.y + watermark.rows / 2); // 将geometry转换为OpenCV的轮廓 vector<Point> points; for (int j = 0; j < shape->nVertices; j++) { double x = shape->padfX[j]; double y = shape->padfY[j]; Point pt(x, y); points.push_back(pt); } vector<vector<Point>> contours; contours.push_back(points); // 创建mask Mat mask = Mat::zeros(watermark.size(), CV_8UC1); fillPoly(mask, contours, Scalar(255)); // 叠加水印 Mat image = imread("data.png", IMREAD_UNCHANGED); Mat roi = image(Rect(topLeft, bottomRight)); Mat maskedWatermark; watermark.convertTo(maskedWatermark, CV_8UC4, 255); vector<Mat> channels; split(maskedWatermark, channels); channels[3] = mask; merge(channels, maskedWatermark); addWeighted(roi, 1, maskedWatermark, 0.5, 0, roi); // 将加了水印的geometry写入输出文件 SHPObject* outShape = SHPCreateSimpleObject(shapeType, shape->nVertices, shape->padfX, shape->padfY, nullptr); DBFWriteIntegerAttribute(outDbf, i, 0, DBFReadIntegerAttribute(dbf, i, 0)); // 复制第一个字段(ID) for (int j = 1; j < fieldCount; j++) { DBFFieldType fieldType = DBFGetFieldInfo(dbf, j, nullptr, nullptr, nullptr); if (fieldType == FTDouble) { DBFWriteDoubleAttribute(outDbf, i, j, DBFReadDoubleAttribute(dbf, i, j)); } else if (fieldType == FTInteger) { DBFWriteIntegerAttribute(outDbf, i, j, DBFReadIntegerAttribute(dbf, i, j)); } else { DBFWriteStringAttribute(outDbf, i, j, DBFReadStringAttribute(dbf, i, j)); } } SHPWriteObject(outShp, -1, outShape); SHPDestroyObject(outShape); } // 关闭所有文件 SHPClose(shp); DBFClose(dbf); SHPClose(outShp); DBFClose(outDbf); return 0; } ``` 需要注意的是,上述示例代码仅支持点、线、面三种类型的geometry,如果要支持更多的geometry类型,需要根据实际情况修改代码。此外,示例代码中使用的水印是一个透明的PNG图像,如果要使用其他类型的水印,需要相应地修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值