Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I have a simple spatial feature selection function that includes:

 public static void SelectByLocation(IFeatureClass sourceFC, ILayer selectLayer)
        {
            Geoprocessor GP = new Geoprocessor();
            SelectLayerByLocation selectLoc = new SelectLayerByLocation();
            selectLoc.in_layer = selectLayer;
            selectLoc.select_features = sourceFC;
            RunTool(GP, selectLoc, null);
            ArcMap.Document.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
        }

It works correctly passing an IFeatureClass and an ILayer, however I would like to pass a selected subset of records from the IFeatureClass (for example: only the record with the most recent date or count). I've tried changing it to accept an ILayer as the first parameter and applying a selection to that with no result. I've also tried passing an IFeature object of the intended feature dynamically cast as an IFeatureClass. This latter method returns every row in the select features layer. For reference, I'm calling it now like this:

 List<string> affectedFeatures = featureSelector(polyFC, layerList["SelectionLayer"], SelectList);

Where featureSelector() calls the spatial select with "polyFC" as IFeatureClass, layerList["selectionLayer"] as a reference to the ILayer selection layer, and SelectList as a list referencing fields to return from the selection layer. So, I suppose what I'm asking is: is it possible to pass an IFeature to the first method and get a proper spatial selection returned? For what it's worth this is always polygons selecting polygons.

share|improve this question
    
I suppose a possible workaround is to create a new temporary Polygon feature class in memory every time I want to use a new feature for selection, but that seems awkward and slow. –  AHigh Jun 26 '12 at 16:07
add comment

2 Answers 2

up vote 3 down vote accepted

To select subsets, I suggest you just avoid using GP, and create IQueryFilter selection procedure, see link below.

Select Map Features by Attribute Query Snippet

Here is an old VBA example of a two layer feature selection:

Private Sub IntersectSelect()

    ' Part 1: Create a cursor of interstates.
    Dim pMxDoc As IMxDocument
    Dim pMap As IMap
    Dim pRoadLayer As IFeatureLayer
    Dim pFeatSelection As IFeatureSelection
    Dim pQueryFilter As IQueryFilter
    Dim pRoadSelSet As ISelectionSet
    Dim pRoadCursor As IFeatureCursor
    Set pMxDoc = ThisDocument
    Set pMap = pMxDoc.FocusMap
    Set pRoadLayer = pMap.Layer(0)
    Set pFeatSelection = pRoadLayer
    ' Select interstates.
    Set pQueryFilter = New QueryFilter
    pQueryFilter.WhereClause = "Route_Desc = 'Interstate'"
    pFeatSelection.SelectFeatures pQueryFilter, esriSelectionResultNew, False
    ' Create a feature cursor of selected interstates.
    Set pRoadSelSet = pFeatSelection.SelectionSet
    pRoadSelSet.Search Nothing, False, pRoadCursor

    ' Part 2: Select high-growth counties that intersect an interstate.
    Dim pCountyLayer As IFeatureLayer
    Dim pElement As IElement
    Dim pCountySelection As IFeatureSelection
    Dim pRoad As IFeature
    Dim pSpatialFilter As ISpatialFilter
    Set pCountyLayer = pMxDoc.FocusMap.Layer(1)
    Set pCountySelection = pCountyLayer
    ' Prepare a spatial filter.
    Set pSpatialFilter = New SpatialFilter
    pSpatialFilter.WhereClause = "change > 15"
    pSpatialFilter.SpatialRel = esriSpatialRelIntersects
    ' Step through each interstate and select counties.
    Set pRoad = pRoadCursor.NextFeature
    Do Until pRoad Is Nothing
        ' Define the geometry of the spatial filter.
        Set pSpatialFilter.Geometry = pRoad.Shape
        ' Select counties and add them to the selection set.
        pCountySelection.SelectFeatures pSpatialFilter, esriSelectionResultAdd, False
        Set pRoad = pRoadCursor.NextFeature
    Loop

    ' Part 3: Draw all selected features and report number of counties selected.
    Dim pActiveView As IActiveView
    Dim pCountySelSet As ISelectionSet
    Set pActiveView = pMxDoc.FocusMap
    ' Draw all selected features.
    pActiveView.PartialRefresh esriViewGeoSelection, Nothing, Nothing
    Set pCountySelSet = pCountySelection.SelectionSet
    MsgBox "There are " & pCountySelSet.Count & " Counties selected"

End Sub
share|improve this answer
    
Thanks. This worked well, though I've had to account for the "newest" feature in the source layer in a different way as subqueries don't appear to work in query filter where clauses for in memory feature classes. i.e. "OBJECTID" = (SELECT MAX("OBJECTID") FROM sourceLayer) –  AHigh Jun 26 '12 at 20:46
add comment

Take a look at help topic http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#/Using_geoprocessing_to_develop_applications/0001000001wt000000/ and look at the section Geoprocessing Misstatements.

Misstatement—Geoprocessing tools only take datasets on disk as input and only write datasets to disks. Another way this has been stated is that geoprocessing is "pathname to pathname" only. Only pathnames to datasets can be used as input and output parameters.

In fact, you can use equivalent ArcObjects anywhere features classes are expected. For example, you can do the following: Pass an object with IFeatureClass or IDataset as input to a tool instead of a pathname string. Create in-memory feature classes, manipulate them, and use them in geoprocessing tools. Use the special in-memory FeatureSet and RecordSet objects instead of feature classes and tables. These two objects behave like their on-disk counterparts.

Misstatement—Geoprocessing is not for processing individual features.

This is a corollary to the preceding misstatement. For example, suppose you have a single point geometry and you need to select nearby polygon features. You can insert this single point geometry into an empty IFeatureClass and use it as input to the Select Layer By Location tool, with a layer of the polygon features created by the Make Feature Layer tool. The output will be a new selection set on the layer that you can persist as a feature class (in-memory or on disk) using the Copy Features tool.

Edit

Here's one way I did this. I created an array of my selected features and created an in memory feature class with that array and used that feature class in the geoprocessor

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

 Dim SubsetArray() As ESRI.ArcGIS.Geodatabase.IFeature
 ReDim SubsetArray(pInFClass.FeatureCount(pQFilter) - 1)

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

 pSelectedFClass = CreateInMemoryFeatures(SubsetArray, "SelectedFeatures", pInFClass)
'pInFClass is the original dataset that is a template for the in-memory feature class
'pSelectedFClass can be used in the geoprocessor

 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

            CreateFC.out_path = "in_memory"
            CreateFC.out_name = Name
            CreateFC.geometry_type = ShapeType
            CreateFC.template = Path
            CreateFC.spatial_reference = GetSpatialReferenceFromDataset(pTemplateFClass) 'this is an ArcGIS snippet

            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

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
    Dim GP As New ESRI.ArcGIS.Geoprocessor.Geoprocessor

    Try
        Result = CType(GP.Execute(Process, Nothing), ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult2)
        GP.ClearMessages()
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.ToString, "Run Geoprocessor")
    End Try

    Return Result

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
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.