我也不知道这玩意主要是干啥用的
实现如下
我用剖分的三角形的三个顶点到中心点的距离和作为颜色, 结果显示: 点越密集的地方, 图片上的颜色越深。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
from scipy.spatial import delaunay
import numpy as np
import matplotlib.pyplot as plt
width = 80
height = 40
pointnumber = 50
points = np.zeros((pointnumber, 2 ))
points[:, 0 ] = np.random.randint( 0 , width, pointnumber)
points[:, 1 ] = np.random.randint( 0 , height, pointnumber)
tri = delaunay(points)
center = np. sum (points[tri.simplices], axis = 1 ) / 3.0
'''
color = []
for sim in points[tri.simplices]:
x1, y1 = sim[0][0], sim[0][1]
x2, y2 = sim[1][0], sim[1][1]
x3, y3 = sim[2][0], sim[2][1]
s = ((x1-x2)**2+(y1-y2)**2)**0.5 + ((x1-x3)**2+(y1-y3)**2)**0.5 + ((x3-x2)**2+(y3-y2)**2)**0.5
color.append(s)
color = np.array(color)
'''
color = []
for index, sim in enumerate (points[tri.simplices]):
cx, cy = center[index][ 0 ], center[index][ 1 ]
x1, y1 = sim[ 0 ][ 0 ], sim[ 0 ][ 1 ]
x2, y2 = sim[ 1 ][ 0 ], sim[ 1 ][ 1 ]
x3, y3 = sim[ 2 ][ 0 ], sim[ 2 ][ 1 ]
s = ((x1 - cx) * * 2 + (y1 - cy) * * 2 ) * * 0.5 + ((cx - x3) * * 2 + (cy - y3) * * 2 ) * * 0.5 + ((cx - x2) * * 2 + (cy - y2) * * 2 ) * * 0.5
color.append(s)
color = np.array(color)
plt.figure(figsize = ( 20 , 10 ))
plt.tripcolor(points[:, 0 ], points[:, 1 ], tri.simplices.copy(), facecolors = color, edgecolors = 'k' )
plt.tick_params(labelbottom = 'off' , labelleft = 'off' , left = 'off' , right = 'off' , bottom = 'off' , top = 'off' )
ax = plt.gca()
plt.scatter(points[:, 0 ],points[:, 1 ], color = 'r' )
#plt.grid()
plt.savefig( 'delaunay.png' , transparent = true, dpi = 600 )
|
补充:生长算法实现点集的三角剖分( 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#-*- 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 = - y2
y3 = - y3
if (y1 ! = y3 and y1 ! = y2 and y2 ! = y3): #判断是否有y坐标相等,即三角形某边斜率为0的情况,避免出现坟分母为0的错误
if (((x3 - x1) / (y3 - y1)) - ((x2 - x1) / (y2 - y1))) = = 0 :
x2 = x2 + 1
x = (((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) / 2
y = - ((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) / 2
y = - ((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) / 2
y = - ((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 none
class 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 = 1
k = 0
mindis = (( int ( self .pointlist[ 0 ][ 0 ]) - int ( self .pointlist[ 1 ][ 0 ])) * * 2 + ( int ( self .pointlist[ 0 ][ 1 ]) - int ( self .pointlist[ 1 ][ 1 ])) * * 2 ) * * 0.5
x = 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.5
if dis < mindis:
mindis = dis
j = i
self .linelist.append((k,j)) #首先计算出距起始点(点号为0)距离最短的点,以这两点的连线作为基线开始生长
self .shengzhangjixian(k,j)
def drawtin( self ): #根据线文件在绘图区绘制出tin
for 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:
continue
if (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):
continue
else :
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 + 1
else :
continue
else : continue
if n = = 0 : #判断是否为d三角形
self .linelist.append((k,i)) #将新生成的边的端点号加入线列表
self .drawtin() #调用绘制函数绘制tin
self .shengzhangjixian(k,i) #以生成的新边作为基线,迭代计算
self .linelist.append((k,j))
self .drawtin()
self .shengzhangjixian(k,j)
else : continue
if __name__ = = '__main__' :
mytin = gettin()
|
通过如下代码生成一组随机的点并存入文件
1
2
3
4
5
6
7
8
9
10
11
12
|
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)
|
通过上面的程序我们得到一组坐标如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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
|
将以上的点在界面中展示出来
点击生长算法运行得到结果
小结
生长算法在三角剖分算法中并不是什么高效的算法,其特点在于算法简单易行,但是计算量大,并且对于新插入的点无法更新,必须重新计算。
相比之下,逐点插入算法虽然计算量仍然较大(似乎三角剖分计算量都不小),但是能实现对新插入点的更新而不用重头计算。
注:文中部分图片及介绍来自百度百科。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。
原文链接:https://blog.csdn.net/hpuhjl/article/details/80975599