Delauney 三角网剖分
算法原理:分为三步:
一、凸包生成:1)求出如下四点:min(x-y)、min(x+y)、max(x-y)、
max(x+y)并顺次放入一个数组,组成初始凸包;2)对于凸包上的
点 I,设它的后续点为 J,计算矢量线段 IJ 右侧的所有点到 IJ 的距
离,求出距离最大的点 K;3)将 K 插入 I,J 之间,并将 K 赋给 J;
4)重复 2,3 步,直到点集中没有在 IJ 右侧的点为止;5)将 J 赋
给 I,J 取其后续点,重复 2,3,4 步,当遍历了一次凸包后,凸
包生成完成。
二、环切边界法凸包三角剖分:在凸包数组中,每次寻找一
个由相邻两条凸包边组成的三角形,在该三角形的内部和边界上
都不包含凸包上的任何其他点,然后去掉该点得到新的凸包链表,
重复这个过程,最终对凸包数组中的点进行三角剖分成功。
三、离散的内插:1)建立三角形的外接圆,找出外接圆包含
待插入点的所有三角形,构成插入区域;2)删除插入区域内的三
角形公共边,形成由影响三角形顶点构成的多边形;3)将插入点
与多边形所有顶点相连,构成新的 Delaunay 三角形;4)重复 1,
2,3,直到所有非凸包上的离散点都插入完为止。
功能实现流程:
1. 在绘图菜单栏下添加一个子菜单项为 Delauney,并且在工具栏
上添加一个工具项。设置 text 为 Delaunay 三角剖分,name 为 delaunay
等属性,添加单击事件,并为单击事件代码
2.为事件函数添加如下代码
Graphics gra = panel1.CreateGraphics();
List
pts = new List();
foreach (Geometry_T geo in choosegeos.Geofeatures)
{
}
if (geo.GetType() == typeof(Point_T))
{
}
Point_T pt = (Point_T)geo;
pts.Add(pt);
List deltins = DelauneyTin(pts);//根据多点构建delauney三角网
foreach (Tin tin in deltins)
{
}
Point[] ctin = new Point[3];
for (int i = 0; i < 3; i++)
{
}
cp = new Point((int)tin.Pthree[i].X, (int)tin.Pthree[i].Y);
ctin[i] = cp;
gra.DrawPolygon(Pens.Red, ctin);
3.三角形 TIN 的数据结构
public class Tin
{
Point_T[] pthree = new Point_T[3];
Line_T[] lthree = new Line_T[3];
public Line_T[] Lthree
{
}
get { return lthree; }
set { lthree = value; }
public Point_T[] Pthree
{
}
get { return pthree; }
set { pthree = value; }
public Tin()
{ }
public Tin(Point_T p1, Point_T p2, Point_T p3)
{
}
pthree[0] = p1;
pthree[1] = p2;
pthree[2] = p3;
lthree[0] = new Line_T(p1, p2);
lthree[1] = new Line_T(p2, p3);
lthree[2] = new Line_T(p3, p1);
}
4.圆的数据结构
public class Circle_T:Geometry_T
{
private Point_T cpt;
public Point_T Cpt
{
}
get { return cpt; }
set { cpt = value; }
double radius;
public double Radius
{
}
get { return radius; }
set { radius = value; }
public Circle_T()
{ }
public Circle_T(Point_T pt, double r)
cpt = pt;
radius = r;
{
}
}
5.实现 Delaunay 三角剖分算法
1) public List
DelauneyTin(List pts)//根据多点构建delauney三角网;
分三步:构建凸包;凸包剖分;离散点内插
{
Graphics gra = panel1.CreateGraphics();
envpts.Add(pts[0]);
envpts.Add(pts[pts.Count - 1]);
othpts.Remove(pts[0]);
othpts.Remove(pts[pts.Count-1]);
pts.Sort(comxandy);
if(!envpts.Contains(pts[0]))
{
}
envpts.Insert(1, pts[0]);
if (!envpts.Contains(pts[pts.Count - 1]))
{
}
envpts.Add(pts[pts.Count - 1]);
othpts.Remove(pts[0]);
othpts.Remove(pts[pts.Count-1]);
//构建以x-y,x+y最大最小值组成的初始矩形框
int i = 0;
int tag = 0;
bool over = true;
while(i dismax)
{
dismax = distance;
tag = j;
over = false;
}
}
}
if (over)
{
}
i++;
else
{
}
//envpts.RemoveAt(i);
envpts.Insert(i+1, othpts[tag]);
over = true;
}
return envpts;
}
public List
EnvelopeDivision(List pts)//凸包剖分
{
List envtins = new List();
List cpts = new List();
foreach (Point_T pt in pts)
{
}
cpts.Add(pt);
while (cpts.Count > 2)
{
int tag = 0;
double minangle = 120;
for (int i = 0; i < cpts.Count; i++)
{
double angle;
if (i == 0)
angle = CalcuAngle(cpts[cpts.Count - 1], cpts[i], cpts[i + 1]);
{
}
else if (i == cpts.Count - 1)
{
}
else
{
angle = CalcuAngle(cpts[i-1], cpts[i], cpts[0]);
angle = CalcuAngle(cpts[i-1], cpts[i], cpts[i + 1]);
}
if ((angle - 60) < minangle)
{
}
minangle = angle - 60;
tag = i;
}
int btag=tag-1;
int atag=tag+1;
if (tag == 0)
{
}
btag = cpts.Count - 1;
else if (tag == cpts.Count - 1)
{
}
atag = 0;
Tin ctin = new Tin(cpts[btag], cpts[tag], cpts[atag]);
envtins.Add(ctin);
cpts.RemoveAt(tag);
}
return envtins;
}
public List
TinInsert(List tins, List pts)//离散点内插
{
List deltins = new List();
List ctins = new List();//临时凸包
foreach (Tin tin in tins)
{
}
ctins.Add(tin);
foreach (Point_T pt in pts)//对离散点遍历,内插
{
List cpts = new List();//临时点集
foreach (Tin tin in ctins)//找到外接圆包含离散点的三角形
{
Circle_T ccir = DelauneyCicle(tin);//构造外接圆
if (IsPointInCircle(pt, ccir))//点是否包含在圆内
{
//for (int i = 0; i < 3; i++)
//{
//
if (!cpts.Contains(tin.Pthree[i]))
{
}
//
//
//
//}
cpts.Add(tin.Pthree[i]);//记录当前点
deltins.Add(tin); //记录保存当前三角形
}
}
//List
ecpts = EnvelopeTin(cpts);//求点集(外接圆包含离散的
三角形)的凸包?,接下来,插入点,构建新三角网
//for (int j = 0; j < ecpts.Count;j++ )
//{
//
//
//
//
//
//
//
//
//
//
//}
Tin tin;
if (j == ecpts.Count-1)
{
}
tin = new Tin(ecpts[j], ecpts[0], pt);
else
{
}
tin=new Tin(ecpts[j],ecpts[j+1],pt);
ctins.Add(tin);
List eli = BorderTin(deltins);
foreach (Line_T line in eli)
{
}
Tin tin = new Tin(line.Frompt, line.Topt, pt);
ctins.Add(tin);
foreach (Tin tin in deltins)//改变临时三角网(删除deltins保存的三角
网)
3)
}
{
{
}
ctins.Remove(tin);
deltins.Clear();
}
return ctins;
public bool IsLeftPoint(Point_T pt, Line_T line)//点在线的左边;叉积大于
bool yes = false;
if ((pt.X - line.Frompt.X) * line.ParaA + (pt.Y - line.Frompt.Y) *
line.ParaB > 0)