Python TIN网生成(Delaunay三角形)

基本算法

生成TIN的算法很多,但作者所学有限,今天仅写依据Delaunay三角形的TIN扩张生成算法,具体流程如下:

  1. 在离散点中随机选取一点作为基线边的起点,寻找与起点最近的另一点作为基线边的终点,生成一条基线边,并存入BaseStack栈中。创建LineList存放边,TriangleList存放生成的三角形。
  2. 在BaseStack栈中取一条基线边出栈,在离散点中遍历查询一个基线边右侧的点使得其与基线边构成的角最大。
  3. 若存在这样的点,则用该点与基线边创建一个Delaunay三角形。基线边为第一条边,基线边起点到该新查询点为第二条边,该新查询点到基线边终点为第三条边,后两新边作为新的基线边压入BaseStack中,若重复则不再压入。再依次将新边、三角形存入LineList和TriangleList,若重复则不在存储。若不存在这样的点,则跳过该基线边。
  4. 重复2、3步骤,直到BaseStack为空,将得到的LineList和TriangleList保存。

数据结构

为了结构化管理数据,我们为数据创建了三种数据结构,即点类(Point)、边类(Line)和三角形类(Triangle)。

点类

具有点名PointName、坐标值X,Y、高程值H等属性、并拥有一个计算当前点与其他点之间距离的方法Cal_Distans(),如下所示:

# 点类
class Point:
    '''包含 点名 数学坐标X 数学坐标Y  高程(z)H'''
    def __init__(self,pointname,x,y,h):
        self.PointName=pointname
        self.X=x
        self.Y=y
        self.H=h
    def Cal_Distans(self,x0,y0):
        d=math.sqrt(math.pow(x0-self.X,2)+math.pow(y0-self.Y,2))
        return d

边类

具有起始点BeginPoint和终止点EndPoint两个来确定边的主要属性,另外拥有Belonging_Triangle列表属性来记录当前边的归属三角形和他所属的邻接三角形(该属性在后续等值线的生长中将发挥巨大作用),除此之外重载了方向不同但投影是相同边的判断运算符(==)用来判断边是否相同,如下所示:

#边类
class Line:
    def __init__(self,point_b,point_e):
        self.BeginPoint=point_b
        self.EndPoint=point_e
        self.Belonging_Triangle=[]
    def __eq__(self, other):
        if(self.BeginPoint.PointName==other.EndPoint.PointName and
            self.EndPoint.PointName==other.BeginPoint.PointName):
            return 1
        elif(self.BeginPoint.PointName==other.BeginPoint.PointName and
              self.EndPoint.PointName==other.EndPoint.PointName):
            return 1
        else:
            return 0

三角形类

根据Delaunay三角形的生成过程,我们定义的三角形类广泛意义上讲是一个有向三角形,它由基线边、基线边的起点到新查询点、新查询点到基线边终点三条有向边构成,除此之外也重载了方向不同但投影是相同三角形的判断运算符(==)用来判断三角形是否相等,如下所示:

# 三角形类
class Triangle:
    def __init__(self,point_b,point_e,point_s):
        self.BaseLine=Line(point_b,point_e)
        self.newLine1=Line(point_b,point_s)
        self.newLine2=Line(point_s,point_e)
    def __eq__(self, other):#重载==
        if(self.BaseLine==other.BaseLine and self.newLine1==other.newLine1 and self.newLine2==other.newLine2):
            return 1
        elif(self.BaseLine==other.BaseLine and self.newLine1==other.newLine2 and self.newLine2==other.newLine1):
            return 1
        elif(self.BaseLine==other.newLine1 and self.newLine1==other.newLine2 and self.newLine2==other.BaseLine):
            return 1
        elif(self.BaseLine==other.newLine1 and self.newLine1==other.BaseLine and self.newLine2==other.newLine2):
            return 1
        elif(self.BaseLine==other.newLine2 and self.newLine1==other.newLine1 and self.newLine2==other.BaseLine):
            return 1
        elif(self.BaseLine==other.newLine2 and self.newLine1==other.BaseLine and self.newLine2==other.newLine1):
            return 1
        else:
            return 0

功能代码实现过程

导入数据

打开指定路径文件,按行读取文件中的内容,直到文件结束。将每行文件内容按“,”分隔符分割,将得到的点名,坐标,高程等实例成一个点对象point。将各个点对象按尾插入法存入point_list列表,方便后续管理和使用数据,如下所示:

# 数据读取 将数据组织到已经封装的点类 再用列表将所有点线性连接在一起 方便调用
def ReadDataTXT(Str_Path):
    point_list=[]
    with open(Str_Path) as f:
        title = f.readline()
        print(title.rstrip())
        while(1):
            line = f.readline()
            if (line==""):
                break
            str_list=[]
            str_list=line.rstrip().split(',')
            point=Point(str_list[1],float(str_list[2]),float(str_list[3]),float(str_list[4]))
            point_list.append(point)
            str_list=[]
    return point_list

生成TIN三角网

查询数据边界

查询定位数据的最大最小横纵坐标,以此矩形框作为可视化显示的边界,也是当前坐标系与屏幕坐标系转换时的比例尺依据,将会在坐标系转换时频繁发生作用,如下所示:

# 查询数据边界
def XYMinMax(Point_List):
    xmax=EPSILON
    xmin=1/EPSILON
    ymax=EPSILON
    ymin=1/EPSILON
    for point in Point_List:
        if (point.X<xmin):
            xmin=point.X
        elif(point.X>xmax):
            xmax=point.X
        if(point.Y<ymin):
            ymin=point.Y
        elif(point.Y>ymax):
            ymax=point.Y
    return xmin,xmax,ymin,ymax

坐标系转换

将数学坐标系下数据的边界范围和屏幕坐标系的屏幕大小关系进行比较,得到横纵比例尺及其对应的函数关系,一次将每一个数学坐标点转换到屏幕坐标系下并显示(通过Tkinter canvas画布),如下所示:

# 数学坐标系转到屏幕坐标系
# 上下个延伸10% 使屏幕有效率达到86% 数据边界不会丢失
def GaussToScreenCor(XYMinMax_List,Gx,Gy):
    dxmax=(XYMinMax_List[1]-XYMinMax_List[0])*1.2
    dymax=(XYMinMax_List[3]-XYMinMax_List[2])*1.2
    xscale=dxmax/800
    yscale=dymax/600
    Sx=int((Gx-XYMinMax_List[0]+dxmax*0.083)/xscale)
    Sy=int((XYMinMax_List[3]-Gy+dymax*0.083)/yscale)
    return Sx,Sy

计算余弦值

算法通过最小角最大化来确定Delaunay三角形,本篇文章采用余弦值法来比较角度的大小关系,即角度越大对应的余弦值越小,如下所示:

# 解算右三角形余弦值
def Solve_Triangle_cos(Triangle):
    c=Triangle.BaseLine.BeginPoint.Cal_Distans(Triangle.BaseLine.EndPoint.X,Triangle.BaseLine.EndPoint.Y)
    b=Triangle.newLine1.EndPoint.Cal_Distans(Triangle.BaseLine.EndPoint.X,Triangle.BaseLine.EndPoint.Y)
    a=Triangle.newLine1.EndPoint.Cal_Distans(Triangle.BaseLine.BeginPoint.X,Triangle.BaseLine.BeginPoint.Y)
    cos=(a*a+b*b-c*c)/(2*a*b)
    return cos
'''

查询最近点

在point_list列表里查询与当前点距离最近的点,并返回其所在列表中的下标索引,如下所示:

# 与某点距离最近的点
def NearistPoint(Point,Point_list):
    d=1/EPSILON
    index=0
    for i in range(len(Point_list)):
        if(Point_list[i].PointName!=Point.PointName):
            if (Point.Cal_Distans(Point_list[i].X,Point_list[i].Y)<d):
                d=Point.Cal_Distans(Point_list[i].X,Point_list[i].Y)
                index=i
    return index

创建Delaunay三角形

在基线边的右边查找离散点使得该离散点与基线边之间形成的夹角最大,若存在这样的点返回这个点的point_list中的下标索引值,若不存在则返回none,如下所示:

# 由基线生成三角形
def CreatTRI(Line,Point_List):
     cos=1.1
     cosmin=1.1
     index=''
     for i in range(len(Point_List)):
        if(Point_List[i].PointName==Line.BeginPoint.PointName or Point_List[i].PointName==Line.EndPoint.PointName):
            continue
        if(Judge_Right(Line,Point_List[i])):
            triangle=Triangle(Line.BeginPoint,Line.EndPoint,Point_List[i])
            cos=Solve_Triangle_cos(triangle)
            if(cos<cosmin):
                cosmin=cos
                index=i
     if(index!=''):
         return index

边判重复

判断新加入边是否已经在Linelist中,在则表示重复,返回1,如下所示:

# 判断边是否添加重复,重复则删除并返回0
def Judge_Dup(Line_List):
    line1=Line_List[-1]
    for i in range(0,len(Line_List)-1):
        if(Line_List[i]==line1):
            return 1

判右

判断离散点是否在基线边的右侧,是则返回1。利用计算机图形学的旋转平移变换技术,将基线边与离散点平移旋转至基线边起点在原点且基线方向与数学坐标x轴同向,若离散点y值小于0,则判定该离散点在基线边的右侧,如下所示:

# 判断寻找点是否在基线边右侧 是返回true (利用图形学平移旋转变化)
def Judge_Right(BaseLine,Point):
    dx=BaseLine.EndPoint.X-BaseLine.BeginPoint.X
    dy=BaseLine.EndPoint.Y-BaseLine.BeginPoint.Y
    d=math.sqrt(dx*dx+dy*dy)
    cos=dx/d
    sin=dy/d
    #旋转平移变换 三角形顺时针旋转基线方向与X正轴重合
    x=(Point.X-BaseLine.BeginPoint.X)*cos+(Point.Y-BaseLine.BeginPoint.Y)*sin
    y=-(Point.X-BaseLine.BeginPoint.X)*sin+(Point.Y-BaseLine.BeginPoint.Y)*cos
    if(y<0):
        return 1

添加边

将新生成的边添加到边的存储列表LineList,若边已经存在则不再添加,若不存在则添加生成,作为画出TIN的数据源,如下所示:

# 添加边
def AddLine(LineList,BaseStack,line):
    LineList.append(line)
    if(Judge_Dup(LineList)):
        del LineList[-1]
        del BaseStack[-1]
    return LineList,BaseStack

添加基线边

向存储基线边的BaseStack栈列表中添加新的基线边,若新基线边已经在BaseStack中存在,则不在添加,反之则加入基线边栈。如下所示:

def AddBaseStack(BaseStack,line):
    BaseStack.append(line)
    if(Judge_Dup(BaseStack)):
        del BaseStack[-1]
    return BaseStack

添加三角形

向三角形列表Triangle_List中添加三角形triangle,若该三角形已经存在于三角形列表则不再添加,反之则添加。添加完成时,要给当前三角形的三边Belonging_Triangle赋值当前三角形的下标索引,记录这个三角形的三边归属三角形。如下所示:

#添加三角形
def AddTriangle(Triangle_List,triangle):
    already=0
    for tri in Triangle_List:
        if(tri==triangle):
            already=1
    if (already==0):
        Triangle_List.append(triangle)
        #三角形存储后 在刚存进的三角形三边上记录该三角形的列表索引号
        Triangle_List[-1].BaseLine.Belonging_Triangle.append(len(Triangle_List)-1)
        Triangle_List[-1].newLine1.Belonging_Triangle.append(len(Triangle_List)-1)
        Triangle_List[-1].newLine2.Belonging_Triangle.append(len(Triangle_List)-1)
    return Triangle_List

边的邻接三角形

除三角形边的当前归属三角形外,边上还应记录边的邻接三角形是哪一个,通过遍历查找将三角形三边的邻接三角形下标索引也存储到Belonging_Triangle,方便后续等值线的生成。如下所示:

# 建立边与三角形间的索引
def EdgeIndexTri(Triangle_List):
    for i in range(0,len(Triangle_List)):
        for j in range(0,len(Triangle_List)):
            if(i==j):
                continue
            else:
                if(Triangle_List[i].BaseLine==Triangle_List[j].BaseLine or Triangle_List[i].BaseLine==Triangle_List[
                    j].newLine1 or Triangle_List[i].BaseLine==Triangle_List[j].newLine2):
                    Triangle_List[i].BaseLine.Belonging_Triangle.append(j)
                if(Triangle_List[i].newLine1==Triangle_List[j].BaseLine or Triangle_List[i].newLine1==Triangle_List[
                    j].newLine1 or Triangle_List[i].newLine1==Triangle_List[j].newLine2):
                    Triangle_List[i].newLine1.Belonging_Triangle.append(j)
                if(Triangle_List[i].newLine2==Triangle_List[j].BaseLine or Triangle_List[i].newLine2==Triangle_List[
                    j].newLine1 or Triangle_List[i].newLine2==Triangle_List[j].newLine2):
                    Triangle_List[i].newLine2.Belonging_Triangle.append(j)
    return Triangle_List

创建TIN

这里是创建TIN的主函数,主要算法在文章开篇已经讲过,不再赘述。如下所示:

# 生成TIN三角网
def CreatTIN(Point_List):
    point_list=Point_List # copy 一份 备用
    line_list=[] # 存放边的列表
    triangle_list=[] # 存放三角形的列表
    base_stack=[]
    basebegin=randint(0,len(point_list)-1)
    basend=NearistPoint(point_list[basebegin],point_list)
    line_list.append(Line(point_list[basebegin],point_list[basend]))
    base_stack.append(Line(point_list[basebegin],point_list[basend]))
    while(len(base_stack)):
        line=base_stack[-1]
        del base_stack[-1]
        index=CreatTRI(line,point_list)
        if(index==None):
            continue
        elif(index!=None):
            triangle=Triangle(line.BeginPoint,line.EndPoint,point_list[index])
            base_stack=AddBaseStack(base_stack,Line(line.BeginPoint,point_list[index]))
            base_stack=AddBaseStack(base_stack,Line(point_list[index],line.EndPoint))
            [line_list,base_stack]=AddLine(line_list,base_stack,Line(line.BeginPoint,point_list[index]))
            [line_list,base_stack]=AddLine(line_list,base_stack,Line(point_list[index],line.EndPoint))
            triangle_list=AddTriangle(triangle_list,triangle)
    Triangle_list=EdgeIndexTri(triangle_list)
    return line_list,Triangle_list

数据可视化

代码设计

'''*******************窗体********************'''
# 生成一个窗体界面 命名为window
window=tk.Tk()
window.title('TIN')
window.geometry('1000x750')

# 在窗体上生成一块画布 用于绘制导线图
canvas = tk.Canvas(window,width=800,height=600,bg = 'white')
canvas.place(x=190,y=10)

# 画出数据点
def Draw_Point(Point_List):
    xyminmax=XYMinMax(Point_List)
    for point in Point_List:
        gxgy=GaussToScreenCor(xyminmax,point.X,point.Y)
        oval = canvas.create_oval(gxgy[0]-1, gxgy[1]-1, gxgy[0]+1, gxgy[1]+1)
        #canvas.create_text(gxgy[0]-13,gxgy[1],text=point.PointName)

# 画出TIN网
def Connect_Point(list1,list2,color):
    line = canvas.create_line(list1[0], list1[1],list2[0],list2[1],fill = color)
def Draw_TIN(Point_List,Line_List):
    xyminmax=XYMinMax(Point_List)
    for line in Line_List:
        gxgy1=GaussToScreenCor(xyminmax,line.BeginPoint.X,line.BeginPoint.Y)
        gxgy2=GaussToScreenCor(xyminmax,line.EndPoint.X,line.EndPoint.Y)
        oval = canvas.create_oval(gxgy1[0]-1, gxgy1[1]-1, gxgy1[0]+1, gxgy1[1]+1)
        ova2 = canvas.create_oval(gxgy1[0]-1, gxgy1[1]-1, gxgy1[0]+1, gxgy1[1]+1)
        Connect_Point(gxgy1,gxgy2,'black')

#********调试********
path="D:\等高线点数据.txt"
point_list=ReadDataTXT(path)
Draw_Point(point_list)
Net=CreatTIN(point_list)
print(len(Net[0]),len(Net[1]))
Draw_TIN(point_list,Net[0])
window.mainloop()
'''*******************所有代码在此之上********************'''

结果

由于版权原因,文章不提供程序中的数据,仅将可视化结果展示。

显示数据点

显示打印数学坐标系做转换后在屏幕坐标系下的结果,黑点为数据点。
数据点的可视化

显示TIN

下图是生成的三角网效果图。
TIN可视化

全部代码

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
import math
import tkinter as tk
import numpy as np
from scipy.interpolate import interp1d
from random import randint
EPSILON=1/10000000000

# 点类
class Point:
    '''包含 点名 数学坐标X 数学坐标Y  高程(z)H'''
    def __init__(self,pointname,x,y,h):
        self.PointName=pointname
        self.X=x
        self.Y=y
        self.H=h
    def Cal_Distans(self,x0,y0):
        d=math.sqrt(math.pow(x0-self.X,2)+math.pow(y0-self.Y,2))
        return d
# 线类
class Line:
    def __init__(self,point_b,point_e):
        self.BeginPoint=point_b
        self.EndPoint=point_e
        self.Belonging_Triangle=[]
    def __eq__(self, other):
        if(self.BeginPoint.PointName==other.EndPoint.PointName and
            self.EndPoint.PointName==other.BeginPoint.PointName):
            return 1
        elif(self.BeginPoint.PointName==other.BeginPoint.PointName and
              self.EndPoint.PointName==other.EndPoint.PointName):
            return 1
        else:
            return 0

# 三角形类
class Triangle:
    def __init__(self,point_b,point_e,point_s):
        self.BaseLine=Line(point_b,point_e)
        self.newLine1=Line(point_b,point_s)
        self.newLine2=Line(point_s,point_e)
    def __eq__(self, other):#重载==
        if(self.BaseLine==other.BaseLine and self.newLine1==other.newLine1 and self.newLine2==other.newLine2):
            return 1
        elif(self.BaseLine==other.BaseLine and self.newLine1==other.newLine2 and self.newLine2==other.newLine1):
            return 1
        elif(self.BaseLine==other.newLine1 and self.newLine1==other.newLine2 and self.newLine2==other.BaseLine):
            return 1
        elif(self.BaseLine==other.newLine1 and self.newLine1==other.BaseLine and self.newLine2==other.newLine2):
            return 1
        elif(self.BaseLine==other.newLine2 and self.newLine1==other.newLine1 and self.newLine2==other.BaseLine):
            return 1
        elif(self.BaseLine==other.newLine2 and self.newLine1==other.BaseLine and self.newLine2==other.newLine1):
            return 1
        else:
            return 0

# 数据读取 将数据组织到已经封装的点类 再用列表将所有点线性连接在一起 方便调用
def ReadDataTXT(Str_Path):
    point_list=[]
    with open(Str_Path) as f:
        title = f.readline()
        print(title.rstrip())
        while(1):
            line = f.readline()
            if (line==""):
                break
            str_list=[]
            str_list=line.rstrip().split(',')
            point=Point(str_list[1],float(str_list[2]),float(str_list[3]),float(str_list[4]))
            point_list.append(point)
            str_list=[]
    return point_list
#
#  生成TIN三角网
#
# 查询数据边界
def XYMinMax(Point_List):
    xmax=EPSILON
    xmin=1/EPSILON
    ymax=EPSILON
    ymin=1/EPSILON
    for point in Point_List:
        if (point.X<xmin):
            xmin=point.X
        elif(point.X>xmax):
            xmax=point.X
        if(point.Y<ymin):
            ymin=point.Y
        elif(point.Y>ymax):
            ymax=point.Y
    return xmin,xmax,ymin,ymax
# 数学坐标系转到屏幕坐标系
# 上下个延伸10% 使屏幕有效率达到86% 数据边界不会丢失
def GaussToScreenCor(XYMinMax_List,Gx,Gy):
    dxmax=(XYMinMax_List[1]-XYMinMax_List[0])*1.2
    dymax=(XYMinMax_List[3]-XYMinMax_List[2])*1.2
    xscale=dxmax/800
    yscale=dymax/600
    Sx=int((Gx-XYMinMax_List[0]+dxmax*0.083)/xscale)
    Sy=int((XYMinMax_List[3]-Gy+dymax*0.083)/yscale)
    return Sx,Sy

# 解算右三角形余弦值
def Solve_Triangle_cos(Triangle):
    c=Triangle.BaseLine.BeginPoint.Cal_Distans(Triangle.BaseLine.EndPoint.X,Triangle.BaseLine.EndPoint.Y)
    b=Triangle.newLine1.EndPoint.Cal_Distans(Triangle.BaseLine.EndPoint.X,Triangle.BaseLine.EndPoint.Y)
    a=Triangle.newLine1.EndPoint.Cal_Distans(Triangle.BaseLine.BeginPoint.X,Triangle.BaseLine.BeginPoint.Y)
    cos=(a*a+b*b-c*c)/(2*a*b)
    return cos

# 与某点距离最近的点
def NearistPoint(Point,Point_list):
    d=1/EPSILON
    index=0
    for i in range(len(Point_list)):
        if(Point_list[i].PointName!=Point.PointName):
            if (Point.Cal_Distans(Point_list[i].X,Point_list[i].Y)<d):
                d=Point.Cal_Distans(Point_list[i].X,Point_list[i].Y)
                index=i
    return index
# 由基线生成三角形
def CreatTRI(Line,Point_List):
     cos=1.1
     cosmin=1.1
     index=''
     for i in range(len(Point_List)):
        if(Point_List[i].PointName==Line.BeginPoint.PointName or Point_List[i].PointName==Line.EndPoint.PointName):
            continue
        if(Judge_Right(Line,Point_List[i])):
            triangle=Triangle(Line.BeginPoint,Line.EndPoint,Point_List[i])
            cos=Solve_Triangle_cos(triangle)
            if(cos<cosmin):
                cosmin=cos
                index=i
     if(index!=''):
         return index

# 判断边是否添加重复,重复则删除并返回0
def Judge_Dup(Line_List):
    line1=Line_List[-1]
    for i in range(0,len(Line_List)-1):
        if(Line_List[i]==line1):
            return 1
# 判断寻找点是否在基线边右侧 是返回true (利用图形学平移旋转变化)
def Judge_Right(BaseLine,Point):
    dx=BaseLine.EndPoint.X-BaseLine.BeginPoint.X
    dy=BaseLine.EndPoint.Y-BaseLine.BeginPoint.Y
    d=math.sqrt(dx*dx+dy*dy)
    cos=dx/d
    sin=dy/d
    #旋转平移变换 三角形顺时针旋转基线方向与X正轴重合
    x=(Point.X-BaseLine.BeginPoint.X)*cos+(Point.Y-BaseLine.BeginPoint.Y)*sin
    y=-(Point.X-BaseLine.BeginPoint.X)*sin+(Point.Y-BaseLine.BeginPoint.Y)*cos
    if(y<0):
        return 1
# 添加边
def AddLine(LineList,BaseStack,line):
    LineList.append(line)
    if(Judge_Dup(LineList)):
        del LineList[-1]
        del BaseStack[-1]
    return LineList,BaseStack
def AddBaseStack(BaseStack,line):
    BaseStack.append(line)
    if(Judge_Dup(BaseStack)):
        del BaseStack[-1]
    return BaseStack
#添加三角形
def AddTriangle(Triangle_List,triangle):
    already=0
    for tri in Triangle_List:
        if(tri==triangle):
            already=1
    if (already==0):
        Triangle_List.append(triangle)
        #三角形存储后 在刚存进的三角形三边上记录该三角形的列表索引号
        Triangle_List[-1].BaseLine.Belonging_Triangle.append(len(Triangle_List)-1)
        Triangle_List[-1].newLine1.Belonging_Triangle.append(len(Triangle_List)-1)
        Triangle_List[-1].newLine2.Belonging_Triangle.append(len(Triangle_List)-1)
    return Triangle_List
# 建立边与三角形间的索引
def EdgeIndexTri(Triangle_List):
    for i in range(0,len(Triangle_List)):
        for j in range(0,len(Triangle_List)):
            if(i==j):
                continue
            else:
                if(Triangle_List[i].BaseLine==Triangle_List[j].BaseLine or Triangle_List[i].BaseLine==Triangle_List[
                    j].newLine1 or Triangle_List[i].BaseLine==Triangle_List[j].newLine2):
                    Triangle_List[i].BaseLine.Belonging_Triangle.append(j)
                if(Triangle_List[i].newLine1==Triangle_List[j].BaseLine or Triangle_List[i].newLine1==Triangle_List[
                    j].newLine1 or Triangle_List[i].newLine1==Triangle_List[j].newLine2):
                    Triangle_List[i].newLine1.Belonging_Triangle.append(j)
                if(Triangle_List[i].newLine2==Triangle_List[j].BaseLine or Triangle_List[i].newLine2==Triangle_List[
                    j].newLine1 or Triangle_List[i].newLine2==Triangle_List[j].newLine2):
                    Triangle_List[i].newLine2.Belonging_Triangle.append(j)
    return Triangle_List
# 生成TIN三角网
def CreatTIN(Point_List):
    point_list=Point_List # copy 一份 备用
    line_list=[] # 存放边的列表
    triangle_list=[] # 存放三角形的列表
    base_stack=[]
    basebegin=randint(0,len(point_list)-1)
    basend=NearistPoint(point_list[basebegin],point_list)
    line_list.append(Line(point_list[basebegin],point_list[basend]))
    base_stack.append(Line(point_list[basebegin],point_list[basend]))
    while(len(base_stack)):
        line=base_stack[-1]
        del base_stack[-1]
        index=CreatTRI(line,point_list)
        if(index==None):
            continue
        elif(index!=None):
            triangle=Triangle(line.BeginPoint,line.EndPoint,point_list[index])
            base_stack=AddBaseStack(base_stack,Line(line.BeginPoint,point_list[index]))
            base_stack=AddBaseStack(base_stack,Line(point_list[index],line.EndPoint))
            [line_list,base_stack]=AddLine(line_list,base_stack,Line(line.BeginPoint,point_list[index]))
            [line_list,base_stack]=AddLine(line_list,base_stack,Line(point_list[index],line.EndPoint))
            triangle_list=AddTriangle(triangle_list,triangle)
    Triangle_list=EdgeIndexTri(triangle_list)
    return line_list,Triangle_list

'''*******************窗体********************'''
# 生成一个窗体界面 命名为window
window=tk.Tk()
window.title('TIN')
window.geometry('1000x750')

# 在窗体上生成一块画布 用于绘制导线图
canvas = tk.Canvas(window,width=800,height=600,bg = 'white')
canvas.place(x=190,y=10)

# 画出数据点
def Draw_Point(Point_List):
    xyminmax=XYMinMax(Point_List)
    for point in Point_List:
        gxgy=GaussToScreenCor(xyminmax,point.X,point.Y)
        oval = canvas.create_oval(gxgy[0]-1, gxgy[1]-1, gxgy[0]+1, gxgy[1]+1)
        #canvas.create_text(gxgy[0]-13,gxgy[1],text=point.PointName)

# 画出TIN网
def Connect_Point(list1,list2,color):
    line = canvas.create_line(list1[0], list1[1],list2[0],list2[1],fill = color)
def Draw_TIN(Point_List,Line_List):
    xyminmax=XYMinMax(Point_List)
    for line in Line_List:
        gxgy1=GaussToScreenCor(xyminmax,line.BeginPoint.X,line.BeginPoint.Y)
        gxgy2=GaussToScreenCor(xyminmax,line.EndPoint.X,line.EndPoint.Y)
        oval = canvas.create_oval(gxgy1[0]-1, gxgy1[1]-1, gxgy1[0]+1, gxgy1[1]+1)
        ova2 = canvas.create_oval(gxgy1[0]-1, gxgy1[1]-1, gxgy1[0]+1, gxgy1[1]+1)
        Connect_Point(gxgy1,gxgy2,'black')

#********调试********
path="D:\等高线点数据.txt"
point_list=ReadDataTXT(path)
Draw_Point(point_list)
Net=CreatTIN(point_list)
Draw_TIN(point_list,Net[0])
window.mainloop()
'''*******************所有代码在此之上********************'''
  • 39
    点赞
  • 160
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值