生长算法实现点集的三角剖分( Python(Tkinter模块))

关于三角剖分

假设V是二维实数域上的有限点集,边e是由点集中的点作为端点构成的封闭线段, E为e的集合。那么该点集V的一个三角剖分T=(V,E)是一个平面图G,该平面图满足条件:
1.除了端点,平面图中的边不包含点集中的任何点。
2.没有相交边。
3.平面图中所有的面都是三角面,且所有三角面的合集是散点集V的凸包。
在实际中运用的最多的三角剖分是Delaunay三角剖分,它是一种特殊的三角剖分。
【定义】Delaunay边:假设E中的一条边e(两个端点为a,b),e若满足下列条件,则称之为Delaunay边:
存在一个圆经过a,b两点,圆内(注意是圆内,圆上最多三点共圆)不含点集V中任何其他的点,这一特性又称空圆特性。
【定义】Delaunay三角剖分:如果点集V的一个三角剖分T只包含Delaunay边,那么该三角剖分称为Delaunay三角剖分。


关于Delaunay三角剖分算法可以参考百度百科Delaunay三角剖分算法

我做三角剖分的目的——构建TIN,不规则三角网

不规则三角网(TIN)是DEM的重要形式之一,相较于规则格网,其具有数据冗余小、细节丢失少的特点。
在分布不规则的高程点之间构建出三角网,其关键技术就是三角剖分

算法步骤

1、首先任选一点,在点集中找出距离改点最近的点连成一条线,以该线为基线。
2、在所有点中寻找能与该基线构成具有空圆性三角形的点,并构成三角形。
3、以新生成的边为基线,重复第二步,直至点集构网完成。

具体代码如下

所使用的python版本为python3.6,编辑器为Pycharm2018.3.1

#-*- coding:utf-8 -*-import tkinter
from tkinter import filedialog
import csv#根据两点坐标计算距离
def caldis(x1,y1,x2,y2):return ((x1-x2)**2+(y1-y2)**2)**0.5#输入三角形三个顶点,计算外接圆圆心及半径
def calcenter(x1,y1,x2,y2,x3,y3):y1=-y1  #计算公式是根据平面直角坐标推算的,原点在左下角,但是计算机屏幕坐标原点在右上角,所以计算式y坐标取负y2=-y2y3=-y3if (y1 != y3 and y1 != y2 and y2 != y3): #判断是否有y坐标相等,即三角形某边斜率为0的情况,避免出现坟分母为0的错误if(((x3-x1)/(y3-y1))-((x2-x1)/(y2-y1)))==0:x2=x2+1x=(((y1+y3)/2)+((x1+x3)/2)*((x3-x1)/(y3-y1))-((y1+y2)/2)-((x1+x2)/2)*((x2-x1)/(y2-y1)))/(((x3-x1)/(y3-y1))-((x2-x1)/(y2-y1)))y=-((x3-x1)/(y3-y1))*x+((y1+y3)/2)+(((x1+x3)/2)*((x3-x1)/(y3-y1)))return (x, -y, caldis(x, y, x1, y1))elif (y1 == y3 and y1 != y2 and y2 != y3):#若存在斜率为0的边则计算可简化x=(x1+x3)/2y=-((x2-x1)/(y2-y1))*x+((y1+y2)/2)+((x2-x1)/(y2-y1))*((x1+x2)/2)return (x, -y, caldis(x, y, x1, y1)) #返回值为元组(圆心横坐标x,圆心纵坐标y,外接圆半径r),计算出来的y值要返回屏幕坐标所以再次取负elif (y1 != y3 and y1 == y2 and y2 != y3):x = (x1 + x2) / 2y = -((x3 - x1) / (y3 - y1)) * x + ((y1 + y3) / 2) + ((x3 - x1) / (y3 - y1)) * ((x1 + x3) / 2)return (x, -y, caldis(x, y, x1, y1))elif (y1 != y3 and y1 != y2 and y2 == y3):x = (x3 + x2) / 2y = -((x3 - x1) / (y3 - y1)) * x + ((y1 + y3) / 2) + ((x3 - x1) / (y3 - y1)) * ((x1 + x3) / 2)return (x, -y, caldis(x, y, x1, y1))else:return Noneclass getTIN: #定义窗口及操作类def __init__(self):self.path=str() #坐标文件路径self.pointlist=[] #存放所有点坐标的列表self.linelist=[] #存放线的列表,每条线用两个点号表示连线self.tk=tkinter.Tk() #定义主窗口self.tk.title('MyTIN')self.tk.geometry('1200x720')self.shengzhang=tkinter.Button(self.tk,text='生长算法',width=15,command=self.drawTIN_shengzhang)self.shengzhang.place(x=1050,y=100)  #定义按钮,关联到生长算法计算TIN的的函数self.readin=tkinter.Button(self.tk,text='读入坐标文件',width=15,command=self.getfile)self.readin.place(x=1050,y=50)self.can=tkinter.Canvas(self.tk,width=950,height=620,bg='white')self.can.place(x=50,y=50)self.tk.mainloop()def getfile(self):  #选择坐标文件(*.csv),从文件中读入坐标存入pointlist列表并在绘图区展示出来self.path=filedialog.askopenfilename()f=open(self.path,'r')fd=csv.reader(f)self.pointlist=list(fd)for i in range(0,len(self.pointlist)):self.can.create_oval(int(self.pointlist[i][0])-2,int(self.pointlist[i][1])-2,int(self.pointlist[i][0])+2,int(self.pointlist[i][1])+2,fill='black')self.can.create_text(int(self.pointlist[i][0])+7,int(self.pointlist[i][1])-7,text=str(i))def drawTIN_shengzhang(self):j = 1k = 0mindis = ((int(self.pointlist[0][0]) - int(self.pointlist[1][0])) ** 2 + (int(self.pointlist[0][1]) - int(self.pointlist[1][1])) ** 2) ** 0.5x = len(self.pointlist)for i in range(1, x):dis = ((int(self.pointlist[0][0]) - int(self.pointlist[i][0])) ** 2 + (int(self.pointlist[0][1]) - int(self.pointlist[i][1])) ** 2) ** 0.5if dis < mindis:mindis = disj = iself.linelist.append((k,j)) #首先计算出距起始点(点号为0)距离最短的点,以这两点的连线作为基线开始生长self.shengzhangjixian(k,j)def drawTIN(self): #根据线文件在绘图区绘制出TINfor i in self.linelist:self.can.create_line(self.pointlist[i[0]][0], self.pointlist[i[0]][1], self.pointlist[i[1]][0], self.pointlist[i[1]][1])def shengzhangjixian(self,i,j): #根据某一基线开始生长的函数x = len(self.pointlist)for k in range(0,x): #遍历没一个点,判断是否与基线构成D三角形n = 0 #n用于统计外接圆内的点数if ((k,i) not in self.linelist) and ((i,k) not in self.linelist) and ((j,k) not in self.linelist) and ((k,j) not in self.linelist):for y in range(0,x): #遍历每一个点,判断if y==i or y==j or y==k:continueif(calcenter(int(self.pointlist[i][0]),int(self.pointlist[i][1]),int(self.pointlist[j][0]),int(self.pointlist[j][1]),int(self.pointlist[k][0]),int(self.pointlist[k][1]))==None):continueelse:xyr=calcenter(int(self.pointlist[i][0]),int(self.pointlist[i][1]),int(self.pointlist[j][0]),int(self.pointlist[j][1]),int(self.pointlist[k][0]),int(self.pointlist[k][1]))if caldis(xyr[0],xyr[1],int(self.pointlist[y][0]),int(self.pointlist[y][1])) < xyr[2]: #判断点是否在外接圆内n=n+1else:continueelse:continueif n == 0: #判断是否为D三角形self.linelist.append((k,i)) #将新生成的边的端点号加入线列表self.drawTIN() #调用绘制函数绘制TINself.shengzhangjixian(k,i) #以生成的新边作为基线,迭代计算self.linelist.append((k,j))self.drawTIN()self.shengzhangjixian(k,j)else:continueif __name__ == '__main__':MyTIN=getTIN()

通过如下代码生成一组随机的点并存入文件

import random
import csv
from tkinter import filedialog
path=filedialog.askopenfilename()
OutAddress=open(path,'a',newline='')
csv_write = csv.writer(OutAddress,dialect='excel')
for i in range(0,20):x=random.randint(30,920)y=random.randint(30,590)out=(x,y)print(out)csv_write.writerow(out)

通过上面的程序我们得到一组坐标如下

550,432
81,334
517,265
842,408
369,123
502,169
271,425
213,482
588,248
94,295
344,350
500,385
912,527
801,491
838,455
104,479
760,160
706,77
227,314
764,576

将以上的点在界面中展示出来

点击生长算法运行得到结果

小结

生长算法在三角剖分算法中并不是什么高效的算法,其特点在于算法简单易行,但是计算量大,并且对于新插入的点无法更新,必须重新计算。相比之下,逐点插入算法虽然计算量仍然较大(似乎三角剖分计算量都不小),但是能实现对新插入点的更新而不用重头计算。

注:文中部分图片及介绍来自百度百科。

生长算法实现点集的三角剖分(Python(Tkinter模块))相关推荐

  1. Python Tkinter 模块简要介绍

    [本文章已于 2022/9/26 重制]         这篇博客将简要地介绍 Python 的 Tkinter 模块,主要供没了解过 Tkinter 模块的人进行了解,让初学者也能进行桌面应用开发! ...

  2. python安装tkinter模块_详解python tkinter模块安装过程

    引言: 在Python3下运行Matplotlib之时,碰到了"No module named _tkinter"的问题,花费数小时进行研究解决,这里讲整个过程记录下来,并尝试分析 ...

  3. python tkinter 安装_详解python tkinter模块安装过程

    引言: 在Python3下运行Matplotlib之时,碰到了"No module named _tkinter"的问题,花费数小时进行研究解决,这里讲整个过程记录下来,并尝试分析 ...

  4. 项目一:使用python tkinter模块做简单的计算器

    小白第一次发博客,可能有很多问题,望指正! 讲的不是很详细,提供思路. 目录: 成果展示 代码说明 其他补充和参考资料 ------分割线-------- 1.成果展示 基本效果图:         ...

  5. Python Tkinter模块详解(后续持续补充)

    声明:该文章是个人学习中写的,目的是总结及当作工具参考,有一定的借鉴成分,后续若有新发现则补充 目录 Tkinter简介 创建组件基本语法 Tkinter组件汇总 Variable 类 常见参数详解 ...

  6. python3.5模块大全-python tkinter模块使用大全(超全)

    1.使用tkinter.Tk() 生成主窗口(root=tkinter.Tk()): root.title("标题名") 修改框体的名字,也可在创建时使用className参数来命 ...

  7. 求助:关于python tkinter模块 pack() 函数问题。请各位大神赐教!

    如下图,我想将图表放置在按钮的左侧.为啥总是在下方,请赐教. 代码: # 功能按钮         # ------------------------------------------------ ...

  8. C#,计算几何,随机点集之三角剖分的德劳内(Delaunay)算法的源代码

    一.三角剖分Delaunay算法简介 点集的三角剖分(Triangulation),对数值分析(比如有限元分析)以及图形学来说,都是极为重要的一项预处理技术.尤其是Delaunay三角剖分,由于其独特 ...

  9. python写科学计算器代码_Python编程使用tkinter模块实现计算器软件完整代码示例...

    Python编程使用tkinter模块实现计算器软件完整代码示例 来源:中文源码网    浏览: 次    日期:2018年9月2日 Python编程使用tkinter模块实现计算器软件完整代码示例 ...

最新文章

  1. 又一个Jupyter神器,操作Excel自动生成Python代码
  2. P1164 小A点菜
  3. 平流式隔油池计算_玻璃钢隔油池
  4. Adapter适配器设计模式
  5. 2018-2019-1 20165330 《信息安全系统设计基础》第二周学习总结
  6. 在 C# 中生成代码的四种方式——包括.NET 5中的Source Generators
  7. 使用反应流API将Akka流与rxJava结合在一起
  8. vue动态监听窗口高度 - 全背景banner
  9. JAVA日期安全格式化之SimpleDateFormat和jodaTime,DateTimeFormatter
  10. L1-014 简单题 (5 分)
  11. 二扩域元素与整数的转换
  12. Solana 海湾流(Gulf Stream)海平面(Sealevel)区别
  13. Shell脚本应用之服务启动脚本
  14. MAC快捷键使用大全
  15. (随笔)无人机集群通信组网系统—无人机自组网
  16. 计算机组成原理与体系结构——随机存储器和只读存储器
  17. windows7计算机启动修复怎么办,Win7电脑开机提示启动修复无法进入系统怎么办?...
  18. 华硕笔记本能通用的BIOS型号
  19. MySQL Workbench报错说 seems to be a different OS
  20. MRF.DDt(U)---MRF模型简介

热门文章

  1. 使用腾讯云Ubuntu20.04搭建代理服务器
  2. 空洞卷积(dilated convolution)理解
  3. 什么是大数据可视化,有什么作用?
  4. 找不到工作的测试员一大把,大厂却招不到优秀软件测试员?高薪难寻测试工程师。
  5. Microsoft OneNote for MacOS 输入中英文字体自动改变
  6. Unicode双向算法详解(bidi算法)(二)
  7. python画矢量场_Python中的图像渐变矢量场
  8. 诱惑视频木马样本态势
  9. android 阅读器自动滚动,在Android手机上实现阅读器翻页效果.doc
  10. B2B2C 商城系统 WSTMart_v2.0.6_180726程序发布