道格拉斯-普克算法(Douglas–Peucker algorithm),亦称为拉默-道格拉斯-普克算法(Ramer–Douglas–Peucker algorithm),这个算法最初由拉默(Urs Ramer)于1972年提出,1973年道格拉斯(David Douglas)和普克(Thomas Peucker)二人又独立于拉默提出了该算法。
在计算机当中,曲线可以用足够多的点来描述,那么如何用尽可能少的点来描述这条曲线呢,这就是该算法要实现的目标,同时因为用来描述曲线的点变少了,也可以认为其对数据进行了压缩,减少了数据量。
算法作用
如何存储一条曲/折线?常见的方式就是使用使用一系列坐标点的集合来表示,点越多越密集,那么所能表示的精度就越高。在GIS画图的时候理想状况下,我们当然希望精度越高越好,但高精度的数据也会带来一些问题,比如对硬件系统的要求变高;比如在一些可视化场景里造成的渲染问题。
道格拉斯-普克算法正是用来解决这些问题的,它可以在保证一定精度的前提下,简化曲线的绘制过程,也是目前被广泛应用的GIS算法。基于线状实体的点压缩算法,用来压缩简化矢量数据。
算法流程
- 输入一系列坐标点组成的曲线。
- 曲线第一个点A和最后一个点B连成一条直线AB。
- 确认一个阈值(这个值用于控制简化后曲线的精度)
- 分别计算曲线上各点到这条直线的距离,并取出其中的最远距离与阈值进行比较。
- 如果最远距离大于阈值,则将该点保留,记为C,此时可以生成两条直线AC、CB,重复步骤4
- 否则将该点舍弃。
这么描述的有点抽象,我们还是看百科里给的动图。
图解







代码实现
# -*- coding:utf-8 -*- """ 道格拉斯算法的实现 程序需要安装shapely模块 """ import math from shapely import wkt, geometry import matplotlib.pyplot as plt class Point: """点类""" x = 0.0 y = 0.0 index = 0 # 点在线上的索引 def __init__(self, x, y, index): self.x = x self.y = y self.index = index class Douglas: """道格拉斯算法类""" points = [] D = 1 # 容差 def readPoint(self): """生成点要素""" g = wkt.loads("LINESTRING(1 4,2 3,4 2,6 6,7 7,8 6,9 5,10 10)") coords = g.coords for i in range(len(coords)): self.points.append(Point(coords[i][0], coords[i][1], i)) def compress(self, p1, p2): """具体的抽稀算法""" swichvalue = False # 一般式直线方程系数 A*x+B*y+C=0,利用点斜式,分母可以省略约区 # A=(p1.y-p2.y)/math.sqrt(math.pow(p1.y-p2.y,2)+math.pow(p1.x-p2.x,2)) A = (p1.y - p2.y) # B=(p2.x-p1.x)/math.sqrt(math.pow(p1.y-p2.y,2)+math.pow(p1.x-p2.x,2)) B = (p2.x - p1.x) # C=(p1.x*p2.y-p2.x*p1.y)/math.sqrt(math.pow(p1.y-p2.y,2)+math.pow(p1.x-p2.x,2)) C = (p1.x * p2.y - p2.x * p1.y) m = self.points.index(p1) n = self.points.index(p2) distance = [] middle = None if (n == m + 1): return # 计算中间点到直线的距离 for i in range(m + 1, n): d = abs(A * self.points[i].x + B * self.points[i].y + C) / math.sqrt(math.pow(A, 2) + math.pow(B, 2)) distance.append(d) dmax = max(distance) if dmax > self.D: swichvalue = True else: swichvalue = False if (not swichvalue): for i in range(m + 1, n): del self.points[i] else: for i in range(m + 1, n): if (abs(A * self.points[i].x + B * self.points[i].y + C) / math.sqrt( math.pow(A, 2) + math.pow(B, 2)) == dmax): middle = self.points[i] self.compress(p1, middle) self.compress(middle, p2) def printPoint(self): """打印数据点""" for p in self.points: print("%d,%f,%f" % (p.index, p.x, p.y)) def main(): """测试""" # p=Point(20,20,1) # print '%d,%d,%d'%(p.x,p.x,p.index) d = Douglas() d.readPoint() # d.printPoint() # 结果图形的绘制,抽稀之前绘制 fig = plt.figure() a1 = fig.add_subplot(121) dx = [] dy = [] for i in range(len(d.points)): dx.append(d.points[i].x) dy.append(d.points[i].y) a1.plot(dx, dy, color='g', linestyle='-', marker='+') d.compress(d.points[0], d.points[len(d.points) - 1]) # 抽稀之后绘制 dx1 = [] dy1 = [] a2 = fig.add_subplot(122) for p in d.points: dx1.append(p.x) dy1.append(p.y) a2.plot(dx1, dy1, color='r', linestyle='-', marker='+') # print "========================\n" # d.printPoint() plt.show() if __name__ == '__main__': main()
讯享网


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/45180.html