前言
道格拉斯-普克算法 (Douglas–Peucker algorithm,亦称为拉默-道格拉斯-普克算法、迭代适应点算法、分裂与合并算法)是将曲线近似表示为一系列点,并减少点的数量的一种算法。它的优点是具有平移和旋转不变性,给定曲线与阈值后,抽样结果一定。
因为网上关于道格拉斯普克算法的讲解很多,主要是使用递归实现的,这里就不赘述了。
远程仓库地址:
https://github.com/XiaoZhong233/GIS_ALG
直接上代码和演示
//概化折线 道格拉斯普克算法
/**
* 根据中间点到首尾点的连线的距离与阈值的关系判断是否保留某点
* @param threshold 阈值越小,保留的点越多,抽稀程度低;阈值越大,删除的点越多,抽稀程度高
* @return
*/
public Polyline simplify_Douglas_Peucker(double threshold) {
//初始化
for(Point point:this.getPoints()) {
point.setEnable(true);
}
List<Point> selectedPoints = new ArrayList<>();
Collections.addAll(selectedPoints, new Point[this.points.size()]);
Collections.copy(selectedPoints, this.points);
simplify(selectedPoints, threshold);
//标记了删除的点,全部删掉
Iterator<Point> iterator = selectedPoints.iterator();
while (iterator.hasNext()) {
Point point = (Point) iterator.next();
if(!point.isEnable()) {
iterator.remove();
}
}
if(debug) {
System.out.println("最后保留的点:");
for(Point p:selectedPoints) {
System.out.println(p.toString());
}
}
//恢复
for(Point point:this.getPoints()) {
point.setEnable(true);
}
return new Polyline(selectedPoints);
}
/**
*
* @param polyline 折线
* @param threshold 阈值越小,保留的点越多,抽稀程度低;阈值越大,删除的点越多,抽稀程度高
* @return
*/
public static Polyline simplify_Douglas_Peucker(Polyline polyline,double threshold) {
return polyline.simplify_Douglas_Peucker(threshold);
}
//抽稀点
private static void simplify(List<Point> points,double threshold) {
//threshold = Math.abs(threshold);
if(points.size()<3) {
return;
}
Line line = new Line(points.get(0),points.get(points.size()-1));
Point maxPoint = null;
double maxDis = 0;
//System.out.println(points.size());
for(Point point:points) {
double dis = line.getDistancefromPoint(point);
if(debug) {
System.out.println(point.toString());
}
//System.out.println(dis);
if(Double.doubleToLongBits(dis)>Double.doubleToLongBits(maxDis) && line.getStart()!=point && line.getEnd()!=point) {
maxDis = dis;
maxPoint = point;
}
}
if(debug) {
System.out.println("max:"+maxDis);
System.out.println("阈值:"+threshold);
System.out.println("保留最大点与首尾点");
}
//保留最大点与首尾点
if(maxDis>threshold && maxPoint!=null) {
if(debug) {
System.out.println("最大点:"+maxPoint.toString());
}
//涉及到删除元素不可以用for或while循环,因为会改变元素的位置
Iterator<Point> iterator = points.iterator();
while (iterator.hasNext()) {
Point p = (Point) iterator.next();
if(!(p==line.getStart()||p==line.getEnd()||p==maxPoint)) {
//标记不可用,这里指删除
//因为还需要留着左右部分的点做进一步的简化,不可以在这里进行删除操作 防止被gc掉
p.setEnable(false);
if(debug) {
System.out.println("删除的点:"+p.toString());
}
}else {
p.setEnable(true);
if(debug) {
System.out.println("保留的点:"+p.toString());
}
}
}
//以maxPoint把折线分为两部分接着简化
List<Point> leftPart = points.subList(0, points.indexOf(maxPoint)+1);
List<Point> rightPart = points.subList(points.indexOf(maxPoint), points.size());
if(debug) {
System.out.println(String.format("left [1]-[%d]", points.indexOf(maxPoint)+1));
System.out.println(String.format("right [%d]-[%d]", points.indexOf(maxPoint)+1, points.size()));
}
simplify(leftPart, threshold);
simplify(rightPart, threshold);
//只保留首尾点
}else {
Iterator<Point> iterator = points.iterator();
while (iterator.hasNext()) {
Point p = (Point) iterator.next();
if(!(p.equals(line.getStart())||p.equals(line.getEnd()))) {
p.setEnable(false);
if(debug) {
System.out.println("删除的非首尾点:"+p.toString());
}
}else {
if(debug) {
System.out.println("保留的首尾点:"+p.toString());
}
p.setEnable(true);
}
}
}
}
结果:
原始图像:
道格拉斯普克算法概化 阈值 130:
道格拉斯普克算法概化 阈值 180:
道格拉斯普克算法概化 阈值 250:
控制台打印:
所有评论(0)