0

How do I create a new transformation class compatible with MapSui.Projections.ITransformation interface using ProjNet4GeoAPI that reads the source coordindate system from a prj file.

From Mapsui source code, there is a MinimalTransformation that implements ITransformation interface to convert between SphericalMercator and WGS84.

From Mapsui documentation : The out of the box Mapsui support for projections is limited. The MinimalProjection class only projects between SphericalMercator (EPSG:3857) and WGS84 (EPSG:4326). It is however possible to create your own Transformation. You need to implement the ITransformation interface. Within this implementation you need to use some other projection library. A recommended one is ProjNet4GeoAPI.

I can create a working the transformation class with ProjNet4GeoAPI but it implements GeoAPI.CoordinateSystems.Transformations.ICoordinateTransformation not Mapsui.Projection.ITransformation

            // (FROM SOURCE) prj name: NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001"
            ICoordinateSystemFactory csFac = new ProjNet.CoordinateSystems.CoordinateSystemFactory();
            string file = @"C:\DRC_Data\Arcview\USA\Townships\NYTOWNS_POLY.prj";
            string wkt= System.IO.File.ReadAllText(file);
            var csFrom = csFac.CreateFromWkt(wkt);

            //(TO) Prj name: "WGS 84 / Pseudo-Mercator"
            file = @"C:\DRC_Data\Arcview\3857.prj";
            wkt = System.IO.File.ReadAllText(file);
            ICoordinateSystem csTo = csFac.CreateFromWkt(wkt);

            //Step 2) Create transformation class.
            CoordinateTransformationFactory ctFac = new CoordinateTransformationFactory();

            //To 3857                
            //var is ICoordinateTransformation
            ICoordinateTransformation ct = ctFac.CreateFromCoordinateSystems(csFrom, ProjNet.CoordinateSystems.ProjectedCoordinateSystem.WebMercator);

How do I use the ICoordinateTransformation class with Mapsui? Do I create a projection class like SphericalMercator in Mapsui.Projection (see code below)?

From Mapsui.Projection:

public class MinimalTransformation : ITransformation
    {
        private readonly IDictionary<string, Func<double, double, Point>> _toLonLat = new Dictionary<string, Func<double, double, Point>>();
        private readonly IDictionary<string, Func<double, double, Point>> _fromLonLat = new Dictionary<string, Func<double, double, Point>>();

        public MinimalTransformation()
        {
            _toLonLat["EPSG:4326"] = (x, y) => new Point(x, y);
            _fromLonLat["EPSG:4326"] = (x, y) => new Point(x, y);
            _toLonLat["EPSG:3857"] = SphericalMercato.ToLonLat;
            _fromLonLat["EPSG:3857"] = SphericalMercator.FromLonLat;
        }
0

When help from pauldendulk, here is a working code to transform layers.

  • Store the supported WKT as string constants.
  • Create a dictionaries of ICoordinateTransformations using GetFromLatLong(WKT) and GetToLatLong(WKT).
  • Create a second set of dictionaries of Func<double, double, Point> generated from GenerateToLatLong(string constant for WKT) and GenerateFromLatLong(string constant for WKT)
  • Reference the last set of dictionaries in funtions public IGeometry Transform(string fromCRS, string toCRS, IGeometry geometry) public BoundingBox Transform(string fromCRS, string toCRS, BoundingBox boundingBox)
using GeoAPI.CoordinateSystems;
using GeoAPI.CoordinateSystems.Transformations;
using Mapsui.Geometries;
using Mapsui.Projection;
using ProjNet.CoordinateSystems;
using ProjNet.CoordinateSystems.Transformations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DRC_SQLITE.Classes
{
    public class CustomMinimalTransformation : ITransformation
    {
        private readonly IDictionary<string, Func<double, double, Point>> _toLonLat = new Dictionary<string, Func<double, double, Point>>();
        private readonly IDictionary<string, Func<double, double, Point>> _fromLonLat = new Dictionary<string, Func<double, double, Point>>();

        private readonly IDictionary<string, ICoordinateTransformation> _ctToDict = new Dictionary<string, ICoordinateTransformation>();
        private readonly IDictionary<string, ICoordinateTransformation> _ctFromDict = new Dictionary<string, ICoordinateTransformation>();


        const string NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001 = "PROJCS[\"NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Lambert_Conformal_Conic\"],PARAMETER[\"False_Easting\",200000.0],PARAMETER[\"False_Northing\",750000.0],PARAMETER[\"Central_Meridian\",-71.5],PARAMETER[\"Standard_Parallel_1\",41.71666666666667],PARAMETER[\"Standard_Parallel_2\",42.68333333333333],PARAMETER[\"Latitude_Of_Origin\",41.0],UNIT[\"Meter\",1.0]]";
        const string NAD83_New_Jersey_ft_US = "PROJCS[\"NAD83_New_Jersey_ft_US\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",38.83333333333334],PARAMETER[\"central_meridian\",-74.5],PARAMETER[\"scale_factor\",0.9999],PARAMETER[\"false_easting\",492125],PARAMETER[\"false_northing\",0],UNIT[\"Foot_US\",0.30480060960121924]]";
        const string GCS_North_American_1983 = "GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]]";
        const string GCS_North_American_1927 = "GEOGCS[\"GCS_North_American_1927\",DATUM[\"D_North_American_1927\",SPHEROID[\"Clarke_1866\",6378206.4,294.9786982]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]";
        const string NAD83_GEO = "GEOGCS[\"NAD83_GEO\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"<custom>\",0.0],UNIT[\"Degree\",0.0174532925199433]]";
        const string NAD_1983_Albers = "PROJCS[\"NAD_1983_Albers\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Albers\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",500000.0],PARAMETER[\"Central_Meridian\",-132.5],PARAMETER[\"Standard_Parallel_1\",61.66666666666666],PARAMETER[\"Standard_Parallel_2\",68.0],PARAMETER[\"Latitude_Of_Origin\",59.0],UNIT[\"Meter\",1.0]]";
        const string GCS_WGS_1984 = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]]";
        const string NAD_1983_UTM_Zone_14N = "PROJCS[\"NAD_1983_UTM_Zone_14N\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-99.0],PARAMETER[\"Scale_Factor\",0.9996],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]";
        const string NAD_1983_UTM_Zone_13N = "PROJCS[\"NAD83(CSRS98) / UTM zone 13N\",GEOGCS[\"NAD83_Canadian_Spatial_Reference_System\",DATUM[\"D_North_American_1983_CSRS\",SPHEROID[\"Geodetic_Reference_System_of_1980\",6378137.0,298.2572221009113]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"false_easting\",500000.0],PARAMETER[\"false_northing\",0.0],PARAMETER[\"central_meridian\",-105.0],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"latitude_of_origin\",0.0],UNIT[\"Meter\",1.0]]";

        //const string NAD_1983_CSRS_New_Brunswick_Stereographic = "PROJCS[\"NAD_1983_CSRS_New_Brunswick_Stereographic\",GEOGCS[\"GCS_North_American_1983_CSRS\",DATUM[\"D_North_American_1983_CSRS\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Double_Stereographic\"],PARAMETER[\"False_Easting\",2500000.0],PARAMETER[\"False_Northing\",7500000.0],PARAMETER[\"Central_Meridian\",-66.5],PARAMETER[\"Scale_Factor\",0.999912],PARAMETER[\"Latitude_Of_Origin\",46.5],UNIT[\"Meter\",1.0]]";                    

        CoordinateTransformationFactory _ctFac;
        ICoordinateTransformation _ctTo;
        ICoordinateTransformation _ctFrom;        

        public CustomMinimalTransformation()
        {            
            LoadCRS();

            _toLonLat["EPSG:4326"] = (x, y) => new Point(x, y);
            _fromLonLat["EPSG:4326"] = (x, y) => new Point(x, y);

            _toLonLat["EPSG:3857"] = SphericalMercator.ToLonLat;
            _fromLonLat["EPSG:3857"] = SphericalMercator.FromLonLat;

            _toLonLat["EPSG:CUSTOM"] = CustomProjectionToLonLat;
            _fromLonLat["EPSG:CUSTOM"] = CustomProjectionFromLonLat;

            _toLonLat["NAD83_New_Jersey_ft_US"] = GenerateToLatLong("NAD83_New_Jersey_ft_US");
            _fromLonLat["NAD83_New_Jersey_ft_US"] = GenerateFromLatLong("NAD83_New_Jersey_ft_US");

            _toLonLat["NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001"] = GenerateToLatLong("NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001");
            _fromLonLat["NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001"] = GenerateFromLatLong("NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001");

            _toLonLat["GCS_North_American_1983"] = GenerateToLatLong("GCS_North_American_1983");
            _fromLonLat["GCS_North_American_1983"] = GenerateFromLatLong("GCS_North_American_1983");

            _toLonLat["GCS_North_American_1927"] = GenerateToLatLong("NAD83_GCS_North_American_1927GEO");
            _fromLonLat["GCS_North_American_1927"] = GenerateFromLatLong("GCS_North_American_1927");

            _toLonLat["NAD83_GEO"] = GenerateToLatLong("NAD83_GEO");
            _fromLonLat["NAD83_GEO"] = GenerateFromLatLong("NAD83_GEO");

            _toLonLat["NAD_1983_Albers"] = GenerateToLatLong("NAD_1983_Albers");
            _fromLonLat["NAD_1983_Albers"] = GenerateFromLatLong("NAD_1983_Albers");

            _toLonLat["GCS_WGS_1984"] = GenerateToLatLong("GCS_WGS_1984");
            _fromLonLat["GCS_WGS_1984"] = GenerateFromLatLong("GCS_WGS_1984");

            _toLonLat["NAD_1983_UTM_Zone_14N"] = GenerateToLatLong("NAD_1983_UTM_Zone_14N");
            _fromLonLat["NAD_1983_UTM_Zone_14N"] = GenerateFromLatLong("NAD_1983_UTM_Zone_14N");

            _toLonLat["NAD83(CSRS98) / UTM zone 13N"] = GenerateToLatLong("NAD83(CSRS98) / UTM zone 13N");
            _fromLonLat["NAD83(CSRS98) / UTM zone 13N"] = GenerateFromLatLong("NAD83(CSRS98) / UTM zone 13N");

        }

        void LoadCRS()
        {
            _ctFromDict.Add("NAD83_New_Jersey_ft_US", GetFromLatLong(NAD83_New_Jersey_ft_US));
            _ctToDict.Add("NAD83_New_Jersey_ft_US", GetToLatLong(NAD83_New_Jersey_ft_US));

            _ctFromDict.Add("NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001", GetFromLatLong(NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001));
            _ctToDict.Add("NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001", GetToLatLong(NAD_1983_StatePlane_Massachusetts_Mainland_FIPS_2001));

            _ctFromDict.Add("GCS_North_American_1983", GetFromLatLong(GCS_North_American_1983));
            _ctToDict.Add("GCS_North_American_1983", GetToLatLong(GCS_North_American_1983));

            _ctFromDict.Add("GCS_North_American_1927", GetFromLatLong(GCS_North_American_1927));
            _ctToDict.Add("GCS_North_American_1927", GetToLatLong(GCS_North_American_1927));

            _ctFromDict.Add("NAD83_GEO", GetFromLatLong(NAD83_GEO));
            _ctToDict.Add("NAD83_GEO", GetToLatLong(NAD83_GEO));

            _ctFromDict.Add("NAD_1983_Albers", GetFromLatLong(NAD_1983_Albers));
            _ctToDict.Add("NAD_1983_Albers", GetToLatLong(NAD_1983_Albers));

            _ctFromDict.Add("GCS_WGS_1984", GetFromLatLong(GCS_WGS_1984));
            _ctToDict.Add("GCS_WGS_1984", GetToLatLong(GCS_WGS_1984));

            _ctFromDict.Add("NAD_1983_UTM_Zone_14N", GetFromLatLong(NAD_1983_UTM_Zone_14N));
            _ctToDict.Add("NAD_1983_UTM_Zone_14N", GetToLatLong(NAD_1983_UTM_Zone_14N));

            _ctFromDict.Add("NAD83(CSRS98) / UTM zone 13N", GetFromLatLong(NAD_1983_UTM_Zone_13N));
            _ctToDict.Add("NAD83(CSRS98) / UTM zone 13N", GetToLatLong(NAD_1983_UTM_Zone_13N));
        }

        ICoordinateTransformation GetFromLatLong(string Wkt)
        {
            ICoordinateSystemFactory csFac = new ProjNet.CoordinateSystems.CoordinateSystemFactory();
            var ctFac = new CoordinateTransformationFactory();
            ICoordinateSystem csSource = csFac.CreateFromWkt(Wkt);
            ICoordinateSystem csTarget = GeographicCoordinateSystem.WGS84;      
            return ctFac.CreateFromCoordinateSystems(csTarget, csSource);
        }
        ICoordinateTransformation GetToLatLong(string Wkt)
        {
            ICoordinateSystemFactory csFac = new ProjNet.CoordinateSystems.CoordinateSystemFactory();
            var ctFac = new CoordinateTransformationFactory();
            ICoordinateSystem csSource = csFac.CreateFromWkt(Wkt);
            ICoordinateSystem csTarget = GeographicCoordinateSystem.WGS84;
            return ctFac.CreateFromCoordinateSystems(csSource, csTarget);
        }


        public IGeometry Transform(string fromCRS, string toCRS, IGeometry geometry)
        {
            Transform(geometry.AllVertices(), _toLonLat[fromCRS]);
            Transform(geometry.AllVertices(), _fromLonLat[toCRS]);
            return geometry; // this method should not have a return value
        }
        private static void Transform(IEnumerable<Point> points, Func<double, double, Point> transformFunc)
        {
            foreach (var point in points)
            {
                var transformed = transformFunc(point.X, point.Y);
                point.X = transformed.X;
                point.Y = transformed.Y;
            }
        }
        public BoundingBox Transform(string fromCRS, string toCRS, BoundingBox boundingBox)
        {
            Transform(boundingBox.AllVertices(), _toLonLat[fromCRS]);
            Transform(boundingBox.AllVertices(), _fromLonLat[toCRS]);
            return boundingBox; // this method not have a return value
        }

        public bool? IsProjectionSupported(string fromCRS, string toCRS)
        {
            if (!_toLonLat.ContainsKey(fromCRS)) return false;
            if (!_fromLonLat.ContainsKey(toCRS)) return false;
            return true;
        }

        public void LoadSourceWKT(string filepath)
        {
            ICoordinateSystemFactory csFac = new ProjNet.CoordinateSystems.CoordinateSystemFactory();
            ICoordinateSystem csSource = null;
            ICoordinateSystem csTarget = null;
            if (!String.IsNullOrWhiteSpace(filepath) && System.IO.File.Exists(filepath))
            {
                string wkt = System.IO.File.ReadAllText(filepath);
                csSource = csFac.CreateFromWkt(wkt);
                csTarget = GeographicCoordinateSystem.WGS84;
            }
            else
            {
                csSource = ProjectedCoordinateSystem.WebMercator;
                csTarget = GeographicCoordinateSystem.WGS84;
            }
            _ctFac = new CoordinateTransformationFactory();

            _ctTo = _ctFac.CreateFromCoordinateSystems(csSource, csTarget);
            _ctFrom = _ctFac.CreateFromCoordinateSystems(csTarget, csSource);
        }

        //From loaded projection file
        public Point CustomProjectionFromLonLat(double lon, double lat)
        {
            Point pt = new Point(lon, lat);
            double[] result = _ctFrom.MathTransform.Transform(pt.ToDoubleArray());
            return new Point(result[0], result[1]);
        }
        public Point CustomProjectionToLonLat(double x, double y)
        {
            Point pt = new Point(x, y);
            double[] result = _ctTo.MathTransform.Transform(pt.ToDoubleArray());
            return new Point(result[0], result[1]);
        }                

        public Func<double, double, Point> GenerateFromLatLong(string crskey)
        {
            return (x, y) => { double[] result = _ctFromDict[crskey].MathTransform.Transform(new Point(x, y).ToDoubleArray()); return new Point(result[0], result[1]); };
        }
        public Func<double, double, Point> GenerateToLatLong(string crskey)
        {
            return (x, y) => { double[] result = _ctToDict[crskey].MathTransform.Transform(new Point(x, y).ToDoubleArray()); return new Point(result[0], result[1]); };
        }

    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.