各大地理座標系互轉

支持互轉座標

支持座標類型:
	WGS84           WGS84座標系[大地座標系]
	GCJ02           火星座標系
	BD09            百度座標系
	BD09MC          百度墨卡託座標系
	Mercator        普通墨卡託座標系座標系

項目

其他版本在開發中,莫急,到時會更新此文檔

緣由

上篇博客說了下商圈數據獲取,但是我們獲取到商圈數據是BD09MC,這就無語了,我們需要將其轉成WGS84GCJ02 纔可以下一步處理,但是直接調百度接口有限額還有性能問題,直接看百度的Web SDK 查看實現邏輯,然後轉後端實現

名詞解釋

座標系統:用於定位的系統,就跟二維笛卡爾座標系統一樣,一個點使用(x,y),就能確定該點在笛卡爾座標系統中的唯一位置。這裏講的座標系統,相對於笛卡爾座標系統,要複雜許多,但作用卻都是一樣,主要用於定位,也就是精確地定位地表上的一點。
地理座標系統:WGS84就是一種地理座標系統。地理座標座標是對地球進行簡單幾何建模,比如將地球看成一個球體或者類球體,然後再將地表上點投影到該球面上形成的座標就是地理座標系統。WGS84就是定義瞭如何將地球抽象成球體或者類球體的規則。或者簡單地來說,WGS84就是一堆參數,用於建立球體或者類球體,來近似地球。
投影座標系統:由於地球是一個球狀,所以一般將其某個區域投影在平面上,形成的座標系稱爲投影座標系。

墨卡託投影:世界地圖並不是世界的真實樣貌!甚至誤差非常大

簡稱解釋

WGS84(大地座標系) :統爲一種大地座標系,也是目前廣泛使用的GPS全球衛星定位系統使用的座標系,Google Earth和中國外的Google Map使用,另外,目前基本上所有定位空間位置的設備都使用這種座標系統,例如手機的GPS系統。
GCJ02(國測局座標系):又稱火星座標系,是由中國國家測繪局制訂的地理信息系統的座標系統。由WGS84座標系經加密後的座標系。
BD09(百度經緯度座標)):爲百度座標系,在GCJ02座標系基礎上再次加密。其中bd09ll表示百度經緯度座標。

BD09mc(百度墨卡託平面座標):百度墨卡托米制座標

反查源碼

  1. 算法實現
    參考:百度拾取座標系統 中的JS源碼 版本: 081 更新時間: 20210122
<script type="text/javascript" src="Js/public.js?20200211"></script>
  1. 前端

    <label class="pointLabel" for="pointLabel"><input type="checkbox" onfocus="this.blur()" id="pointLabel">座標反查</label>
    

    可以看到class 是pointLabel,在反查時肯定會檢測checkbox 是否被勾選

  2. 查看public.js

    1. pointLabel 哪裏使用了

      function beginsearch(b, a) {
          var c = filtQuery(Fe.G("localvalue").value);
          // 處理特殊城市
          if (isInArray(c)) {
              trickCity(c);
              return;
          }
      
          if (!c || c == "請輸入關鍵字進行搜索") {
              return
          }
          if (Fe.G("pointLabel").checked) {
              searchByPoint(c)  // 這裏被調用
          } else {
              if (!a) {
                  b.setLocation(map)
              }
              b.search(c)
          }
      }
      
    2. 然後搜searchByPoint函數的調用

       var f = projection.pointToLngLat(new BMap.Pixel(d[0], d[1]));
      

      可以看到調用pointToLngLat來返解析墨卡託座標

      那麼projection 是哪裏初始化的?

    3. projection

      function initMap() {
          window.map = new BMap.Map("MapHolder", {enableMapClick: false});
          window.projection = new BMap.MercatorProjection(); // 這裏初始化的
        	...
      }
      

      可以看到MercatorProjection 的含義就是墨卡託投影

    4. 查看BMap的定義

      js 文件:

      <script type="text/javascript" src="https://api.map.baidu.com/getscript?v=2.0&amp;ak=E4805d16520de693a3fe707cdc962045&amp;services=&amp;t=20210113094335"></script>
      

      這個js文件被壓縮過,直接Pretty-print後查看

    5. 在源代碼中搜pointToLngLat

      function U(a, b) { // 將b 的屬性賦值給 a
              for (var c in b)
                  a[c] = b[c]
          }
      
      ....
      
      var Gf = T.prototype;
          U(Gf, {
              lngLatToPoint: Gf.fy,
              pointToLngLat: Gf.Dj  // 綁定 pointToLngLat 的實現,其實就是T.Dj
          });
          var Hf = ib.prototype;
          U(Hf, {
              lngLatToPoint: Hf.fy,
              pointToLngLat: Hf.Dj // 綁定 pointToLngLat 的實現,還是T.Dj
          });
      

      這裏Hf.Dj在定義是:

      var Hf = ib.prototype; 
      
      --> 
         function ib() {
                this.ij = "bj"
            }
          ib.prototype = new T;  // 本質上還是 T.Dj
      

      T.DJ 的定義:

      x.extend(T.prototype, {
      ...
              Dj: function(a) {
                  a = new H(a.x,a.y);
                  return eb(T.ub(a), this.map)
              },
      ...
      }
      

      這裏,我們需要確定H,T.ub,eb函數的實現,其中這些函數的內部依賴我就整理到一起了

      H:函數

      // 依賴
      function ab(a) {
              return "string" == typeof a
          }
      
      var Jb = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
          function Kb(a) {
              var b = "", c, d, e = "", f, g = "", i = 0;
              f = /[^A-Za-z0-9\+\/\=]/g;
              if (!a || f.exec(a))
                  return a;
              a = a.replace(/[^A-Za-z0-9\+\/\=]/g, "");
              do
                  c = Jb.indexOf(a.charAt(i++)),
                  d = Jb.indexOf(a.charAt(i++)),
                  f = Jb.indexOf(a.charAt(i++)),
                  g = Jb.indexOf(a.charAt(i++)),
                  c = c << 2 | d >> 4,
                  d = (d & 15) << 4 | f >> 2,
                  e = (f & 3) << 6 | g,
                  b += String.fromCharCode(c),
                  64 != f && (b += String.fromCharCode(d)),
                  64 != g && (b += String.fromCharCode(e));
              while (i < a.length);return b
          }
      
      // 實現: 創建點,百度摩卡託座標系
      function H(a, b) {
              isNaN(a) && (a = Kb(a),
              a = isNaN(a) ? 0 : a);
              ab(a) && (a = parseFloat(a));
              isNaN(b) && (b = Kb(b),
              b = isNaN(b) ? 0 : b);
              ab(b) && (b = parseFloat(b));
              this.lng = a;
              this.lat = b;
              this.of = "inner"
          }
      

      T.ub函數:

      // 外部依賴:
      p = null
      j = void 0
      
      x.extend(T, {
      			// 內部依賴
              CP: 6370996.81,
              JG: [1.289059486E7, 8362377.87, 5591021, 3481989.83, 1678043.12, 0],
              Lu: [75, 60, 45, 30, 15, 0],
              IP: [[1.410526172116255E-8, 8.98305509648872E-6, -1.9939833816331, 200.9824383106796, -187.2403703815547, 91.6087516669843, -23.38765649603339, 2.57121317296198, -0.03801003308653, 1.73379812E7], [-7.435856389565537E-9, 8.983055097726239E-6, -0.78625201886289, 96.32687599759846, -1.85204757529826, -59.36935905485877, 47.40033549296737, -16.50741931063887, 2.28786674699375, 1.026014486E7], [-3.030883460898826E-8, 8.98305509983578E-6, 0.30071316287616, 59.74293618442277, 7.357984074871, -25.38371002664745, 13.45380521110908, -3.29883767235584, 0.32710905363475, 6856817.37], [-1.981981304930552E-8, 8.983055099779535E-6, 0.03278182852591, 40.31678527705744, 0.65659298677277, -4.44255534477492, 0.85341911805263, 0.12923347998204, -0.04625736007561, 4482777.06], [3.09191371068437E-9, 8.983055096812155E-6, 6.995724062E-5, 23.10934304144901, -2.3663490511E-4, -0.6321817810242, -0.00663494467273, 0.03430082397953, -0.00466043876332, 2555164.4], [2.890871144776878E-9, 8.983055095805407E-6, -3.068298E-8, 7.47137025468032, -3.53937994E-6, -0.02145144861037, -1.234426596E-5, 1.0322952773E-4, -3.23890364E-6, 826088.5]],
              GG: [[-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5], [8.277824516172526E-4, 111320.7020463578, 6.477955746671607E8, -4.082003173641316E9, 1.077490566351142E10, -1.517187553151559E10, 1.205306533862167E10, -5.124939663577472E9, 9.133119359512032E8, 67.5], [0.00337398766765, 111320.7020202162, 4481351.045890365, -2.339375119931662E7, 7.968221547186455E7, -1.159649932797253E8, 9.723671115602145E7, -4.366194633752821E7, 8477230.501135234, 52.5], [0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5], [-3.441963504368392E-4, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5], [-3.218135878613132E-4, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45]],
        
        			GK: function(a, b) {
                  if (a && b) {
                      var c = b[0] + b[1] * Math.abs(a.lng)
                        , d = Math.abs(a.lat) / b[9]
                        , d = b[2] + b[3] * d + b[4] * d * d + b[5] * d * d * d + b[6] * d * d * d * d + b[7] * d * d * d * d * d + b[8] * d * d * d * d * d * d
                        , c = c * (0 > a.lng ? -1 : 1)
                        , d = d * (0 > a.lat ? -1 : 1);
                      return new H(c,d)
                  }
              },
                				
        
        		  // 定義: 座標轉換
              ub: function(a) {
                  if (a === p || a === j)
                      return new H(0,0);
                  var b, c;
                  b = new H(Math.abs(a.lng),Math.abs(a.lat));
                  for (var d = 0; d < this.JG.length; d++)
                      if (b.lat >= this.JG[d]) {
                          c = this.IP[d];
                          break
                      }
                  a = this.GK(a, c);
                  return a = new H(a.lng.toFixed(6),a.lat.toFixed(6))
              },
       }
      

      eb函數:

       // 實現:
    function eb(a, b) {
               if (b && b.B && 3 === b.B.Xw && a instanceof H) {
                   var c = Bc(a);
                   return new N(c.lng,c.lat)
               }
               return b && b.B && 5 === b.B.Xw && a instanceof H ? new N(a.lng,a.lat) : a
           }
    
    1. 最後,我們可以定位出以下函數

      function coordtransform
      qc 火星座標系->百度座標系
      BC 百度座標系->火星座標系
      T.ub 百度墨卡託座標系 - > 百度座標系
      T.tb 百度座標系-> 百度墨卡託座標系
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章