最近根据业务须要,编写了一个小的算法,用于从设备的轨迹中提取出设备的驻留点。其中关于时间的验证,使用了上一篇文章中的时间工具js,设备的轨迹是用一个点数组来表示的,驻留点也是一个点的数组。javascript
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方法计算两点之间的距离。
该算法须要传递两个参数,一个是驻留距离,一个是驻留的最短期,也就是说,一个设备在最短驻留时间内移动的距离小于驻留距离那么这个设备在此期间就被定义为驻留点了。java
最后算法中还内定了一个偏差的默认值(5),表明了若是一个设备的定位点有5m的偏差,在5m内的移动将被忽略,这样作将某台设备在一段时间内没有移动的状况进行了简单的过滤处理,很大程度的提高了算法的效率。算法
代码若有须要提高的地方,还望你们指正,或者您有什么好的提议也能够拿来与我讨论。数组
原创文章,转载请说明出处。
工具