Last active
October 5, 2015 11:47
-
-
Save tebben/b5fee144c5237b0a6d27 to your computer and use it in GitHub Desktop.
Reproject Longitude and Latitude (EPSG:4326) from and to RD_NEW (EPSG:28992) or Spherical Mercator (EPSG:3857)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Windows; | |
namespace SimpleProjection | |
{ | |
public class RD | |
{ | |
/// <summary> | |
/// Project WGS84 lat/long to RD coordinates | |
/// </summary> | |
/// <param name="lon">longitude (datum Amersfoort)</param> | |
/// <param name="lat">latitude (datum Amersfoort)</param> | |
/// <param name="x_out">RD x coordinate out</param> | |
/// <param name="y_out">RD y coordinate out</param> | |
public static void AmersfoortLonLatToRd(double lon, double lat, out double x_out, out double y_out) | |
{ | |
var rd = AmersfoortLonLatToRdCalculation(lon, lat); | |
x_out = rd.X; | |
y_out = rd.Y; | |
} | |
/// <summary> | |
/// Project WGS84 lat/long to RD coordinates | |
/// Returns a Point | |
/// </summary> | |
/// <param name="lon">longitude (datum Amersfoort)</param> | |
/// <param name="lat">latitude (datum Amersfoort)</param> | |
public static Point AmersfoortLonLatToRd(double lon, double lat) | |
{ | |
return AmersfoortLonLatToRdCalculation(lon, lat); | |
} | |
private static Point AmersfoortLonLatToRdCalculation(double lon, double lat) | |
{ | |
var lonlatX = lon; | |
var lonlatY = lat; | |
// Calculate x and y in units of 10000 seconds | |
// (Note: lat, lon are converted to degrees (0-360)) | |
var lambda1 = ((lonlatX / Values.D2R) - Values.AmersfoortXll) * 3600.0 / 10000.0; | |
var phi1 = ((lonlatY / Values.D2R) - Values.AmersfoortYll) * 3600.0 / 10000.0; | |
/* Precompute powers */ | |
var phi2 = phi1 * phi1; | |
var phi3 = phi2 * phi1; | |
var phi4 = phi3 * phi1; | |
var lambda2 = lambda1 * lambda1; | |
var lambda3 = lambda2 * lambda1; | |
var lambda4 = lambda3 * lambda1; | |
var lambda5 = lambda4 * lambda1; | |
/* Calculate coordinates in meters | |
* "DG Rijkswaterstaat. Coordinaattransformaties en kaartprojecties. 1993, p. 19" | |
*/ | |
var xOut = Values.AmersfoortXrd | |
+ 190066.98903 * lambda1 | |
- 11830.85831 * phi1 * lambda1 | |
- 144.19754 * phi2 * lambda1 | |
- 32.38360 * lambda3 | |
- 2.34078 * phi3 * lambda1 | |
- 0.60639 * phi1 * lambda3 | |
+ 0.15774 * phi2 * lambda3 | |
- 0.04158 * phi4 * lambda1 | |
- 0.00661 * lambda5; | |
var yOut = Values.AmersfoortYrd | |
+ 309020.31810 * phi1 | |
+ 3638.36193 * lambda2 | |
- 157.95222 * phi1 * lambda2 | |
+ 72.97141 * phi2 | |
+ 59.79734 * phi3 | |
- 6.43481 * phi2 * lambda2 | |
+ 0.09351 * lambda4 | |
- 0.07379 * phi3 * lambda2 | |
- 0.05419 * phi1 * lambda4 | |
- 0.03444 * phi4; | |
return new Point(xOut, yOut); | |
} | |
/// <summary> | |
/// Transforms RD coordinates to Amersfoort lat/long | |
/// </summary> | |
/// <param name="xIn">x coordinate</param> | |
/// <param name="yIn">y coordinate</param> | |
/// <param name="lonOut">longitude (datum Amersfoort)</param> | |
/// <param name="latOut">latitude (datum Amersfoort)</param> | |
public static void RdToAmersfoortLonLat(double xIn, double yIn, out double lonOut, out double latOut) | |
{ | |
var lonLat = RdToAmersfoortLonLatCalculation(xIn, yIn); | |
lonOut = lonLat.X; | |
latOut = lonLat.Y; | |
} | |
/// <summary> | |
/// Transforms RD coordinates to Amersfoort lat/long | |
/// Returns Point | |
/// </summary> | |
/// <param name="xIn">x coordinate</param> | |
/// <param name="yIn">y coordinate</param> | |
public static Point RdToAmersfoortLonLat(double xIn, double yIn) | |
{ | |
return RdToAmersfoortLonLatCalculation(xIn, yIn); | |
} | |
static Point RdToAmersfoortLonLatCalculation(double xIn, double yIn) | |
{ | |
/* Calculate coordinates in 100 kilometers units | |
* with Amersfoort(155,463) as origin | |
*/ | |
var x = xIn; | |
var y = yIn; | |
x = (x - Values.AmersfoortXrd) / 100000.0; | |
y = (y - Values.AmersfoortYrd) / 100000.0; | |
/* Precompute second, third and fourth power */ | |
var x2 = x * x; | |
var x3 = x2 * x; | |
var x4 = x3 * x; | |
var x5 = x4 * x; | |
var y2 = y * y; | |
var y3 = y2 * y; | |
var y4 = y3 * y; | |
var y5 = y4 * y; | |
/* | |
* Calculate coordinates in lat-long seconds | |
* "DG Rijkswaterstaat. Coordinaattransformaties en kaartprojecties. 1993, p. 20" | |
* (Lambda = X direction, phi is Y direction) | |
*/ | |
var lambda = +5261.3028966 * x | |
+ 105.9780241 * x * y | |
+ 2.4576469 * x * y2 | |
- 0.8192156 * x3 | |
- 0.0560092 * x3 * y | |
+ 0.0560089 * x * y3 | |
- 0.0025614 * x3 * y2 | |
+ 0.0012770 * x * y4 | |
+ 0.0002574 * x5 | |
- 0.0000973 * x3 * y3 | |
+ 0.0000293 * x5 * y | |
+ 0.0000291 * x * y5; | |
var phi = +3236.0331637 * y | |
- 32.5915821 * x2 | |
- 0.2472814 * y2 | |
- 0.8501341 * x2 * y | |
- 0.0655238 * y3 | |
- 0.0171137 * x2 * y2 | |
+ 0.0052771 * x4 | |
- 0.0003859 * x2 * y3 | |
+ 0.0003314 * x4 * y | |
+ 0.0000371 * y4 | |
+ 0.0000143 * x4 * y2 | |
- 0.0000090 * x2 * y4; | |
/* x and y are in seconds from Amersfoort. Recompute degrees | |
* and add Amersfoort in degrees | |
*/ | |
var lonOut = Values.D2R * (Values.AmersfoortXll + (lambda / 3600.0)); | |
var latOut = Values.D2R * (Values.AmersfoortYll + (phi / 3600.0)); | |
return new Point(lonOut, latOut); | |
} | |
/// <summary> | |
/// Transforms RD coordinates to WGS84 lat/long | |
/// </summary> | |
/// <param name="xIn">RD x coordinate</param> | |
/// <param name="yIn">RD y coordinate</param> | |
/// <param name="lonOut">WGS84 longitude out</param> | |
/// <param name="latOut">WGS84 latitude out</param> | |
public static void RdToLonLat(double xIn, double yIn, out double lonOut, out double latOut) | |
{ | |
var aLonLat = RdToAmersfoortLonLatCalculation(xIn, yIn); | |
var lonLat = AmersfoortLonLatToLonLatCalculation(aLonLat.X, aLonLat.Y); | |
lonOut = lonLat.X; | |
latOut = lonLat.Y; | |
} | |
/// <summary> | |
/// Transforms RD coordinates to WGS84 lat/long\n | |
/// Returns a Point | |
/// </summary> | |
/// <param name="xIn">RD x coordinate</param> | |
/// <param name="yIn">RD y coordinate</param> | |
public static Point RdToLonLat(double xIn, double yIn) | |
{ | |
var aLonLat = RdToAmersfoortLonLatCalculation(xIn, yIn); | |
var lonLat = AmersfoortLonLatToLonLatCalculation(aLonLat.X, aLonLat.Y); | |
return new Point(lonLat.X * 57.2957795, lonLat.Y * 57.2957795); | |
} | |
/// <summary> | |
/// Transforms WGS84 Lon Lat coordinates to RD | |
/// </summary> | |
/// <param name="lon">WGS84 lon coordinate</param> | |
/// <param name="lat">WGS84 lat coordinate</param> | |
/// <param name="xOut">RD x coordinate out</param> | |
/// <param name="yOut">RD y coordinate out</param> | |
public static void LonLatToRd(double lon, double lat, out double xOut, out double yOut) | |
{ | |
var aLonLat = LonLatToAmersfoortLonLatCalculation(lon, lat); | |
var rd = AmersfoortLonLatToRdCalculation(aLonLat.X, aLonLat.Y); | |
xOut = rd.X; | |
yOut = rd.Y; | |
} | |
/// <summary> | |
/// Transforms WGS84 Lon Lat coordinates to RD | |
/// </summary> | |
/// <param name="lon">WGS84 lon coordinate</param> | |
/// <param name="lat">WGS84 lat coordinate</param> | |
public static Point LonLatToRd(double lon, double lat) | |
{ | |
var aLonLat = LonLatToAmersfoortLonLatCalculation(lon * 0.0174532925, lat * 0.0174532925); | |
var rd = AmersfoortLonLatToRdCalculation(aLonLat.X, aLonLat.Y); | |
return rd; | |
} | |
/// <summary> | |
/// Transform Amersfoort lon/lat to WGS84 lon/lat | |
/// </summary> | |
/// <param name="lonIn">longitude (datum Amersfoort)</param> | |
/// <param name="latIn">latitude (datum Amersfoort)</param> | |
/// <param name="lonOut">longitude (datum WGS84) out</param> | |
/// <param name="latOut">latitude (datum WGS84) out</param> | |
public static void AmersfoortLonLatToLonLat(double lonIn, double latIn, out double lonOut, out double latOut) | |
{ | |
var lonLat = AmersfoortLonLatToLonLatCalculation(lonIn, latIn); | |
lonOut = lonLat.X; | |
latOut = lonLat.Y; | |
} | |
/// <summary> | |
/// Transform Amersfoort lon/lat to WGS84 lon/lat | |
/// </summary> | |
/// <param name="lonIn">longitude (datum Amersfoort)</param> | |
/// <param name="latIn">latitude (datum Amersfoort)</param> | |
public static Point AmersfoortLonLatToLonLat(double lonIn, double latIn) | |
{ | |
return AmersfoortLonLatToLonLatCalculation(lonIn, latIn); | |
} | |
static Point AmersfoortLonLatToLonLatCalculation(double lonIn, double latIn) | |
{ | |
// delta(WGSlat, WGSlong) = (c1, c2) + A * delta(Blat, Blong) | |
// in which A is the matrix: | |
// a11 a12 | |
// a21 a22 | |
// and the deltas are offsets from (52, 5) | |
// formula from an article by ir.T.G.Schut | |
// published in NGT Geodesia, june 1992. | |
//input is in rad, these are converted to degrees first | |
lonIn = lonIn / Values.D2R; | |
latIn = latIn / Values.D2R; | |
const double c1 = -96.862 / 100000.0; | |
const double c2 = -37.902 / 100000.0; | |
const double a11 = -11.714 / 100000.0 + 1.0; | |
const double a12 = -0.125 / 100000.0; | |
const double a21 = 0.329 / 100000.0; | |
const double a22 = -14.667 / 100000.0 + 1.0; | |
const double lat0 = 52.0; // North | |
const double long0 = 5.0; // East | |
var deltaLat = latIn - lat0; | |
var deltaLong = lonIn - long0; | |
var latOut = c1 + lat0 + a11 * deltaLat + a12 * deltaLong; | |
var lonOut = c2 + long0 + a21 * deltaLat + a22 * deltaLong; | |
//and back from degrees to rad | |
lonOut = lonOut * Values.D2R; | |
latOut = latOut * Values.D2R; | |
return new Point(lonOut, latOut); | |
} | |
/// <summary> | |
/// Transform WGS84 lat/long to Amersfoort lat/long | |
/// </summary> | |
/// <param name="lonIn">longitude (datum WGS84)</param> | |
/// <param name="latIn">latitude (datum WGS84)</param> | |
/// <param name="lonOut">longitude (datum Amersfoort)</param> | |
/// <param name="latOut">latitude (datum Amersfoort)</param> | |
public static void LonLatToAmersfoortLonLat(double lonIn, double latIn, out double lonOut, out double latOut) | |
{ | |
var lonLat = LonLatToAmersfoortLonLatCalculation(lonIn, latIn); | |
lonOut = lonLat.X; | |
latOut = lonLat.Y; | |
} | |
/// <summary> | |
/// Transform WGS84 lat/long to Amersfoort lat/long | |
/// </summary> | |
/// <param name="lonIn">longitude (datum WGS84)</param> | |
/// <param name="latIn">latitude (datum WGS84)</param> | |
public static Point LonLatToAmersfoortLonLat(double lonIn, double latIn) | |
{ | |
return LonLatToAmersfoortLonLatCalculation(lonIn, latIn); | |
} | |
/// <summary> | |
/// Transform Lon Lat to Amersfoort Lon Lat | |
/// </summary> | |
/// <param name="lonIn"></param> | |
/// <param name="latIn"></param> | |
/// <returns></returns> | |
public static Point LonLatToAmersfoortLonLatCalculation(double lonIn, double latIn) | |
{ | |
// delta(Blat, Blong) = D * { delta(WGSlat, WGSlong) - (c1, c2) } | |
// in which D is the inverse van matrix A | |
// and the deltas are offsets from (52, 5) | |
//input is in rad, these are converted to degrees first | |
lonIn = lonIn / Values.D2R; | |
latIn = latIn / Values.D2R; | |
const double c1 = -96.862 / 100000.0; | |
const double c2 = -37.902 / 100000.0; | |
const double a11 = -11.714 / 100000.0 + 1.0; | |
const double a12 = -0.125 / 100000.0; | |
const double a21 = 0.329 / 100000.0; | |
const double a22 = -14.667 / 100000.0 + 1.0; | |
const double lat0 = 52.0; // North | |
const double long0 = 5.0; // East | |
const double normA = 1.0 / (a11 * a22 - a12 * a21); | |
const double d11 = +a22 * normA; | |
const double d12 = -a12 * normA; | |
const double d21 = -a21 * normA; | |
const double d22 = +a11 * normA; | |
var deltaLat = latIn - lat0 - c1; | |
var deltaLong = lonIn - long0 - c2; | |
var latOut = lat0 + d11 * deltaLat + d12 * deltaLong; | |
var lonOut = long0 + d21 * deltaLat + d22 * deltaLong; | |
//and back from degrees to rad | |
lonOut = lonOut * Values.D2R; | |
latOut = latOut * Values.D2R; | |
return new Point(lonOut, latOut); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Windows; | |
namespace SimpleProjection | |
{ | |
public class Spherical | |
{ | |
/// <summary> | |
/// Transforms WGS84 Lat Lon to Spherical Mercator | |
/// </summary> | |
/// <param name="lon">Longitude</param> | |
/// <param name="lat">Latitude</param> | |
/// <param name="xOut"></param> | |
/// <param name="yOut"></param> | |
public static void LonLatToSpherical(double lon, double lat, out double xOut, out double yOut) | |
{ | |
var spherical = LonLatToSphericalCalculation(lon, lat); | |
xOut = spherical.X; | |
yOut = spherical.Y; | |
} | |
/// <summary> | |
/// Transforms WGS84 Lat Lon to Spherical Mercator | |
/// Returns Point | |
/// </summary> | |
/// <param name="lon">Longitude</param> | |
/// <param name="lat">Latitude</param> | |
public static Point LonLatToSpherical(double lon, double lat) | |
{ | |
return LonLatToSphericalCalculation(lon, lat); | |
} | |
static Point LonLatToSphericalCalculation(double lon, double lat) | |
{ | |
var lonRadians = (Values.D2R * lon); | |
var latRadians = (Values.D2R * lat); | |
var x = Values.Radius * lonRadians; | |
var y = Values.Radius * Math.Log(Math.Tan(Math.PI * 0.25 + latRadians * 0.5)); | |
return new Point((float)x, (float)y); | |
} | |
/// <summary> | |
/// Transforms Spherical Mercator to Lon Lat WGS84 | |
/// </summary> | |
/// <param name="x">Spherical x</param> | |
/// <param name="y">Spherical y</param> | |
/// <param name="xOut">WGS84 Longitude output value</param> | |
/// <param name="yOut">WGS84 Latitude output value</param> | |
public static void SphericalToLonLat(double x, double y, out double xOut, out double yOut) | |
{ | |
var lonLat = SphericalToLonLatCalculation(x, y); | |
xOut = lonLat.X; | |
yOut = lonLat.Y; | |
} | |
/// <summary> | |
/// Transforms Spherical Mercator to Lon Lat WGS84 | |
/// Returns a System.Windows.Point | |
/// </summary> | |
/// <param name="x">Spherical x</param> | |
/// <param name="y">Spherical y</param> | |
public static Point SphericalToLonLat(double x, double y) | |
{ | |
return SphericalToLonLatCalculation(x, y); | |
} | |
private static Point SphericalToLonLatCalculation(double x, double y) | |
{ | |
var ts = Math.Exp(-y / (Values.Radius)); | |
var latRadians = Values.HalfPi - 2 * Math.Atan(ts); | |
var lonRadians = x / (Values.Radius); | |
var lon = (lonRadians / Values.D2R); | |
var lat = (latRadians / Values.D2R); | |
return new Point(lon, lat); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace SimpleProjection | |
{ | |
internal static class Values | |
{ | |
internal static readonly double D2R = Math.PI / 180.0; | |
internal static readonly double TwoPi = Math.PI + Math.PI; | |
internal static readonly double HalfPi = Math.PI / 2; | |
internal static readonly double Radius = 6378137; | |
/* Coordinates of Amersfoort in degrees: 5 23' 15.5'', 52 9' 22.178'' */ | |
internal static readonly double AmersfoortXll = 5.0 + (23.0 / 60.0) + (15.500 / 3600.0); | |
internal static readonly double AmersfoortYll = 52.0 + (9.0 / 60.0) + (22.178 / 3600.0); | |
/* Coordinates of Amersfoort in Rijksdriehoek meting */ | |
internal static readonly double AmersfoortXrd = 155000.0; | |
internal static readonly double AmersfoortYrd = 463000.0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment