当我们处理gps设备传过来的数据时,最让人头疼的事情莫过于设备定位异常所传输的异常点了,我们习惯的叫它为飘点。这些数据是设备层面的异常,目前没有什么有效的方法来减少设备发送的飘点。但是我们可以通过程序来过滤掉这些点。
原理
- 获取时间范围内(默认一天)设备的连续gps信息。
- 遍历这些信息,计算两个相邻点的距离,这个距离要根据实际情况确定
- 若距离大于可容忍距离。则证明该两个相邻点其中有一个点异常
- 根据3的原理,我们将正常的轨迹通过异常点切分为若干个小的轨迹(d1,d2,d3)
- 找出若干个小轨迹分段中最常的一个将其视为合法轨迹(这里如果合法轨迹都是飘点,那使用的设备也没啥使用的意义了)
- 将5找出的合法轨迹的起始点和结束点均作为起点,向整条轨迹的两侧遍历,计算两点之间的距离,若距离大于可容忍距离,则过滤该点。
图示
代码
/**
*获得合法轨迹的list起止下标
*计算两点距离的工具类(LocationConvertUtils)自行百度
*实体中用到的信息就是经纬度和时间,我这里时间用的是毫秒的时间戳
*/
private String getSafeIndex(List<CarriskAlarmVO> gpsList){
int start=0;
int end=0;
List<String> indexList = new ArrayList<>();
CarriskAlarmVO dangerBefore = null;
for(int i=1;i<gpsList.size();i++){
CarriskAlarmVO dangerVo = gpsList.get(i);
if(dangerBefore == null){
dangerBefore = gpsList.get(i-1);
}
double disKM = LocationConvertUtils.getGPSDistanceKM(dangerVo.getGpslng(),dangerVo.getGpslat(),dangerBefore.getGpslng(),dangerBefore.getGpslat());
long time = Math.abs(dangerVo.getGpsts()-dangerBefore.getGpsts());
double speed = disKM*1000*3600/time;
if(speed>200){
if(end>start){
indexList.add(end+"-"+start);
}
start=i;
}
end =i;
dangerBefore = dangerVo;
}
if(end>start){
indexList.add(end+"-"+start);
}
int maxIndx = 0;
int max = 0;
for(int i=0;i<indexList.size();i++){
int tmpEnd = Integer.valueOf(indexList.get(i).split("-")[0]);
int tmpStart = Integer.valueOf(indexList.get(i).split("-")[1]);
if(tmpEnd-tmpStart>max){
max = tmpEnd-tmpStart;
maxIndx = i;
}
}
return indexList.get(maxIndx);
}
找出飘点
private void removeErrorPoint( List<CarriskAlarmVO> gpsList){
String safeInxs = getSafeIndex(gpsList);
int startIndex = Integer.valueOf(safeInxs.split("-")[1]);
int endIndex = Integer.valueOf(safeInxs.split("-")[0]);
if(startIndex==0 && endIndex==gpsList.size()-1){
return;//轨迹正常
}
List<String> deleteList = new ArrayList<>();
CarriskAlarmVO safeVo = gpsList.get(startIndex);
for(int i=startIndex-1;i>-1;i--){
CarriskAlarmVO dangerVo = gpsList.get(i);
double disKM = LocationConvertUtils.getGPSDistanceKM(dangerVo.getGpslng(),dangerVo.getGpslat(),safeVo.getGpslng(),safeVo.getGpslat());
long time = Math.abs(dangerVo.getGpsts()-safeVo.getGpsts());
double speed = disKM*1000*3600/time;
if(speed>200){
deleteList.add(dangerVo.getId());
}else{
safeVo = dangerVo;
}
}
safeVo = gpsList.get(endIndex);
for(int i = endIndex+1;i<gpsList.size();i++){
CarriskAlarmVO dangerVo = gpsList.get(i);
double disKM = LocationConvertUtils.getGPSDistanceKM(dangerVo.getGpslng(),dangerVo.getGpslat(),safeVo.getGpslng(),safeVo.getGpslat());
long time = Math.abs(dangerVo.getGpsts()-safeVo.getGpsts());
double speed = disKM*1000*3600/time;
if(speed>200){
deleteList.add(dangerVo.getId());
}else{
safeVo = dangerVo;
}
}
if(!deleteList.isEmpty()){
//TODO 对飘点自行处理
}
}