Surfinsanta
Surfinsanta

Reputation: 43

How to get Geographic Coordinates of a Mouse Click using C# ArcObjects

I've got an ArcObjects C# tool (most of this code was found here on Stack Exchange) in ArcGIS that identifies map coordinates when a user clicks on a location within a map. Here's the code that I have used:

    public override void OnMouseDown(int Button, int Shift, int X, int Y)
    {
        if (Button == 1)
        {
            ESRI.ArcGIS.Display.IScreenDisplay screenDisplay = (m_application.Document as IMxDocument).ActiveView.ScreenDisplay;
            ESRI.ArcGIS.Geometry.IPoint point = screenDisplay.DisplayTransformation.ToMapPoint(X, Y);

            MessageBox.Show("X position is " + point.X.ToString() + " Y position is " + point.Y.ToString());
        }
    }

Our map uses units of feet so the tool displays the feet coordinates. How can I have this tool return degrees-minutes-seconds? The standard Identify tool from ESRI does this and is what I'm looking to get similar results to.

Upvotes: 1

Views: 3089

Answers (2)

TechGuy
TechGuy

Reputation: 11

You have to first transform the screenpoints into the maps current coordinate system, then you need to project the point into WGS84, then just convert to Degrees Minutes Seconds. I've created a Class below. You're welcome dude.

Implementation

Public Overrides Sub OnMouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Integer, ByVal Y As Integer)
    Dim getMethod As New DecimalDegreesToDegreesMinutesSeconds
    getMethod.PointFromScreenPoint(X, Y)
End Sub

    Public Class DecimalDegreesToDegreesMinutesSeconds
' Used by both
Private pSpRFc As ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment

' WGS1984
Private pSpRef1 As ESRI.ArcGIS.Geometry.ISpatialReference
Private pGCS As ESRI.ArcGIS.Geometry.IGeographicCoordinateSystem

'' NAD83 FEET STATEPLANES NC 
'Private pSpRef2 As ESRI.ArcGIS.Geometry.ISpatialReference
'Private pPCS As ESRI.ArcGIS.Geometry.IProjectedCoordinateSystem

Private ReadOnly Property WGS84() As ESRI.ArcGIS.Geometry.ISpatialReference
    Get
        ' WGS1984
        pSpRFc = New ESRI.ArcGIS.Geometry.SpatialReferenceEnvironment
        pGCS = pSpRFc.CreateGeographicCoordinateSystem(4326)
        pSpRef1 = pGCS
        pSpRef1.SetFalseOriginAndUnits(-180, -90, 1000000)
        Return pSpRef1
    End Get
End Property

' pass the original screen point into this function
Public Sub PointFromScreenPoint(pX As Double, pY As Double)
    Dim scrDisp As ESRI.ArcGIS.Display.IScreenDisplay = Nothing
    Dim pnt As ESRI.ArcGIS.Geometry.IPoint = Nothing
    Dim pGeoSpRef As ESRI.ArcGIS.Geometry.IGeometry = Nothing

    Try
        '
        scrDisp = New ESRI.ArcGIS.Display.ScreenDisplay
        scrDisp = SGProperties.pActiveView.ScreenDisplay ' the activeview
        scrDisp.StartDrawing(scrDisp.hDC, CShort(ESRI.ArcGIS.Display.esriScreenCache.esriNoScreenCache))
        '
        pnt = scrDisp.DisplayTransformation.ToMapPoint(pX, pY)
        '
        pGeoSpRef = pnt
        pGeoSpRef.SpatialReference = SGProperties.pMap.SpatialReference ' the current maps
        pGeoSpRef.Project(WGS84())

        Windows.Forms.MessageBox.Show("X position is " + ConvertDegrees(pnt.X, DegreesType.Longitude).ToString() + " Y position is " + ConvertDegrees(pnt.Y, DegreesType.Latitude).ToString())
    Catch ex As Exception

    Finally
        If scrDisp IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(scrDisp)
        scrDisp = Nothing
        If pnt IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(pnt)
        pnt = Nothing
        If pGeoSpRef IsNot Nothing Then System.Runtime.InteropServices.Marshal.ReleaseComObject(pGeoSpRef)
        pGeoSpRef = Nothing
    End Try
End Sub

Enum DegreesType
    Latitude
    Longitude
End Enum

Private Function ConvertDegrees(pInDegrees As Double, pInType As DegreesType)
    Dim degrees As Integer
    Dim submin As Double
    Dim minutes As Double
    Dim subsecsonds As Double
    Dim direction As String
    Dim output As String

    Try

        degrees = Math.Truncate(pInDegrees)
        submin = Math.Abs((pInDegrees - Math.Truncate(pInDegrees)) * 60)
        minutes = Math.Truncate(submin)
        subsecsonds = Math.Abs((submin - Math.Truncate(submin)) * 60)
        direction = ""

        If pInType.ToString().Trim().ToUpper() = "Latitude".ToUpper() Then
            If degrees < 0 Then
                direction = "S"
            ElseIf (degrees > 0) Then
                direction = "N"
            Else
                direction = ""
            End If
        ElseIf pInType.ToString().Trim().ToUpper() = "Longitude".ToUpper() Then
            If degrees < 0 Then
                direction = "W"
            ElseIf (degrees > 0) Then
                direction = "E"
            Else
                direction = ""
            End If
        End If

        output = degrees.ToString() + ":" + minutes.ToString() + ":" + subsecsonds.ToString().Substring(0, 5) + direction

        Return output
    Catch ex As Exception
        Return Nothing
    End Try
End Function

End Class

Upvotes: 1

Katah
Katah

Reputation: 121

You can easily change the maps units of your IDisplayTransformation object, before getting the coordinates:

        ESRI.ArcGIS.Display.IDisplayTransformation displayTransformation = screenDisplay.DisplayTransformation;
        displayTransformation.Units = ESRI.ArcGIS.esriSystem.esriUnits.esriMeters; // or another unit
        ESRI.ArcGIS.Geometry.IPoint point = displayTransformation.ToMapPoint(X, Y);

You can get information about the different ESRI Units here

Upvotes: 1

Related Questions