[3D基础]Delaunay与Triangulate构网

Delaunay三角剖分(Delaunay Triangulation)和Triangulate构网是两种常用于生成三角网格的方法,它们都有其独特的特点和应用场景。

  1. Delaunay三角剖分

Delaunay三角剖分是一种经典的三角剖分方法,其特点是任意三角形的外接圆不包含任何其他顶点。换句话说,对于给定的点集,Delaunay三角剖分是使得生成的三角形尽可能接近等边三角形,并且最大化了三角形的最小角。这种特性使得Delaunay三角剖分在许多应用中都具有优越性,例如地理信息系统、有限元分析、计算机图形学等领域。

Delaunay三角剖分的算法有多种实现方式,包括增量构建法、分治法、凸壳法等。其中增量构建法是最常见的一种,其基本思想是逐步将点集中的点加入到一个初始空的三角形网格中,使得生成的三角形满足Delaunay条件。

  1. Triangulate构网

Triangulate构网是一种简单而直观的三角剖分方法,其基本思想是将给定的区域分割成许多小三角形。Triangulate方法通常用于离散化几何图形或表面,生成用于渲染或分析的三角网格。

Triangulate构网的实现方式通常比Delaunay三角剖分简单,因为它不需要满足Delaunay条件。常见的Triangulate构网方法包括:最近邻三角化、四边形划分、有限元分析中的特定方法等。这些方法可以根据应用的需求和性能要求选择合适的算法。

总的来说,Delaunay三角剖分适用于需要满足特定条件(如Delaunay条件)的应用,而Triangulate构网适用于一般的离散化和三角化需求。选择合适的方法取决于具体的应用场景、性能要求和计算资源等因素。

Delaunay.js 是一个 JavaScript 库,用于在浏览器中执行 Delaunay 三角剖分。它提供了一种方便的方法来将点集转换为三角形网格,这在许多领域中都很有用,例如计算机图形学、地理信息系统、物理模拟等。

以下是对 Delaunay.js 库的详细解释:

  1. 功能特点

    • Delaunay.js 库提供了一个方便的接口,允许你将给定的点集转换为 Delaunay 三角剖分。
    • 它可以处理任意数量的点,即使是大型点集也可以快速处理。
    • 该库还提供了用于检查给定点是否在三角形内部的方法,以及查找包含给定点的三角形的方法。
    • Delaunay.js 还支持 Voronoi 图的计算,允许你根据 Delaunay 三角形网格构建 Voronoi 图。
  2. 使用方法

    • 首先,在你的 HTML 页面中引入 Delaunay.js 库的 JavaScript 文件。
    • 使用 Delaunay.from() 方法将给定的点集转换为 Delaunay 三角剖分。
    • 一旦得到了三角剖分对象,你可以使用它的方法执行各种操作,比如查找包含给定点的三角形、获取三角形的顶点等。
    • 如果需要构建 Voronoi 图,可以使用 Delaunay.voronoi() 方法来获取 Voronoi 图对象。
  3. 示例用途

    • Delaunay.js 可以用于创建网格化地理数据的可视化效果,例如地图和地形图。
    • 它可以用于模拟物理系统中的三角形网格,例如流体模拟、粒子系统等。
    • 该库还可以用于计算三角形网格上的几何性质,例如计算三角形的面积、周长等。

总的来说,Delaunay.js 是一个功能强大且易于使用的 JavaScript 库,适用于执行 Delaunay 三角剖分和 Voronoi 图计算。它在许多领域中都有广泛的应用,并且提供了丰富的功能和灵活的接口,使其成为处理三角网格数据的理想选择。


var Delaunay;

(function() {
    "use strict";

    var EPSILON = 1.0 / 1048576.0;

    function supertriangle(vertices) {
        var xmin = Number.POSITIVE_INFINITY,
            ymin = Number.POSITIVE_INFINITY,
            xmax = Number.NEGATIVE_INFINITY,
            ymax = Number.NEGATIVE_INFINITY,
            i, dx, dy, dmax, xmid, ymid;

        for(i = vertices.length; i--; ) {
            if(vertices[i][0] < xmin) xmin = vertices[i][0];
            if(vertices[i][0] > xmax) xmax = vertices[i][0];
            if(vertices[i][1] < ymin) ymin = vertices[i][1];
            if(vertices[i][1] > ymax) ymax = vertices[i][1];
        }
        dx = xmax - xmin;
        dy = ymax - ymin;
        dmax = Math.max(dx, dy);
        xmid = xmin + dx * 0.5;
        ymid = ymin + dy * 0.5;
        return [
            [xmid - 20 * dmax, ymid -      dmax],
            [xmid            , ymid + 20 * dmax],
            [xmid + 20 * dmax, ymid -      dmax]
        ];
    }

    function circumcircle(vertices, i, j, k) {
        var x1 = vertices[i][0],
            y1 = vertices[i][1],
            x2 = vertices[j][0],
            y2 = vertices[j][1],
            x3 = vertices[k][0],
            y3 = vertices[k][1],
            fabsy1y2 = Math.abs(y1 - y2),
            fabsy2y3 = Math.abs(y2 - y3),
            xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;

        /* Check for coincident points */
        if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
            throw new Error("Eek! Coincident points!");

        if(fabsy1y2 < EPSILON) {
            m2  = -((x3 - x2) / (y3 - y2));
            mx2 = (x2 + x3) / 2.0;
            my2 = (y2 + y3) / 2.0;
            xc  = (x2 + x1) / 2.0;
            yc  = m2 * (xc - mx2) + my2;
        }

        else if(fabsy2y3 < EPSILON) {
            m1  = -((x2 - x1) / (y2 - y1));
            mx1 = (x1 + x2) / 2.0;
            my1 = (y1 + y2) / 2.0;
            xc  = (x3 + x2) / 2.0;
            yc  = m1 * (xc - mx1) + my1;
        }

        else {
            m1  = -((x2 - x1) / (y2 - y1));
            m2  = -((x3 - x2) / (y3 - y2));
            mx1 = (x1 + x2) / 2.0;
            mx2 = (x2 + x3) / 2.0;
            my1 = (y1 + y2) / 2.0;
            my2 = (y2 + y3) / 2.0;
            xc  = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
            yc  = (fabsy1y2 > fabsy2y3) ?
                m1 * (xc - mx1) + my1 :
                m2 * (xc - mx2) + my2;
        }

        dx = x2 - xc;
        dy = y2 - yc;
        return {i: i, j: j, k: k, x: xc, y: yc, r: dx * dx + dy * dy};
    }

    function dedup(edges) {
        var i, j, a, b, m, n;

        for(j = edges.length; j; ) {
            b = edges[--j];
            a = edges[--j];

            for(i = j; i; ) {
                n = edges[--i];
                m = edges[--i];

                if((a === m && b === n) || (a === n && b === m)) {
                    edges.splice(j, 2);
                    edges.splice(i, 2);
                    break;
                }
            }
        }
    }

    Delaunay = {
        triangulate: function(vertices, key) {
            var n = vertices.length,
                i, j, indices, st, open, closed, edges, dx, dy, a, b, c;

            /* Bail if there aren't enough vertices to form any triangles. */
            if(n < 3)
                return [];

            /* Slice out the actual vertices from the passed objects. (Duplicate the
             * array even if we don't, though, since we need to make a supertriangle
             * later on!) */
            vertices = vertices.slice(0);

            if(key)
                for(i = n; i--; )
                    vertices[i] = vertices[i][key];

            /* Make an array of indices into the vertex array, sorted by the
             * vertices' x-position. Force stable sorting by comparing indices if
             * the x-positions are equal. */
            indices = new Array(n);

            for(i = n; i--; )
                indices[i] = i;

            indices.sort(function(i, j) {
                var diff = vertices[j][0] - vertices[i][0];
                return diff !== 0 ? diff : i - j;
            });

            /* Next, find the vertices of the supertriangle (which contains all other
             * triangles), and append them onto the end of a (copy of) the vertex
             * array. */
            st = supertriangle(vertices);
            vertices.push(st[0], st[1], st[2]);

            /* Initialize the open list (containing the supertriangle and nothing
             * else) and the closed list (which is empty since we havn't processed
             * any triangles yet). */
            open   = [circumcircle(vertices, n + 0, n + 1, n + 2)];
            closed = [];
            edges  = [];

            /* Incrementally add each vertex to the mesh. */
            for(i = indices.length; i--; edges.length = 0) {
                c = indices[i];

                /* For each open triangle, check to see if the current point is
                 * inside it's circumcircle. If it is, remove the triangle and add
                 * it's edges to an edge list. */
                for(j = open.length; j--; ) {
                    /* If this point is to the right of this triangle's circumcircle,
                     * then this triangle should never get checked again. Remove it
                     * from the open list, add it to the closed list, and skip. */
                    dx = vertices[c][0] - open[j].x;
                    if(dx > 0.0 && dx * dx > open[j].r) {
                        closed.push(open[j]);
                        open.splice(j, 1);
                        continue;
                    }

                    /* If we're outside the circumcircle, skip this triangle. */
                    dy = vertices[c][1] - open[j].y;
                    if(dx * dx + dy * dy - open[j].r > EPSILON)
                        continue;

                    /* Remove the triangle and add it's edges to the edge list. */
                    edges.push(
                        open[j].i, open[j].j,
                        open[j].j, open[j].k,
                        open[j].k, open[j].i
                    );
                    open.splice(j, 1);
                }

                /* Remove any doubled edges. */
                dedup(edges);

                /* Add a new triangle for each edge. */
                for(j = edges.length; j; ) {
                    b = edges[--j];
                    a = edges[--j];
                    open.push(circumcircle(vertices, a, b, c));
                }
            }

            /* Copy any remaining open triangles to the closed list, and then
             * remove any triangles that share a vertex with the supertriangle,
             * building a list of triplets that represent triangles. */
            for(i = open.length; i--; )
                closed.push(open[i]);
            open.length = 0;

            for(i = closed.length; i--; )
                if(closed[i].i < n && closed[i].j < n && closed[i].k < n)
                    open.push(closed[i].i, closed[i].j, closed[i].k);

            /* Yay, we're done! */
            return open;
        },
        contains: function(tri, p) {
            /* Bounding box test first, for quick rejections. */
            if((p[0] < tri[0][0] && p[0] < tri[1][0] && p[0] < tri[2][0]) ||
                (p[0] > tri[0][0] && p[0] > tri[1][0] && p[0] > tri[2][0]) ||
                (p[1] < tri[0][1] && p[1] < tri[1][1] && p[1] < tri[2][1]) ||
                (p[1] > tri[0][1] && p[1] > tri[1][1] && p[1] > tri[2][1]))
                return null;

            var a = tri[1][0] - tri[0][0],
                b = tri[2][0] - tri[0][0],
                c = tri[1][1] - tri[0][1],
                d = tri[2][1] - tri[0][1],
                i = a * d - b * c;

            /* Degenerate tri. */
            if(i === 0.0)
                return null;

            var u = (d * (p[0] - tri[0][0]) - b * (p[1] - tri[0][1])) / i,
                v = (a * (p[1] - tri[0][1]) - c * (p[0] - tri[0][0])) / i;

            /* If we're outside the tri, fail. */
            if(u < 0.0 || v < 0.0 || (u + v) > 1.0)
                return null;

            return [u, v];
        }
    };

    if(typeof module !== "undefined")
        module.exports = Delaunay;
})();

在 Python 中,Triangle 库是一个用于进行二维三角剖分的第三方库。它是 Triangle 库的 Python 封装版本,Triangle 库本身是一个用 C 语言编写的高效三角剖分工具。Python 的 Triangle 库提供了 Triangle 库的功能,并将其包装成一个 Python 模块,方便在 Python 中调用。

以下是对 Triangle 库的简要解释以及一个使用案例:

  1. 功能特点

    • Triangle 库用于进行二维三角剖分,它能够将给定的点集转换为三角形网格。
    • 该库支持约束三角剖分、最大最小角限制、区域约束等功能。
    • Triangle 库提供了高效的算法和数据结构,能够处理大型点集和复杂的几何形状。
  2. 使用方法

    • 首先,需要安装 Triangle 库。你可以在 Python 中使用 pip 安装它:pip install triangle
    • 导入 triangle 模块:import triangle
    • 使用 triangle 模块提供的函数来执行三角剖分。最常用的函数是 triangle.triangulate(),它用于执行简单的点集三角剖分。你还可以使用其他函数来执行不同类型的三角剖分,例如约束三角剖分、最大最小角限制等。
    • 一旦完成三角剖分,你可以使用返回的对象来访问三角剖分的结果,例如三角形的顶点、边、面等。
  3. 示例用途

    • Triangle 库可以用于生成三角形网格,用于计算机图形学、地理信息系统、有限元分析等领域的模拟和可视化。
    • 它还可以用于执行几何计算,例如计算三角形的面积、周长、重心等。
    • Triangle 库的约束三角剖分功能可以用于生成符合特定要求的三角形网格,例如在给定约束条件下进行网格划分。
import triangle
import matplotlib.pyplot as plt

# 创建一个随机点集
points = triangle.get_data('spiral')

# 执行三角剖分
tri = triangle.triangulate({'vertices': points})

# 绘制三角剖分结果
plt.triplot(points[:, 0], points[:, 1], tri['triangles'])
plt.plot(points[:, 0], points[:, 1], 'o')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Triangle Triangulation')
plt.show()

构网要素:顶点坐标、顶点颜色、索引(三角形由那几个点构建)

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import Delaunay

# 输入经纬度坐标和颜色集合
lon_lat = np.array([[lon1, lat1], [lon2, lat2], [lon3, lat3], ...])  # 输入经纬度坐标
colors = np.array([[r1, g1, b1, a1], [r2, g2, b2, a2], [r3, g3, b3, a3], ...])  # 输入颜色集合

# 使用Delaunay三角剖分算法获取三角形网格
tri = Delaunay(lon_lat)

# 创建绘图对象
fig, ax = plt.subplots()

# 绘制三角形并填充颜色
for vertices, color in zip(tri.simplices, colors):
    ax.fill(lon_lat[vertices, 0], lon_lat[vertices, 1], color=color)

# 隐藏坐标轴
ax.axis('off')

# 保存图像为PNG格式
plt.savefig('triangles.png', bbox_inches='tight', pad_inches=0, transparent=True)

# 显示图像(可选)
plt.show()

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

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

相关文章

【linux-IMX6ULL中断配置流程】

目录 1. Cortex-A7和GIC中断概述1. 1 Cortex-A7中断系统&#xff1a;1. 2 GIC中断控制器简介&#xff1a; 2. 中断配置概述3. 底层中断文件配置3.1 对启动文件.s的配置思路3.2 对中断函数配置思路 4. 上层中断配置流程 1. Cortex-A7和GIC中断概述 学习IMX6UL的中断处理系统&…

页面嵌套,界面套娃,除了用iframe,还有其他方式吗?

UIOTOS可以了解下&#xff0c;uiotos.net&#xff0c;通过连线来代替脚本逻辑开发&#xff0c;复杂的交互界面&#xff0c;通过页面嵌套轻松解决&#xff0c;是个很新颖的思路&#xff0c;前端零代码&#xff01; 蓝图连线尤其是独创的页面嵌套和属性继承技术&#xff0c;好家…

独有病眼花,春风吹不落。 (二维坐标压缩成一个点,并查集)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 3 8 1 1 D 1 1 R 1 2 D 2 1 D 2 2 R 3 1 R 3 2 R 2 3 D 输出 8 思路&#xff1a; 根据题意&#xff0c;要求连接线段后&#xff0c;操作多少次&#xff0c;连接的线段闭合&…

javaweb学习笔记1

1、基本概念 1.1、前言 web开发&#xff1a; web&#xff0c;网页的意思&#xff0c;www.baidu.com 静态web html,css 提供给所有人看的数据始终不会发生变化&#xff01; 动态web 淘宝&#xff0c;几乎是所有的网站&#xff1b; 提供给所有人看的数据始终会发生变化&…

00后设计师如何通过咸鱼接单实现副业月入过万?

大家好&#xff0c;我是一个00后&#xff0c;拥有6年设计经验的平面/包装/品牌设计师。在裸辞探索自由职业的过程中&#xff0c;误打误撞地通过咸鱼接单做副业&#xff0c;首月收入竟然超过了万元&#xff01;在这里&#xff0c;我将分享具体的实操经验、心得体会以及一些额外的…

c++游戏小技巧16:实例1(地牢生成算法)

1.前言 (头图) &#xff08;其实最开始是想写恶魔轮盘的&#xff0c;但没想到它竟然更新了&#xff09; &#xff08;等我有时间在更&#xff0c;最近很忙&#xff0c;玩第五玩的&#xff09; 想法来源&#xff1a;房间和迷宫&#xff1a;一个地牢生成算法https://indienova…

【牛客】值周

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 差分。 因为l<100000000,所以数组开1e8。 唯一需要注意的点就是前面给b[0]单独赋值为1&#xff08;因为如果在循环中给b[0]赋值&…

MIT加州理工等革命性KAN破记录,发现数学定理碾压DeepMind!KAN论文解读

KAN的数学原理 如果f是有界域上的多元连续函数&#xff0c;那么f可以被写成关于单个变量和加法二元操作的连续函数的有限组合。更具体地说&#xff0c;对于光滑函数f&#xff1a;[0, 1]ⁿ → R&#xff0c;有 f ( x ) f ( x 1 , … , x n ) ∑ q 1 2 n 1 Φ q ∑ p 1 n …

解决Pyppeteer下载chromium慢或者失败的问题[INFO] Starting Chromium download.

文章目录 1.进入网址2.选择上面对应自己系统的文件夹进去3. 然后找到自己的python环境中的site-packages中pyppeteer中的chromium_downloader.py文件并打开 在首次使用Pyppeteer时需要下载chromium 1.进入网址 https://registry.npmmirror.com/binary.html?pathchromium-bro…

贪心算法应用例题

最优装载问题 #include <stdio.h> #include <algorithm>//排序int main() {int data[] { 8,20,5,80,3,420,14,330,70 };//物体重量int max 500;//船容最大总重量int count sizeof(data) / sizeof(data[0]);//物体数量std::sort(data, data count);//排序,排完数…

品高虚拟化后端存储的发展演进

在品高虚拟化技术不断发展的过程中&#xff0c;虚拟化的后端存储一直是关注的焦点之一。 本文将从最初的文件存储和NFS开始&#xff0c;追溯到集中式存储SAN&#xff0c;然后选择了Ceph的RBD方式&#xff0c;并最终抵达选择支持vhost协议的后端存储的现状&#xff0c;我们将探…

使用wxPython和pandas模块生成Excel文件

介绍&#xff1a; 在Python编程中&#xff0c;有时我们需要根据特定的数据生成Excel文件。本文将介绍如何使用wxPython和pandas模块来实现这个目标。我们将创建一个简单的GUI应用程序&#xff0c;允许用户选择输出文件夹和输入的Excel文件&#xff0c;并根据Excel文件中每个单…

图像处理技术与应用(四)

图像处理技术与应用入门 颜色空间及其转换 颜色空间是一种用于在数字图像中表达和指定颜色的方法。不同的颜色空间使用不同的方式来定义颜色&#xff0c;每种方式都有其特定的用途和优势。以下是一些常见的颜色空间及其特点&#xff1a; RGB&#xff08;红绿蓝&#xff09;&a…

每日一题(PTAL2):列车调度--贪心+二分

选择去维护一个最小区间 代码1&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n;cin>>n;int num;vector <int> v;int res0;for(int i0;i<n;i){cin>>num;int locv.size();int left0;int rightv.size()-1;while(left<…

AIGC技术带给我们什么?基于AIGC原理及其技术更迭的思考

AIGC技术带给我们什么&#xff1f;基于AIGC原理以及技术更迭的思考 前言 AI&#xff0c;这个词在如今人们的视野中出现频率几乎超过了所有一切其他的事物&#xff0c;更有意思的是&#xff0c;出现频率仅次于这个词的&#xff0c;几乎都会加上一个修饰亦或是前缀——AI&#…

快速排序找出第K大的元素

有序数组里第 K 大的元素就是index 为 array.length - k 的元素。 快速排序的思路主要就是选一个基准值p&#xff0c;然后将小于p的值放在p的左右&#xff0c;大于p的值放在p的右边&#xff0c;然后对左右数组进行递归。 利用这个思路&#xff0c;当我们找到这个基准值对应的 i…

【教学类-50-14】20240505“数一数”图片样式12:数一数(12个“人物”图案)

作品展示 背景需求&#xff1a; 前文做了“”材料”图片的数一数学具&#xff0c;效果不错&#xff0c; https://blog.csdn.net/reasonsummer/article/details/138466325https://blog.csdn.net/reasonsummer/article/details/138466325 为了让图案内容更丰富&#xff0c;我又…

Python Dash库:一个Web应用只需几行代码

大家好&#xff0c;在数据科学领域&#xff0c;数据可视化是将数据以图形化形式展示出来&#xff0c;帮助我们更直观地理解数据。Python中有一个非常流行的数据可视化库叫做Dash&#xff0c;Dash以其简洁、高效和强大的功能而闻名&#xff0c;它允许开发者快速构建交互式Web应用…

【智能算法】人类进化优化算法(HEOA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年&#xff0c;J Lian受到人类进化启发&#xff0c;提出了人类进化优化算法&#xff08;Human Evolutionary Optimization Algorithm, HEOA&#xff09;。 2.算法原理 2.1算法思想 …

JavaWEB 框架安全:Spring 漏洞序列.(CVE-2022-22965)

什么叫 Spring 框架. Spring 框架是一个用于构建企业级应用程序的开源框架。它提供了一种全面的编程和配置模型&#xff0c;可以简化应用程序的开发过程。Spring 框架的核心特性包括依赖注入&#xff08;Dependency Injection&#xff09;、面向切面编程&#xff08;Aspect-Or…
最新文章