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

news2024/11/26 18:55:08

一、三角剖分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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode: 160.相交链表(令人赞叹的优雅)

160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 目录 官方双指针解法&#xff1a; 博主的辣眼代码&#xff1a; 每日一表情包&#xff1a; 博主还未学习哈希表&#xff0c;所以介绍的是双指针法&#xff0c;此题的哈希表解法时O&#xff08;nm&#xff09;空O&…

MySQL窗口函数--lead()函数

lead()函数&#xff1a; 查询当前行向下偏移n行对应的结果 该函数有三个参数&#xff1a;第一个为待查询的参数列名&#xff0c;第二个为向下偏移的位数&#xff0c;第三个参数为超出最下面边界的默认值。 如下代码&#xff1a; 查询向下偏移 2 位的年龄 SELECT user_id,user…

JavaScript高级:深浅拷贝

目录 1 引言 2 浅拷贝 2.1 拷贝数组 1.2 拷贝对象 3 赋值操作和浅拷贝的比较 4 深拷贝 4.1 前置知识 --> 递归函数 4.2 使用递归实现深拷贝 4.3 js库中的lodash里面的cloneDeep内部实现深拷贝 4.4 利用JSON实现深拷贝 深浅拷贝只针对引用数据类型 1 引言 假如我们…

leetcode 19 , 118

19 .删除链表倒数第n个节点 思路1&#xff1a; 我首先想到的就是使用两个loop来进行解决&#xff1a; 遍历所有节点&#xff0c;得到需要删除节点的位置。再遍历一边所有节点&#xff0c;找到需要删除节点进行删除。 解决方案1&#xff1a; class Solution {public ListNod…

DevOps落地笔记-07|案例分析:如何有效管理第三方组件

上一讲主要介绍了如何通过代码预检查的方式提高入库代码的质量&#xff0c;将代码检查尽可能前置&#xff0c;降低修复问题的成本&#xff0c;从而提高交付软件的质量。除了代码本身的问题&#xff0c;依赖组件也是经常困扰开发者的一个问题。比如&#xff0c;依赖组件的某个版…

项目管理构建不只是Maven,还有更优越的它!

教程全文阅读请转至《项目管理构建不只是Maven,还有更优越的它&#xff01;》 Gradle简介 Gradle是一种现代化的构建工具&#xff0c;用于构建Java、C、Python、Android等项目。它是一种基于Groovy语言的自动化构建工具&#xff0c;可以自动化执行各种构建任务&#xff0c;例…

matlab基本操作

目录 1 清空workspace 2 清空命令行窗口 3 求字符的ASCII码 4 矩阵的表示 5 矩阵的转置 6 按列输出 7 求逆矩阵 8 创建零矩阵 9 生成随机数 10 生成空数组 11 生成单位矩阵 12 生成幻方矩阵 13 结构体 14 重复 15 点乘与叉乘 16 寻找符合条件的元素…

2024年1月份实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先&#xff0c;来看下效果图 在线体验地址&#xff1a;https://geojson.hxkj.vip&#xff0c;并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

spring cache的使用(Redis)

要在Spring Boot应用中使用Redis作为缓存&#xff0c;你需要遵循一些步骤来配置和使用Redis。以下是使用Spring Cache抽象与Redis进行整合的详细说明&#xff1a; 1. 添加依赖 首先&#xff0c;需要在pom.xml中添加Spring Boot的Redis starter依赖以及缓存的starter依赖。这会…

vivado 与系统设计师接口

与系统设计师接口 作为迭代I/O和时钟规划过程的一部分&#xff0c;您可以交换有关AMD设备通过导出CSV文件和IBIS模型&#xff0c;与PCB或系统设计者进行引脚连接。根据PCB或设计规范的变化&#xff0c;您可能需要将引脚重新导入为如定义和配置I/O端口中所述。完成I/O和时钟中的…

如何在 Mac 中运行 Office 办公软件

虽然 Office 软件也有 Mac 版本的&#xff0c;但是有蛮多小伙伴用起来还是感觉不得劲&#xff0c;毕竟接触了太久的 Windows&#xff0c;所以想要使用 Windows 版本的 Office 软件。 今天就给大家介绍一下怎么在 Mac 电脑中运行 Windows 版本的办公软件&#xff0c;在这里就需…

【Qt】—— Qt Creator 创建项目

目录 &#xff08;一&#xff09;Qt Creator概览 &#xff08;二&#xff09;使⽤Qt Creator新建项⽬ &#xff08;一&#xff09;Qt Creator概览 从开始菜单或者快捷⽅式打开Qt Creator集成开发环境&#xff0c;启动之后看到类似下⾯的界⾯&#xff1a; 【解释说明】 菜单栏…

0101appscan安装与使用入门-扫描-信息收集

1 简介 HCL AppScan&#xff08;原IBM Security AppScan&#xff09;是原IBM的Rational软件部门的一组网络安全测试和监控工具&#xff0c;2019年被HCL技术公司收购。AppScan旨在在开发过程中对Web应用程序的安全漏洞进行测试[1]。该产品学习每个应用程序的行为&#xff0c;无…

杂题——试题-算法训练-P0604-runaround数

分析&#xff1a; 题目有三个关键点&#xff1a; 一&#xff1a;结束时&#xff0c;回到起始位置&#xff08;比较结束时和起始时的下标位置是否相同&#xff09;二&#xff1a;该整数的所有数字都必须遍历一遍&#xff0c;且只能遍历一遍&#xff08;把遍历过的数字做个标记&a…

牛客,OR36 链表的回文结构,快慢指针和反转链表的实践

链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 还是比较简单的&#xff0c;主要分为三个步骤&#xff0c;两种需掌握的函数实现 目录 主要思路过程&#xff0c;1&#xff0c;找到中间结点&#xff0c;2&#xff0c;反转中间结点往后的结点&#xff0c;3&#xff0c;遍历比…

如何将AI智能监控应用在物业中打造智慧物业系统

方案背景 随着视频智能化发展&#xff0c;仅靠人力管理的传统物业已然成为历史&#xff0c;为了降低人工成本&#xff0c;实现精细化管理&#xff0c;人工智能的帮助必不可少&#xff0c;旭帆科技AI智能监控系统在物业中可以用于打造智慧物业系统&#xff0c;提升物业管理的效…

MacBook安装虚拟机VMware Fusion

MacBook安装虚拟机VMware Fusion 官方下载地址: https://customerconnect.vmware.com/cn/downloads/info/slug/desktop_end_user_computing/vmware_fusion/11_0 介绍 之前的版本都要收费,现在出了对个人免费的版本, 棋哥给的破解版的版本是8,升级系统后用不了了. 官方去下载…

VR全景技术如何运用在文旅展示,VR全景技术对景区有哪些好处

引言&#xff1a; 随着科技的不断进步和社会的不断发展&#xff0c;VR全景技术越来越受到人们的关注。在文化旅游行业中&#xff0c;VR全景技术的应用为景区提供了全新的展示方式和体验内容&#xff0c;极大地丰富了游客的文化旅游体验。那么VR全景技术能给文旅展示带来哪些好…

AI的安全应答之道

作者&#xff1a;统信UOS技术团队 2023,随着各种大语言模型的爆发&#xff0c;整个AI生态正处于从决策式AI进化到生成式AI的进程中。各类AI模型和AI应用层出不穷&#xff0c;也随之带来了与AI相关的各类潜在风险。AI开发和使用过程中的风险防范和治理&#xff0c;成为了不可忽…

020 switch多选择结构

什么是switch多选择结构 switch语句中的变量类型为char的示例 char grade A; switch (grade){case A:System.out.println("成绩为A");break;case B:System.out.println("成绩为B");break;case C:System.out.println("成绩为C");break;case D:S…