真实的GPS(WGS84)转化成 GCJ02、BD09坐标

619 阅读5分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

今天公司一个硬件定位的东西;用的是北斗的定位的组件,不得不说定位是真的准确。后面我演示地址就明白。我查了很多资料。发现网上都是千篇一律的如何处理;没有一个实质性答案。我来告诉广大的网友是什么是真正的串口给的 WGS84的坐标转化的出来的GCJ02BD09的坐标。

硬件定位的给的串口的坐标长什么样呢

原始的GPS的坐标长这个样子 纬度:ddmm.mmmmmm,经度:dddmm.mmmmm。 纬度ddmm.mmmmmm(度分)格式;经度:ddmm.mmmmm(度分)格式。这才是真正的# GPS串口数据格式。我这边给一个我硬件返回真实的坐标信息(数据已处理) ("10502.23516 E","3136.57887 N")我这边经过一系列处理转化成啦 火星坐标系;这个是国家规定的名字。自己去测试地址吧。这个也叫 GCJ02 ;把这个地址 放在高德地图坐标拾取上测试。不要用百度地图啊,百度还要转化为一遍高德地图拾取地址

接下来实操。我们串口获取数据为 ddmm.mmmmmm。但是我们要的 是 dd.dddddd形式。我们这边就需要把mm.mmmmmm转化为 dddddd的形式。其实 我们都是知道 进制 是 60;我这边只需要吧 m的部分 除以 60 就没了。我们就是转化为成啦。 但是只是完成了一部分。我们国家的坐标都是加密你懂的。这个实际的位置还是有出入;不准确的。我们这边还要转化。其中GCJ02这个是 火星坐标系 很常用的 高德地图就是用的这个。BD02这个是百度地图的用 他在火星坐标系上加入偏移量;说白了坐标再一次加密了。接下来直接上代码。

GPS的坐标第一次转化为 dd.ddddd
lon := "10502.23516 E"
lat := "3136.57887 N"
fmt.Println("WGS84 to GCJ02")
lonNum, _ := strconv.ParseFloat(lon[:len(lon)-2], 64)
latNum, _ := strconv.ParseFloat(lat[:len(lat)-2], 64)
// 获取 dd 部分
lonD := int(lonNum / 100)
latD := int(latNum / 100)
// 获取 mm 部分
lonM := lonNum - float64(lonD*100)
latM := latNum - float64(latD*100)
// 计算 相加起来
lonF := float64(lonD) + lonM/60
latF := float64(latD) + latM/60
fmt.Println(lonF, latF)
坐标的第二次转化为 其他家 高德地图 和 百度 以及火星坐标系
// WGS84坐标系(dd.dddd形式):即地球坐标系,国际上通用的坐标系。
// GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。Google Maps,高德在用。
// BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。

const (
   XPi    = math.Pi * 3000.0 / 180.0
   OFFSET = 0.00669342162296594323
   AXIS   = 6378245.0
)

// BD09toGCJ02 百度坐标系->火星坐标系
func BD09toGCJ02(lon, lat float64) (float64, float64) {
   x := lon - 0.0065
   y := lat - 0.006

   z := math.Sqrt(x*x+y*y) - 0.00002*math.Sin(y*XPi)
   theta := math.Atan2(y, x) - 0.000003*math.Cos(x*XPi)

   gLon := z * math.Cos(theta)
   gLat := z * math.Sin(theta)

   return gLon, gLat
}

// GCJ02toBD09 火星坐标系->百度坐标系
func GCJ02toBD09(lon, lat float64) (float64, float64) {
   z := math.Sqrt(lon*lon+lat*lat) + 0.00002*math.Sin(lat*XPi)
   theta := math.Atan2(lat, lon) + 0.000003*math.Cos(lon*XPi)

   bdLon := z*math.Cos(theta) + 0.0065
   bdLat := z*math.Sin(theta) + 0.006

   return bdLon, bdLat
}

// WGS84toGCJ02 WGS84坐标系(dd.dddd形式)->火星坐标系
func WGS84toGCJ02(lon, lat float64) (float64, float64) {
   if isOutOFChina(lon, lat) {
      return lon, lat
   }

   mgLon, mgLat := delta(lon, lat)

   return mgLon, mgLat
}

// GCJ02toWGS84 火星坐标系->WGS84坐标系(dd.dddd形式)
func GCJ02toWGS84(lon, lat float64) (float64, float64) {
   if isOutOFChina(lon, lat) {
      return lon, lat
   }

   mgLon, mgLat := delta(lon, lat)

   return lon*2 - mgLon, lat*2 - mgLat
}

// BD09toWGS84 百度坐标系->WGS84坐标系(dd.dddd形式)
func BD09toWGS84(lon, lat float64) (float64, float64) {
   lon, lat = BD09toGCJ02(lon, lat)
   return GCJ02toWGS84(lon, lat)
}

// WGS84toBD09 WGS84坐标系(dd.dddd形式)->百度坐标系
func WGS84toBD09(lon, lat float64) (float64, float64) {
   lon, lat = WGS84toGCJ02(lon, lat)
   return GCJ02toBD09(lon, lat)
}

func delta(lon, lat float64) (float64, float64) {
   dlat, dlon := transform(lon-105.0, lat-35.0)
   radlat := lat / 180.0 * math.Pi
   magic := math.Sin(radlat)
   magic = 1 - OFFSET*magic*magic
   sqrtmagic := math.Sqrt(magic)

   dlat = (dlat * 180.0) / ((AXIS * (1 - OFFSET)) / (magic * sqrtmagic) * math.Pi)
   dlon = (dlon * 180.0) / (AXIS / sqrtmagic * math.Cos(radlat) * math.Pi)

   mgLat := lat + dlat
   mgLon := lon + dlon

   return mgLon, mgLat
}
func transform(lon, lat float64) (x, y float64) {
   var lonlat = lon * lat
   var absX = math.Sqrt(math.Abs(lon))
   var lonPi, latPi = lon * math.Pi, lat * math.Pi
   var d = 20.0*math.Sin(6.0*lonPi) + 20.0*math.Sin(2.0*lonPi)
   x, y = d, d
   x += 20.0*math.Sin(latPi) + 40.0*math.Sin(latPi/3.0)
   y += 20.0*math.Sin(lonPi) + 40.0*math.Sin(lonPi/3.0)
   x += 160.0*math.Sin(latPi/12.0) + 320*math.Sin(latPi/30.0)
   y += 150.0*math.Sin(lonPi/12.0) + 300.0*math.Sin(lonPi/30.0)
   x *= 2.0 / 3.0
   y *= 2.0 / 3.0
   x += -100.0 + 2.0*lon + 3.0*lat + 0.2*lat*lat + 0.1*lonlat + 0.2*absX
   y += 300.0 + lon + 2.0*lat + 0.1*lon*lon + 0.1*lonlat + 0.1*absX
   return
}

func isOutOFChina(lon, lat float64) bool {
   return !(lon > 72.004 && lon < 135.05 && lat > 3.86 && lat < 53.55)
}
完整代码
package main

import (
   "fmt"
   "math"
   "strconv"
)

// WGS84坐标系(dd.dddd形式):即地球坐标系,国际上通用的坐标系。
// GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。Google Maps,高德在用。
// BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。

const (
   XPi    = math.Pi * 3000.0 / 180.0
   OFFSET = 0.00669342162296594323
   AXIS   = 6378245.0
)

// BD09toGCJ02 百度坐标系->火星坐标系
func BD09toGCJ02(lon, lat float64) (float64, float64) {
   x := lon - 0.0065
   y := lat - 0.006

   z := math.Sqrt(x*x+y*y) - 0.00002*math.Sin(y*XPi)
   theta := math.Atan2(y, x) - 0.000003*math.Cos(x*XPi)

   gLon := z * math.Cos(theta)
   gLat := z * math.Sin(theta)

   return gLon, gLat
}

// GCJ02toBD09 火星坐标系->百度坐标系
func GCJ02toBD09(lon, lat float64) (float64, float64) {
   z := math.Sqrt(lon*lon+lat*lat) + 0.00002*math.Sin(lat*XPi)
   theta := math.Atan2(lat, lon) + 0.000003*math.Cos(lon*XPi)

   bdLon := z*math.Cos(theta) + 0.0065
   bdLat := z*math.Sin(theta) + 0.006

   return bdLon, bdLat
}

// WGS84toGCJ02 WGS84坐标系(dd.dddd形式)->火星坐标系
func WGS84toGCJ02(lon, lat float64) (float64, float64) {
   if isOutOFChina(lon, lat) {
      return lon, lat
   }

   mgLon, mgLat := delta(lon, lat)

   return mgLon, mgLat
}

// GCJ02toWGS84 火星坐标系->WGS84坐标系(dd.dddd形式)
func GCJ02toWGS84(lon, lat float64) (float64, float64) {
   if isOutOFChina(lon, lat) {
      return lon, lat
   }

   mgLon, mgLat := delta(lon, lat)

   return lon*2 - mgLon, lat*2 - mgLat
}

// BD09toWGS84 百度坐标系->WGS84坐标系(dd.dddd形式)
func BD09toWGS84(lon, lat float64) (float64, float64) {
   lon, lat = BD09toGCJ02(lon, lat)
   return GCJ02toWGS84(lon, lat)
}

// WGS84toBD09 WGS84坐标系(dd.dddd形式)->百度坐标系
func WGS84toBD09(lon, lat float64) (float64, float64) {
   lon, lat = WGS84toGCJ02(lon, lat)
   return GCJ02toBD09(lon, lat)
}

func delta(lon, lat float64) (float64, float64) {
   dlat, dlon := transform(lon-105.0, lat-35.0)
   radlat := lat / 180.0 * math.Pi
   magic := math.Sin(radlat)
   magic = 1 - OFFSET*magic*magic
   sqrtmagic := math.Sqrt(magic)

   dlat = (dlat * 180.0) / ((AXIS * (1 - OFFSET)) / (magic * sqrtmagic) * math.Pi)
   dlon = (dlon * 180.0) / (AXIS / sqrtmagic * math.Cos(radlat) * math.Pi)

   mgLat := lat + dlat
   mgLon := lon + dlon

   return mgLon, mgLat
}
func transform(lon, lat float64) (x, y float64) {
   var lonlat = lon * lat
   var absX = math.Sqrt(math.Abs(lon))
   var lonPi, latPi = lon * math.Pi, lat * math.Pi
   var d = 20.0*math.Sin(6.0*lonPi) + 20.0*math.Sin(2.0*lonPi)
   x, y = d, d
   x += 20.0*math.Sin(latPi) + 40.0*math.Sin(latPi/3.0)
   y += 20.0*math.Sin(lonPi) + 40.0*math.Sin(lonPi/3.0)
   x += 160.0*math.Sin(latPi/12.0) + 320*math.Sin(latPi/30.0)
   y += 150.0*math.Sin(lonPi/12.0) + 300.0*math.Sin(lonPi/30.0)
   x *= 2.0 / 3.0
   y *= 2.0 / 3.0
   x += -100.0 + 2.0*lon + 3.0*lat + 0.2*lat*lat + 0.1*lonlat + 0.2*absX
   y += 300.0 + lon + 2.0*lat + 0.1*lon*lon + 0.1*lonlat + 0.1*absX
   return
}

func isOutOFChina(lon, lat float64) bool {
   return !(lon > 72.004 && lon < 135.05 && lat > 3.86 && lat < 53.55)
}

func main() {
   lon := "10502.23516 E"
   lat := "3136.57887 N"
   lonNum, _ := strconv.ParseFloat(lon[:len(lon)-2], 64)
   latNum, _ := strconv.ParseFloat(lat[:len(lat)-2], 64)
   lonD := int(lonNum / 100)
   latD := int(latNum / 100)
   lonM := lonNum - float64(lonD*100)
   latM := latNum - float64(latD*100)
   lonF := float64(lonD) + lonM/60
   latF := float64(latD) + latM/60
   fmt.Println(lonF, latF)
   fmt.Println("WGS84 to GCJ02")
   lon2, lat2 := WGS84toGCJ02(lonF, latF)
   fmt.Println(lon2, ",", lat2)
}

GitHub地址 github.com/Fluox-Etine…