我记录了一些坐标数据。不幸的是,他们似乎并不是真的很好。他们有时会跳过地图。所以现在我正在寻找一些平整或过滤算法,使路线看起来更逼真。
目前我唯一的过滤器是计算一秒钟内(在公共汽车或汽车或步行中)行走的最大可能米数,并将它们与坐标进行比较,将这些坐标丢弃,这在时间范围内是不可能的。因此,如果一个人可以在一秒钟内行走2.5米,并且我有两个距离彼此相距10米的坐标,并且它们在两秒钟内被记录下来,我试图找到它们并将它们扔掉。这有点帮助。
这是代码:
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;
};
为了让您更轻松,我创建了这个小提琴,它已经实现了我的第一个过滤器,并且还可以添加新的过滤器。
我有一些进一步的想法:
所以我认为这是一个真正令人讨厌的问题,我希望你能理解我所谈论的一切。我感谢你们的帮助!
编辑:我发现了一些关于线性最小二乘和卡尔曼滤波器的信息。虽然因为我绝对不是数学专家,但我很感激。在这方面我会感激不尽。
编辑2 进展:)我实现了@geocodezip提升给我的DouglasPeucker算法。单独的算法并没有解决所有问题,但是我现在的“max_possible_travel”的组合看起来几乎是完美的。如果我与第二个参数玩一点点就会变得非常有用。请查看新的小提琴,并确保检查过滤器“walkfilter”和“gdouglaspeucker”。 http://jsfiddle.net/z4hB7/8/
答案 0 :(得分:10)
Ramer-Douglas-Peucker算法是一种用于减少曲线中由一系列点近似的点数的算法。
至少有one implementation for the Google Maps API v3
来自Bill Chadwick's site的Javascript实施代码:
/* 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;
}