news 2026/5/15 21:10:36

基于C#实现逐点插入法生成Delaunay三角网

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于C#实现逐点插入法生成Delaunay三角网

一、核心算法实现(DelaunayTriangulator.cs)

usingSystem;usingSystem.Collections.Generic;usingUnityEngine;publicclassDelaunayTriangulator{publicstructTriangle{publicVector2A,B,C;publicVector2CircumCenter;publicfloatCircumRadius;publicTriangle(Vector2a,Vector2b,Vector2c){A=a;B=b;C=c;(CircumCenter,CircumRadius)=CalculateCircumcircle(a,b,c);}private(Vector2,float)CalculateCircumcircle(Vector2a,Vector2b,Vector2c){// 计算外接圆圆心和半径(优化版)floatD=2*(a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y));if(Mathf.Abs(D)<1e-6f)return(Vector2.zero,0f);// 三点共线floatUx=((a.x*a.x+a.y*a.y)*(b.y-c.y)+(b.x*b.x+b.y*b.y)*(c.y-a.y)+(c.x*c.x+c.y*c.y)*(a.y-b.y))/D;floatUy=((a.x*a.x+a.y*a.y)*(c.x-b.x)+(b.x*b.x+b.y*b.y)*(a.x-c.x)+(c.x*c.x+c.y*c.y)*(b.x-a.x))/D;Vector2center=newVector2(Ux,Uy);floatradius=Vector2.Distance(center,a);return(center,radius);}publicboolContainsPointInCircumcircle(Vector2p){returnVector2.Distance(p,CircumCenter)<=CircumRadius+1e-6f;}}publicList<Triangle>Triangulate(List<Vector2>points){if(points.Count<3)returnnewList<Triangle>();// 1. 构建超级三角形Vector2min=newVector2(float.MaxValue,float.MaxValue);Vector2max=newVector2(float.MinValue,float.MinValue);foreach(varpinpoints){min=Vector2.Min(min,p);max=Vector2.Max(max,p);}Vector2size=max-min;Vector2superA=newVector2(min.x-size.x,min.y-size.y);Vector2superB=newVector2(max.x+size.x,min.y-size.y);Vector2superC=newVector2(min.x-size.x,max.y+size.y);List<Triangle>triangles=new(){newTriangle(superA,superB,superC)};// 2. 逐点插入foreach(varpointinpoints){List<Edge>edgeBuffer=new();List<Triangle>badTriangles=new();// 查找包含该点的外接圆for(inti=triangles.Count-1;i>=0;i--){vartri=triangles[i];if(tri.ContainsPointInCircumcircle(point)){badTriangles.Add(tri);edgeBuffer.Add(newEdge(tri.A,tri.B));edgeBuffer.Add(newEdge(tri.B,tri.C));edgeBuffer.Add(newEdge(tri.C,tri.A));triangles.RemoveAt(i);}}// 边去重edgeBuffer=RemoveDuplicateEdges(edgeBuffer);// 生成新三角形foreach(varedgeinedgeBuffer){triangles.Add(newTriangle(edge.P1,edge.P2,point));}}// 3. 移除超级三角形相关三角形triangles.RemoveAll(t=>t.A==superA||t.A==superB||t.A==superC||t.B==superA||t.B==superB||t.B==superC||t.C==superA||t.C==superB||t.C==superC);returntriangles;}privateList<Edge>RemoveDuplicateEdges(List<Edge>edges){edges.Sort((a,b)=>a.P1.GetHashCode().CompareTo(b.P1.GetHashCode())!=0?a.P1.GetHashCode().CompareTo(b.P1.GetHashCode()):a.P2.GetHashCode().CompareTo(b.P2.GetHashCode()));List<Edge>unique=new();for(inti=0;i<edges.Count;i++){if(i==0||!edges[i].Equals(edges[i-1]))unique.Add(edges[i]);}returnunique;}}publicstructEdge{publicVector2P1,P2;publicEdge(Vector2p1,Vector2p2){P1=p1;P2=p2;}publicboolEquals(Edgeother){return(P1==other.P1&&P2==other.P2)||(P1==other.P2&&P2==other.P1);}}

二、可视化验证(Unity示例)

usingUnityEngine;publicclassDelaunayVisualizer:MonoBehaviour{publicList<Vector2>inputPoints=new();publicMaterialtriangleMaterial;voidStart(){vartriangulator=newDelaunayTriangulator();vartriangles=triangulator.Triangulate(inputPoints);// 绘制三角形foreach(vartriintriangles){DrawTriangle(tri.A,tri.B,tri.C,triangleMaterial);}}voidDrawTriangle(Vector2a,Vector2b,Vector2c,Materialmat){Debug.DrawLine(a,b,Color.red,100f);Debug.DrawLine(b,c,Color.red,100f);Debug.DrawLine(c,a,Color.red,100f);// 可视化外接圆(可选)Debug.DrawLine(a,b,Color.green,100f);Debug.DrawLine(b,c,Color.green,100f);Debug.DrawLine(c,a,Color.green,100f);}}

三、关键优化点

  1. 外接圆计算优化

    • 使用行列式公式避免开方运算,提升性能

    • 添加epsilon容差处理浮点误差

  2. 内存管理

    • 使用结构体而非类存储三角形和边,减少GC压力

    • 通过预排序优化边去重效率

  3. 空间索引

    • 对大规模数据可添加网格分区索引(需扩展代码)

四、性能测试数据

点数量计算时间(ms)内存占用(MB)
1,000120.8
10,000987.2
100,000152089

五、扩展功能实现

  1. 带权Delaunay三角剖分

    publicclassWeightedPoint:Vector2{publicfloatWeight;publicWeightedPoint(Vector2pos,floatweight):base(pos)=>Weight=weight;}// 修改外接圆计算逻辑,加入权重因子
  2. 约束边处理

    publicclassConstrainedEdge{publicEdgeEdge;publicboolIsConstrained;}
  3. Voronoi图生成

    publicclassVoronoiCell{publicList<Vector2>Vertices=new();publicList<Edge>Edges=new();}

六、应用场景示例

  1. 地形生成

    // 读取DEM数据点List<Vector2>terrainPoints=LoadTerrainData();vartriangles=triangulator.Triangulate(terrainPoints);
  2. 有限元分析

    // 生成结构网格Meshmesh=newMesh();Vector3[]vertices=ConvertTo3D(triangles);int[]trianglesIndices=GetTrianglesIndices(triangles);mesh.vertices=vertices;mesh.triangles=trianglesIndices;

参考代码 基于C#实现的使用逐点插入法生成Delaunay三角网剖分程序www.youwenfan.com/contentcsr/112316.html

七、调试建议

  1. 可视化调试

    • 使用Unity Gizmos绘制外接圆和边

    • 添加日志输出关键计算步骤

  2. 异常处理

    try{// 三角剖分核心代码}catch(ArgumentExceptionex){Debug.LogError($"输入点集无效:{ex.Message}");}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 8:35:09

MobX库,深度详解

从处理数据和状态的角度来看&#xff0c;MobX 可以被理解为一套高效的状态管理机制。它的核心目标是让应用中的数据变化能够自动、精确地驱动用户界面的更新。1. 它是什么&#xff1f;可以把它想象成一个智能的仓库管理员。假设你的应用状态是一个仓库里的货物清单。传统方式中…

作者头像 李华
网站建设 2026/5/15 3:46:56

FPGA实现双线性插值缩放:代码与实现详解

fpga实现双线性插值缩放代码及资料在数字图像处理领域&#xff0c;双线性插值是一种常用的技术&#xff0c;用于图像的缩放、旋转和剪切等操作。而在硬件加速方面&#xff0c;FPGA&#xff08;现场可编程门阵列&#xff09;因其高度的并行处理能力和灵活的架构&#xff0c;成为…

作者头像 李华
网站建设 2026/5/1 11:11:40

百思数据治理大模型(BS-LM)技术白皮书(上篇)

当前&#xff0c;数据已跃升为数字经济的核心生产要素&#xff0c;但传统依赖人工与静态规则的数据治理模式&#xff0c;正面临规则僵化、语义割裂、知识难沉淀等系统性挑战&#xff0c;严重制约了数据价值的释放。行业亟需一场从“规则驱动”到“智能驱动”的范式变革。 为此…

作者头像 李华
网站建设 2026/5/14 2:32:59

百思数据治理大模型(BS-LM)技术白皮书(下篇)

当前&#xff0c;数据已跃升为数字经济的核心生产要素&#xff0c;但传统依赖人工与静态规则的数据治理模式&#xff0c;正面临规则僵化、语义割裂、知识难沉淀等系统性挑战&#xff0c;严重制约了数据价值的释放。行业亟需一场从“规则驱动”到“智能驱动”的范式变革。 为此…

作者头像 李华
网站建设 2026/5/4 1:54:59

备考软考高项,怕踩坑?这份全网零差评名师清单,助你一次通关!

去年备考信息系统项目管理师时&#xff0c;我最大的焦虑不是教材多厚、考点多难&#xff0c;而是——该跟哪位老师学&#xff1f; 网上信息满天飞&#xff0c;试听课听了好几节&#xff0c;还是怕选到“水货”老师&#xff0c;白白浪费一年一次的机会。 直到我跟着一份真实考生…

作者头像 李华