本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
今天公司一个硬件定位的东西;用的是北斗的定位的组件,不得不说定位是真的准确。后面我演示地址就明白。我查了很多资料。发现网上都是千篇一律的如何处理;没有一个实质性答案。我来告诉广大的网友是什么是真正的串口给的 WGS84的坐标转化的出来的GCJ02和BD09的坐标。
硬件定位的给的串口的坐标长什么样呢
原始的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)
}