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
Solved! Go to Solution.
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
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
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
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