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 polygon drawn on top of a layer using the graphicsContainer of the current activeView, then I want to be able to show a custom context menu if the user right clicks INSIDE the polygon. So I have to figure out a way to determine if the mouse click falls within the polygon. I have tried to use the IRelationalOperator2 as suggested in this question Does anyone know a function to determine if a Point exists within a polygon?, but I can't seem to get it working properly. Here is what I have so far:

System.Drawing.Point screenMousePoint = System.Windows.Forms.Form.MousePosition;
IPoint screenPoint = new Point();
screenPoint.X = screenMousePoint.X;
screenPoint.Y = screenMousePoint.Y;

IPoint mapPoint = this.controller.GetMapCoordinatesFromScreenCoordinates(screenPoint, activeView);

// this.currentDefinedArea is a polygon
IRelationalOperator2 relation = this.currentDefinedArea as IRelationalOperator2;

if (relation.Contains(mapPoint))
{
    // Show context menu
}

UPDATE:

The "GetMapCoordinatesFromScreenCoordinates" method looks like this, and it's one of the snippets that is included in arcobjects:

public IPoint GetMapCoordinatesFromScreenCoordinates(IPoint screenPoint, IActiveView activeView)
    {
        if (screenPoint == null || screenPoint.IsEmpty || activeView == null)
        {
            return null;
        }

        IScreenDisplay screenDisplay = activeView.ScreenDisplay;
        IDisplayTransformation displayTransformation = screenDisplay.DisplayTransformation;

        return displayTransformation.ToMapPoint((System.Int32)screenPoint.X, (System.Int32)screenPoint.Y);
    }

UPDATE 2:

OK, found out what was causing the above code to fail. Using:

System.Drawing.Point screenMousePoint = System.Windows.Forms.Form.MousePosition;

...gives a different set of X, Y coordinates than using the MouseEventArgs provided by the OnMouseDown method. Don't know why I wasn't using them in the first place...here's how my working code looks:

protected override void OnMouseDown(ESRI.ArcGIS.Desktop.AddIns.Tool.MouseEventArgs arg)
{
    if (arg.Button == System.Windows.Forms.MouseButtons.Right)
    {
        if (this.controller.CurrentDefinedArea != null)
        {
            IPoint screenPoint = new Point();
            screenPoint.X = arg.X;
            screenPoint.Y = arg.Y;

            IPoint mapPoint = this.controller.GetMapCoordinatesFromScreenCoordinates(screenPoint, activeView);

            IRelationalOperator2 relation = this.controller.CurrentDefinedArea as IRelationalOperator2;

            if (relation.Contains(mapPoint))
            {
                this.controller.CreateContextMenu(ArcMap.Application);
            }
        }
    }
}
share|improve this question
    
Does the spatial reference of the mapPoint match that of the polygon? –  Kirk Kuykendall Sep 29 '11 at 13:00
    
Have you confirmed that the transformation to map coordinates is correct? It is very rarely done from the screen coordinates, but instead from the physical coordinates of the activeview window. These are not the same unless the active view fits the whole screen. –  Petr Krebs Sep 29 '11 at 13:04
    
@Kirk: The polygon has a SRID of 25832 and so has the mapPoint. That means they have the same spatial reference right?...sorry still very new to this... –  Claus_L Sep 30 '11 at 6:32
    
@Petr: I'm not really sure how to confirm the transformation to map coordinates... –  Claus_L Sep 30 '11 at 6:36
    
You can display a message box with the transformed coordinates and compare them to those displayed in ArcMap's status bar. –  Petr Krebs Sep 30 '11 at 8:06
show 3 more comments

1 Answer

As Peter Krebs has suggested on mouse down use IDisplayTransformation.ToMapPoint to assign the XY info to a point graphic. You can then use that graphic as a selector against your polygon layer.

public override void OnMouseDown(int Button, int Shift, System.Int32 X, System.Int32 Y)
{
    //MyBase.OnMouseDown(Button, Shift, X, Y)
    try {
        IMxApplication pMxApp = null;
        IActiveView ActiveView = default(IActiveView);

        pMxApp = (IMxApplication)m_App;

        m_MxDoc = (IMxDocument)m_App.Document;
        m_mxDocument = (MxDocument)m_App.Document;
        ActiveView = (IActiveView)(Map)m_MxDoc.FocusMap;

        IMap pMap = default(IMap);
        ISpatialReference pSpatialRef = default(ISpatialReference);

        pMap = m_MxDoc.FocusMap;
        pSpatialRef = pMap.SpatialReference;

        IScreenDisplay m_pDisplay = ActiveView.ScreenDisplay;

        m_pDisplay.StartDrawing(m_pDisplay.hDC, Convert.ToInt16(esriScreenCache.esriNoScreenCache));
        ISimpleMarkerSymbol simpleMarkerSymbol = new SimpleMarkerSymbolClass();

        ISymbol symbol = simpleMarkerSymbol as ISymbol;
        // Dynamic Cast
        m_pDisplay.SetSymbol(symbol);
        IDisplayTransformation displayTransformation = m_pDisplay.DisplayTransformation;

        // X and Y are in device coordinates
        m_Point = displayTransformation.ToMapPoint(X, Y);

        m_pDisplay.DrawPoint(m_Point);
        m_pDisplay.FinishDrawing();

        SelectFeature();

    } catch (Exception ex) {
        MessageBox.Show("Caught an unspecified error in the calling code: " + Constants.vbCrLf + ex.ToString());
    }

}



public void SelectFeature()
{
    //SelectFeature
    try {
        ILayer pLayer = default(ILayer);
        IActiveView pActiveView = default(IActiveView);
        IEnvelope pEnvelope = default(IEnvelope);
        ISpatialFilter pSF = default(ISpatialFilter);
        IEnumLayer pEnumLayer = default(IEnumLayer);

        m_MxDoc = (IMxDocument)m_App.Document;
        m_mxDocument = (MxDocument)m_App.Document;
        m_map = (Map)m_MxDoc.FocusMap;

        pActiveView = (IActiveView)m_map;
        if (m_map.LayerCount == 0)
            return;

        pEnumLayer = m_map.Layers;

        pLayer = pEnumLayer.Next;
        while (!(pLayer == null)) {
            if (pLayer.Name == "My Polygon Layer") {
                m_FLayer = (IFeatureLayer)pLayer;
            } else {
                return;
            }
            pLayer = pEnumLayer.Next;
        }

        m_FSel = (IFeatureSelection)m_FLayer;
        //Expand the points envelope to give better search results
        pEnvelope = m_MxDoc.CurrentLocation.Envelope;
        pEnvelope.Expand(m_MxDoc.SearchTolerance, m_MxDoc.SearchTolerance, false);
        pSF = new SpatialFilter();
        pSF.Geometry = pEnvelope;
        pSF.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
        pSF.GeometryField = m_FLayer.FeatureClass.ShapeFieldName;

        //Refresh the old selection to erase it
        //pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, Nothing, Nothing)
        //Perform the selection using a point created on mouse down
        m_FSel.SelectFeatures(pSF, esriSelectionResultEnum.esriSelectionResultNew, false);

        ISelectionSet pSelSet2 = default(ISelectionSet);
        // Draw all selected features.
        pSelSet2 = m_FSel.SelectionSet;

        if (pSelSet2.Count == 0) {
            MessageBox.Show("Polygon not selected");
        } else {
            MessageBox.Show("Polygon selected");
        }

        //Refresh again to draw the new selection
        pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
    } catch (Exception ex) {
        MessageBox.Show("Caught an unspecified error in the calling code: " + Constants.vbCrLf + ex.ToString());
    }

}
share|improve this answer
    
Thanks artwork21! I had a little time this morning and found out what was wrong in my original code and I got it to work. –  Claus_L Oct 3 '11 at 6:59
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.