(原创:小牙,QQ328959,转载请注明出处)
从GPS设备取得真实坐标,转换为火星坐标(你懂得的),是比较头疼的一件事。
比较主流的办法是根据纠偏数据(0.1级,0.01级)进行纠偏:通过选取与要校正的真实坐标最接近的点的偏移数据,加到真实坐标上,得到纠正后的火星坐标。
这种方法受纠偏数据精度影响,当真实坐标离纠偏点比较远时,偏差很大,并且由于纠偏数据不连续,导致一组连续的坐标纠偏后,有比较明显的锯齿。
从实际应用效果来看,采用0.1的纠偏数据,数据量比较小,大概1M多,但偏差大,锯齿明显;采用0.01的纠偏,已经比较精确,但数据量较大,大概40~50M,并且在17级仍有锯齿感。(对0.01的纠偏数据,boboking通过实际的道路测试,证明已经比较精确,在17级,轨迹基本在路上,没有明显的偏差,但仍有少量锯齿感)。
如果想用比较少量的纠偏数据,比如0.1,又想完美消除锯齿感,则必须采取插值算法,对纠偏数据进行再处理。对此,我前两天实现了一个算法,通过实际的道路测试,已经完美拟合火星坐标,并且消除了锯齿。方法如下:
前提:我们假设在o.1精度下,临近的四个纠偏点之内,火星偏移是比较接近平整的倾斜面,没有明显的抖动。
基本思路:根据真实坐标点与四个纠偏点的距离,计算四个点纠偏数据对真实坐标点纠偏数据(结果)的影响系数,再对四个点的纠偏数据乘以该影响系数后加权得到纠偏结果。
其中某个纠偏点的纠偏数据对结果的影响系数为该点对角区域的面积。比如对于纠偏点3,它的影响系数为图中阴影区域的面积。
对于纬度偏移,将4个纠偏的纬度偏移分别乘以其影响系数后,再相加后即可得到。经度偏移按同样方法计算。
实现步骤:
第一步,根据真实坐标、纠偏数据精度,通过上取整、下取整,取得4个纠偏点的坐标(x0,y0),(x1,y1),(x2,y2),(x3,y3);
第二步,根据纠偏点坐标取得纠偏数据m0(lat,lng),m1(lat,lng),m2(lat,lng),m3(lat,lng);
第三步,根据真实坐标与四个纠偏点的坐标计算分别计算影响系数,得到coef0,coef1,coef2,coef3;
第四步,计算纠偏偏移量结果。
marsOffset.lat=m0.lat*coef0+m1.lat*coef1+m2.lat*coef2+m3.lat*coef3;
marsOffset.lng=m0.lng*coef0+m1.lng*coef1+m2.lng*coef2+m3.lng*coef3;
第五步,把该结果的经纬度偏移加到真实坐标上,即可得到对应的非常精确的火星坐标。
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel.Composition;
using System.Globalization;
using System.Windows;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Prism.Events;
using SmartClient.Infrastructure;
using SmartClient.Infrastructure.Models;
using SmartClient.Modules.GPS.Comm;
using System.Windows.Resources;
namespace SmartClient.Modules.GPS
{
[Export(typeof(IRegulateService))]
[PartCreationPolicy(CreationPolicy.Shared)]
class RegulateService : IRegulateService
{
private const int REGULATE_ZOOM_COEF = 1000000; //经纬度放大系数,为了将校正数据的小数点部分换算成整数。0.1精度时为1000000
private int _stepNum = 1; //经纬度校正表,精度系数(0.1精度时) = 0.1 * MapRegBig * ExpLong
private int _expLong = 10; //经纬度放大系数,为了将校正表格点的小数点部分换算成整数。0.1精度时为10
private int _minX = 0;
private int _maxX = 0;
private int _minY = 0;
private int _maxY = 0;
private BinaryReader _regulateReader;
[ImportingConstructor]
public RegulateService()
{
StreamResourceInfo resourceInfo = Application.GetResourceStream(new Uri("/data/Regulate.dat", UriKind.Relative));
Byte[] regulateByte = null;
using (BinaryReader reader = new BinaryReader(resourceInfo.Stream))
{
regulateByte = reader.ReadBytes((Int32)resourceInfo.Stream.Length);
}
MemoryStream stream = new MemoryStream(regulateByte);
this._regulateReader = new BinaryReader(stream);
resourceInfo.Stream.Close();
_regulateReader.BaseStream.Position = 0;
_minX = ********;//此处涉及boboking的纠偏数据索引方法,不便提供
_maxX = ********;
_minY = ********;
_maxY = ********;
}
public MarsOffset getMarsOffset(Position position)
{
double latConvert = position.Latitude.DecimalDegrees * _expLong;
double lngConvert = position.Longitude.DecimalDegrees * _expLong;
//计算该真实坐标点四周的纠偏点坐标(上取整,下取整)
int x0 = (int)Math.Floor(latConvert), y0 = (int)Math.Floor(lngConvert);
int x1 = (int)Math.Floor(latConvert), y1 = (int)Math.Ceiling(lngConvert);
int x2 = (int)Math.Ceiling(latConvert), y2 = (int)Math.Ceiling(lngConvert);
int x3 = (int)Math.Ceiling(latConvert), y3 = (int)Math.Floor(lngConvert);
if(x0 < _minX || x1 > _maxX || y0 < _minY || y1 > _maxY)
return new MarsOffset(0.0, 0.0);
//根据四个周边点的取整(已放大),读取纠偏数据
MarsOffset mo0 = getRegulateData(x0, y0);
MarsOffset mo1 = getRegulateData(x1, y1);
MarsOffset mo2 = getRegulateData(x2, y2);
MarsOffset mo3 = getRegulateData(x3, y3);
//计算纠偏点影响系数
double coef0 = (x2 - latConvert) * (y2 - lngConvert);
double coef1 = (x3 - latConvert) * (lngConvert - y3);
double coef2 = (latConvert - x0) * (lngConvert - y0);
double coef3 = (latConvert - x1) * (y1 - lngConvert);
MarsOffset marsOffset = new MarsOffset();
marsOffset.latOffset = mo0.latOffset * coef0 + mo1.latOffset * coef1 + mo2.latOffset * coef2 + mo3.latOffset * coef3;
marsOffset.lngOffset = mo0.lngOffset * coef0 + mo1.lngOffset * coef1 + mo2.lngOffset * coef2 + mo3.lngOffset * coef3;
return marsOffset;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SmartClient.Infrastructure.Models
{
public struct MarsOffset
{
public double latOffset;
public double lngOffset;
public MarsOffset(double lat, double lng)
{
this.latOffset = lat;
this.lngOffset = lng;
}
}
}
以上方法在上地周边几公里进行实际的道路测试,拟合非常完美和平滑。
(声明:本人无意破解任何算法,只是为美化显示效果做了以上工作,如您采用以上算法涉及任何法律问题,本人不承担相关责任。)