Collapse small polygons into surrounding larger ones?

3931
4
02-08-2011 06:59 AM
PamTurner
New Contributor III
Hi All,

I have what I thought would be a simple editing task, but has turned out to be cumbersome to put it mildly.

I have a set of land cover polygons from image data classified at a resolution of 1 foot.  Because the resolution of the reference data are so precise, I'm getting small 1 sqft polygons in the middle of the larger ones.  For example, a 1 sqft impervious surface poly surrounded by 50 sqft of managed turf.  I would like to be able to dissolve these tiny polygons into the bigger ones.

I've tried topologies, but that doesn't work correctly because I don't want to lose the resolution of the data that are already there, which happens with high cluster tolearances.  I can delete the polygons of less than a certain area, but then I'm left with tiny gaps that I have to hand edit out, which could potentially be in the hundreds of thousands.

Is there any way to programmatically collapse polygons under a certain size, without losing the integrity of the rest of the data?  I'm just trying to clean it up a little bit.

Thanks.

Pam
Tags (2)
0 Kudos
4 Replies
KenBuja
MVP Esteemed Contributor
Hi Pam,

This is code I use in an application (in VB.NET, ArcGIS 9.2) where the user can select whether to merge polygons smaller than a specified area with the largest adjacent polygon or the polygon with the longer adjacent border.

  Friend Sub EliminateSlivers(ByVal m_app As ESRI.ArcGIS.Framework.IApplication, ByVal pFLayer As ESRI.ArcGIS.Carto.IFeatureLayer, ByVal MMU As Double, ByVal EliminateType As String)

    Dim IsEditing As Boolean = True
    Dim pDataset As ESRI.ArcGIS.Geodatabase.IDataset
    Dim pEditor As ESRI.ArcGIS.Editor.IEditor
    Dim pEditLayers As ESRI.ArcGIS.Editor.IEditLayers
    Dim pFCursor As ESRI.ArcGIS.Geodatabase.IFeatureCursor
    Dim pFeature As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pArea As ESRI.ArcGIS.Geometry.IArea
    Dim pAdjFeature As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pTopoOp As ESRI.ArcGIS.Geometry.ITopologicalOperator

    Try
      pDataset = pFLayer
      pEditor = m_app.FindExtensionByName("ESRI Object Editor")
      If pEditor.EditState <> ESRI.ArcGIS.Editor.esriEditState.esriStateEditing Then
        IsEditing = False
        pEditor.StartEditing(pDataset.Workspace)
      End If
      pEditLayers = pEditor
      pEditLayers.SetCurrentLayer(pFLayer, 0)
      pEditor.StartOperation()
      pFCursor = pFLayer.FeatureClass.Search(Nothing, False)
      pFeature = pFCursor.NextFeature
      Do Until pFeature Is Nothing
        pArea = pFeature.Shape
        If pArea.Area < MMU Then
          If EliminateType = "Border" Then
            pAdjFeature = GetLongestBorderAdjacent(pFeature)
          Else
            pAdjFeature = GetLargestAdjacent(pFeature)
          End If
          If pAdjFeature IsNot Nothing Then
            pTopoOp = pAdjFeature.ShapeCopy
            pAdjFeature.Shape = pTopoOp.Union(pFeature.ShapeCopy)
            pAdjFeature.Store()
            pFeature.Delete()
          End If
        End If
        pFeature = pFCursor.NextFeature
      Loop

      pEditor.StopOperation("Merge")
      If Not IsEditing Then
        pEditor.StopEditing(True)
      End If

    Catch ex As Exception
      ExceptionMessage(ex, "Eliminate Slivers")
    Finally
      Release(pFCursor)
    End Try

  End Sub

  Private Function GetArea(ByVal pArea As ESRI.ArcGIS.Geometry.IArea) As Double
    GetArea = pArea.Area
  End Function

  Public Function GetBorderLen(ByVal pPoly1 As ESRI.ArcGIS.Geometry.IPolygon, ByVal pPoly2 As ESRI.ArcGIS.Geometry.IPolygon) As Double

    Dim pTopoOp As ESRI.ArcGIS.Geometry.ITopologicalOperator = pPoly1
    Dim pGeo As ESRI.ArcGIS.Geometry.IGeometry = pTopoOp.Intersect(pPoly2, ESRI.ArcGIS.Geometry.esriGeometryDimension.esriGeometry1Dimension)

    If Not pGeo.IsEmpty Then
      Dim pPoly3 As ESRI.ArcGIS.Geometry.IPolyline = pGeo
      Return pPoly3.Length
    Else
      Return 0.0
    End If

  End Function

  Friend Function GetLargestAdjacent(ByVal pFeat As ESRI.ArcGIS.Geodatabase.IFeature) As ESRI.ArcGIS.Geodatabase.IFeature

    Dim pSF As ESRI.ArcGIS.Geodatabase.ISpatialFilter = New ESRI.ArcGIS.Geodatabase.SpatialFilter
    Dim pFC As ESRI.ArcGIS.Geodatabase.IFeatureClass
    Dim pFCur As ESRI.ArcGIS.Geodatabase.IFeatureCursor
    Dim pFeat2 As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pLargestFeat As ESRI.ArcGIS.Geodatabase.IFeature
    Dim dMaxArea As Double

    Try
      pSF.Geometry = pFeat.Shape
      pSF.SpatialRel = ESRI.ArcGIS.Geodatabase.esriSpatialRelEnum.esriSpatialRelIntersects

      pFC = pFeat.Class
      pFCur = pFC.Search(pSF, False)
      pFeat2 = pFCur.NextFeature
      Do Until pFeat2 Is Nothing
        If pLargestFeat Is Nothing Then
          pLargestFeat = pFeat2
          dMaxArea = GetArea(pFeat2.Shape)
        Else
          If GetArea(pFeat2.Shape) > dMaxArea Then
            pLargestFeat = pFeat2
            dMaxArea = GetArea(pFeat2.Shape)
          End If
        End If

        pFeat2 = pFCur.NextFeature
      Loop

      Return pLargestFeat

    Catch ex As Exception
      ExceptionMessage(ex, "Get Largest Feature")
      Return Nothing
    End Try

  End Function

  Public Function GetLongestBorderAdjacent(ByVal pFeat As ESRI.ArcGIS.Geodatabase.IFeature) As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pSF As ESRI.ArcGIS.Geodatabase.ISpatialFilter = New ESRI.ArcGIS.Geodatabase.SpatialFilter
    Dim pFC As ESRI.ArcGIS.Geodatabase.IFeatureClass
    Dim pFCur As ESRI.ArcGIS.Geodatabase.IFeatureCursor
    Dim pFeat2 As ESRI.ArcGIS.Geodatabase.IFeature
    Dim pLongestBorderFeat As ESRI.ArcGIS.Geodatabase.IFeature
    Dim dMaxLen As Double

    Try
      pSF.Geometry = pFeat.Shape
      pSF.SpatialRel = ESRI.ArcGIS.Geodatabase.esriSpatialRelEnum.esriSpatialRelIntersects

      pFC = pFeat.Class
      pFCur = pFC.Search(pSF, False)

      pFeat2 = pFCur.NextFeature
      Do Until pFeat2 Is Nothing
        If pFeat2.OID <> pFeat.OID Then
          If pLongestBorderFeat Is Nothing Then
            pLongestBorderFeat = pFeat2
            dMaxLen = GetBorderLen(pFeat.Shape, pFeat2.Shape)
          Else
            If GetBorderLen(pFeat.Shape, pFeat2.Shape) > dMaxLen Then
              pLongestBorderFeat = pFeat2
              dMaxLen = GetBorderLen(pFeat.Shape, pFeat2.Shape)
            End If
          End If
        End If
        pFeat2 = pFCur.NextFeature
      Loop

      Return pLongestBorderFeat

    Catch ex As Exception
      ExceptionMessage(ex, "Get Longest Feature")
      Return Nothing
    Finally
      Release(pFCur)
    End Try

  End Function
0 Kudos
BrianKozar
New Contributor
I have tried to implement this code but am getting errors. I am somewhat green on using VB in ArcGIS so any assistance would be appreciated.

Thank you for any assistance
Brian
0 Kudos
PamTurner
New Contributor III
Brian - If you have the ArcInfo licensing level there's a tool called "Eliminate" in the Generalization toolbox that does this. I found it a little bit ago, unfortuately it was several months after I needed it :).

Good Luck!
0 Kudos
BrianKozar
New Contributor
Thanks Pam but I don't have ArcInfo license so unless I can find this as a tool, dll or script I can't use it. Thanks though
0 Kudos