[GIS] Coordinate conversion – Lat Long to State Plane, ArcServer-Silverlight

ccoordinate systemcoordinatesweb-mercator

I am trying to project a Lat/Long value I get from a table to a x/y value that I can use to plot a graphic.

I have seen one way to do this may be to use something like this:

feature.Geometry = mercator.FromGeographic(new MapPoint(lat, lon));
feature.Symbol = LayoutRoot.Resources["TRUCK"] as ESRI.ArcGIS.Client.Symbols.Symbol;
graphicsLayer.Graphics.Add(feature);

However my graphics aren't showing up overlapping my tiled basemap service. I tried the mercator.FromGeographic and Mercator.ToGeographic with unsuccessful results.

My Lat/Long value: 37.1223133333333,-93.27893
Mercator.FromGeographic converted value: X=-10382795.4374339, Y=4469266.40579955, WKID=102100
Mercator.ToGeographic converted value: X=-0.000837860806483038, Y=0.000334317600035687, WKID=4326

Neither of these coordinates put my graphics in the correct location. It should be closer to something like this: X=1424565.77, Y=501970.98. I am trying to learn more about coordinate systems, conversions between systems, etc. Any thoughts on what I can try next?

I am still in the beginner phase of learning programming so thanks for your help. Would you have this as a standalone class in your project?

Here is the code I have so far:

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Symbols;
using System.Runtime.Serialization;
using ESRI.ArcGIS.Client.Tasks;
using System.Windows.Threading;
using ESRI.ArcGIS.Client.Bing;

namespace TruckGPS_Test
{
    public partial class MainPage : UserControl
    {
        //private static ESRI.ArcGIS.Client.Projection.WebMercator mercator = new ESRI.ArcGIS.Client.Projection.WebMercator();

        public MainPage()
        {
            InitializeComponent();
            //AddMarkerGraphics();

            QueryTask queryTaskTruckGPS = new QueryTask("http://gisaprd/ArcGIS/rest/services/TruckGPS/MapServer/8");
            queryTaskTruckGPS.ExecuteCompleted += QueryTask_ExecuteCompletedTruckGPS;
            ESRI.ArcGIS.Client.Tasks.Query queryTruckGPS = new ESRI.ArcGIS.Client.Tasks.Query();
            queryTruckGPS.OutFields.Add("*");
            queryTruckGPS.ReturnGeometry = false;
            queryTruckGPS.Where = "1=1";
            queryTaskTruckGPS.ExecuteAsync(queryTruckGPS, "initial");

            //This timer updates the outage feature count after a 30 second wait
            System.Windows.Threading.DispatcherTimer myDispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 10, 0);
            myDispatcherTimer.Tick += new EventHandler(Each_Tick);
            myDispatcherTimer.Start();
        }

        public void Each_Tick(object o, EventArgs sender)
        {
            QueryTask queryTaskTruckGPS = new QueryTask("http://gisaprd/ArcGIS/rest/services/TruckGPS/MapServer/8");
            queryTaskTruckGPS.ExecuteCompleted += QueryTask_ExecuteCompletedTruckGPS;
            ESRI.ArcGIS.Client.Tasks.Query queryTruckGPS = new ESRI.ArcGIS.Client.Tasks.Query();
            queryTruckGPS.OutFields.Add("*");
            queryTruckGPS.ReturnGeometry = false;
            queryTruckGPS.Where = "1=1";
            queryTaskTruckGPS.ExecuteAsync(queryTruckGPS, "initial");
        }

        private void QueryTask_ExecuteCompletedTruckGPS(object sender, ESRI.ArcGIS.Client.Tasks.QueryEventArgs args)
        {
            //If Counter isn't working check the web service, make sure the table is added to the map service

            FeatureSet featureSet = args.FeatureSet;
            GraphicsLayer graphicsLayer = MyMap.Layers["TruckGPS"] as GraphicsLayer;
            graphicsLayer.ClearGraphics();
            if (featureSet != null && featureSet.Features.Count > 0)
            {
                ////Check the system time and subtract the time amount wanted from the last gps systime read for movement or idle truck
                //System.DateTime dTime = DateTime.Now;
                //// tSpan is 0 days, 0 hours, 0 minutes, and 0 seconds.
                //System.TimeSpan tSpan = new System.TimeSpan(0, 1, 0, 0);
                //System.DateTime result = dTime - tSpan;
                foreach (ESRI.ArcGIS.Client.Graphic feature in featureSet.Features)
                {
                    if ((feature.Attributes["LONGITUDE"] != null) && (feature.Attributes["LATITUDE"] != null))
                    //&& (feature.Attributes["S"])
                    {
                        var Machine_Name = feature.Attributes["MACHINE_NAME"].ToString();
                        var User_Name = feature.Attributes["USER_NAME"].ToString();
                        double lat = Convert.ToDouble(feature.Attributes["LONGITUDE"]);
                        double lon = Convert.ToDouble(feature.Attributes["LATITUDE"]);

                        feature.Geometry = new MapPoint(lat, lon);
                        //if (User_Name == "CU656")
                        //{
                        //feature.Geometry = mercator.ToGeographic(new MapPoint(lat, lon));
                        feature.Symbol = LayoutRoot.Resources["TRUCK"] as ESRI.ArcGIS.Client.Symbols.Symbol;
                        graphicsLayer.Graphics.Add(feature);
                        //}
                        //else
                        //{
                        //    feature.Symbol = LayoutRoot.Resources["RedMarkerSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol;
                        //    graphicsLayer.Graphics.Add(feature);
                        //}
                    }
                }
                { (MyMap.Layers["TruckGPS"] as GraphicsLayer).Refresh(); };
            }
            else
            {
                graphicsLayer.ClearGraphics();
                //MessageBox.Show("No features returned from query");
            }
        }
        private void MyMap_MouseMove(object sender, System.Windows.Input.MouseEventArgs args)
        {
            if (MyMap.Extent != null)
            {
                System.Windows.Point screenPoint = args.GetPosition(MyMap);
                ScreenCoordsTextBlock.Text = string.Format("Screen Coords: X = {0}, Y = {1}",
                    screenPoint.X, screenPoint.Y);

                ESRI.ArcGIS.Client.Geometry.MapPoint mapPoint = MyMap.ScreenToMap(screenPoint);
                if (MyMap.WrapAroundIsActive)
                    mapPoint = ESRI.ArcGIS.Client.Geometry.Geometry.NormalizeCentralMeridian(mapPoint) as ESRI.ArcGIS.Client.Geometry.MapPoint;
                MapCoordsTextBlock.Text = string.Format("Map Coords: X = {0}, Y = {1}",
                    Math.Round(mapPoint.X, 4), Math.Round(mapPoint.Y, 4));
            }
        } 
    }
}

At what point would I use the geometry service or call the class you stubbed out?

Best Answer

You can use the ArcGIS Server REST API out-of-the-box Geometry Service, which has a Project operation, to project a coordinate pair, and then create a graphic from it. The Geometry Service is included in the ESRI Silverlight API as the GeometryService class.

If you haven't your own ArcGIS Server, perhaps you can try the ESRI-published sample servers.

Example class hacked out of one of mine:

using System;
using System.Net;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
using ESRI.ArcGIS.Client.Tasks;
using System.Collections.Generic;

namespace YabaDabaDoo
{
  /// <summary>
  /// A Service for projecting a point to another coordinate system
  /// and return its coordinates. This service can only operate on
  /// points.
  /// </summary>
  public class ProjectionService
  {
    #region Private/Protected Fields
    private GeometryService _gService = null;
    private SpatialReference _tosr = null;
    #endregion

    public ProjectionService(string gserveUrl, int toSrid)
    {     
      //gserveUrl should be like: http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer
      //if you don't know your SRID, check the lists at: http://resources.arcgis.com/en/help/rest/apiref/usingspatialreferences.html
      _gService = new GeometryService(gserveUrl);
      _tosr = new SpatialReference(toSrid);
      _gService.ProjectCompleted += new EventHandler<GraphicsEventArgs>(_gService_ProjectCompleted);
      _gService.Failed += new EventHandler<TaskFailedEventArgs>(_gService_Failed);
    }

    /// <summary>
    /// This does the real work of the service. In this case, the input SR is that of the graphic.
    /// </summary>
    public void ProjectPoint(Graphic editGraphic)
    {
      try
      {
        //check that the geometry is a point
        if (editGraphic.Geometry is MapPoint)
        {
          _gService.ProjectAsync(new List<Graphic>() { new Graphic() { Geometry = Geometry.Clone(editGraphic.Geometry) } }, _tosr);
        }
        else
        {
          // can't do this
        }
      }
      catch (Exception e)
      {
        //TODO: do something sensible
      }
    }
    #endregion

    #region Private/Protected methods - GeometryService event handlers
    void _gService_ProjectCompleted(object sender, GraphicsEventArgs e)
    {
      MapPoint p = e.Results[0].Geometry as MapPoint;

      //TODO: do something with p
    }

    private void _gService_Failed(object sender, TaskFailedEventArgs e)
    {
      //TODO: do something sensible
    }
    #endregion
  }
}
Related Question