自學(xué)HarmonyOS應(yīng)用開發(fā)(54)- 校正定位偏差

上一篇文章已經(jīng)介紹了如果獲取當(dāng)前所在位置的方法,這種方法存在一個(gè)問題:和實(shí)際位置之前存在500米左右的偏差。
原因調(diào)查
經(jīng)過一番調(diào)查,結(jié)論是gps信號(hào)使用的是WGS-84坐標(biāo)系,而高德地圖使用的是GCJ-02火星坐標(biāo)系,只有經(jīng)過坐標(biāo)變換才能顯示正確的位置。這方面的文章網(wǎng)上有很多,這里采用以下博客文章中的代碼:
https://www.cnblogs.com/blogger-Li/p/11616835.html
代碼如下:
// 本代碼引用自Hugo_nice下面的博客文章// https://www.cnblogs.com/blogger-Li/p/11616835.htmlpackage xwg.harmony.stopwatch;import java.math.BigDecimal;import java.math.RoundingMode;/*** gps糾偏算法,適用于google,高德體系的地圖*/public abstract class GpsUtil {private final static double a = 6378245.0;private final static double pi = 3.1415926535897932384626;private final static double ee = 0.00669342162296594323;/*** 計(jì)算地球上任意兩點(diǎn)(經(jīng)緯度)距離** @param lat1* 第一點(diǎn)緯度* @param lng1* 第一點(diǎn)經(jīng)度* @param lat2* 第二點(diǎn)緯度* @param lng2* 第二點(diǎn)經(jīng)度* @return 返回距離 單位:米*/public static double distance(double lat1, double lng1, double lat2, double lng2) {double a, b, R;R = 6378137; // 地球半徑lat1 = lat1 * Math.PI / 180.0;lat2 = lat2 * Math.PI / 180.0;a = lat1 - lat2;b = (lng1 - lng2) * Math.PI / 180.0;double d;double sa2, sb2;sa2 = Math.sin(a / 2.0);sb2 = Math.sin(b / 2.0);d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));return d;}/*** Description: WGS-84 to GCJ-02 <BR> ** @author dsn* @date 2017年10月24日 下午2:09:27* @param latitude* 緯度* @param longitude* 經(jīng)度* @return [緯度,經(jīng)度]* @version 1.0*/public static double[] toGCJ02Point(double latitude, double longitude) {double[] dev = calDev(latitude, longitude);double retLat = latitude + dev[0];double retLon = longitude + dev[1];return new double[] { retLat, retLon };}/*** Description: WGS-84 to GCJ-02 <BR> ** @author dsn* @date 2017年10月24日 下午2:09:27* @param latitude* 緯度* @param longitude* 經(jīng)度* @param scale* 經(jīng)緯度保留小數(shù)位數(shù)* @return [緯度,經(jīng)度]* @version 1.0*/public static double[] toGCJ02Point(double latitude, double longitude, int scale) {double[] dev = calDev(latitude, longitude);double retLat = latitude + dev[0];double retLon = longitude + dev[1];return new double[] { new BigDecimal(retLat).setScale(scale, RoundingMode.DOWN).doubleValue(),new BigDecimal(retLon).setScale(scale, RoundingMode.DOWN).doubleValue() };}/*** Description:GCJ-02 to WGS-84 <BR> ** @author dsn* @date 2017年10月24日 下午2:09:54* @param latitude* 緯度* @param longitude* 經(jīng)度* @return [緯度,經(jīng)度]* @version 1.0*/public static double[] toWGS84Point(double latitude, double longitude) {double[] dev = calDev(latitude, longitude);double retLat = latitude - dev[0];double retLon = longitude - dev[1];dev = calDev(retLat, retLon);retLat = latitude - dev[0];retLon = longitude - dev[1];return new double[] { retLat, retLon };}private static double[] calDev(double wgLat, double wgLon) {if (isOutOfChina(wgLat, wgLon)) {return new double[] { 0, 0 };}double dLat = calLat(wgLon - 105.0, wgLat - 35.0);double dLon = calLon(wgLon - 105.0, wgLat - 35.0);double radLat = wgLat / 180.0 * pi;double magic = Math.sin(radLat);magic = 1 - ee * magic * magic;double sqrtMagic = Math.sqrt(magic);dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);return new double[] { dLat, dLon };}private static boolean isOutOfChina(double lat, double lon) {if (lon < 72.004 || lon > 137.8347)return true;if (lat < 0.8293 || lat > 55.8271)return true;return false;}private static double calLat(double x, double y) {double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;return ret;}private static double calLon(double x, double y) {double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;return ret;}}
偏移調(diào)整
public void setLocation(double long_deg, double lat_deg){double ret[] = GpsUtil.toGCJ02Point(lat_deg, long_deg);latitude = ret[0];longitude = ret[1];invalidate();}
在設(shè)定經(jīng)緯度之前,調(diào)用轉(zhuǎn)換方法即可。經(jīng)過轉(zhuǎn)換之后的位置和實(shí)際位置之間的偏差可以在幾十米范圍之內(nèi)。
參考代碼
完整代碼可以從以下鏈接下載:
https://github.com/xueweiguo/Harmony/tree/master/StopWatch
參考資料
GCJ-02火星坐標(biāo)系和WGS-84坐標(biāo)系轉(zhuǎn)換關(guān)系:
https://www.cnblogs.com/blogger-Li/p/11616835.html
獲取設(shè)備的位置信息:
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/device-location-info-0000000000031900
作者著作介紹
《實(shí)戰(zhàn)Python設(shè)計(jì)模式》是作者去年3月份出版的技術(shù)書籍,該書利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過可執(zhí)行的示例對(duì)23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說明。這樣一方面可以使讀者了解真實(shí)的軟件開發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場景和想要解決的問題;另一方面通過對(duì)這些問題的解決過程進(jìn)行說明,讓讀者明白在編寫代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。

對(duì)設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過本書可以快速跨越從理解到運(yùn)用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書中的示例作為設(shè)計(jì)和開發(fā)的參考;使用Python 語言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。
覺得本文有幫助?請(qǐng)分享給更多人。
關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_發(fā),面向?qū)ο笏伎迹?/span>
