Voronoi图和Delaunay三角形和凸包



写一下最近写的一点东西...

最近在上算法课,上课老师讲到了维诺图,自己觉得很有意思就研究了一下,并用java写了一个简单的se程序用来显示维诺图和Delaunay三角形还有凸包。

首先介绍一下凸包,凸包在数学里是很常见的,给定一些点,然后找出包含这些的最小凸包,一般是这么做的。至于凸包的定义维基百科或者百度都行,自己查一查就知道,通俗的讲就是延长每一条边,剩下的图形总在边的一边。

(界面有点丑)

这边给出一下我程序运行出来的凸包

然后是Delaunay三角形,这个三角形是这样的,可以在凸包里面进行插入点,然后连接各个节点和插入点,然后会形成三角形,再插入还会再次分割三角形,并且形成的三角形是不包括第四个点的。

Voronoi图在上述三角形的基础上求得每一个三角形外接圆的圆心,连接各个这样的圆心可以得到这么一个voronoi图。

好了这是我的效果展示图,具体代码我上传到Github上供大家学习参考,有些一点注释,但因为写的比较匆忙不是写的很详细,大家有问题可以一起讨论讨论。

Github地址:https://github.com/monster5475/JAVACore/tree/master/

接下来说一下我做这个过程中遇到的一些问题和一些事情,首先要感谢一下给我帮助蛮多的几篇博客。

https://www.cnblogs.com/zhiyishou/p/4430017.html 这篇主要讲三角形的切割形成

https://blog.csdn.net/u012328159/article/details/50808360 这篇主要讲用graphScan的方法形成的凸包

https://blog.csdn.net/gdut2015go/article/details/48208983 这是一个参考博客。

https://blog.csdn.net/k346k346/article/details/52244123 这是我主要参考的,按照实现的博客,这个博客写的挺好的,我基本参考这个思路走的。

忘了补充一下Bowyer-Watson算法,我还查看《基于Bowyer_Watson三角网生成算法的研究_周雪梅》这篇文章中的一些伪代码。

真的是前人栽树,后人乘阴,感谢前辈!



现在来介绍一下主要思路

(1)首先是java窗体设计,以及一些按钮的绑定什么的,画图,大概一天完成的,窗体画图有点忘了。

(2)然后是第一步随机生成点函数,这个没什么难度,主要要注意不要生成重复点,然后不要超过边界。(一开始以为会存在画图x y和现实中x y的差距,后来发现不用考虑)

(3)得到一个point的arraylist,先找到y最低点,得到一个扇形图类似如此

然后p0就一定是凸包上的一个点,p1点也必定是凸包上的一点,然后将这两个点进栈,开始判断其他点,这边首先要了解一下叉乘的概念,向量a叉乘向量b,得到的结果向量是垂直于向量a和b组成的平面,方向是根据a和b的叉乘的顺序根据右手法则判断的,那么我们就可以通过叉乘的结果的正负来确定点的位置比如在向量p0p1 和向量p1p2的叉乘中(注意叉乘首先要让两个向量是同一个起点),根据右手法则得到的就是一个垂直纸面向外的向量,那么就可以说明点p2在向量p0p1的逆时针一边。如果p2在p0p1在的顺时针一边,则叉乘结果应该是垂直纸面向内的向量。根据这一点,我们就可以一个一个判断,比如p0p1判断完p2是我们要的点,那么进栈,这个时候栈中元素为(p0,p1,p2)p2位栈顶元素,这时候我们再连接p2p3,用向量p1p2(栈顶的两个点)叉乘p2p3,发现结果向量垂直纸面向内,那么点p3是在p1p2的顺时针的方向,那么就跟我们凸包的定义出错,因为我们在之前说了凸包上的所有点会在边的同一侧,现在p3在顺时针一边,p0在逆时针一边,所以p2不是凸包上的一点,将p2出栈,p3入栈,如此如此 直到最后。。这个是Graham扫描法,因为我们一开始选定是从逆时针方向,所以判断的时候相关,当然我们也可以选择顺时针方向,那时候我们就是从p12 p11那边算起,那时候我们就要判断点是否在当前栈的两个点组成的边的顺时针方向。

(4)然后我们得到了这些点组成的凸包,现在我们将要进行Delaunay三角形的构造,我一开始是确定用Bowyer-Watson算法进行生成,但是在其中第二步的时候我有些疑惑,后来自己想了一种办法解决,不知道是否有漏洞,但是画图画出来倒是都ok的,我这边拷贝一下上面链接中一个博主发的话

Delaunay剖分是一种三角剖分的标准,实现它有多种算法。本次采用Bowyer-Watson算法,算法的基本步骤是:

(1)构造一个超级三角形,包含所有散点,放入三角形链表。

(2)将点集中的散点依次插入,在三角形链表中找出其外接圆包含

插入点的三角形(称为该点的影响三角形),删除影响三角形的公共边,将插入点同影响三角形的全部顶点连接起来,从而完成一个点在Delaunay三角形链表中的插入。

(3)根据优化准则对局部新形成的三角形进行优化。将形成的三角形放入Delaunay三角形链表。

(4)循环执行上述第2步,直到所有散点插入完毕。

关键步骤2如下图所示:

步骤3的局部优化的准则指的是:

1.对新形成的三角形进行优化,将两个具有共同边的三角形合成一个多边形。

2.以最大空圆准则作检查,看其第四个顶点是否在三角形的外接圆之内。

3.如果在,修正对角线即将对角线对调,即完成局部优化过程的处理。

LOP (Local Optimization Procedure)处理过程如下图所示:

---------------------

本文来自 Dablelv 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/k346k346/article/details/52244123?utm_source=copy

我这边疑惑的是第二步中怎么去“删除影响三角形的公共边,将插入点同影响三角形的全部顶点连接起来”,后来在写代码中想到了一种方法,我现在在这里进行一下说明,首先我们得到了凸包,现在我们在凸包中插入一个点,那么怎么进行三角形的划分呢?是不是直接拿各个凸包的点和插入点连接就可以完成了三角形的划分,得到一个Triangles,然后我们现在进行第二个点的插入,我们检测Triangle的外接圆发现这个点在三个三角形内,我们称这三个三角形是受影响的三角形,我们可以判断这三个三星形是连在一起的,我们将这三个三角形从Triangles中删除,并用这三个三角形的边形成了一个多边形,然后这个插入点就在这个多边形中间,这是不是就是变成我们插入第一个点的情况。。我们只需连接各个点与插入点就可以得到全新的三星形集合,加入Triangles即可。这边还值得注意的是局部优化修正过程,一开始不是很理解这个情况,后来自己想了一下这种情况应该是要避免外接圆中的刚好两个点是直径的情况然后第四个点在园内,要修改对角线,形成小的外接圆,将其中一个点分叉出去。

等以上工作全部做完以后你就可以得到一个Triangles的列表,画出来就可以

(5)最后一步是维诺图的建立,其实维诺图的建立在Delaunay三角形上就已经很方便了,只要找出上一步的各个Triangle的外接圆圆心,然后将具有共同边的外接圆圆心连接起来就可以得到我们需要的初步维诺图,还有的是值得注意的是维诺图中存在一些射线。我就是在画图过程中被这些射线搞得烦死了。只有真正有画图的需求才知道射线好难决定。。我也说不清楚,如果按我写的代码中我处理很复杂,虽然是画出来了,但是还有一点点问题。可能有时候会失效。。

上面就是我写这个小项目的过程,其中用了一些java8的stream特性,觉得java8还挺好用的。。加油加油。



下面放几个类的小截图,给也想要试一下你的一些感觉,当然你可以去看看我的代码。如果觉得我还可以的,麻烦给我Github的项目小星星~~~

这是主要算法类:Algorithm

这是Edge的类 主要重写了equals和tostring

这是窗体类

这是画板类

稍微贴几张图,具体可以去看代码~~~

这是自己实现的一个代码,发现网上资料有是有,但是没看到一个真正可以跑起来的,自己做一个例子happy一下,额~这个大概用了我五天的时间去写完。当然是断断续续,因为最近也在上课了。

原文地址:https://www.cnblogs.com/monster5475/p/9726543.html

时间: 2024-10-08 17:47:15

Voronoi图和Delaunay三角形和凸包的相关文章

OpenCV生成点集的Delaunay剖分和Voronoi图

实现内容: 设置一副图像大小为600*600,图像像素值全为0,为黑色. 在图像中Rect(100,100,400,400)的区域随机产生20个点,并画出. 产生这些点集的Delaunay剖分和Voronoi图,并画出. 程序 #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> using namespace cv; using

Voronoi图及matlab实现

[题外话:想一想真是...美赛时我预测求爱尔兰的充电站位置分布,画Voronoi图,程序跑了一个小时...] Voronoi图,又叫泰森多边形或Dirichlet图,它是由一组由连接两邻点直线的垂直平分线组成的连续多边形组成.N个在平面上有区别的点,按照最邻近原则划分平面:每个点与它的最近邻区域相关联.Delaunay三角形是由与相邻Voronoi多边形共享一条边的相关点连接而成的三角形.Delaunay三角形的外接圆圆心是与三角形相关的Voronoi多边形的一个顶点. 对于点集 里的种子点 ,

Java调用AE实现创建泰森多边形(voronoi图)

在网上搜索 AE 创建泰森多边形,都是基于VB或者C#的, 鉴于C#和Java相近,就将C#的代码翻译成Java, 但修改后的程序运行无结果, 经多次尝试,设置了addFromFeatureClass方法的第三个参数,终于获得了泰森多边形. 现把代码共享,如下: public void CreatVoronoi(IFeatureClass pointFeaCls,IFeatureClass voronoiFeaCls,IPolygon clippingPolygon){ try { if (po

hdu2202(最大三角形 )凸包

最大三角形 Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3184    Accepted Submission(s): 1075 Problem Description 老师在计算几何这门课上给Eddy布置了一道题目,题目是这样的:给定二维的平面上n个不同的点,要求在这些点里寻找三个点,使他们构成的三角形拥有的面积最大.Eddy对这道

Voronoi图简介及C语言实现

Voronoi图广泛应用在几何学.地理学.晶体学.信息系统等学科之中.Voronoi图是由图中各个相邻点连线的中垂线组成的连续多边形组成.图中的各个点归属于该点最邻近的多边形,入下图所示: Voronoi图相应的C语言实现代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #define N_SITES 150 double site[N_SITES][2]; unsigned char rg

HDU2202--最大三角形(凸包,枚举)

Problem Description 老师在计算几何这门课上给Eddy布置了一道题目,题目是这样的:给定二维的平面上n个不同的点,要求在这些点里寻找三个点,使他们构成的三角形拥有的面积最大.Eddy对这道题目百思不得其解,想不通用什么方法来解决,因此他找到了聪明的你,请你帮他解决这个题目. Input 输入数据包含多组测试用例,每个测试用例的第一行包含一个整数n,表示一共有n个互不相同的点,接下来的n行每行包含2个整数xi,yi,表示平面上第i个点的x与y坐标.你可以认为:3 <= n <=

Hadoop 分析图中节点的重要性,求解图中节点三角形个数

Hadoop 求解无向图中节点的重要性,通过求解节点的三角形个数来展现: 求解图中节点重要性,并排序,在大数据,分布式处理大型图组织形式的数据时很重要,找出重要节点,并对重要节点做特殊处理是很重要的 下面讲解如何来求解 这篇文章分为三部分: 1,python生成无向图的邻接矩阵 2,python画出这个无向图 3,hadoop mapreduce 求解图中每个节点的三角形个数 关于hadoop求解矩阵相乘,请看之前的文章:http://blog.csdn.net/thao6626/article

Delaunay Triangulation in OpenCascade

Delaunay Triangulation in OpenCascade [email protected] 摘要:本文简要介绍了Delaunay三角剖分的基础理论,并使用OpenCascade的三角剖分算法将边界BRep表示的几何体进行三角离散化后在OpenSceneGraph中显示. 关键字:Delaunay Triangulation.OpenCascade.OpenSceneGraph 一. 概述 三角剖分是平面剖分中的一个重要课题,在数字图像处理.计算机三维曲面造型.有限元计算.逆向

重新网格化(Remesh)

原文链接 Remesh并没有一个严格的定义,简单的讲,Remesh就是从一个输入网格生成另一个网格,并且满足一定的要求.根据网格改动大小,可以分为这么几类: 保持顶点拓扑和几何信息,优化网格连接关系 保持顶点拓扑信息,同时优化顶点几何和网格连接关系 顶点重采样,优化网格连接关系 Remesh对原网格的改动比较大,实际应用中要谨慎使用.尽量使用改动比较小的Remesh方法. Delaunay三角化 Delaunay三角化,是点云的一种三角化方法,它具有某些好的性质: 网格中的最小角最大化 任意三角