Bowyer-Watson算法

news2025/1/16 0:48:26

数学原理及算法过程

Delaunay 三角剖分是一种特殊的三角剖分方法,它满足以下两个重要性质:

  • 最大化最小角性质:Delaunay 三角剖分通过避免细长的三角形来最大化所有三角形的最小角。
  • 空外接圆性质:在 Delaunay 三角剖分中,每个三角形的外接圆不包含任何其他点。这意味着,对于三角剖分中的任意三角形,其外接圆内没有其他输入点。

基于这些性质,Delaunay 三角剖分算法的一种实现方式是 Bowyer-Watson 算法,这是一种增量算法。以下是具体的算法步骤:

算法过程
  1. 初始化超级三角形:
  • 创建一个足够大的超级三角形,包含所有输入点。这个三角形的三个顶点坐标远离实际输入点的范围,使其能够覆盖所有点。
  1. 逐点插入:
  • 对于每个输入点,找到所有包含该点的外接圆的三角形。这些三角形被称为“坏三角形”。
  1. 构建多边形:
  • 对于所有坏三角形,它们的每条边,如果只被一个坏三角形共享,则称其为边界边。这些边将形成一个多边形。
  1. 删除坏三角形:
  • 将所有坏三角形从三角剖分中删除。
  1. 重新三角化多边形:
  • 用新插入的点和多边形的边构成新的三角形,并将这些三角形加入三角剖分中。
  1. 移除超级三角形的影响:
  • 在所有点都插入后,移除包含超级三角形顶点的所有三角形,得到最终的 Delaunay 三角剖分。

数学原理

  • 外接圆计算

    • 对于每个三角形,计算其外接圆。外接圆的圆心(外心)和半径可以通过三角形顶点的坐标计算。
    • 设三角形顶点为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1, y_1), (x_2, y_2), (x_3, y_3) (x1,y1),(x2,y2),(x3,y3)。外接圆的圆心 ( u , v ) (u, v) (u,v) 计算如下:
      d = 2 ( x 1 ( y 2 − y 3 ) + x 2 ( y 3 − y 1 ) + x 3 ( y 1 − y 2 ) ) d = 2 \left( x_1(y_2 - y_3) + x_2(y_3 - y_1) + x_3(y_1 - y_2) \right) d=2(x1(y2y3)+x2(y3y1)+x3(y1y2))

    u = ( ( x 1 2 + y 1 2 ) ( y 2 − y 3 ) + ( x 2 2 + y 2 2 ) ( y 3 − y 1 ) + ( x 3 2 + y 3 2 ) ( y 1 − y 2 ) ) d u = \frac{((x_1^2 + y_1^2)(y_2 - y_3) + (x_2^2 + y_2^2)(y_3 - y_1) + (x_3^2 + y_3^2)(y_1 - y_2))}{d} u=d((x12+y12)(y2y3)+(x22+y22)(y3y1)+(x32+y32)(y1y2))

    v = ( ( x 1 2 + y 1 2 ) ( x 3 − x 2 ) + ( x 2 2 + y 2 2 ) ( x 1 − x 3 ) + ( x 3 2 + y 3 2 ) ( x 2 − x 1 ) ) d v = \frac{((x_1^2 + y_1^2)(x_3 - x_2) + (x_2^2 + y_2^2)(x_1 - x_3) + (x_3^2 + y_3^2)(x_2 - x_1))}{d} v=d((x12+y12)(x3x2)+(x22+y22)(x1x3)+(x32+y32)(x2x1))

    r = ( x 1 − u ) 2 + ( y 1 − v ) 2 r = \sqrt{(x_1 - u)^2 + (y_1 - v)^2} r=(x1u)2+(y1v)2

import matplotlib.pyplot as plt
import numpy as np

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Triangle:
    def __init__(self, p1, p2, p3):
        self.p1 = p1
        self.p2 = p2
        self.p3 = p3
        self.circumcenter, self.circumradius = self.circumcircle()
    
    def circumcircle(self):
        """Calculate the circumcenter and circumradius of the triangle."""
        ax, ay = self.p1.x, self.p1.y
        bx, by = self.p2.x, self.p2.y
        cx, cy = self.p3.x, self.p3.y
        
        d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by))
        
        ux = ((ax*ax + ay*ay) * (by - cy) + (bx*bx + by*by) * (cy - ay) + (cx*cx + cy*cy) * (ay - by)) / d
        uy = ((ax*ax + ay*ay) * (cx - bx) + (bx*bx + by*by) * (ax - cx) + (cx*cx + cy*cy) * (bx - ax)) / d
        
        circumcenter = Point(ux, uy)
        circumradius = np.sqrt((ax - ux)**2 + (ay - uy)**2)
        
        return circumcenter, circumradius
    
    def contains_point(self, p):
        """Check if the point p is inside the circumcircle of the triangle."""
        return np.sqrt((p.x - self.circumcenter.x)**2 + (p.y - self.circumcenter.y)**2) < self.circumradius

def delaunay_triangulation(points):
    """Perform Delaunay triangulation on a set of points."""
    super_triangle = Triangle(Point(-1e5, -1e5), Point(1e5, -1e5), Point(0, 1e5))
    triangulation = [super_triangle]
    
    for p in points:
        bad_triangles = []
        for tri in triangulation:
            if tri.contains_point(p):
                bad_triangles.append(tri)
        
        polygon = []
        for tri in bad_triangles:
            for edge in [(tri.p1, tri.p2), (tri.p2, tri.p3), (tri.p3, tri.p1)]:
                is_shared = False
                for other in bad_triangles:
                    if other != tri and (edge in [(other.p1, other.p2), (other.p2, other.p3), (other.p3, other.p1)] or edge[::-1] in [(other.p1, other.p2), (other.p2, other.p3), (other.p3, other.p1)]):
                        is_shared = True
                        break
                if not is_shared:
                    polygon.append(edge)
        
        for tri in bad_triangles:
            triangulation.remove(tri)
        
        for edge in polygon:
            triangulation.append(Triangle(edge[0], edge[1], p))
    
    triangulation = [tri for tri in triangulation if not (super_triangle.p1 in [tri.p1, tri.p2, tri.p3] or super_triangle.p2 in [tri.p1, tri.p2, tri.p3] or super_triangle.p3 in [tri.p1, tri.p2, tri.p3])]
    
    return triangulation

def plot_triangulation(triangles, points):
    for tri in triangles:
        plt.plot([tri.p1.x, tri.p2.x], [tri.p1.y, tri.p2.y], 'b-')
        plt.plot([tri.p2.x, tri.p3.x], [tri.p2.y, tri.p3.y], 'b-')
        plt.plot([tri.p3.x, tri.p1.x], [tri.p3.y, tri.p1.y], 'b-')
    
    for p in points:
        plt.plot(p.x, p.y, 'ro')
    
    plt.show()
# Generate random points in the unit square
rectangle_corners = [Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1)]
random_points = [Point(np.random.rand(), np.random.rand()) for _ in range(20)]
points = rectangle_corners + random_points

triangles = delaunay_triangulation(points)
plot_triangulation(triangles, points)

在这里插入图片描述

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

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

相关文章

lib库和dll库的介绍和使用

lib&#xff08;静态库&#xff09; 静态库定义&#xff1a;.lib文件是静态库文件&#xff0c;包含了在编译时被链接到目标程序的代码。使用静态库时&#xff0c;库的代码会被复制到最终生成的可执行文件中。优点&#xff1a; 性能&#xff1a;由于库代码在编译时就被集成到可…

大创报名步骤

目录 一、注册 二、创建项目 三、报名 一、注册 进入注册/登录 点击 点击 填写个人信息 二、创建项目 找到解压的文件 随便选一个 项目简介在你选择的文件中截取一段 询问自己寝室的人 被邀请者需要在微信公众号上搜索 “全国大学生创业服务网” 选择我的消息中同意 三、报名…

springcloud第4季 springcloud-gateway网关filter案例场景

一 filter作用 1.1 filter搭建流程 1.1.1 网关配置 1.1.2 服务提供者 1.1.3 测试验证 1.启动consul 2.启动zipkin 3.启动应用微服务 4.进行访问&#xff1a; http://localhost:6666/pay/wg/filter 1.2 其他常见API RemoveRequestHeadersec-fetch-site # 删除请求…

身份证数字识别DBNET

采用DBNET检测身份证数字所在区域&#xff0c;然后使用切割字符的方法&#xff0c;使用PCASVM训练和分类&#xff0c;支持C/PYTHON开发&#xff0c;只需要OPENCV 身份证数字识别DBNETPCASVM

网关(Gateway)- 内置过滤器工厂

官方文档&#xff1a;Spring Cloud Gateway 内置过滤器工厂 AddRequestHeaderGatewayFilterFactory 为请求添加Header Header的名称及值 配置说明 server:port: 8088 spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8847username: nacos…

栈排序00

题目链接 栈排序 题目描述 注意点 对栈进行排序使最小元素位于栈顶最多只能使用一个其他的临时栈存放数据不得将元素复制到别的数据结构&#xff08;如数组&#xff09;中栈中的元素数目在[0, 5000]范围内 解答思路 本题是要实现一个小顶堆&#xff0c;可以直接使用Priori…

Autonomous Mobile 3D Printing of Large-Scale Trajectories——文献精读

一、文章信息 标题&#xff1a;Autonomous Mobile 3D Printing of Large-Scale Trajectories 作者&#xff1a;Julius Sustarevas 发表刊物&#xff1a;IEEE/RSJ 智能机器人与系统国际会议 &#xff08;IROS&#xff09; 发表时间&#xff1a;2022年10月23-27日 二、背景 大…

AI短片制作全流程详解——掌握未来视频创作新技能!

老铁们! 期待已久的AI短片免费直播分享来了&#xff01;&#xff01;&#xff01; 还是老规矩&#xff0c;只讲干货&#xff0c;全程不废话! 在这个直播中&#xff0c;我们将深入探讨AI短片制作的全过程&#xff0c;从构思到最终输出&#xff0c;全方位解析每一个步骤的关键要素…

Ant Design Vue Table组件全单元格编辑实现方案

在ant上的table常见用法是一行的元素可编辑&#xff0c;如下&#xff1a; 但是现在有一个需求是全部单元格均可编辑&#xff0c;如何实现呢&#xff1f; 表格组件 <a-tablev-if"query.personnel_type 0"size"middle"row-key"id":scroll&qu…

中继器、集线器、网桥、交换机、路由器和网关

目录 前言一、中继器、集线器1.1 中继器1.2 集线器 二、网桥、交换机2.1 网桥2.1.1 认识网桥2.1.2 网桥的工作原理2.1.3 生成树网桥 2.2 交换机2.2.1 交换机的特征2.2.2 交换机的交换模式2.2.3 交换机的功能 三、路由器、网关3.1 路由器的介绍3.2 路由器的工作过程3.2.1 前置知…

迅雷极简易下载

一、简介 1、迅雷是一家全球领先的去中心化服务商&#xff0c;以技术构建商业&#xff0c;以服务创造共识&#xff0c;从而建立一个高效可信的存储与传输网络。 迅雷成立于2003年&#xff0c;总部位于中国深圳&#xff0c;2014年于纳斯达克上市&#xff08;纳斯达克股票代码&a…

Threejs墙体挖洞做门或窗

在使用Threejs代码构建的展厅中&#xff0c;需要在一面墙中间挖个洞作为门或窗户&#xff0c;效果如下&#xff1a; 引入ThreeBSP.js <script src"plugins/three/ThreeBSP.js"></script> 创建 // 1 定义墙面var cubeGeometry new THREE.BoxGeometry(1…

4.2 索引及其操作

对数据库中的表进行查询操作时有两种搜索扫描方式&#xff0c;一种是全表扫描&#xff0c;另一种就是使用表上建立的索引进行扫描。 全表扫描要查找某个特定的行&#xff0c;必须从头开始一一查看表中的每一行&#xff0c;与查询条件做对比&#xff0c;返回满足条件的记录&…

FFA-Net:用于单图像去雾的特征融合注意力网络

摘要 论文链接&#xff1a;https://arxiv.org/pdf/1911.07559v2 在这篇论文中&#xff0c;我们提出了一种端到端的特征融合注意力网络&#xff08;FFA-Net&#xff09;来直接恢复无雾图像。FFA-Net架构由三个关键组件组成&#xff1a; 一种新颖的特征注意力&#xff08;FA&…

Mac下删除系统自带输入法ABC,正解!

一、背景说明 MacOS 在 14.2 以下的系统存在中文输入法 BUG&#xff0c;会造成系统卡顿&#xff0c;出现彩虹圆圈。如果为了解决这个问题&#xff0c;有两种方法&#xff1a; 升级到最新的 14.5 系统使用第三方输入法 在使用第三方输入法的时候&#xff0c;会发现系统自带的 …

[论文笔记]Mixtral of Experts

引言 今天带来大名鼎鼎的Mixtral of Experts的论文笔记&#xff0c;即Mixtral-8x7B。 作者提出了Mixtral 8x7B&#xff0c;一种稀疏专家混合(Sparse Mixture of Experts&#xff0c;SMoE)语言模型。Mixtral与Mistral 7B具有相同的架构&#xff0c;不同之处在于每个层由8个前馈…

数据结构【树】(理论篇)

树的概念 树是一个非线性的数据结构&#xff0c;前面我们学习的顺序表、链表等等等等&#xff0c;他们的逻辑结构都是成一条线的&#xff0c;都是所有元素都是排成一条的&#xff1b;而树他是有多个分支的&#xff0c;是发散的。 树是由n&#xff08;n>0&#xff09;个有限…

AI编程新手快速体验SpringCloud Alibaba 集成AI功能

上周六写了一篇文章 震撼发布&#xff01;Spring AI 框架重磅上线&#xff0c;Java 集成 AI 轻松搞定&#xff01; 部分同学可能没有科学上网的条件&#xff0c;本地ollama 集成又比较笨重。趁着周六&#xff0c;写一篇基于SpringCloud Alibaba 集成AI的文章。 先简单介绍…

Ollama教程,本地部署大模型Ollama,docker安装方法,仅供学习使用

不可商用&#xff01;&#xff01;仅仅提供学习使用&#xff01; 先上视频教学&#xff1a; Ollama教程&#xff0c;本地部署大模型Ollama&#xff0c;docker安装方法&#xff0c;仅供学习使用&#xff01; 资料获取 &#xff1a; Ollama下载包和安装文档在这里&#xff…

AI大模型还没有到卷长文的时候

AI风口上&#xff0c;国内大模型技术突飞猛进&#xff0c;很多人都沉浸在用AI来辅助办公&#xff0c;辅助学习等等工具化应用落地&#xff0c;但也有趁着风口想大赚一笔&#xff0c;为了估值什么都敢说的。 前几天&#xff0c;Kimi对外宣称自己的技术狂飙到能读200万字甚至100…