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;
}
初始化字段,主要包括创建字段和读出投影,投影直接存储为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