Sunday 15 September 2019

arcobjects - Selecting an Area/ Boundary on MouseDown Event and find all the feature class within that boundary scope Using C#


I was thinking to select an area or a boundary in ArcMap on MouseDown Event and select all the features inside it.


How do I select the boundary with the code in C#?


Here is what I did:


public override void OnMouseDown(int Button, int Shift, int X, int Y)
{
screenPoint = new ESRI.ArcGIS.Geometry.Point();
screenPoint.X = X;
screenPoint.Y = Y;


IScreenDisplay screenDisplay = (m_application.Document as IMxDocument).ActiveView.ScreenDisplay;

mapPoint = screenDisplay.DisplayTransformation.ToMapPoint(X, Y);

IMxDocument pMxDoc = (IMxDocument)m_application.Document;
IMap pMap = (IMap)pMxDoc.FocusMap;
mapPoint.SpatialReference = pMap.SpatialReference;

ITopologicalOperator pTopOp = mapPoint as ITopologicalOperator;


ISpatialFilter pSpatFlt = new SpatialFilterClass();
//pSpatFlt.SpatialRel =esriSpatialRelEnum.esriSpatialRelIntersects;
pSpatFlt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;

ESRI.ArcGIS.esriSystem.UID pFeatLayerUID = new
ESRI.ArcGIS.esriSystem.UIDClass();
pFeatLayerUID.Value = "{40A9E885-5533-11d0-98BE-00805F7CED21}"; /* refer http:// help.arcgis.com/EN/sdk/10.0/ArcObjects_NET/componenthelp/index.html#/Layers_Property/001200000m9t000000/ */
IEnumLayer pEnumLayer = pMap.get_Layers(pFeatLayerUID, true);
ILayer pThisLayer;

//IFeatureLayer pThisFeatLayer = pThisLayer as IFeatureLayer;
IActiveView activeView = (m_application.Document as IMxDocument).ActiveView;
IFeatureLayer pThisFeatLayer;
while ((pThisLayer = pEnumLayer.Next()) != null)
{
pThisFeatLayer = pThisLayer as IFeatureLayer;
IFeatureCursor pFtCur = pThisFeatLayer.Search(pSpatFlt, true);
IFeature pFt = pFtCur.NextFeature();
FlashFeature(activeView, pFt);
if (pFt != null)

{
IFeatureClass fC = (IFeatureClass)pFt.Class;
MessageBox.Show(fC.AliasName.ToString());
break;
}
}

Answer



You're very close, you have all the objects you need but if I can make some recommendations. The topological operator, screen point and feature class aren't used so I got rid of them.


Selection is done in two rounds:




  1. Search the polygon layers in the map for a polygon feature that intersects the clicked point.

  2. Using the found polygon search all other layers.


I suspect your main problem is that the ISpatialFilter is never assigned a geometry to select with. I find it best to project the selecting geometry to the same spatial reference as the feature class before setting the ISpatialFilter.Geometry property.


public override void OnMouseDown(int Button, int Shift, int X, int Y)
{
IApplication m_application = ArcMap.Application;
IScreenDisplay screenDisplay = (m_application.Document as IMxDocument).ActiveView.ScreenDisplay;
IMxDocument pMxDoc = (IMxDocument)m_application.Document;
IMap pMap = (IMap)pMxDoc.FocusMap;


ISpatialFilter pSpatFlt = new SpatialFilterClass();
pSpatFlt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;

ESRI.ArcGIS.esriSystem.UID pFeatLayerUID = new ESRI.ArcGIS.esriSystem.UIDClass();
pFeatLayerUID.Value = "{40A9E885-5533-11d0-98BE-00805F7CED21}"; /* refer http:// help.arcgis.com/EN/sdk/10.0/ArcObjects_NET/componenthelp/index.html#/Layers_Property/001200000m9t000000/ */
IEnumLayer pEnumLayer = pMap.get_Layers(pFeatLayerUID, true);
ILayer pThisLayer;
IActiveView activeView = (m_application.Document as IMxDocument).ActiveView;
IFeatureLayer pThisFeatLayer;

IFeatureLayer pSelectFromFeatLayer = null;
IFeature pSelectingFeature = null;

// first loop through the layers, but only the polygon feature layers
// to find a polygon where the user clicks.
while ((pThisLayer = pEnumLayer.Next()) != null)
{
if (pThisLayer.Valid) // returns true if the layers' data source is not broken
{
pThisFeatLayer = pThisLayer as IFeatureLayer;

if (pThisFeatLayer.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolygon)
{
// only selecting polygons on this round
IPoint mapPoint = screenDisplay.DisplayTransformation.ToMapPoint(X, Y);
mapPoint.SpatialReference = pMap.SpatialReference;
mapPoint.Project((pThisFeatLayer.FeatureClass as IGeoDataset).SpatialReference);
pSpatFlt.Geometry = mapPoint; // Assign the selecting geometry to the spatial filter

IFeatureCursor pFtCur = pThisFeatLayer.Search(pSpatFlt, true);
IFeature pFt = pFtCur.NextFeature();


if (pFt != null)
{
pSelectFromFeatLayer = pThisFeatLayer;
pSelectingFeature = pFt;
break; // break on the first polygon feature layer that creates a selection from the point
}
}
}
}


if (pSelectFromFeatLayer != null) // go to the second round of selection only if a selecting polygon found
{
pEnumLayer = pMap.get_Layers(pFeatLayerUID, true); // restart the enum for the layers
pMap.ClearSelection(); // clear the current selection

while ((pThisLayer = pEnumLayer.Next()) != null)
{
if (pThisLayer.Valid)// returns true if the layers' data source is not broken
{

pThisFeatLayer = pThisLayer as IFeatureLayer;
if (pThisFeatLayer.Name != pSelectFromFeatLayer.Name)
{
// don't select the same layer
IGeometry pSelGeom = pSelectingFeature.ShapeCopy; // always get with shapecopy
pSelGeom.Project((pThisFeatLayer.FeatureClass as IGeoDataset).SpatialReference);
pSpatFlt.Geometry = pSelGeom; // assign the polygon geometry to the spatial filter.

if (pThisFeatLayer.FeatureClass.FeatureCount(pSpatFlt) > 0)// there will be something selected on this feature class
{

// select the features from this layer on the map
(pThisFeatLayer as IFeatureSelection).SelectFeatures(pSpatFlt, esriSelectionResultEnum.esriSelectionResultAdd, false);
}
}
}
}
FlashFeature(activeView, pSelectingFeature); // I'm assuming that this will refresh the display first with IActiveView.Refresh();
}
}


One thing to beware of, selecting from the feature class ignores any definition queries set on the feature layer, you can set the ISpatialFilter.WhereClause to the (pThisFeatLayer as IFeatureLayerDefinition).DefinitionExpression and ISpatialFilter.SearchOrder to esriSearchOrder.esriSearchOrderAttribute to use the where clause of the layer before trying to select by geometry; attribute queries are usually much faster than geometry queries so it makes sense to do that first.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...