Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/455.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 平滑GPS跟踪路线坐标_Javascript_Google Maps_Polyline_Geography - Fatal编程技术网

Javascript 平滑GPS跟踪路线坐标

Javascript 平滑GPS跟踪路线坐标,javascript,google-maps,polyline,geography,Javascript,Google Maps,Polyline,Geography,我有一些我记录的坐标数据。不幸的是,他们似乎不是很好。他们有时跳过地图。因此,现在我正在寻找一些使路线看起来更真实的平坦或过滤算法 目前,我唯一的过滤器是计算在一秒钟内行驶的最大可能米数(在公共汽车、汽车或步行中),并将其与坐标进行比较,丢弃那些在时间范围内不可能实现的坐标。因此,如果一个人能在一秒钟内走到2.5米,我有两个相互距离10米的coords,它们在两秒钟内被记录下来,我试着找到它们并扔掉。这有点帮助 代码如下: filters.max_possible_travel = functi

我有一些我记录的坐标数据。不幸的是,他们似乎不是很好。他们有时跳过地图。因此,现在我正在寻找一些使路线看起来更真实的平坦或过滤算法

目前,我唯一的过滤器是计算在一秒钟内行驶的最大可能米数(在公共汽车、汽车或步行中),并将其与坐标进行比较,丢弃那些在时间范围内不可能实现的坐标。因此,如果一个人能在一秒钟内走到2.5米,我有两个相互距离10米的coords,它们在两秒钟内被记录下来,我试着找到它们并扔掉。这有点帮助

代码如下:

filters.max_possible_travel = function(data) {
    //http://en.wikipedia.org/wiki/Preferred_walking_speed
    //I switched to 16, as the route was made by driving with a bus...
    var maxMetersPerSec = 16,
        i, m, last, result = [];

    for(i=0;i<data.length;i++) {
        m = data[i];
        if (last) {
            // seconds between current and last coord
            var diff = (m.created.getTime() - last.created.getTime()) / 1000;
            // the maximum amount of meters a person,bus,car etc can make per sec.
            var maxDistance = diff * maxMetersPerSec;
            // the actual distance traveled
            var traveledDistance = google.maps.geometry.spherical.computeDistanceBetween(last.googLatLng, m.googLatLng);

            if (traveledDistance > maxDistance) {
                continue;
            } else {
                result.push(m);
            }
        }
        last = m;
    }
    return result;
};
filters.max\u可能的行程=功能(数据){
//http://en.wikipedia.org/wiki/Preferred_walking_speed
//我换成了16路,因为路线是由一辆公交车决定的。。。
var MaxMeterPersec=16,
i、 m,last,result=[];
对于(i=0;i最大距离){
继续;
}否则{
结果:推力(m);
}
}
last=m;
}
返回结果;
};
为了让事情变得更简单,我创建了这个fiddle,它已经实现了我的第一个过滤器,还提供了添加新过滤器的功能

我还有一些更进一步的想法:

  • 扔掉特定半径内的所有坐标。这最终会消除一些令人不安的协调,如果你只是站在周围几分钟
  • 将所有坐标按n秒帧分组,并尝试确定此块中最相关的坐标。不幸的是,我不知道如何:(
所以我认为这是一个非常有趣的问题,我希望你们理解我所说的一切。我感谢你们的帮助

编辑:我发现了一些关于线性最小二乘法和卡尔曼滤波的知识。我很喜欢它,但因为我绝对不是数学专家,我希望在这方面能得到任何帮助

编辑2 进度:)我实现了@geocodezip向我推广的DouglasPeucker算法。单靠算法并不能解决所有问题,但结合我目前的“最大可能行程”,它看起来几乎完美无瑕。如果我和第二个参数玩一点,它会变得有趣。请查看新的小提琴,确保您同时检查了“walkfilter”和“gdouglaspeucker”两个过滤器。 您可以试试

Ramer–Douglas–Peucker算法是一种减少曲线中由一系列点近似的点数量的算法

至少有

Javascript实现代码来自:

/*基于堆栈的Douglas Peucker线简化例程
返回的是一个简化的google.maps.LatLng数组
在Gary J.Robinson博士编写代码之后,
环境系统科学中心,
雷丁大学,雷丁,英国
*/
函数GDouglasPeucker(源,扭结)
/*source[]在google.maps.LatLngs中输入坐标*/
/*扭结以米为单位,超过此深度的扭结保持不变*/
/*扭结深度是三角形abc的高度,其中a-b和b-c是两条连续线段*/
{
变量n_源、n_堆栈、n_目的、开始、结束、i、sig;
var dev_sqr、max dev_sqr、band_sqr;
变量x12、y12、d12、x13、y13、d13、x23、y23、d23;
var F=((数学PI/180.0)*0.5);
var index=new Array();/*要包含在缩减行中的源点索引的数组*/
var sig_start=new Array();/*工作段开始和结束的索引*/
var sig_end=新数组();
/*检查简单的案例*/
如果(震源长度<3)
返回(源);/*一个或两个点*/
/*更复杂的情况。初始化堆栈*/
n_source=source.length;
band_sqr=扭结*360.0/(2.0*Math.PI*6378137.0);/*现在以度为单位*/
band_sqr*=band_sqr;
n_dest=0;
sig_start[0]=0;
sig_end[0]=n_源-1;
n_堆栈=1;
/*虽然堆栈不是空的*/
而(n_堆栈>0){
/*…从堆栈中弹出最上面的条目*/
start=sig_start[n_stack-1];
end=sig_end[n_stack-1];
n_堆栈--;
如果((结束-开始)>1){/*任何中间点?*/
/*…是的,所以找到最不正常的中间点
连接起点和终点的线的任一侧*/
x12=(源[end].lng()-source[start].lng());
y12=(源[end].lat()-source[start].lat());
如果(数学abs(x12)>180.0)
x12=360.0-数学abs(x12);
x12*=Math.cos(F*(source[end].lat()+source[start].lat());/*使用平均lat减少lng*/
d12=(x12*x12)+(y12*y12);
对于(i=start+1,sig=start,max_dev_sqr=-1.0;i180.0)
x13=360.0-数学abs(x13);
x13*=Math.cos(F*(源[i].lat()+源[start].lat());
d13=(x13*x13)+(y13*y13);
x23=(源[i].lng()-源[end].lng());
y23=(源[i].lat()-source[end].lat());
如果(数学绝对值(x23)>180.0)
x23=360.0-数学绝对值(x23);
x23*=Math.cos(F*(源[i].lat()+源[end].lat());
d23=(x23*x23)+(y23*y23);
如果(d13>=(d12+d23))
dev_sqr=d23;
否则如果(d23>=(d12+d13))
dev_sqr=d13;
其他的
dev_sqr=(x13*y12-y13*x12)*(x13*y12-y13*x12)/d12;//求解三角形
如果(开发sqr>最大开发sqr){
sig=i;
/* Stack-based Douglas Peucker line simplification routine 
   returned is a reduced google.maps.LatLng array 
   After code by  Dr. Gary J. Robinson,
   Environmental Systems Science Centre,
   University of Reading, Reading, UK
*/

function GDouglasPeucker (source, kink)
/* source[] Input coordinates in google.maps.LatLngs    */
/* kink in metres, kinks above this depth kept  */
/* kink depth is the height of the triangle abc where a-b and b-c are two consecutive line segments */
{
    var n_source, n_stack, n_dest, start, end, i, sig;    
    var dev_sqr, max_dev_sqr, band_sqr;
    var x12, y12, d12, x13, y13, d13, x23, y23, d23;
    var F = ((Math.PI / 180.0) * 0.5 );
    var index = new Array(); /* aray of indexes of source points to include in the reduced line */
    var sig_start = new Array(); /* indices of start & end of working section */
    var sig_end = new Array();  

    /* check for simple cases */

    if ( source.length < 3 ) 
        return(source);    /* one or two points */

    /* more complex case. initialize stack */

    n_source = source.length;
    band_sqr = kink * 360.0 / (2.0 * Math.PI * 6378137.0);  /* Now in degrees */
    band_sqr *= band_sqr;
    n_dest = 0;
    sig_start[0] = 0;
    sig_end[0] = n_source-1;
    n_stack = 1;

    /* while the stack is not empty  ... */
    while ( n_stack > 0 ){

        /* ... pop the top-most entries off the stacks */

        start = sig_start[n_stack-1];
        end = sig_end[n_stack-1];
        n_stack--;

        if ( (end - start) > 1 ){  /* any intermediate points ? */        

                /* ... yes, so find most deviant intermediate point to
                       either side of line joining start & end points */                                   

            x12 = (source[end].lng() - source[start].lng());
            y12 = (source[end].lat() - source[start].lat());
            if (Math.abs(x12) > 180.0) 
                x12 = 360.0 - Math.abs(x12);
            x12 *= Math.cos(F * (source[end].lat() + source[start].lat()));/* use avg lat to reduce lng */
            d12 = (x12*x12) + (y12*y12);

            for ( i = start + 1, sig = start, max_dev_sqr = -1.0; i < end; i++ ){                                    

                x13 = (source[i].lng() - source[start].lng());
                y13 = (source[i].lat() - source[start].lat());
                if (Math.abs(x13) > 180.0) 
                    x13 = 360.0 - Math.abs(x13);
                x13 *= Math.cos (F * (source[i].lat() + source[start].lat()));
                d13 = (x13*x13) + (y13*y13);

                x23 = (source[i].lng() - source[end].lng());
                y23 = (source[i].lat() - source[end].lat());
                if (Math.abs(x23) > 180.0) 
                    x23 = 360.0 - Math.abs(x23);
                x23 *= Math.cos(F * (source[i].lat() + source[end].lat()));
                d23 = (x23*x23) + (y23*y23);

                if ( d13 >= ( d12 + d23 ) )
                    dev_sqr = d23;
                else if ( d23 >= ( d12 + d13 ) )
                    dev_sqr = d13;
                else
                    dev_sqr = (x13 * y12 - y13 * x12) * (x13 * y12 - y13 * x12) / d12;// solve triangle

                if ( dev_sqr > max_dev_sqr  ){
                    sig = i;
                    max_dev_sqr = dev_sqr;
                }
            }

            if ( max_dev_sqr < band_sqr ){   /* is there a sig. intermediate point ? */
                /* ... no, so transfer current start point */
                index[n_dest] = start;
                n_dest++;
            }
            else{
                /* ... yes, so push two sub-sections on stack for further processing */
                n_stack++;
                sig_start[n_stack-1] = sig;
                sig_end[n_stack-1] = end;
                n_stack++;
                sig_start[n_stack-1] = start;
                sig_end[n_stack-1] = sig;
            }
        }
        else{
                /* ... no intermediate points, so transfer current start point */
                index[n_dest] = start;
                n_dest++;
        }
    }

    /* transfer last point */
    index[n_dest] = n_source-1;
    n_dest++;

    /* make return array */
    var r = new Array();
    for(var i=0; i < n_dest; i++)
        r.push(source[index[i]]);
    return r;

}