2021-04-26 道格拉斯算法(Douglas)稀释地图轨迹上的点

道格拉斯算法简介

道格拉斯-普克算法(Douglas–Peucker algorithm,亦称为拉默-道格拉斯-普克算法、迭代适应点算法、分裂与合并算法)是将曲线近似表示为一系列点,并减少点的数量的一种算法。它的优点是具有平移和旋转不变性,给定曲线与阈值后,抽样结果一定。

算法思想

算法的基本思路是:对每一条曲线的首末点虚连一条直线,求所有点与直线的距离,并找出最大距离值dmax ,用dmax与限差D相比:若dmax

应用场景

最近有需求是 页面展示某物体的运动轨迹,但是在数据库中存入了这个物体的运动轨迹,但是存入的点太多,有上万个,担心前段地图展示会比较卡。所以需要java 后端 来对运动轨迹的点来做一下抽稀。此时就比较适合考虑道格拉斯算法来对轨迹的点进行处理了.

代码实现
//地图点实体类  get,set方法 以及其他不重要的字段已省略.
public class Point{
	private double lng;
	private double lat;
}
//douglas算法实现类
public class DouglasUtils{

	//定义允许点的最大偏差距离
	public static final double max = 1f;
	
	//利用三角形的勾股定理来求两点的距离
	public static double calDistance(Point p1,Point p2){
		double a = Math.round( (p2.getLng()-p1.getLng() )*100000);//求经度方向的距离差,同一纬度,经度每差一度,距离差大约 110000米
		double b = Math.round( (p2.getLat()-p1.getLat() )*111320);//求纬度方向的距离差,同一经度,纬度每差一度,距离大约差100000米
		return Math.sqrt(Math.pow(a,2) + Math.pow(b,2) );
	}
	
	//计算点到直线的距离,将点和线的起点终点来看成为三角形,求点到直线的距离,就是求点到这条线的高, 来利用海伦公式利用三边长来求出面积,在利用面积和底边长来求出高
	public static double calPointToLine(Point start,Point end,Point target){
		//求三边长
		double a = calDistance(target,start);
		double b = calDistance(target,end);
		double c = calDistance(start,end);
		double p = (a + b + c)/2.0;
		//求出三角形面积
		double s = Math.sqrt(Math.abs( p*(p-a)*(p-b)*(p-c) ));
		return s*2.0/c;
	}
	//递归方法实现轨迹点压缩
	public static void compressLine(List<Point> points,int start,int end,List<Point> resList){
		Point startPoint = points.get(start);
		Point endPoint = points.get(end);
		double maxDistance = 0;
		int index = 0;
		//遍历出离线距离最大的点
		for(int i=start;i<=end;i++){
			double currDistance = calPointToLine(startPoint,points.get(),points.get(i));
			if(currDistance>maxDistance){
				maxDistance = currDistance;
				index = i;
			}
		}
		//如果离线最大距离 没有超过了我们设置的最大偏移距离,就再以这个点为界限,分成两段,再分别去递归查询,并且要把这个点添加到存放压缩点的resList
		//添加元素一定要在递归该点之前的路线之后添加,这样可以保证点的相对顺序不会变,否则点会顺序不对,在地图上连线是有问题的
		if(maxDistance>max && index!=0){
			compressLine(points,start,index-1,resList);
			if(!resList.contains(points.get(index))){
				resList.add(points.get(index));
			}
			compressLine(points,index+1,end-1,resList);
		}
	}

	//获取压缩点的结果的方法,要想用道格拉斯算法抽稀点就可以调用此方法,传入点的集合即可.
	public static List<Point> getCompressList(List<Point> list){
		//存放压缩后点的集合
		List<Point> resList = new ArrayList<>();
		if(list.isEmpty()){
			return resList;
		}
		compressLine(list,0,list.size()-1,resList);
		return resList;
		
	}
}

经纬度丢失计算距离

1.纬度相同,经度不同
在纬度相同的情况下:
经度每隔0.00001度,距离相差约1米;
每隔0.0001度,距离相差约10米;
每隔0.001度,距离相差约100米;
每隔0.01度,距离相差约1000米;
每隔0.1度,距离相差约10000米。
2.经度相同,纬度不同
纬度每隔0.00001度,距离相差约1.1米;
每隔0.0001度,距离相差约11米;
每隔0.001度,距离相差约111米;
每隔0.01度,距离相差约1113米;
每隔0.1度,距离相差约11132米。

你可能感兴趣的:(java后端,#,百度地图,java,道格拉斯算法)