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