Mapping coordinates to/from WGS84

Apr 21, 2011 at 7:51 PM

Nice job, the look&feel of the Mapsui library is really great!

But I can't figure out how to map WGS84 coordinates to or from the pixel coordinates of the MapControl. I added the following code to the Window1 constructor of the Mapsui.Wpf sample:

mapControl.MouseMove += (s, e) =>
{
  var pos = e.GetPosition(mapControl);
  var

point = mapControl.View.ViewToWorld(pos.X, pos.Y);
  
var wgs84 = ProjNet.CoordinateSystems.GeographicCoordinateSystem.WGS84;
 
var cf = new ProjNet.CoordinateSystems.CoordinateSystemFactory();
 
var epsg3785 = cf.CreateFromWkt(
@"PROJCS[""Popular Visualisation CRS / Mercator"",
  GEOGCS[""Popular Visualisation CRS"",
  DATUM[""Popular Visualisation Datum"",
  SPHEROID[""Popular Visualisation Sphere"", 6378137, 0, AUTHORITY[""EPSG"",""7059""]],
  TOWGS84[0, 0, 0, 0, 0, 0, 0],
  AUTHORITY[""EPSG"",""6055""]],
  PRIMEM[""Greenwich"", 0, AUTHORITY[""EPSG"", ""8901""]],
  UNIT[""degree"", 0.01745329251994328, AUTHORITY[""EPSG"", ""9122""]],
  AXIS[""E"", EAST],
  AXIS[""N"", NORTH],
  AUTHORITY[""EPSG"",""4055""]],
  PROJECTION[""Mercator_1SP""],
  PARAMETER[""Central_Meridian"", 0],
 
PARAMETER[""scale_factor"", 1],
  PARAMETER[""False_Easting"", 0],
  PARAMETER[""False_Northing"", 0],
  PARAMETER[""Latitude_of_origin"", 0],
  UNIT[""metre"", 1, AUTHORITY[""EPSG"", ""9001""]],
  AUTHORITY[""EPSG"",""3785""]]"
);
 
var ctFact = new CoordinateTransformationFactory();
 
var transformation = ctFact.CreateFromCoordinateSystems(epsg3785, wgs84);
 
var coords = transformation.MathTransform.Transform(new[] { point.X, point.Y });

 

I expected that coords[0] will contain the WGS84 longitute and coords[1] will contain the WGS84 latitude. But the returned values are not correct. The latitude value is off by approx. -0.2°. Also, the returned coords array has 3(!) elements. What does the 3rd element represent?

The same problem exists in the other direction. I'm trying to draw shapes (Polylines) above the map. The coordinates of the Polyline.Points come from data in WGS84 format. When I transform them to the EPSG:3785 coordinate system and then to the view (WorldToView), they are off by a approx. 100 pixels in Y direction.

Can someone please help me out?

};

Apr 23, 2011 at 9:10 AM

I assume this is a problem with proj.net. The plan is the switch from proj.net to DotSpatial.Projections.

In the meantime you could do the projections yourself with this piece of code:

http://pauldendulk.com/2011/04/projecting-from-wgs84-to.html

Paul

Apr 24, 2011 at 3:47 PM
Edited Apr 24, 2011 at 3:54 PM

If I understand, you need to position correctly a shape on a map.

I needed to show my GPS tracks (obvoiusly in WGS84 coordinates) over a map; I did it this way :

- I defined a ICoordinateTransformation from 4326 to 3857. (see proj.net)

- I had a Track class that contain a Collection of points (coordinates) in WGS84 format, in this class I created a new Method :

 

        public Geometry GetGPath()
        {
            if (_gPath == null)
            {
                Collection c
<SharpMap.Geometries.Point> = new Collection<SharpMap.Geometries.Point>();
                foreach (GeoPoint gp in _points)
                {
                    if (gp.latitude != 0d)
                    {
                        double[] point1 = myCT.MathTransform.Transform(new double[] { gp.longitude, gp.latitude  });
                        c.Add(new SharpMap.Geometries.Point(point1[0], point1[1]));
                    }
                }
                _gPath = new LineString(c);
            }
            return _gPath;
        }

where MyCT is the ICoordinateTransformation

 

- Added a new Layer to the map with

DataSource = new MemoryProvider(t.GetGPath()),

  

that's all, hope it will help you

bye

Fabio

 

Apr 26, 2011 at 7:18 AM

Hi Paul,

thanks a lot for sharing the SphericalMercator/WGS84 projection code. With your code, the calculation is now correct. So I guess your right with your assumption that it is a problem of the Proj.Net library.

Chris

Apr 26, 2011 at 7:39 AM

Hi Fabio,

thanks for your input. I am also trying to show a GPS track (from WGS84 coordinates) and other "shapes" on the map. These "shapes" actually are interactive controls. I also want to show the coordinate at the mouse cursor position in the StatusBar of my application. For this reason I must be able to transform coordinates in both directions.

Currently I'm doing this:

1. Have a mapsui:MapControl in a Grid layout of the MainWindow.

2. Have my custom "TracksView" control above the MapControl (same Grid cell).

3. The TracksView control is bound to a TracksViewModel class which hold a collection of GpsTracks. Each GpsTrack holds a collection of TrackPoints. Each TrackPoint has two coordinate representations: a Point in raw, original WGS84 coordinates plus a System.Windows.Point in view coordinates (=pixels).

4. The TracksView control has WPF DataTemplates for the GpsTrack and TrackPoint types which map them to standard WPF Polylines and filled Ellipses, placed on a Canvas. The X/Y and Canvas.Left/Canvas.Top properties are databound to the view coordinates of each TrackPoint.

5. Subscribe to the MapControl.ViewChanged event and update the view coordinates or each TrackPoint (i. e. all view coordinates inside my TracksViewModel are updated when the MapControl view changes).

I'm doing it that way because I want to stick with WPF standard controls in my TrackView. I don't want to be limited by SharpMap's counterparts (e. g. SharpMap.Geometries.LineString).

I'm heavily relying on WPF databinding because my data is dynamic (TrackPoints are added and displayed in real time as they are read from the GPS receiver).

I have doubts (e. g. performance, design (MVVM violations)) if this is the right way to do it. I'm new to SharpMap and mapsui and need to get a better feeling of how to do things right. I already have an implementation running with the DotSpatial MapWindow control, but this is WinForms/GDI and I want to replace that with a pure WPF implementation.

Chris