+ p c. F2 c @2 b6 E- I: {: x. G& o7 }
l 为什么要进行坐标系转换? . _% R1 d- h3 a- t! N: K
因为国内对地理坐标有特殊的政策,GPS获取的原始坐标不能在互联网上对外提供,所有电子地图必须对位置做偏移处理,这就导致从底层接口得到的坐标展示在地图上会有偏移。这种偏移不是线性的,不能简单地通过加减来校正,并且不同的地图提供商采用的算法也不一样。不同的坐标系之间可能有几十到几百米的偏移,所以在地图上绘制矢量图形、做地理数据可视化时,需要修正不同坐标系之间的偏差。
+ }6 o7 c/ D$ {' u$ V/ K5 X9 h l 关于坐标系
0 i9 A9 z& Y& B! H; F 通常GPS获取的是WGS84坐标体系,包括很多国外地图厂商提供的地图数据也是WGS84坐标体系,但是在我国,由于政策原因,在地图发布和出版的时候,坐标至少需要经过国家测绘局加密,也就是对WGS84坐标进行一次非线性加偏,得到GCJ02坐标系,俗称火星坐标。 7 \, L. G4 b- H8 Y7 S
另外,国内许多地图公司,由于各种原因,会在火星坐标的基础上进行二次非线性加偏,得到自己的坐标系统,各地图厂商使用坐标系情况如下 。
( H1 [' L) O2 K1 F
+ C9 a4 C$ H4 Q8 |# @% P5 O6 ]0 K$ \ l 坐标转换方法8 U D8 d( J% P
整理了一下坐标系转换的方法,仅限单个数组转换 4 a- s7 R+ u( C. `6 v' X; o8 b& f
火星坐标转wgs84 . l) L- b6 x9 n+ L$ d4 n1 {
// 火星坐标转wgs844 [+ u; ^; H4 i+ f# F( O& c
function gcj02towgs84(lng, lat) {1 x8 w$ H! l+ H1 B! ]1 r* i5 F
var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
( V# e! X! I4 H$ Y% M4 T. V var PI = 3.1415926535897932384626;
8 v. A u' L8 y- k var a = 6378245.0;
0 S0 s5 m8 q* t- T; q var ee = 0.00669342162296594323;2 F" |6 a, L9 C4 U- c& u- b
if ((lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false)) { E% c6 _( o. v& b
return [lng, lat]
) p9 ]% R0 w6 u }& ]6 U) T' z) k, m5 O# ^% z+ |
else {
! d0 p# S4 T4 z var dlat = ((lng, lat) => {+ Y! g, y5 I5 b' H$ i
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
; G6 g+ l! p; E/ S9 X ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;+ _3 f; L- Z" S8 D+ W$ f
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
' s' H n1 }) s9 E ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;" b u7 s- Z$ K7 \: Y# a
return ret
3 [2 K+ }; Z* h' F; I6 a })(lng - 105.0, lat - 35.0);( p7 F0 g9 P. ]* ]( ` j
var dlng = ((lng, lat) => {% W8 O; M2 J) u5 Q/ P
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));: v% j/ S/ m+ g* W9 Y9 c0 { }
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;/ p7 Y, [2 L/ G) U
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
+ t9 L# c" @; |/ A5 r* J ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;2 E) x/ A% i' M6 h8 Y
return ret2 a7 o/ w; K- x5 e
})(lng - 105.0, lat - 35.0);* z7 W( m% q5 _- |9 i; O
var radlat = lat / 180.0 * PI;
5 |/ P' r7 y J$ R# W' b var magic = Math.sin(radlat);
9 R9 j( ]! }( Y6 J. Q magic = 1 - ee * magic * magic;
& @4 t$ U! ~9 Z7 @& n var sqrtmagic = Math.sqrt(magic);
% }) w z5 h- n1 z( }2 b: ^2 O+ G dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
T( z6 u" }5 q" e7 G, v dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
! Y0 `) z2 g @4 v. J mglat = lat + dlat;& Z/ f1 Q; k- a. e/ @
mglng = lng + dlng;3 {5 j, G: K7 i9 {1 Z# u1 N$ ?
return [lng * 2 - mglng, lat * 2 - mglat]; R# t) K. u* y
}
! u& i0 K* N. V } : m6 ^/ k/ H; A8 `' _1 k. z/ Y
wgs84转火星坐标
, Q! [% ?( R3 o; h // wgs84转火星坐标( Y8 j. y6 y) j! s& b
function wgs84togcj02(lng, lat) {
2 R( O% Y1 a W var x_PI = 3.14159265358979324 * 3000.0 / 180.0;. V2 |# z3 m$ `4 Q# v/ ^
var PI = 3.1415926535897932384626;' R4 I2 Z" t/ K# _9 ~" F8 L
var a = 6378245.0;
" A/ |- E' z* f- C/ r& N var ee = 0.00669342162296594323;7 u# m1 _! {* ]+ `6 [: y- M7 O1 q5 [
if ((lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false)) {
+ O% L+ b" |' B% ~$ L0 I return [lng, lat]
' |3 C2 J" l' o: M N$ ?5 s4 R- J } else {
4 {" V2 P/ V8 T- v# @ var dlat = ((lng, lat) => {
) v0 _) O$ y, N I& Q( p ~' K$ n x+ O var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));1 J8 C$ Q3 @2 S8 i7 j7 j' J
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
% @' K6 |8 w( M0 ^6 s ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;2 Y$ J2 C0 b: j6 A7 Q8 |6 m+ c9 Y/ w
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
# ?/ L9 y: ~3 w1 D* } return ret2 {0 w3 Y! ]$ ?- f
})(lng - 105.0, lat - 35.0);
1 p% Z* P+ }1 w! r6 M, A* X var dlng = ((lng, lat) => {% H2 D- W# u4 z: @$ f$ U
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
* [4 ^) Q" s* s- k. c$ ` ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;1 _4 j# `' r( D2 ~1 b% o+ q
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
" l2 A& f" N; m ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;+ Y! @) I/ U' V: o& U; m$ n
return ret
4 k' ]; v l7 C+ `+ O6 `2 X }
) a% @0 W- h; ]1 v7 u )(lng - 105.0, lat - 35.0);. M* j- n3 S' L) J) C+ _! t3 Z. j
var radlat = lat / 180.0 * PI;9 W6 u9 A$ t% H! H' l$ k( j
var magic = Math.sin(radlat);
% L0 {: A0 Z+ x$ h magic = 1 - ee * magic * magic;
2 X( j4 c; v2 [4 y) P7 f( f var sqrtmagic = Math.sqrt(magic);
0 G6 C9 G3 W& T$ f( [3 ]/ B dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
1 \# N8 F. w7 l" X2 F dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
2 b. v$ y2 ?% g) F: L var mglat = lat + dlat;- x& @) M) f! z! R
var mglng = lng + dlng;
7 Y8 I( Z6 K4 Z, R* | return [mglng, mglat]8 e3 k: O$ ~0 ?9 p
}( @7 k# p; m4 u5 {$ U5 ?
}
( n9 d/ S3 p, e 百度转火星坐标 * @; v I0 Z e- \) {4 y
// 百度转火星坐标" g& }# n- ^1 W9 n3 f6 u
const bd2xh = (bd_lng, bd_lat) => {
7 \9 \ ?, ~6 w) p* Y5 x& h const x_pi = Math.PI * 3000.0 / 180.0;
! G! g6 q# Y S8 k% n2 R; M* s' K const x = bd_lng - 0.0065;
9 B0 P2 C/ c, l' o6 h' Y0 `' T const y = bd_lat - 0.006;
1 w6 @8 J0 r [$ j let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);2 c9 o/ m( \0 B# i6 R- A& I8 `- M) A
let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);. \* B" O5 ~+ B% q
return [z * Math.cos(theta), z * Math.sin(theta)];
' ^! a) I: C" I* V( J5 {& q" T }
( L8 U9 _/ D: R+ o# n# [ l 坐标转换工具
0 b" {' j) S) {# o. K& O: H6 M 有的静态数据不需要动态转换也有现成的在线坐标系转换工具可以直接拿来用 $ [- E: J/ L" A; Y
: v) k0 U, k: h5 k
支持常见百度地图(BD09)、火星坐标系(GCJ02)、WGS84坐标系之间的相互转换
6 o* s; R* p- a# C% @ 具体支持的坐标系转换如下
- H% c7 i9 ^# ^9 J2 _ r0 } 1)WGS-84 → GCJ-02 / A' z1 i+ A$ ^+ N5 Z g
2)WGS-84 → BD-09
: C3 A6 g# T( m& A. P 2)GCJ-02 → WGS-84 7 E" e g3 o/ ~6 T9 M" m
3)GCJ-02 → BD-09 0 F0 E7 U, y" O3 j- u* }( ~
4)BD-09 → GCJ-02 2 c( x$ u. Y# S0 A+ K! e1 F* w
5)BD-09 → WGS-84
9 {) F0 {0 Y* D/ H5 d 支持单个数组、不包含嵌套关系的对象、标准GeoJSON ! g+ m& N: [" y1 C, V
这个工具也还可以获取行政边界数据、地图数据模拟
& C9 t: {6 |8 B' f% Q* G( F
2 k6 S# \ M& G1 c* ~3 d 关注【官方微信公众号】,查看更多可视化资讯~等你呦1、EasyV数字孪生可视化2、易知微数字孪生世界 EasyV数字孪生可视化平台免费试用易知微官网,申请EasyV免费试用,个人版已上线,立即去免费体验!
( E6 h7 y1 }+ h% J7 I 免费试用期间:运营、产品、设计、技术人员专业一对一拉群指导,解答疑惑。
# Q4 k( _# G0 H0 G
7 ^ v [1 \; j7 Q3 Q$ P
- n. _/ \7 N x/ n* g6 r$ {, g$ e9 y9 L7 C" N) {7 u7 H! u
8 k" }) _( n1 B& e8 q8 \7 D |