/* * ## 当前互联网地图的坐标系现状 * ### 地球坐标(WGS84) * - 国际标准,从 GPS 设备中取出的数据的坐标系 * - 国际地图提供商使用的坐标系 * ### 火星坐标(GCJ-02)也叫国测局坐标系 * - 中国标准,从国行移动设备中定位获取的坐标数据使用这个坐标系 * - 国家规定: 国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密. * * ### 百度坐标(BD-09) * - 百度标准,百度 SDK,百度地图,GeoCoding 使用 * -(本来就乱了,百度又在火星坐标上来个二次加密) * * ## 开发过程需要注意的事 * - 从设备获取经纬度(GPS)坐标 * * 如果使用的是百度sdk那么可以获得百度坐标(bd09)或者火星坐标(GCJ02),默认是bd09 * 如果使用的是ios的原生定位库,那么获得的坐标是WGS84 * 如果使用的是高德sdk,那么获取的坐标是GCJ02 * - 互联网在线地图使用的坐标系 * * 火星坐标系: * iOS 地图(其实是高德) * Google国内地图(.cn域名下) * 搜搜、阿里云、高德地图、腾讯 * 百度坐标系: * 当然只有百度地图 * WGS84坐标系: * 国际标准,谷歌国外地图、osm地图等国外的地图一般都是这个 * 从JavaScript版本转到C#版本 * Created by Wander gis on 2015/7/8. * 提供了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换 * 修复了,中国范围的经纬度. */ using System; namespace Masuit.Tools.Maths; /// /// UMD魔法代码,地图坐标转换偏移代码 /// public static class CoordinateConvert { private const double x_Pi = 3.14159265358979324 * 3000.0 / 180.0; private const double a = 6378245.0; private const double ee = 0.00669342162296594323; private const double Pi = 3.1415926535897932384626; /// /// WGS84转GCJ02 /// /// /// /// /// public static void WGS84ToGCJ02(double wgsLon, double wgsLat, out double gcjLon, out double gcjLat) { if (OutOfChina(wgsLon, wgsLat)) { gcjLon = wgsLon; gcjLat = wgsLat; return; } var dLat = TransformLat(wgsLon - 105.0, wgsLat - 35.0); var dLon = TransformLon(wgsLon - 105.0, wgsLat - 35.0); var radLat = wgsLat / 180.0 * Pi; var magic = Math.Sin(radLat); magic = 1 - magic * ee * magic; var sqrtMagic = Math.Sqrt(magic); dLat = dLat * 180.0 / (a * (1 - ee) / (magic * sqrtMagic) * Pi); dLon = dLon * 180.0 / (a / sqrtMagic * Math.Cos(radLat) * Pi); gcjLat = wgsLat + dLat; gcjLon = wgsLon + dLon; } /// /// GCJ02 转换为 WGS84 /// /// /// /// /// public static void GCJ02ToWGS84(double gcjLon, double gcjLat, out double wgsLon, out double wgsLat) { if (OutOfChina(gcjLon, gcjLat)) { wgsLon = gcjLon; wgsLat = gcjLat; return; } var dLat = TransformLat(gcjLon - 105.0, gcjLat - 35.0); var dLon = TransformLon(gcjLon - 105.0, gcjLat - 35.0); var radLat = gcjLat / 180.0 * Pi; var magic = Math.Sin(radLat); magic = 1 - magic * magic * ee; var sqrtMagic = Math.Sqrt(magic); dLat = dLat * 180.0 / (a * (1 - ee) / (magic * sqrtMagic) * Pi); dLon = dLon * 180.0 / (a / sqrtMagic * Math.Cos(radLat) * Pi); wgsLat = gcjLat - dLat; wgsLon = gcjLon - dLon; } /// /// 百度坐标系(BD-09) 与 火星坐标系(GCJ-02)的转换,即 百度 转 谷歌、高德 /// /// /// /// /// public static void BD09ToGCJ02(double bdLon, double bdLat, out double gcjLon, out double gcjLat) { var x = bdLon - 0.0065; var y = bdLat - 0.006; var z = Math.Sqrt(x * x + y * y) - 0.00002 * Math.Sin(y * x_Pi); var theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * x_Pi); gcjLon = z * Math.Cos(theta); gcjLat = z * Math.Sin(theta); } /// /// 火星坐标系(GCJ-02) 与百度坐标系(BD-09) 的转换,即谷歌、高德 转 百度 /// /// /// /// /// public static void GCJ02ToBD09(double gcjLon, double gcjLat, out double bdLon, out double bdLat) { var z = Math.Sqrt(gcjLon * gcjLon + gcjLat * gcjLat) + 0.00002 * Math.Sin(gcjLat * x_Pi); var theta = Math.Atan2(gcjLat, gcjLon) + 0.000003 * Math.Cos(gcjLon * x_Pi); bdLon = Math.Cos(theta) * z + 0.0065; bdLat = Math.Sin(theta) * z + 0.006; } /// /// 判断是否在国内,不在国内则不做偏移 /// /// /// /// private static bool OutOfChina(double lon, double lat) => // https://cn.bing.com/search?q=%E4%B8%AD%E5%9B%BD%E7%BB%8F%E7%BA%AC%E5%BA%A6%E8%8C%83%E5%9B%B4&qs=n&form=QBRE&sp=-1&pq=%E4%B8%AD%E5%9B%BD%E7%BB%8F%E7%BA%AC%E5%BA%A6%E8%8C%83%E5%9B%B4&sc=5-7&sk=&cvid=A687C2BEA56F4B08BE0913ADDA0C6674&ghsh=0&ghacc=0&ghpl= // 经度范围:73°33′E至135°05′E; 纬度范围:3°51′N至53°33′N lon is < 73.33 or > 135.05 || lat is < 3.51 or > 53.33; /// /// 转换纬度 /// /// 经度 /// 纬度 /// private static double TransformLat(double lon, double lat) { var ret = -100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat + 0.1 * lon * lat + 0.2 * Math.Sqrt(Math.Abs(lon)); ret += 20.0 * Math.Sin(6.0 * lon * Pi) + 20.0 * Math.Sin(2.0 * lon * Pi) * 2.0 / 3.0; ret += 20.0 * Math.Sin(lat * Pi) + 40.0 * Math.Sin(lat / 3.0 * Pi) * 2.0 / 3.0; ret += (160.0 * Math.Sin(lat / 12.0 * Pi) + 320 * Math.Sin(lat * Pi / 30.0) * 2.0) / 3.0; return ret; } /// /// 转换经度 /// /// 经度 /// 纬度 /// private static double TransformLon(double lon, double lat) { var ret = 300.0 + lon + 2.0 * lat + 0.1 * lon * lon + 0.1 * lon * lat + 0.1 * Math.Sqrt(Math.Abs(lon)); ret += (20.0 * Math.Sin(6.0 * lon * Pi) + 20.0 * Math.Sin(2.0 * lon * Pi)) * 2.0 / 3.0; ret += (20.0 * Math.Sin(lon * Pi) + 40.0 * Math.Sin(lon / 3.0 * Pi)) * 2.0 / 3.0; ret += (150.0 * Math.Sin(lon / 12.0 * Pi) + 300.0 * Math.Sin(lon / 30.0 * Pi)) * 2.0 / 3.0; return ret; } }