最近根據業務須要,編寫了一個小的算法,用於從設備的軌跡中提取出設備的駐留點。其中關於時間的驗證,使用了上一篇文章中的時間工具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內的移動將被忽略,這樣作將某臺設備在一段時間內沒有移動的狀況進行了簡單的過濾處理,很大程度的提高了算法的效率。算法
代碼若有須要提高的地方,還望你們指正,或者您有什麼好的提議也能夠拿來與我討論。數組
原創文章,轉載請說明出處。
工具