How do you use Clip in .NET 10.3 ArcObjects? (c#)

7042
3
Jump to solution
03-24-2015 08:10 AM
KennethLathan
New Contributor II

Hi all,

I am grabbing a bunch of polygon features (footprints) from a mosaic dataset and I want to clip them and re-add them to the database. I'm getting the records with a Search Cursor within an edit session. So far that part is working just fine, I can update the table fields and Store them back to the db.

I'm running into trouble when I try to clip the features. I cannot seem to get the parameters right. It complains with every kind of output I've tried. Ideally I'd output back to the original input feature, but failing that I'd like to output to memory. I tried creating a memory workspace, but I don't know how to get the results of the clip into it. Has anyone ever done anything similar? The documentation on using geoprocessor in ArcObjects doesn't seem very clear.

It seems funny it's so incredibly easy to do what I want in ArcMap 10.3 and it's so hard programmatically. I can start an edit session, select my records, select my clipping feature, and hit the Clip in the Editor menu, and boom... done. But it doesn't seem like the Editor clip method is exposed in ArcObjects.

Thanks!

-Ken

0 Kudos
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor

This is how I have use the Clip geoprocessing tool in a VB.NET project

pClippedFClass = Clip(pAggregatedMPAFClass, pAnalysisExtentFClass, pResultsWS.PathName & "\AllMPAsClipped")

which uses a bunch of functions to create the in memory feature class and clip the data.

    Public Function Clip(ByVal pInFClass As ESRI.ArcGIS.Geodatabase.IFeatureClass, ByVal pClipFClass As ESRI.ArcGIS.Geodatabase.IFeatureClass, ByVal OutputName As String) As ESRI.ArcGIS.Geodatabase.IFeatureClass

        Dim Clipper As New ESRI.ArcGIS.AnalysisTools.Clip
        Dim Result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2

        Try
            Using releaser As New ESRI.ArcGIS.ADF.ComReleaser
                releaser.ManageLifetime(Clipper)
                Clipper.in_features = pInFClass
                Clipper.clip_features = pClipFClass
                Clipper.out_feature_class = OutputName

                Result = RunTool(Clipper, Nothing)
                If Result Is Nothing Then
                    System.Windows.Forms.MessageBox.Show("Could not clip dataset")
                    Return Nothing
                End If

                Return ReturnObjectfromResult(Result, "Feature Class")
            End Using

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Clip error")
            Return Nothing
        End Try

    End Function    
    
    Friend Function ReturnObjectfromResult(ByVal result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2, ByVal Type As String) As Object

        Dim GPVal As ESRI.ArcGIS.Geodatabase.IGPValue
        Dim InMemFC As String
        Dim GPUtil As ESRI.ArcGIS.Geoprocessing.IGPUtilities3 = New ESRI.ArcGIS.Geoprocessing.GPUtilities

        Try
            GPVal = result.GetOutput(0)
            InMemFC = GPVal.GetAsText()

            Select Case Type
                Case "Feature Class"
                    Return GPUtil.OpenFeatureClassFromString(InMemFC)
                Case "Table"
                    Return GPUtil.OpenTableFromString(InMemFC)
            End Select

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Return FeatureClass error")
            Return Nothing
        End Try

    End Function

    Private Sub ReturnMessages(ByVal pResult As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2, ByVal Title As String)

        Dim ErrorMessage As String

        If pResult.MessageCount > 0 Then
            For Count As Integer = 0 To pResult.MessageCount - 1
                ErrorMessage += pResult.GetMessage(Count)
            Next
        End If

        System.Windows.Forms.MessageBox.Show(ErrorMessage, Title)

    End Sub
    
    Friend Function RunTool(ByVal Process As ESRI.ArcGIS.Geoprocessor.IGPProcess, ByVal TC As ESRI.ArcGIS.esriSystem.ITrackCancel2) As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2

        Dim Result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2

        Try
            Result = CType(Globals.GP.Execute(Process, Nothing), ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2)
            If Result.Status <> ESRI.ArcGIS.esriSystem.esriJobStatus.esriJobSucceeded Then ReturnMessages(Result, "Geoprocessing Error")
            Globals.GP.ClearMessages()
        Catch ex As Exception
            ReturnMessages(Result, "Fail")
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Run Geoprocessor")
        End Try

        Return Result

    End Function

View solution in original post

3 Replies
KenBuja
MVP Esteemed Contributor

This is how I have use the Clip geoprocessing tool in a VB.NET project

pClippedFClass = Clip(pAggregatedMPAFClass, pAnalysisExtentFClass, pResultsWS.PathName & "\AllMPAsClipped")

which uses a bunch of functions to create the in memory feature class and clip the data.

    Public Function Clip(ByVal pInFClass As ESRI.ArcGIS.Geodatabase.IFeatureClass, ByVal pClipFClass As ESRI.ArcGIS.Geodatabase.IFeatureClass, ByVal OutputName As String) As ESRI.ArcGIS.Geodatabase.IFeatureClass

        Dim Clipper As New ESRI.ArcGIS.AnalysisTools.Clip
        Dim Result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2

        Try
            Using releaser As New ESRI.ArcGIS.ADF.ComReleaser
                releaser.ManageLifetime(Clipper)
                Clipper.in_features = pInFClass
                Clipper.clip_features = pClipFClass
                Clipper.out_feature_class = OutputName

                Result = RunTool(Clipper, Nothing)
                If Result Is Nothing Then
                    System.Windows.Forms.MessageBox.Show("Could not clip dataset")
                    Return Nothing
                End If

                Return ReturnObjectfromResult(Result, "Feature Class")
            End Using

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Clip error")
            Return Nothing
        End Try

    End Function    
    
    Friend Function ReturnObjectfromResult(ByVal result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2, ByVal Type As String) As Object

        Dim GPVal As ESRI.ArcGIS.Geodatabase.IGPValue
        Dim InMemFC As String
        Dim GPUtil As ESRI.ArcGIS.Geoprocessing.IGPUtilities3 = New ESRI.ArcGIS.Geoprocessing.GPUtilities

        Try
            GPVal = result.GetOutput(0)
            InMemFC = GPVal.GetAsText()

            Select Case Type
                Case "Feature Class"
                    Return GPUtil.OpenFeatureClassFromString(InMemFC)
                Case "Table"
                    Return GPUtil.OpenTableFromString(InMemFC)
            End Select

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Return FeatureClass error")
            Return Nothing
        End Try

    End Function

    Private Sub ReturnMessages(ByVal pResult As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2, ByVal Title As String)

        Dim ErrorMessage As String

        If pResult.MessageCount > 0 Then
            For Count As Integer = 0 To pResult.MessageCount - 1
                ErrorMessage += pResult.GetMessage(Count)
            Next
        End If

        System.Windows.Forms.MessageBox.Show(ErrorMessage, Title)

    End Sub
    
    Friend Function RunTool(ByVal Process As ESRI.ArcGIS.Geoprocessor.IGPProcess, ByVal TC As ESRI.ArcGIS.esriSystem.ITrackCancel2) As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2

        Dim Result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2

        Try
            Result = CType(Globals.GP.Execute(Process, Nothing), ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2)
            If Result.Status <> ESRI.ArcGIS.esriSystem.esriJobStatus.esriJobSucceeded Then ReturnMessages(Result, "Geoprocessing Error")
            Globals.GP.ClearMessages()
        Catch ex As Exception
            ReturnMessages(Result, "Fail")
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Run Geoprocessor")
        End Try

        Return Result

    End Function
KennethLathan
New Contributor II

Thanks Ken! That definitely helps. Still having trouble with the input though. It seems like the clip geoprocessing tool only wants to take a FeatureClass as input. I am trying to grab a subset of features from an SDE database with a query. Do you happen to know of an easy way to input this into the clip tool?

Thanks,

-Ken

0 Kudos
KenBuja
MVP Esteemed Contributor

One thing I did was to create an array of features that I put into an in-memory feature class to be used in the Clip function.

pClippedFClass = Clip(CreateInMemoryFeatures(SubsetArray, "tempComparisonAOI", pFClass), pAnalysisExtentFClass, "in_memory\tempClip")

The array is built using this code

pFCursor = pFClass.Search(pQFilter, False)
pFeature = pFCursor.NextFeature
Counter = 0

ReDim SubsetArray(pFClass.FeatureCount(pQFilter) - 1)

Do Until pFeature Is Nothing
    SubsetArray(Counter) = pFeature
    Counter += 1
    pFeature = pFCursor.NextFeature
Loop

These are the utility functions I used to build the in-memory feature class

Public Function CreateInMemoryFeatures(ByVal FeatureArray() As ESRI.ArcGIS.Geodatabase.IFeature, ByVal Name As String, ByVal pFeatureClass As ESRI.ArcGIS.Geodatabase.IFeatureClass) As ESRI.ArcGIS.Geodatabase.IFeatureClass

        Dim pFClass As ESRI.ArcGIS.Geodatabase.IFeatureClass
        Dim pBuffer As ESRI.ArcGIS.Geodatabase.IFeatureBuffer
        Dim pFCursor As ESRI.ArcGIS.Geodatabase.IFeatureCursor

        Try
            pFClass = CreateInMemoryFeatureClass(Name, pFeatureClass)
            If pFClass Is Nothing Then Return Nothing
            pBuffer = pFClass.CreateFeatureBuffer
            pFCursor = pFClass.Insert(True)

            For Each pFeature As ESRI.ArcGIS.Geodatabase.IFeature In FeatureArray
                For i As Integer = 0 To pFeature.Fields.FieldCount - 1
                    If pBuffer.Fields.Field(i).Type <> ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeOID Then pBuffer.Value(i) = pFeature.Value(i)
                Next
                pFCursor.InsertFeature(pBuffer)
            Next
            pFCursor.Flush()

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Create InMemory Feature error")
        Finally
            Release(pFCursor)
        End Try

        Return pFClass

    End Function

    Private Function CreateInMemoryFeatureClass(ByVal Name As String, ByVal pTemplateFClass As ESRI.ArcGIS.Geodatabase.IFeatureClass) As ESRI.ArcGIS.Geodatabase.IFeatureClass

        Dim CreateFC As New ESRI.ArcGIS.DataManagementTools.CreateFeatureclass
        Dim ShapeType As String
        Dim dataset As ESRI.ArcGIS.Geodatabase.IDataset
        Dim Result As ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2
        Dim Path As String

        Try
            Using releaser As New ESRI.ArcGIS.ADF.ComReleaser
                releaser.ManageLifetime(CreateFC)

                Select Case pTemplateFClass.ShapeType
                    Case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint
                        ShapeType = "Point"
                    Case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline
                        ShapeType = "Line"
                    Case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon
                        ShapeType = "Polygon"
                    Case Else
                        Return Nothing
                End Select

                dataset = pTemplateFClass
                Path = dataset.Workspace.PathName & "\" & dataset.Name
                If dataset.Workspace.WorkspaceFactory.WorkspaceType = ESRI.ArcGIS.Geodatabase.esriWorkspaceType.esriFileSystemWorkspace Then
                    If TypeOf dataset.Workspace.WorkspaceFactory Is ESRI.ArcGIS.DataSourcesFile.ShapefileWorkspaceFactory Then
                        Path = Path & ".shp"
                    End If
                End If

                If InStr(Path, "InMemory") <> 0 Then Path = Nothing

                Dim pSR As ESRI.ArcGIS.Geometry.ISpatialReference3 = GetSpatialReferenceFromDataset(pTemplateFClass)

                CreateFC.out_path = "in_memory"
                CreateFC.out_name = Name
                CreateFC.geometry_type = ShapeType
                CreateFC.template = Path
                CreateFC.spatial_reference = GetSpatialReferenceFromDataset(pTemplateFClass)

                Result = RunTool(CreateFC, Nothing)
                If Result Is Nothing Then
                    System.Windows.Forms.MessageBox.Show("Could not create InMemory dataset")
                    Return Nothing
                End If

                Return ReturnObjectfromResult(Result, "Feature Class")
            End Using

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.ToString, "Create InMemory Featureclass error")
            Return Nothing
        End Try

    End Function