轨迹中的驻留点计算
最近根据业务需要,编写了一个小的算法,用于从设备的轨迹中提取出设备的驻留点。其中关于时间的验证,使用了上一篇文章中的时间工具js,设备的轨迹是用一个点数组来表示的,驻留点也是一个点的数组。
function checkDistance(pointArrayBeforenowPoint,nowPoint,stayDistance){
var pf=pointArrayBeforenowPoint;
if(pf.length==1){
return 1;//代表此点是第二个点,可以直接返回ture
}else{
for(var i=0;i<pf.length;i++){
var distance=getDistanceBetween(pf[i],nowPoint);
if(distance<5){//误差距离,在此处默认为5m,也就说说,5米范围内的点可以作为另外一个点的误差点,而不需要额外计算。
return 2;//代表此点可忽略
}else{
if(distance<(stayDistance*2)){
continue;
}else{
return 0;//代表此点不符合距离要求,驻留点序列断裂
}
}
}
return 1;//符合要求的主流点被加入。
}
}
function checkTime(stayPointSet,stayTime){
var lastIndex=stayPointSet.length-1;
var startPointSetTime=getDateFromformatString(stayPointSet[0].createtime,"YYYY-MM-DD hh:mm:ss.S");
var endPointSetTime=getDateFromformatString(stayPointSet[lastIndex].createtime,"YYYY-MM-DD hh:mm:ss.S");
var howLong = endPointSetTime.minusDate(startPointSetTime);
if(howLong>=stayTime){
return true;
}else{
return false;
}
}
function getStayPoints(stayPointSetsArray){
var stayPoints = new Array();
for(var i=0;i<stayPointSetsArray.length;i++){
var stayPointsInfo=new Array();
var sumX=0,sumY=0,averageX=0,averageY=0,n=0;
var setLength=stayPointSetsArray[i].length;
for(var j=0;j<setLength;j++){
if(j==0){
stayPointsInfo.startTime=stayPointSetsArray[i][j].createtime;
}else if(j==setLength-1){
stayPointsInfo.endTime=stayPointSetsArray[i][j].createtime;
}
sumX+=stayPointSetsArray[i][j].x;
sumY+=stayPointSetsArray[i][j].y;
n+=1;
}
averageX=sumX/n;
averageY=sumY/n;
stayPointsInfo.point=new EzCoord(averageX,averageY);
stayPoints.push(stayPointsInfo);
}
return stayPoints;
}
function getDistanceBetween(point1,point2){
var pos1 = new EzCoord(point1.x,point1.y);
var pos2 = new EzCoord(point2.x,point2.y);
return pos1.distanceTo(pos2);
}
/**
* 创建定位点序列类
*/
function PositionList(PositionList){
this.positionList=PositionList;
}
/**
* 根据传入的驻留时间和驻留距离,计算出整个轨迹序列点钟的所有驻留点。返回一个EzCoord型数据组成的数组。
* @param stayTime 最短驻留时间,低于这个时间的驻留,不被定义为驻留点,默认30min
* @param stayDistance 驻留距离,驻留期间,所有定位点的位置都分布在一个以“驻留距离”为半径的圆内部(在圆弧上的点不在圆的内部)。
* 默认50m(不包括50m,半径50m,直径则为100m)。
* @returns stayPoints array
* @author yin_zhida
*/
PositionList.prototype.getStayPoints=function(stayTime,stayDistance){
if(stayTime==undefined||stayTime==null){
stayTime=1000*60*30;//单位毫秒
}
if(stayDistance==undefined||stayDistance==null){
stayDistance=50;//单位M
}
var _positionArray=this.positionList;
var stayPointSetsArray=new Array();
for(var i=0;i<_positionArray.length;i++){
var checkPointSet=new Array();
var stayPointSet=new Array();
var nowPoint=_positionArray[i];
var nextPoint=null;
var nextDistance=null;
if(i<(_positionArray.length-1)){
var nexti=i+1;
nextPoint=_positionArray[nexti];
}
if(nextPoint!=null){
nextDistance=getDistanceBetween(nowPoint,nextPoint);
}
if(nextDistance!=null&&nextDistance<(stayDistance*2)){
stayPointSet.push(_positionArray[i]);
checkPointSet.push(_positionArray[i]);
var nextI=i+1;
for(var j=nextI;j<_positionArray.length;j++){
var jPoint=_positionArray[j];
var jprePoint=null;
var jpreDistance=null;
var prej=j-1;
jprePoint=_positionArray[prej];
jpreDistance=getDistanceBetween(jPoint,jprePoint);
if(jpreDistance!=null&&jpreDistance<(stayDistance*2)){
var chk = checkDistance(checkPointSet,jPoint,stayDistance);
if(chk==0){
i=j-1;
break;
}else if(chk==1){
stayPointSet.push(_positionArray[j]);
checkPointSet.push(_positionArray[j]);
}else if(chk==2){
stayPointSet.push(_positionArray[j]);
}
}else{
i=j-1;
break;
}
}
}
if(stayPointSet.length>1&&checkTime(stayPointSet,stayTime)){
stayPointSetsArray.push(stayPointSet);
}
}
return getStayPoints(stayPointSetsArray);
};
代码相关的注释写的很清楚,其中 new EzCoord(x,y)是笔者所使用的地图接口创建“地图点”类的方法,通过该类自带的distanceTo方法计算两点之间的距离。
该算法需要传递两个参数,一个是驻留距离,一个是驻留的最短时间,也就是说,一个设备在最短驻留时间内移动的距离小于驻留距离那么这个设备在此期间就被定义为驻留点了。
最后算法中还内定了一个误差的默认值(5),代表了如果一个设备的定位点有5m的误差,在5m内的移动将被忽略,这样做将某台设备在一段时间内没有移动的情况进行了简单的过滤处理,很大程度的提升了算法的效率。
代码如有需要提升的地方,还望大家指正,或者您有什么好的提议也可以拿来与我讨论。
原创文章,转载请说明出处。