使用GDAL库读写SHP文件

2 篇文章 0 订阅

       本文介绍如何读写shp文件的矢量线。shape文件包括一个主文件,一个索引文件,和一个dBASE表,其中主文件的后缀就是.shp,图形索引文件的后缀是.shx,dBASE表的后缀是.dbf,每个图形的属性数据存储在dBase格式的数据表之中。其它的文件还包括:Shapefile空间索引格式(.sbn),这是一个二进制的空间索引文件,仅仅可以应用在ESRI的软件之中。其文件格式没有公开的文档,其他厂商也没有实现这个文件。.sbn并不是必须的,因为.shp文件之中已经包含了所有的解析空间数据所需的信息。

在项目中,我们经常需要提取一些道路标线等对象保存为shp文件。本文使用到了Eigen库,需要的同学自己下载使用。

使用GDAL读写shp需要注意以下的问题:

(1)为了支持中文路径,在注册了驱动之后,加上第三句就可以了。必须设置为“NO”。

GDALAllRegister();
OGRAllRegister();
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");

(2)为了支持Shp中的中文属性输入,在注册了驱动之后,也得加上一句。 

CPLSetConfigOption( "SHAPE_ENCODING", "" );

有时候,也可以指定函数第二个选项为“CP936”

CPLSetConfigOption("SHAPE_ENCODING","CP936");

(3)使用double或者float类型作为属性值输入,需要设置字段的宽度:

	// create the attributes tables:
	OGRFieldDefn poFieldID("ID", OFTInteger);
	OGRFieldDefn oFieldx("x坐标", OFTReal);
	OGRFieldDefn oFieldy("y坐标", OFTReal);
	OGRFieldDefn oFieldz("z坐标", OFTReal);

	poFieldID.SetWidth(40);
	oFieldx.SetPrecision(8);
	oFieldy.SetPrecision(8);
	oFieldz.SetPrecision(8);

(4)版本问题:在GDAL 2.0+的C/C++版本中移除了对于OGRDatasource及OGRSFDriver的支持。分别用GDALDataset、GDALDriver代替,类下的方法不变。

GDAL2.0以下版本读取矢量线shp文件:

bool readPolylineShp(const std::string &filename, std::vector<std::vector<Eigen::Vector3f>> &pts) 
{
    // if this file exist, else exit!
    if((_access(filename.c_str(), 0)) != -1)
	{
        std::cout << "This .shp file exist." << filename << std::endl;
        //注册所有的文件格式驱动,这个函数注册了GDAL/OGR支持的所有格式
        OGRRegisterAll();
        //下一步我们将打开输入的OGR数据文件。数据文件可以是文件,关系型数据库,文件路径,甚至可能是远程的网络服务,这点取决于我们使用的驱动。但是,数据源的名字通常只是一个简单的字符串。既然这样拿我们就编写一个打开shapefile的程序。第二个参数(FLALSE)告诉OGRSFDriverRegistrar::Open() 函数我们不需要update access。如果失败返回NULL,并报错。
        OGRDataSource *poDS;
        poDS = OGRSFDriverRegistrar::Open(filename.c_str(), TRUE);
        if(poDS == NULL)
		{
            std::cout << "Failed in opening adding shp file;" << std::endl;
            OGRDataSource::DestroyDataSource(poDS);
            exit(1);
        }
        //一个OGRDataSource可能包含很多的层。所包含层的数量我们可以用过调        OGRDataSource::GetLayerCount()得到,并且其中每一个曾我们利用索引调用OGRDataSource::GetLayer()得到。也可以利用层的名字得到。
        int layerN = poDS->GetLayerCount();
        //std::cout << "layer count is: " << layerN << std::endl;
        OGRLayer *poLayer;
        poLayer = poDS->GetLayer(0);
        if(poLayer == NULL)
		{
            std::cout << "Failed in getting layer in existing .shp file" << std::endl;
            OGRDataSource::DestroyDataSource(poDS);
            return false;
        }

        // get vertexes on lines
        std::vector<std::vector<Eigen::Vector3f>>().swap(pts);

        //自从我们开始fresh with这个层,就没有这么严格了。很明智地我们需要调用Layer::ResetReading()来确保我们是从层的开头开始。
        poLayer->ResetReading();
        // 现在我们开始读取层里面的features。在开始之前我们需要指定一个attribute或者spatial filter来严格控制我们得到的feature。不过现在我们只是得到所有的features。
        OGRSpatialReference *shp_spf;
        shp_spf = poLayer->GetSpatialRef();     // geographical projection information

        //
        int iFeatureCount = poLayer->GetFeatureCount();
        pts.resize(iFeatureCount);

        OGRFeature *poFeature=NULL;
        // traverse all features in the layer:我们不断地调用OGRLayer::GetNextFeature()函数来遍历所有的features,当遍历完所有的features后返回NULL。
        int flag_line = 0;
        while ((poFeature = poLayer->GetNextFeature()) != NULL)
		{
            //feature里面提取出几何(geometry)数据
            OGRGeometry *poGeometry = poFeature->GetGeometryRef();
            OGRwkbGeometryType geotype;
            geotype = poGeometry->getGeometryType();
            OGRPoint *poPoint = NULL;
            OGRLineString *poLine = NULL;
            //确定这个几何数据的类型,如果是点,我们将他标为点并且进行操作,如果是其他的内省我们write占位符。这里的类型是多段线
            if(wkbLineString25D == geotype)
			{
                poLine = (OGRLineString*)poGeometry;
                int pNUM = poLine->getNumPoints();
                for(int i = 0; i < pNUM; ++i)
				{
                    Eigen::Vector3f temp_pt;
                    temp_pt[0] = poLine->getX(i);
                    temp_pt[1] = poLine->getY(i);
                    temp_pt[2] = poLine->getZ(i);
                    pts[flag_line].push_back(temp_pt);
                }
            }
            flag_line++;
            delete  poPoint;
            delete poLine;
        }
        //资源清理
        GDALClose(poDS);
        return true;
    }
	else
	{
        std::cout << "This .shp file is not exist!" << std::endl;
        return false;
    }
}

GDAL2.0以下版本写矢量线shp文件:

bool WriteShp(string filename)
{
	//创建
	const char *pszDriverName = "ESRI Shapefile";
	OGRSFDriver *poDriver;
	OGRRegisterAll();

	poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(pszDriverName);
	if (poDriver == NULL)
	{
		std::cout << pszDriverName << " : This driver is not available!" << std::endl;
		exit(1);
	}
	
	OGRDataSource* poDS;
	if ((_access(filename.c_str(), 0)) != -1)
	{
		std::cout << "Exist this shp file." << std::endl;
		remove(filename.c_str());
	}
	poDS = poDriver->CreateDataSource(filename.c_str(), NULL);
	if (poDS == NULL)
	{
		std::cout << "Failed in creating layers" << std::endl;
		exit(1);
	}
	// create layers:
	OGRLayer *poLayer;
	//poLayer = poDS->CreateLayer("curbs3D", NULL, wkbMultiLineString25D, NULL);
	poLayer = poDS->CreateLayer("point_out", NULL, wkbPoint, NULL);
	if (poLayer == NULL)
	{
		std::cout << "Layer creation failed!" << std::endl;
		exit(1);
	}


	// create the attributes tables:
	OGRFieldDefn poFieldID("ID", OFTInteger);
	poFieldID.SetWidth(40);
	if (poLayer->CreateField(&poFieldID) != OGRERR_NONE)
	{
		std::cout << "ID field creation failed!" << std::endl;
		exit(1);
	}
	OGRFieldDefn oField("Name", OFTString);
	oField.SetWidth(32);
	if (poLayer->CreateField(&oField) != OGRERR_NONE)
	{
		printf("Creating Name field failed.\n");
		exit(1);
	}
	//下面从stdin中循环读取  “x,y,name”格式的点信息。
	double x = 0, y = 100;
	char szName[33];
	for (int a = 0; a != 10; ++a)
	{
		x += a;
		y += a;
		OGRFeature *poFeature;
		poFeature = new OGRFeature(poLayer->GetLayerDefn());
		poFeature->SetField("Name", szName);
		OGRPoint pt;
		pt.setX(x);
		pt.setY(y);
		poFeature->SetGeometry(&pt);
		if (poLayer->CreateFeature(poFeature) != OGRERR_NONE)
		{
			cout << "创建要素失败" << endl;
		}
		//OGRFeature::DestroyFeature(*poFeature);//创建一个feature.OGRLayer::CreateFeature() 只是重新复制了一个feature,因此操作完成后需要清除feature对象
	}
	OGRDataSource::DestroyDataSource(poDS);

	return true;
}

 

UE5读取shp文件的基本思路是通过使用第三方或插件来实现。首先,需要导入相关的或插件,如GDAL(Geospatial Data Abstraction Library)或Shapefile Plugin。然后,使用或插件提供的函数或接口来读取shp文件的数据。这些函数或接口可以帮助解析shp文件的格式和结构,并将其转换为UE5所支持的数据类型,如点、线或多边形。读取的数据可以存储在UE5的数据结构中,如数组或容器中。最后,可以根据读取到的数据在UE5中进行进一步的处理和渲染。总之,基本思路是导入相关的或插件,使用其提供的函数或接口来读取shp文件的数据,并将其转换为UE5所支持的数据类型,然后进行进一步的处理和渲染。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [使用GDAL读写SHP文件](https://blog.csdn.net/jacken123456/article/details/106096323)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [java中读取shp文件数据存入数据](https://download.csdn.net/download/weixin_43228814/87965964)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值