一、搜索方式(转自zhuangyuehuang)
图层之间在现实世界中具有一定的空间关系,有时需要根据空间关系将某一个图层的字段属性赋值给另一个图层。如宗地图层有很多宗地,每个宗地包含了很 多房屋,要将宗地的地籍号属性赋值给它所包含的房屋的隶属宗地属性。
由于是空间关系,只能通过IFeatureClass的搜索和更新来完成。一般算法也就是遍历宗地图层,对每个宗地执行一次包含房屋查询,对搜索到 的房屋进行赋值。(IWorkspace、ITable仅针对属性表的更新,不支持空间关系查询和更新。对于空间关系查询和更新只能通过 IFeatureClass接口。)
以下是对同一份数据的测试结果
没有缓冲的搜索:15分钟37秒
start:2009-4-27 18:53:09
Destination Features Count:8086
Excuting:2009-4-27 18:53:09
End:2009-4-27 19:08:46
有缓冲的搜索: 28秒
start:2009-4-27 19:09:27
Destination Features Count:8086
Caching:2009-4-27 19:09:27
Excuting:2009-4-27 19:09:34
End:2009-4-27 19:09:55
没有缓冲的搜索和更新:18分9秒
Click:空间关系属性赋值
start:2009-4-27 18:03:04
Destination Features Count:8086
Excuting:2009-4-27 18:03:04
End:2009-4-27 18:21:15
有缓冲的搜索和每次搜索即更新:19分钟28秒
start:2009-4-27 18:29:34
Destination Features Count:8086
Caching:2009-4-27 18:29:34
Excuting:2009-4-27 18:29:39
End:2009-4-27 18:49:02
有缓冲的遍历搜索赋值,再一次遍历更新: 28-30秒
start:2009-4-29 23:41:01
Destination Features Count:8086
Caching:2009-4-29 23:41:02
Excuting:2009-4-29 23:41:07
End:2009-4-29 23:41:28
相关代码:
1.启动空间缓存
''' <summary>
''' 启用空间缓存
''' </summary>
''' <param name="featClass"></param>
''' <param name="cacheEnv"></param>
''' <param name="reFillCache"></param>
''' <remarks></remarks>
Public Sub EnableSpatialCache(ByVal featClass As IFeatureClass, ByVal cacheEnv As IEnvelope, ByVal reFillCache As Boolean)
Dim pDataset As IDataset = CType(featClass, IDataset)
Dim pWorkspace As IWorkspace = pDataset.Workspace
Dim pSpatialCache As ISpatialCacheManager3 = CType(pWorkspace, ISpatialCacheManager3)
If reFillCache Then
pSpatialCache.EmptyCache()
End If
If Not pSpatialCache.CacheIsFull Then
pSpatialCache.FillCache(cacheEnv)
End If
End Sub
2.构造空间包含关系条件
Private m_spatialContainFilter As ISpatialFilter
'构建空间包含过滤子
Private Function BuildSharedContainsFilter(ByVal geoContains As IGeometry) As ISpatialFilter
If m_spatialContainFilter Is Nothing Then
m_spatialContainFilter = New SpatialFilter
m_spatialContainFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains
m_spatialContainFilter.SearchOrder = esriSearchOrder.esriSearchOrderSpatial
End If
'构造SpatialFilter
Dim pGeo As IGeometry = geoContains
Dim pTopoOperator As ITopologicalOperator = CType(geoContains, ITopologicalOperator)
Dim pBuffer As IGeometry = pTopoOperator.Buffer(0.02)
pBuffer.SpatialReference = pGeo.SpatialReference
m_spatialContainFilter.Geometry = pBuffer
Return m_spatialContainFilter
End Function
3.空间关系赋值
''' 通过空间包含关系,进行字段赋值。如:根据宗地赋值房屋的隶属宗地;根据行政区赋值界址点的坐落代码等
Public Sub CopyAttributeBySpatialContain(ByVal sourceClass As IFeatureClass, ByVal sourceFieldAliasName As String, ByVal destClass As IFeatureClass, ByVal destFieldAliasName As String)
'取得字段对应关系
Dim indexSourceField As Integer = sourceClass.Fields.FindFieldByAliasName(sourceFieldAliasName)
Dim indexDestField As Integer = destClass.Fields.FindFieldByAliasName(destFieldAliasName)
'搜索原图层的所有要素,由于原图层要素不修改值,所以用Recycling模式
Dim pSourceFeatCursor As IFeatureCursor = sourceClass.Search(Nothing, True)
Dim pSourceFeat As IFeature = pSourceFeatCursor.NextFeature
Dim pDestSearchCursor As IFeatureCursor
Dim pDestFeat As IFeature
'遍历原图层的所有要素
While Not pSourceFeat Is Nothing
If Not pSourceFeat.Shape.IsEmpty Then
m_spatialContainFilter = BuildSharedContainsFilter(pSourceFeat.Shape)
'通过空间关系赋值
pDestSearchCursor = destClass.Search(m_spatialContainFilter, False)
pDestFeat = pDestSearchCursor.NextFeature
While Not pDestFeat Is Nothing
'这里仅修改值不保存,因为每次修改即保存很耗费时间
'通过测试发现,这里修改的值,在Update Cursor里也能读到,所以使用UpdateCursor来做保存
pDestFeat.Value(indexDestField) = pSourceFeat.Value(indexSourceField)
pDestFeat = pDestSearchCursor.NextFeature
End While
System.Runtime.InteropServices.Marshal.ReleaseComObject(pDestSearchCursor)
Else
Debug.WriteLine("Empty OID:" & pSourceFeat.OID.ToString)
End If
pSourceFeat = pSourceFeatCursor.NextFeature
End While
System.Runtime.InteropServices.Marshal.ReleaseComObject(pSourceFeatCursor)
'遍历保存
Dim pDestUpdateCursor As IFeatureCursor = destClass.Update(Nothing, False)
Dim pUpdateFeature As IFeature = pDestUpdateCursor.NextFeature
While Not pUpdateFeature Is Nothing
pDestUpdateCursor.UpdateFeature(pUpdateFeature)
pUpdateFeature = pDestUpdateCursor.NextFeature
End While
pDestUpdateCursor.Flush()
实际使用中,一般是先缓存图层,例如缓存宗地图层:
Dim isFillCache As Boolean = pCadastralRelation.EnableSpatialCacheOfXZQ()
If Not isFillCache Then
pCadastralRelation.EnableSpatialCache(m_ZDLayer.FeatureClass, m_ZDLayer.AreaOfInterest, True)
End If
Public Sub EnableSpatialCache(ByVal featClass As IFeatureClass, ByVal cacheEnv As IEnvelope, ByVal reFillCache As Boolean)
Dim pDataset As IDataset = CType(featClass, IDataset)
Dim pWorkspace As IWorkspace = pDataset.Workspace
Dim pSpatialCache As ISpatialCacheManager3 = CType(pWorkspace, ISpatialCacheManager3)
If reFillCache Then
pSpatialCache.EmptyCache()
End If
If Not pSpatialCache.CacheIsFull Then
pSpatialCache.FillCache(cacheEnv)
End If
End Sub
然后构建搜索游标,进行遍历搜索赋值,但不马上保存:
...
Dim pDltbCLASS As IFeatureClass = Me.DLTBLayer.FeatureClass
...
Dim pSpatialFilter As ISpatialFilter = Me.GetContainsFilter(zdFeature)
pSpatialFilter.GeometryField = pDltbCLASS.ShapeFieldName
Dim pDltbCursor As IFeatureCursor = pDltbCLASS.Search(pSpatialFilter, False)
Dim pDltbFeature As IFeature = pDltbCursor.NextFeature
While Not pDltbFeature Is Nothing
....
进行赋值,不保存
...
pDltbFeature = pDltbCursor.NextFeature
End While
最后构建更新游标,进行遍历更新,并调用: Flush批量保存
Dim pUpdateDltbCursor As IFeatureCursor = pDltbCLASS.Update(pSpatialFilter, False)
Dim pUpdateDltbFeature As IFeature = pUpdateDltbCursor.NextFeature
While Not pUpdateDltbFeature Is Nothing
pUpdateDltbCursor.UpdateFeature(pUpdateDltbFeature)
pUpdateDltbFeature = pUpdateDltbCursor.NextFeature
End While
注意:如果是对选择集进行批量更新时,可以构建选择集的IGeometry
Dim pEnumGeom As IEnumGeometry = New EnumFeatureGeometry
Dim pEnumGeomBind As IEnumGeometryBind = pEnumGeom
Dim pGeomFactory As IGeometryFactory = New GeometryEnvironment
pEnumGeomBind.BindGeometrySource(Nothing, pFeatureSelection.SelectionSet)'pFeatureSelection.SelectionSet是选择集
If pEnumGeom Is Nothing Then Exit Sub
Dim pGeo As IGeometry = pGeomFactory.CreateGeometryFromEnumerator(pEnumGeom)
然后调用重载方法:
GetContainsFilter(ByVal geoContains As IGeometry) As ISpatialFilter
GetContainsFilter(ByVal featContains As IFeature) As ISpatialFilter
Dim pSpatialFilter As ISpatialFilter = Me.GetContainsFilter(pGeo)
构建过滤因子...
最后别忘了
'释放资源
System.Runtime.InteropServices.Marshal.ReleaseComObject(pSpatialFilter)
System.Runtime.InteropServices.Marshal.ReleaseComObject(pDltbCursor)
'System.Runtime.InteropServices.Marshal.ReleaseComObject(pUpdateDltbCursor)