基于GDAL库读写shp文件的C++代码

因为项目需要,学习了解了GDAL读取shp文件的方式,贴出代码以供参考

 

我自己封装的包含shp读写操作的类,并不完整,留下了一些接口,有兴趣或者有需要的可以自己补充完整

头文件SHP_RW.h

#pragma once

#include 
#include 
#include 

using namespace std;

class SHP_RW
{
public:
	SHP_RW();
	~SHP_RW();

	OGRGeometry *poGeometry;
	OGRLayer *poLayer;

	int Get_Point(double &X, double &Y, double &Z);
	int Get_LineString(vector &vecX, vector &vecY, vector &vecZ);
	int Get_Polygon(map> &coordinate, map < int, map>> &innerring);
	int Get_MultiPoint();
	int Get_MultiLineString();
	int Get_MultiPolygon();
	int Get_GeometryCollection();

	int Set_Point();
	int Set_LineString();
	int Set_Polygon();
	int Set_MultiPoint();
	int Set_MultiLineString();
	int Set_MultiPolygon();
	int Set_GeometryCollection();

	int SetFieldDefn(vector fieldname, vector fieldtype, vector fieldwidth);

private:

};

.cpp文件 SHP_RW.cpp

#include "SHP_RW.h"


SHP_RW::SHP_RW()
{
}

SHP_RW::~SHP_RW()
{
}

int SHP_RW::Get_Point(double &X, double &Y, double &Z)
{
	OGRPoint *poPoint = (OGRPoint *)poGeometry;
	X = poPoint->getX();
	Y = poPoint->getY();
	Z = poPoint->getZ();
	return 0;
}

int SHP_RW::Get_LineString(vector &vecX, vector &vecY, vector &vecZ)
{
	OGRLineString* pLineGeo = (OGRLineString*)poGeometry;
	int pointnums = pLineGeo->getNumPoints();
	for (int i = 0; i < pointnums; i++)
	{
		vecX.push_back(pLineGeo->getX(i));
		vecY.push_back(pLineGeo->getY(i));
		vecZ.push_back(pLineGeo->getZ(i));
	}
	return 0;
}

int SHP_RW::Get_Polygon(map> &coordinate, map < int, map>> &innerring)
{
	OGRPolygon *poPolygon = (OGRPolygon *)poGeometry;
	OGRPoint point;
	OGRLinearRing *pOGRLinearRing = poPolygon->getExteriorRing();
	//printf("nums = %d\n", pOGRLinearRing->getNumPoints());
	for (int i = 0; i < pOGRLinearRing->getNumPoints(); i++)
	{
		coordinate["X"].push_back(pOGRLinearRing->getX(i));
		coordinate["Y"].push_back(pOGRLinearRing->getY(i));
		coordinate["Z"].push_back(pOGRLinearRing->getZ(i));
		//printf("%.3f, %.3f, %.3f\n", pOGRLinearRing->getX(i), pOGRLinearRing->getY(i), pOGRLinearRing->getZ(i));
	}

	int innernums = poPolygon->getNumInteriorRings();
	printf("innernums = %d\n", innernums);
	if (innernums > 0)
	{
		for (int i = 0; i < innernums; i++)
		{
			pOGRLinearRing = poPolygon->getInteriorRing(i);
			for (int j = 0; j < pOGRLinearRing->getNumPoints(); j++)
			{
				innerring[i]["X"].push_back(pOGRLinearRing->getX(j));
				innerring[i]["Y"].push_back(pOGRLinearRing->getY(j));
				innerring[i]["Z"].push_back(pOGRLinearRing->getZ(j));
			}
		}
	}

	//pOGRLinearRing->getPoint(0, &point);	//得到第一个点的坐标
	//staX = point.getX();
	//staY = point.getY();
	return 0;
}

int SHP_RW::Get_MultiPoint()
{
	return 0;
}

int SHP_RW::Get_MultiLineString()
{
	return 0;
}

int SHP_RW::Get_MultiPolygon()
{
	return 0;
}

int SHP_RW::Get_GeometryCollection()
{
	return 0;
}


/* *************** 文件写入操作 ********************* */
int SHP_RW::Set_Point()
{


	return 0;
}

int SHP_RW::Set_LineString()
{
	return 0;
}

int SHP_RW::Set_Polygon()
{
	int x, y;
	int a = 10, b = 100;
	for (int i = 0; i < 10; i++)		// 控制要素数量
	{
		OGRFeature *poFeature;
		poFeature = OGRFeature::CreateFeature(poLayer->GetLayerDefn());
		poFeature->SetField("ID", i);
		//string name = "第" + to_string(i + 1) + "个要素";

		poFeature->SetField("NAME", "name");
		x = (rand() % (b - a)) + a;
		y = (rand() % (b - a)) + a;
		poFeature->SetField("VALUE", x + y);
		//polygon
		OGRPolygon polygon;
		// 外环
		OGRLinearRing ringOut;
		ringOut.addPoint(80, 30);
		ringOut.addPoint(80, 40);
		ringOut.addPoint(90, 40);
		ringOut.addPoint(90, 30);
		ringOut.closeRings();

		polygon.addRing(&ringOut);

		//内环
		int numringIn = 5;		// 设置内环个数
		for (int i = 0; i < numringIn; i++)
		{
			OGRLinearRing ringIn0;
			ringIn0.addPoint(82, 32);
			ringIn0.addPoint(82, 38);
			ringIn0.addPoint(88, 38);
			ringIn0.addPoint(88, 32);
			ringIn0.closeRings();

			polygon.addRing(&ringIn0);
		}
		//polygon.addRingDirectly(&ringIn0);

		poFeature->SetGeometry((OGRGeometry *)(&polygon));
		if (poLayer->CreateFeature(poFeature) != OGRERR_NONE)
		{
			printf("Failed to create feature in shapefile.\n");
			return 0;
		}

		OGRFeature::DestroyFeature(poFeature);

	}
	return 0;
}

int SHP_RW::Set_MultiPoint()
{
	return 0;
}

int SHP_RW::Set_MultiLineString()
{
	return 0;
}

int SHP_RW::Set_MultiPolygon()
{
	return 0;
}

int SHP_RW::Set_GeometryCollection()
{
	return 0;
}

int SHP_RW::SetFieldDefn(vector fieldname, vector fieldtype, vector fieldwidth)
{
	
	for (int i = 0; i < fieldname.size(); i++)
	{
		OGRFieldDefn Field(fieldname[i].c_str(), fieldtype[i]);	//创建字段 字段+字段类型
		Field.SetWidth(fieldwidth[i]);		//设置字段宽度,实际操作需要根据不同字段设置不同长度
		poLayer->CreateField(&Field);
	}
	return 0;
}
/* *************** 文件写入操作 ********************* */

读写cpp

#include 
#include 
#include 
#include 
#include "SHP_RW.h"
#include 
#include 
#include 
#include 
#include 

using namespace std;

//读shp文件
int shpread(const char* file_path_name)
{
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");	// 支持中文路径
	CPLSetConfigOption("SHAPE_ENCODING", "");			//属性表支持中文字段


	GDALAllRegister();

	GDALDataset *poDS = (GDALDataset*)GDALOpenEx(file_path_name, GDAL_OF_VECTOR, NULL, NULL, NULL);
	if (poDS == NULL)
	{
		printf("Open failed.\n");
		exit(1);
	}
	cout << "Open successfully!" << endl;

	
	//获取图层数量
	cout << "<--------获取图层数量-------->" << endl;
	int LayerCount = poDS->GetLayerCount();
	cout << "图层数量: " << LayerCount << endl;

	//获取shp图层
	cout << "<--------获取shp图层-------->" << endl;
	OGRLayer  *poLayer = poDS->GetLayer(0);  //	 根据序号获取相应shp图层,这里表示第一层
	//OGRLayer  *poLayer = poDS->GetLayerByName("point");		//根据名称获取相应图层

	//获取当前图层的属性表结构
	cout << "<--------获取当前图层的属性表结构-------->" << endl;
	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();

	//重置要素读取顺序
	cout << "<--------重置要素读取顺序-------->" << endl;
	poLayer->ResetReading();	// ResetReading() 函数功能为把要素读取顺序重置为从第一个开始

	//设置要素指针
	cout << "<--------设置要素指针-------->" << endl;
	OGRFeature *poFeature;		//用于获取图层上的要素

    //创建文件存放数据
	shpname = shpname.substr(0, shpname.find_last_of(".")) + "_";
	string attrfile = "D:/output/" + shpname + "attrfile_shp.txt";			// 属性文件
	string datafile = "D:/output/" + shpname + "datafile_shp.txt";			// 数据文件
	cout << attrfile << ' ' << datafile << endl;
	fstream tmpfile(attrfile, ios::out);
	fstream tmpdatafile(datafile, ios::out);

	
	int num = 0;		//用于标记第几个要素

	while ((poFeature = poLayer->GetNextFeature()) != NULL)
	{
		cout << "图层属性->" << endl;

		for (int iField = 0; iField < poFDefn->GetFieldCount(); iField++)
		{
			OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(iField);

			cout << poFieldDefn->GetNameRef() << ": ";		// 属性表字段名
			switch (poFieldDefn->GetType())			// 不同数据类型按不同方式,根据字段号获取相应字段的数据
			{
			case OFTInteger:
				printf("%d,", poFeature->GetFieldAsInteger(iField));
				tmpfile << poFeature->GetFieldAsInteger(iField) << "\t";		// 写入文件
				break;
			case OFTInteger64:
				printf(CPL_FRMT_GIB ",", poFeature->GetFieldAsInteger64(iField));
				tmpfile << poFeature->GetFieldAsInteger64(iField) << "\t";		// 写入文件
				break;
			case OFTReal:
				printf("%.3f,", poFeature->GetFieldAsDouble(iField));
				tmpfile << poFeature->GetFieldAsDouble(iField) << "\t";		// 写入文件
				break;
			case OFTString:
				printf("%s,", poFeature->GetFieldAsString(iField));
				tmpfile << poFeature->GetFieldAsString(iField) << "\t";		// 写入文件
				break;
			default:
				printf("%s,", poFeature->GetFieldAsString(iField));
				tmpfile << poFeature->GetFieldAsString(iField) << "\t";		// 写入文件
				break;
			}
			/*printf("\n");*/
		}
		tmpfile << endl;


		OGRGeometry *poGeometry = poFeature->GetGeometryRef();
		double staX, staY, staZ;
		vector vecX, vecY, vecZ;
		double area;
		//判断当前要素的几何类型,是否为点图层,利用 getGeometryType() 函数获取要素类型
		SHP_RW geo;
		geo.poGeometry = poGeometry;

		if (poGeometry != NULL)	
		{	
			auto GeometryType = wkbFlatten(poGeometry->getGeometryType());	// getGeometryType() 返回的类型可能会有2.5D类型,通过宏 wkbFlatten 转换为2D类型
			if (GeometryType == wkbPoint)		// 1
			{
				cout << "点图层要素" << endl;
				geo.Get_Point(staX, staY, staZ);
				//printf("X= %.3f, Y= %.3f, Z= %.3f\n", staX, staY, staZ);
				tmpdatafile << staX << "\t" << staY << "\t" << staZ << endl;		// 写入文件
			}
			else if (GeometryType == wkbLineString)		// 2
			{
				cout << "线图层要素" << endl;
				geo.Get_LineString(vecX, vecY, vecZ);
				for (int i = 0; i < vecX.size(); i++)
					//printf("X= %.3f, Y= %.3f, Z= %.3f\n", vecX[i], vecY[i], vecZ[i]);
					tmpdatafile << vecX[i] << "\t" << vecY[i] << "\t" << vecZ[i] << endl;		// 写入文件
			}
			else if (GeometryType == wkbPolygon)		// 3
			{
				cout << "多边形图层要素" << endl;			
				map> coordinate;		// 外环
				map < int, map>> innerring;	//内环
				coordinate["X"], coordinate["Y"], coordinate["Z"];
				geo.Get_Polygon(coordinate, innerring);

				// 将数据写入文件
				tmpdatafile << "<----- 第" + to_string(1 + num++) + "个要素 ---->" << endl;
				tmpdatafile << "外环数据" << endl;
				cout << "数据个数:" << coordinate["X"].size() << endl;

				for (int j = 0; j < coordinate["X"].size(); j++)
				{
					tmpdatafile << coordinate["X"][j] << "\t" << coordinate["Y"][j] << "\t" << coordinate["Z"][j] << endl;		// 写入文件
				}


				tmpdatafile << "内环数据" << endl;
				for (int i = 0; i < innerring.size(); i++)
				{
					for (int k = 0; k < innerring[i]["X"].size(); k++)
						tmpdatafile << innerring[i]["X"][k] << "\t" << innerring[i]["Y"][k] << "\t" << innerring[i]["Z"][k] << endl;		// 写入文件
				}
			}
			else if (GeometryType == wkbMultiPoint)		// 4
			{
				cout << "点集合图层要素" << endl;
			}
			else if (GeometryType == wkbMultiLineString)	// 5
			{
				cout << "线集合图层要素" << endl;
			}
			else if (GeometryType == wkbMultiPolygon)		// 6
			{
				cout << "多边形集合图层要素" << endl;
			}
			else if (GeometryType == wkbGeometryCollection)		// 7
			{
				cout << "几何体集合图层要素" << endl;
			}
			else if (GeometryType == wkbNone)
			{
				cout << "该数据只有属性表" << endl;
			}

		}
		else
		{
			printf("no  geometry\n");
		}
		OGRFeature::DestroyFeature(poFeature);
	}
	tmpfile.close();

	GDALClose(poDS);
	return 0;

}


// 写shp文件
int shpwrite(const char* file_path_name)
{
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");	// 支持中文路径
	CPLSetConfigOption("SHAPE_ENCODING", "");			//属性表支持中文字段

	//注册所有驱动
	OGRRegisterAll();
	const char *pszDriverName = "ESRI Shapefile";
	GDALDriver *poDriver;
	poDriver = GetGDALDriverManager()->GetDriverByName(pszDriverName);
	if (poDriver == NULL)
	{
		printf("%s driver not available.\n", pszDriverName);
		return 0;
	}

	//创建数据源
	GDALDataset *poDS;
	poDS = poDriver->Create(file_path_name, 0, 0, 0, GDT_Unknown, NULL); //创建shp文件
	if (poDS == NULL)
	{
		printf("Creation of output file failed.\n");
		return 0;
	}


	OGRLayer *poLayer;
	SHP_RW write_shp;
	//OGRwkbGeometryType layertype;
	//layertype = wkbPolygon;
	string layertype = "多边形";
	vector fieldname = { "ID", "NAME", "VALUE" };
	vector fieldtype = { OFTInteger, OFTString, OFTReal };
	vector fieldwidth = { 32, 32, 32 };


	if (layertype == "点")
	{
		// 创建图层,这里没有指定空间参考,如果需要的话,需要在这里进行指定
		poLayer = poDS->CreateLayer("point_out", NULL, wkbPoint, NULL);
		write_shp.poLayer = poLayer;
		write_shp.SetFieldDefn(fieldname, fieldtype, fieldwidth);
		write_shp.Set_Point();
	}
	else if (layertype == "线")
	{
		poLayer = poDS->CreateLayer("string_out", NULL, wkbLineString, NULL);
		write_shp.poLayer = poLayer;
		write_shp.SetFieldDefn(fieldname, fieldtype, fieldwidth);
		write_shp.Set_LineString();
	}
	else if (layertype == "多边形")
	{
		poLayer = poDS->CreateLayer("string_out", NULL, wkbPolygon, NULL);
		write_shp.poLayer = poLayer;
		write_shp.SetFieldDefn(fieldname, fieldtype, fieldwidth);
		write_shp.Set_Polygon();
	}
	else if (layertype == "点集合")
	{

	}
	else if (layertype == "线集合")
	{

	}
	else if (layertype == "多边形集合")
	{

	}


	GDALClose(poDS);

	return 0;
}


int main()
{
    shpread("D:/originshp/tmppath/0806.shp");
    system("pause");

    return 0;
}

 

 

你可能感兴趣的:(C++,GDAL)