利用ArcGis API 解析FileGDB文件

1 篇文章 0 订阅

FileGDB是ArcGis一种文件型数据,最近ArcGis官网发布了其相关API,有各个平台的,window平台主要C++版本和C#版本,本文主要介绍如何使用C++ API解析FileGDB文件。

1.打开DataBase

fgdbError hr;
Geodatabase geodatabase;
hr = OpenGeodatabase(wstrFileName, geodatabase);
if (hr != S_OK)
{
	cout << "打开dataBase失败!!" << endl;
}

打开DataBase是关键,如果这一步都失败的话无从谈起,另外OpenGeodatabase的第一个参数是wstring,如果传入的是string的话需要转换为wstring。

2.加载Layer

加载Layer对于解析fileGDB尤其重要,通过加载Layer,我们可以获取数据集个数、每个数据集的类型、字段等信息

bool LoadLayer(Geodatabase &geodatabase, const std::wstring &root)
{
	std::vector<wstring> tables;
	std::vector<wstring> featureclasses;
	std::vector<wstring> featuredatasets;
	fgdbError hr;

	//纯属性表
	hr = geodatabase.GetChildDatasets(root, L"Table", tables);
	if (hr != S_OK)
	{
		return GDBErr(hr, "Error reading Tables in " + WStringToString(root));
	}

	if (tables.size() > 0 && ! OpenFGDBTables(geodatabase, L"Table", tables))
	{
		return false;
	}

	//点、线、面
	hr = geodatabase.GetChildDatasets(root, L"Feature Class", featureclasses);
	if (hr != S_OK)
	{
		return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(root));
	}

	if (featureclasses.size() > 0 && ! OpenFGDBTables(geodatabase, L"Feature Class", featureclasses))
	{
		return false;
	}

	//关系类
	hr = geodatabase.GetChildDatasets(root, L"Feature Dataset", featuredatasets);
	if (hr != S_OK)
	{
		return GDBErr(hr, "Error reading Feature Datasets in " + WStringToString(root));
	}

	for (unsigned int i = 0; i < featuredatasets.size(); i++)
	{
		hr = geodatabase.GetChildDatasets(featuredatasets[i], L"Feature Class", featureclasses);
		if (hr != S_OK)
		{
			return GDBErr(hr, "Error reading Feature Classes in " + WStringToString(featuredatasets[i]));
		}
		if (featureclasses.size() > 0 && ! OpenFGDBTables(geodatabase, L"Feature Class", featureclasses))
		{
			return false;
		}
	}

	return true;
}

打开Table,本步骤主要是获取数据集个数和初始化Table指针,Table指针主要用于后续取Geometry

bool OpenFGDBTables(Geodatabase &geodatabase, const std::wstring &type, const std::vector<std::wstring> &layers)
{
	fgdbError hr;
	for (unsigned int i = 0; i < layers.size(); i++)
	{
		Table* pTable = new Table;
		hr = geodatabase.OpenTable(layers[i], *pTable);

 		if (hr != S_OK)
		{
			continue;
		}

		Layer *pLayer = new Layer;
		if (!Initialize(geodatabase, pTable, layers[i], type, pLayer))
		{
			return GDBErr(hr, "Error initializing OGRLayer for " + WStringToString(layers[i]));
		}

		m_arrLayers.push_back(pLayer);
	}

	return true;
}

初始化Layer,主要是字段和投影相关信息

bool Initialize(Geodatabase &geodatabase, Table *pTable, std::wstring wstrTablePath, std::wstring wstrType, Layer *pLayer)
{
	long hr;
	wstring wstrQueryName;

	hr = geodatabase.GetQueryName(wstrTablePath, wstrQueryName);
	if (hr != S_OK)
	{
		return GDBErr(hr, "Failed at getting underlying table name for " + WStringToString(wstrTablePath));
	}

	string tableDef;
	hr = pTable->GetDefinition(tableDef);
	if (hr != S_OK)
	{
		return GDBErr(hr, "Failed at getting table definition for " + WStringToString(wstrTablePath));
	}
	
	istringstream inputStrngstream(tableDef);
	TiXmlDocument document;
	inputStrngstream >> document;
	TiXmlElement *pRoot = document.FirstChildElement();
	if (NULL != pRoot)
	{
		TiXmlElement *pChild = NULL;
		while (pChild = (TiXmlElement *)pRoot->IterateChildren(pChild))
		{
			string strFileName = "";
			if (pChild->Type() == TiXmlNode::TINYXML_ELEMENT)
			{
				strFileName = pChild->ValueStr();
				if (strFileName == "OIDFieldName")
				{
					string strValue   =  pChild->FirstChild()->ValueStr();
					m_strOIDFieldName = strValue;
				}

				if (strFileName == "Fields")
				{
					if (pChild->FirstChild()->ValueStr() == "FieldArray")
					{
						InitFieldInfo(pLayer, (TiXmlElement*)pChild->FirstChild());
					}
				}
			}
		}
	}

	return true;	
}


通过GetDefinition函数获取的是一个字符串,字符串中主要存储字段、投影、Geometry类型等信息,对于一些软件刚开始的时候就要创建字段、数据集等需要解析本字符串,本文是采用将字符串读入流中,然后利用TinyXml这个xml解析库解析出相关内容。

初始化字段,主要包括创建字段和读出投影,投影直接存储为WKT字符串。

void InitFieldInfo(Layer *pLayer, TiXmlElement *pChild)
{
	if (NULL == pLayer || NULL == pChild)
	{
		return;
	}

	if (pChild->FirstChild()->ValueStr() == "Field")
	{
		TiXmlNode *pNode = pChild->FirstChild();
		while (pNode = pChild->IterateChildren(pNode))
		{
			TiXmlNode *pChildNode = NULL;
			string strFieldName = "";
			string strFieldType = "";

			while(pChildNode = pNode->IterateChildren(pChildNode))
			{
				string strValue = pChildNode->ValueStr();
				if (strValue == "Name")
				{
					strFieldName = strValue;
				}

				if (strValue == "Type")
				{
					strFieldType = strValue;
				}

				if (strValue == "GeometryDef")
				{
					if (!ParseGemetryDef(pLayer, pChildNode))
					{
						return;
					}
				}

				if (strFieldType == "esriFieldTypeOID")
				{
					continue;
				}

				if (strFieldType == "esriFieldTypeGeometry")
				{
					continue;
				}

				//创建字段
				Field *pField = new Field;
				if (strFieldType == "esriFieldTypeSmallInteger")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeSmallInteger;
				}
				else if (strFieldType == "esriFieldTypeInteger")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeInteger;
				}
				else if (strFieldType == "esriFieldTypeSingle")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeSingle;
				}
				else if (strFieldType == "esriFieldTypeDouble")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeDouble;
				}
				else if (strFieldType == "esriFieldTypeString" ||
					strFieldType == "esrifieldTypeGUID"        ||
					strFieldType == "esrifieldTypeGlobalID"    ||
					strFieldType == "esrifieldTypeXML")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeString;
				}
				else if (strFieldType == "esriFieldTypeDate")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeDate;
				}
				else if (strFieldType == "esriFieldTypeBlobe")
				{
					pField->m_strFiledName = strFieldName;
					pField->m_FileType     = FieldType::fieldTypeBlob;
				}

				pLayer->m_arrField.push_back(pField);
			}
		}
	}
}

解析Geometrydef,从中得到数据集类型、是否还有三维对象等

bool ParseGemetryDef(Layer *pLayer, TiXmlNode *pNode)
{
	if (NULL == pLayer || NULL == pNode)
	{
		return false;
	}

	bool      bHasGeometry = false;
	TiXmlNode *pChildNode  = NULL;

	while(pChildNode = pNode->IterateChildren(pChildNode))
	{
		string strValue = pChildNode->ValueStr();
		if (strValue == "GeometryType")
		{
			//Gemetry类型,用于设置数据的类型
			bHasGeometry = true;
			continue;
		}

		//是否有Z值,用于构造3D对象
		if (strValue == "HasZ")
		{
			pLayer->m_bHasZ = true;
			continue;
		}
	
		//设置投影,投影是WKT字符串
		if (strValue == "SpatialReference")
		{
			TiXmlNode *pWKTNode = pChildNode->FirstChild();
			if (pWKTNode->ValueStr() == "WKT")
			{
				string strWkT = pWKTNode->FirstChild()->ValueStr();
				if (!strWkT.empty())
				{
					pLayer->m_strPrj = strWkT;
				}
			}
			
			continue;
		}
	}

	return bHasGeometry;
}

3.解析Geometry,ArcGis FileGDB中的Geometry类型主要有点、多点、线、面、多面,其中包括三维对象。其或者主要是通过Table查询得到。

/*
 *	读Geometry,Geometry索引从1开始
 */
bool ReadGeometry(int nGeometryIndex)
{
	EnumRows enumRows;
	fgdbError hr;

	ostringstream osQuery;
	osQuery << m_strOIDFieldName << "=" << nGeometryIndex;
	string strQuery = osQuery.str();

	hr = m_pTable->Search(L"*", StringToWstring(strQuery), true, enumRows);
	if (hr != S_OK)
	{
		return GDBErr(hr, "");
	}

	Row row;
	hr = enumRows.Next(row);
	if (hr != S_OK)
	{
		return GDBErr(hr, "");
	}

	ShapeBuffer gdbGeometry;
	row.GetGeometry(gdbGeometry);

	GeometryType geometryType;
	gdbGeometry.GetGeometryType(geometryType);

	bool bHasReaded = false;

	switch(geometryType)
	{
	case geometryPoint:  //点
		{
			PointShapeBuffer *pGeoPoint = (PointShapeBuffer*)&gdbGeometry;
			bHasReaded = ReadPoint(pGeoPoint);
		}
		break;
	case geometryMultipoint: //多点
		{
			MultiPointShapeBuffer *pGeoMultiPoint = (MultiPointShapeBuffer*)&gdbGeometry;
			bHasReaded = ReadMultiPoint(pGeoMultiPoint);
		}
		break;
	case geometryPolyline:  //线
		{
			MultiPartShapeBuffer *pGeoLine = (MultiPartShapeBuffer*)&gdbGeometry;
			bHasReaded = ReadLine(pGeoLine);
		}
		break;
	case geometryPolygon:  //面
		{
			MultiPartShapeBuffer *pGeoPolygon = (MultiPartShapeBuffer*)&gdbGeometry;
			bHasReaded = ReadPolygon(pGeoPolygon);
		}
		break;
	case geometryMultiPatch: //多面
		{
			MultiPatchShapeBuffer *pGeoMultiPatch = (MultiPatchShapeBuffer*)&gdbGeometry;
			bHasReaded = ReadMultiPatch(pGeoMultiPatch);
		}
		break;
	default:
		break;
	}

	enumRows.Close();

	return bHasReaded;
}

到目前为止通过ArcGis API对FileGDB的解析介绍结束,貌似显得很粗糙,欢迎大家指正。


本文完整代码见:http://download.csdn.net/detail/haoswich/7507699







  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值