javascript实现道格拉斯-普克Douglas-Peuker轨迹抽希算法

1、算法概述

道格拉斯-普克算法(Douglas–Peucker algorithm,亦称为拉默-道格拉斯-普克算法迭代适应点算法分裂与合并算法)是将曲线近似表示为一系列点,并减少点的数量的一种算法。该算法的原始类型分别由乌尔斯·拉默(Urs Ramer)于1972年以及大卫·道格拉斯(David Douglas)和托马斯·普克(Thomas Peucker)于1973年提出,并在之后的数十年中由其他学者予以完善。

算法步骤如下图所示:

1、其中曲线0是原始数据,设置阈值距离为5m,开始循环;

2、循环查找距离起始点最远的点c,其距离为b,判断若b<5则直接以起始点连线为结果,否则将曲线以c分成前后2段;

3、分别对前后两段执行迭代步骤2;

4、得到最终结果;

2、算法实现

由之前的距离公式(https://blog.csdn.net/chaoyang89111/article/details/89440855)很容易写出格拉斯-普克的实现代码。

//计算距离
function calculationDistance(point1, point2){
	let lat1 = point1.C_COORDINATEY;
	let lat2 = point2.C_COORDINATEY;
	let lng1 = point1.C_COORDINATEX;
	let lng2 = point2.C_COORDINATEX;
	let radLat1 = lat1 * Math.PI / 180.0;
	let radLat2 = lat2 * Math.PI / 180.0;
	let a = radLat1 - radLat2;
	let b = (lng1 * Math.PI / 180.0) - (lng2 * Math.PI / 180.0);
	let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
		+ Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
	return s * 6370996.81;
};
//计算垂距
function distToSegment(start, end, center){
	//下面用海伦公式计算面积
	let a = Math.abs(calculationDistance(start, end));
	let b = Math.abs(calculationDistance(start, center));
	let c = Math.abs(calculationDistance(end, center));
	let p = (a + b + c) / 2.0;
	let s = Math.sqrt(Math.abs(p * (p - a) * (p - b) * (p - c)));
	return s * 2.0 / a;
};
//递归方式压缩轨迹
function compressLine (coordinate, result, start, end, dMax){
	if (start < end) {
		let maxDist = 0;
		let currentIndex = 0;
		let startPoint = coordinate[start];
		let endPoint = coordinate[end];
		for (let i = start + 1; i < end; i++) {
			let currentDist = distToSegment(startPoint, endPoint, coordinate[i]);
			if (currentDist > maxDist) {
				maxDist = currentDist;
				currentIndex = i;
			}
		}
		if (maxDist >= dMax) {
			//将当前点加入到过滤数组中
			result.push(coordinate[currentIndex]);
			//将原来的线段以当前点为中心拆成两段,分别进行递归处理
			compressLine(coordinate, result, start, currentIndex, dMax);
			compressLine(coordinate, result, currentIndex, end, dMax);
		}
	}
	return result;
};
/**
 *
 *@param coordinate 原始轨迹Array<{latitude,longitude}>
 *@param dMax 允许最大距离误差
 *@return douglasResult 抽稀后的轨迹
 *
 */
function douglasPeucker(coordinate, dMax ){
	if (!coordinate || !(coordinate.length > 2)) {
		return null;
	}
	coordinate.forEach((item, index) => {
		item.key = index;
	});
	let result = compressLine(coordinate, [], 0, coordinate.length - 1, dMax);
	result.push(coordinate[0]);
	result.push(coordinate[coordinate.length - 1]);
	let resultLatLng = result.sort((a, b) => {
		if (a.key < b.key) {
			return -1;
		} else if (a.key > b.key)
			return 1;
		return 0;
	});
	resultLatLng.forEach((item) => {
		item.key = undefined;
	});
	return resultLatLng;
};

3、算法结果 

如下图红色为抽稀后结果,蓝线为原始数据,原始总共2589,处理后还剩313个点,压缩率非常不错 。

猜你喜欢

转载自blog.csdn.net/chaoyang89111/article/details/89456749
今日推荐