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

一、三角剖分Delaunay算法简介

点集的三角剖分(Triangulation),对数值分析(比如有限元分析)以及图形学来说,都是极为重要的一项预处理技术。尤其是Delaunay三角剖分,由于其独特性,关于点集的很多种几何图都和Delaunay三角剖分相关,如Voronoi图,EMST树,Gabriel图等。Delaunay三角剖分有最大化最小角,“最接近于规则化的“的三角网和唯一性(任意四点不能共圆)两个特点。

 EMST(Euclidean minimum spanning tree)

Delaunay 三角剖分广泛应用于许多不同应用程序中的科学计算。虽然有大量的计算三角剖分的算法,但 Delaunay 三角剖分以其实用的几何属性广受欢迎。

 Gabriel Graph

基本属性是 Delaunay 规则。如果是二维三角剖分,通常将其称为空外接圆规则。对于一组二维点而言,这些点的 Delaunay 三角剖分可确保与每个三角形相关的外接圆的内部都不包含其他点。这种三角剖分便是 Delaunay 三角剖分。

Delaunay 三角剖分堪称“外形整齐”,原因在于为满足空外接圆属性,优先选择带有较大内角的三角形,而不是带有较小内角的三角形。非 Delaunay 三角剖分中的三角形在顶点 V2 和 V4 处呈锐角。如果将 {V2, V4} 边替换为连接 V1 和 V3 的边,会实现最小角的最大化并且使得该三角剖分变为 Delaunay 三角剖分。另外,Delaunay 三角剖分将最近邻点的点连接在一起。这两个特征(外形整齐和最近邻点关系)在实践中具有重要的作用,有助于促进在散点数据插值中使用 Delaunay 三角剖分。

虽然 Delaunay 属性定义明确,但存在退化点集时三角剖分的拓扑并不唯一。在二维中,4 个或更多特征点位于同一圆中时会引发退化。例如,正方形的顶点不具有唯一的 Delaunay 三角剖分。
 

二、三角剖分Delaunay算法的源代码


namespace Legalsoft.Truffer.Algorithm
{
    public struct Vertex
    {
        public int x;
        public int y;
        public int z;
    }

    public struct Triangle
    {
        public int vv0;
        public int vv1;
        public int vv2;
    }

    public class Delaunay
    {
        public const int MaxVertices = 500;
        public const int MaxTriangles = 1000;
        public Vertex[] Vertex = new Vertex[MaxVertices];
        public Triangle[] Triangle = new Triangle[MaxTriangles];

        private bool InCircle(int xp, int yp, int x1, int y1, int x2, int y2, int x3, int y3, double xc, double yc, double r)
        {
            double eps;
            double m1;
            double m2;
            double mx1;
            double mx2;
            double my1;
            double my2;
            double dx;
            double dy;
            double rsqr;
            double drsqr;
            eps = 0.000000001;
            if (Math.Abs(y1 - y2) < eps && Math.Abs(y2 - y3) < eps)
            {
                MessageBox.Show("INCIRCUM - F - Points are coincident !!");
                return false;
            }

            if (Math.Abs(y2 - y1) < eps)
            {
                m2 = (-(Convert.ToDouble(x3) - Convert.ToDouble(x2)) / (Convert.ToDouble(y3) - Convert.ToDouble(y2)));
                mx2 = Convert.ToDouble((x2 + x3) / 2.0);
                my2 = Convert.ToDouble((y2 + y3) / 2.0);
                xc = Convert.ToDouble((x2 + x1) / 2.0);
                yc = Convert.ToDouble(m2 * (xc - mx2) + my2);
            }
            else if (Math.Abs(y3 - y2) < eps)
            {
                m1 = (-(Convert.ToDouble(x2) - Convert.ToDouble(x1)) / (Convert.ToDouble(y2) - Convert.ToDouble(y1)));
                mx1 = Convert.ToDouble((x1 + x2) / 2.0);
                my1 = Convert.ToDouble((y1 + y2) / 2.0);
                xc = Convert.ToDouble((x3 + x2) / 2.0);
                yc = Convert.ToDouble(m1 * (xc - mx1) + my1);
            }
            else
            {
                m1 = (-(Convert.ToDouble(x2) - Convert.ToDouble(x1)) / (Convert.ToDouble(y2) - Convert.ToDouble(y1)));
                m2 = (-(Convert.ToDouble(x3) - Convert.ToDouble(x2)) / (Convert.ToDouble(y3) - Convert.ToDouble(y2)));
                mx1 = Convert.ToDouble((x1 + x2) / 2.0);
                mx2 = Convert.ToDouble((x2 + x3) / 2.0);
                my1 = Convert.ToDouble((y1 + y2) / 2.0);
                my2 = Convert.ToDouble((y2 + y3) / 2.0);
                xc = Convert.ToDouble((m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2));
                yc = Convert.ToDouble(m1 * (xc - mx1) + my1);
            }
            dx = (Convert.ToDouble(x2) - Convert.ToDouble(xc));
            dy = (Convert.ToDouble(y2) - Convert.ToDouble(yc));
            rsqr = Convert.ToDouble(dx * dx + dy * dy);
            r = Convert.ToDouble(Math.Sqrt(rsqr));
            dx = Convert.ToDouble(xp - xc);
            dy = Convert.ToDouble(yp - yc);
            drsqr = Convert.ToDouble(dx * dx + dy * dy);
            if (drsqr <= rsqr)
            {
                return true;
            }
            return false;
        }

        private int WhichSide(int xp, int yp, int x1, int y1, int x2, int y2)
        {
            double equation;
            equation = ((Convert.ToDouble(yp) - Convert.ToDouble(y1)) * (Convert.ToDouble(x2) - Convert.ToDouble(x1))) - ((Convert.ToDouble(y2) - Convert.ToDouble(y1)) * (Convert.ToDouble(xp) - Convert.ToDouble(x1)));
            if (equation > 0)
            {
                return -1;
            }
            else if (equation == 0)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        }

        public int Triangulate(int nvert)
        {
            bool[] Complete = new bool[MaxTriangles];
            long[,] Edges = new long[3, MaxTriangles * 3 + 1];
            int Nedge;
            int xmin;
            int xmax;
            int ymin;
            int ymax;
            int xmid;
            int ymid;
            double dx;
            double dy;
            double dmax;
            int i;
            int j;
            int k;
            int ntri;
            double xc = 0.0;
            double yc = 0.0;
            double r = 0.0;
            bool inc;
            xmin = Vertex[1].x;
            ymin = Vertex[1].y;
            xmax = xmin;
            ymax = ymin;
            for (i = 2; i <= nvert; i++)
            {
                if (Vertex[i].x < xmin)
                {
                    xmin = Vertex[i].x;
                }
                if (Vertex[i].x > xmax)
                {
                    xmax = Vertex[i].x;
                }
                if (Vertex[i].y < ymin)
                {
                    ymin = Vertex[i].y;
                }
                if (Vertex[i].y > ymax)
                {
                    ymax = Vertex[i].y;
                }
            }
            dx = Convert.ToDouble(xmax) - Convert.ToDouble(xmin);
            dy = Convert.ToDouble(ymax) - Convert.ToDouble(ymin);
            if (dx > dy)
            {
                dmax = dx;
            }
            else
            {
                dmax = dy;
            }
            xmid = (xmax + xmin) / 2;
            ymid = (ymax + ymin) / 2;
            Vertex[nvert + 1].x = Convert.ToInt64(xmid - 2 * dmax);
            Vertex[nvert + 1].y = Convert.ToInt64(ymid - dmax);
            Vertex[nvert + 2].x = xmid;
            Vertex[nvert + 2].y = Convert.ToInt64(ymid + 2 * dmax);
            Vertex[nvert + 3].x = Convert.ToInt64(xmid + 2 * dmax);
            Vertex[nvert + 3].y = Convert.ToInt64(ymid - dmax);
            Triangle[1].vv0 = nvert + 1;
            Triangle[1].vv1 = nvert + 2;
            Triangle[1].vv2 = nvert + 3;
            Complete[1] = false;
            ntri = 1;
            for (i = 1; i <= nvert; i++)
            {
                Nedge = 0;
                j = 0;
                do
                {
                    j = j + 1;
                    if (Complete[j] != true)
                    {
                        inc = InCircle(Vertex[i].x, Vertex[i].y, Vertex[Triangle[j].vv0].x, Vertex[Triangle[j].vv0].y, Vertex[Triangle[j].vv1].x, Vertex[Triangle[j].vv1].y, Vertex[Triangle[j].vv2].x, Vertex[Triangle[j].vv2].y, xc, yc, r);
                        if (inc)
                        {
                            Edges[1, Nedge + 1] = Triangle[j].vv0;
                            Edges[2, Nedge + 1] = Triangle[j].vv1;
                            Edges[1, Nedge + 2] = Triangle[j].vv1;
                            Edges[2, Nedge + 2] = Triangle[j].vv2;
                            Edges[1, Nedge + 3] = Triangle[j].vv2;
                            Edges[2, Nedge + 3] = Triangle[j].vv0;
                            Nedge = Nedge + 3;
                            Triangle[j].vv0 = Triangle[ntri].vv0;
                            Triangle[j].vv1 = Triangle[ntri].vv1;
                            Triangle[j].vv2 = Triangle[ntri].vv2;
                            Complete[j] = Complete[ntri];
                            j = j - 1;
                            ntri = ntri - 1;
                        }
                    }
                }
                while (j < ntri);
                for (j = 1; j <= Nedge - 1; j++)
                {
                    if (Edges[1, j] != 0 && Edges[2, j] != 0)
                    {
                        for (k = j + 1; k <= Nedge; k++)
                        {
                            if (Edges[1, k] != 0 && Edges[2, k] != 0)
                            {
                                if (Edges[1, j] == Edges[2, k])
                                {
                                    if (Edges[2, j] == Edges[1, k])
                                    {
                                        Edges[1, j] = 0;
                                        Edges[2, j] = 0;
                                        Edges[1, k] = 0;
                                        Edges[2, k] = 0;
                                    }
                                }
                            }
                        }
                    }
                }
                for (j = 1; j <= Nedge; j++)
                {
                    if (Edges[1, j] != 0 && Edges[2, j] != 0)
                    {
                        ntri = ntri + 1;
                        Triangle[ntri].vv0 = Edges[1, j];
                        Triangle[ntri].vv1 = Edges[2, j];
                        Triangle[ntri].vv2 = i;
                        Complete[ntri] = false;
                    }
                }
            }
            i = 0;
            do
            {
                i = i + 1;
                if (Triangle[i].vv0 > nvert || Triangle[i].vv1 > nvert || Triangle[i].vv2 > nvert)
                {
                    Triangle[i].vv0 = Triangle[ntri].vv0;
                    Triangle[i].vv1 = Triangle[ntri].vv1;
                    Triangle[i].vv2 = Triangle[ntri].vv2;
                    i = i - 1;
                    ntri = ntri - 1;
                }
            }
            while (i < ntri);
            return ntri;
        }
    }
}

 ——————————————————————

POWER BY 315SOFT.COM &
TRUFFER.CN

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/353563.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

03 Redis之命令(基本命令+Key命令+String型Value命令与应用场景)

Redis 根据命令所操作对象的不同&#xff0c;可以分为三大类&#xff1a;对 Redis 进行基础性操作的命令&#xff0c;对 Key 的操作命令&#xff0c;对 Value 的操作命令。 3.1 Redis 基本命令 一些可选项对大小写敏感, 所以应尽量将redis的所有命令大写输入 首先通过 redis-…

Nodejs前端学习Day3_准备工作

妈的&#xff0c;这几天真tm冷&#xff0c;前天上午还下了一整天的雪&#xff0c;大雪 文章目录 前言一、Node.js简介1.1何为1.2有什么 二、Node.js可以做什么三、学习路线四、下载nodejs4.1小坑记录4.2LTS和Current版本的不同 五、什么是终端六、在nodejs中执行js代码七、powe…

【PyTorch】n卡驱动、CUDA Toolkit、cuDNN全解安装教程

文章目录 GPU、NVIDIA Graphics Drivers、CUDA、CUDA Toolkit和cuDNN的关系使用情形判断仅仅使用PyTorch使用torch的第三方子模块 安装NVIDIA Graphics Drivers&#xff08;可跳过&#xff09;前言Linux法一&#xff1a;图形化界面安装&#xff08;推荐&#xff09;法二&#x…

用友U8接口-部署和简要说明(1)

概括 本专栏文章目的说明对目前用友U8ERP接口介绍对底层接口二次封装的介绍 说明 过去发布过介绍U8接口文章简介&#xff0c;参考以下链接。 U8接口开发方式 本专栏文章与下面的HTTP接口相辅相成&#xff0c;主要是写给正在使用&#xff0c;或未来使用本套接口的开发人员&am…

PhpStorm调试docker容器中的php项目

背景 已经通过docker容器启动了一个web服务&#xff0c;并在宿主机可以访问http://localhost:8080访问网页。 现在想使用phpstorm打断点调试代码。 方法 1. 容器内安装xdebug 进入容器 docker exec -it <container-name> bash为php安装xdebug拓展 apt install php8…

市场复盘总结 20240122

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 昨日主题投资 连板进级率 6/39 15.3% 二进三&#xff1a; 进级率低 0% 最常用的二种方法&#xff1a; 方法…

数据湖技术之发展现状篇

一. 大数据处理架构&#xff1a; 大数据处理架构的发展过程具体可以分为三个主要阶段&#xff1a;批处理架构、混合处理架构&#xff08;Lambda、Kappa架构&#xff09;、湖仓一体。首先是随着Hadoop生态相关技术的大量应用&#xff0c;批处理架构应运而生&#xff0c;借助离线…

用C语言实现贪吃蛇游戏!!!

前言 大家好呀&#xff0c;我是Humble&#xff0c;不知不觉在CSND分享自己学过的C语言知识已经有三个多月了&#xff0c;从开始的C语言常见语法概念说到C语言的数据结构今天用C语言实现贪吃蛇已经有30余篇博客的内容&#xff0c;也希望这些内容可以帮助到各位正在阅读的小伙伴…

MongoDB:从容器使用到 Mongosh、Python/Node.js 数据操作

文章目录 1. 容器与应用之间的关系介绍2. 使用 Docker 容器安装 MongoDB3. Mongosh 操作3.1 Mongosh 连接到 MongoDB3.2 基础操作与 CRUD 4. Python 操作 MongoDB5. Nodejs 操作 MongoDB参考文献 1. 容器与应用之间的关系介绍 MongoDB 的安装有时候并不是那么容易的&#xff0…

Qt项目文件以及对象树

"在哪里走散&#xff0c;你都会找到我~" 前篇&#xff0c;我们仅仅对Qt创建了第一个简单的项目。相比于使用其他IDE创建工程项目&#xff0c;Qt会为自动创建诸如&#xff1a;.pro、.h\.cpp、.iu等文件&#xff0c;这些文件到底是什么&#xff1f;我们在使用Qt时 应该…

c++ QT 信号的个人理解 信号就是独立文件调用的一种“协议”

一. 简介 就我个人来理解&#xff0c;信号槽机制与Windows下消息机制类似&#xff0c;消息机制是基于回调函数&#xff0c;Qt中用信号与槽来代替函数指针&#xff0c;使程序更安全简洁。 信号和槽机制是 Qt 的核心机制&#xff0c;可以让编程人员将互不相关的对象绑定在一起&a…

IntelliJ IDE 插件开发 | (五)VFS 与编辑器

系列文章 IntelliJ IDE 插件开发 |&#xff08;一&#xff09;快速入门IntelliJ IDE 插件开发 |&#xff08;二&#xff09;UI 界面与数据持久化IntelliJ IDE 插件开发 |&#xff08;三&#xff09;消息通知与事件监听IntelliJ IDE 插件开发 |&#xff08;四&#xff09;来查收…

[GYCTF2020]Ezsqli1

打开环境&#xff0c;下面有个提交表单 提交1&#xff0c;2有正确的查询结果&#xff0c;3以后都显示Error Occured When Fetch Result. 题目是sql&#xff0c;应该考察的是sql注入 简单fuzz一下 发现information_schema被过滤了&#xff0c;猜测是盲注了。 测试发现只要有东…

Qt : Style Sheet

When a style sheet is active, the QStyle returned by QWidget::style() is a wrapper “style sheet” style, not the platform-specific style. The wrapper style ensures that any active style sheet is respected and otherwise forwards the drawing operations to t…

Linux 系统相关的命令

目录 一. 系统用户相关1.1 查看当前访问的主机和用户1.2 切换用户1.2.1 设置root用户密码1.2.2 普通用户和root用户切换 1.4 系统状态1.4.1 vmstat 查看当前系统的状态1.4.2 history 查看系统中输入过的命令 二. 系统文件相关2.1 权限修改2.2 磁盘占用2.2.1 每秒钟监视当前磁盘…

在 VUE 项目中,使用 Axios 请求数据时,提示跨域,该怎么解决?

在 VUE 项目开发时&#xff0c;遇到个问题&#xff0c;正常设置使用 Axios 库请求数据时&#xff0c;报错提示跨域问题。 那在生产坏境下&#xff0c;该去怎么解决呢&#xff1f; 其可以通过以下几种方式去尝试解决&#xff1a; 1、设置允许跨域请求的响应头 1.1 在响应头中…

LINUX基础培训十九之常见服务nfs介绍

前言、本章学习目标 了解nfs服务用途掌握nfs服务器的配置掌握nfs客户端的配置使用 一、NFS简介 NFS&#xff08;Network File System&#xff09;即网络文件系统&#xff0c;它允许网络中的计算机之间通过TCP/IP网络共享资源。在NFS的应用中&#xff0c;本地NFS的客户端应用…

机器学习第一个项目-----鸢尾花数据集加载及报错解决

项目步骤 如刚开始做&#xff0c;从 “项目开始” 看&#xff1b; 如遇到问题从 “问题” 开始看&#xff1b; 问题 报错如下 ModuleNotFoundError: No module named sklearn解决过程 查看官网&#xff0c;感觉可能是python版本和skilearn版本不匹配&#xff0c;更新一下p…

使用vue_cli脚手架创建Vue项目(cmd和图形化方式)

使用vue_cli脚手架创建Vue项目&#xff08;cmd和图形化方式&#xff09; 创建项目(cmd方式) vue create vue_cli1.方向键选择manually select feature(手动选择方式创建)&#xff0c;回车 2.按空格键选择需要的组件&#xff1a;Babel、PWA、Router、Vuex、CSS&#xff0c;回…

【GitHub项目推荐--游戏模拟器(switch)】【转载】

01 任天堂模拟器 yuzu 是 GitHub 上斩获 Star 最多的开源 Nintendo Switch 模拟器 &#xff0c;使用 C 编写&#xff0c;考虑到了可移植性&#xff0c;该模拟器包括 Windows 和 Linux 端。 如果你的 PC 满足必要的硬件要求&#xff0c;该模拟器就能够运行大多数商业游戏&…