Fix Voronoi failing for meshes with undead vertices.

This commit is contained in:
wo80
2022-02-18 16:27:20 +01:00
parent 2264b4d7fd
commit 62b7153a8a
3 changed files with 94 additions and 9 deletions
@@ -0,0 +1,71 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
using TriangleNet.Geometry;
using TriangleNet.Meshing;
using TriangleNet.Smoothing;
namespace TriangleNet.Tests.Smoothing
{
public class SimpleSmootherTest
{
[Test]
public void TestSmoothWithDuplicate()
{
var poly = GetPolygon();
var options = new ConstraintOptions() { ConformingDelaunay = true };
var quality = new QualityOptions()
{
MinimumAngle = 30.0
};
var mesh = poly.Triangulate(options, quality);
Assert.AreEqual(1, mesh.Vertices
.Where(v => v.Type == VertexType.UndeadVertex)
.Count());
quality.MaximumArea = 0.2;
mesh.Refine(quality, true);
Assert.AreEqual(1, mesh.Vertices
.Where(v => v.Type == VertexType.UndeadVertex)
.Count());
var smoother = new SimpleSmoother();
// Smooth mesh.
smoother.Smooth(mesh, 25);
}
private Polygon GetPolygon()
{
var poly = new Polygon(7);
var p = new List<Vertex>()
{
new Vertex(0.0, 0.0, 1),
new Vertex(2.0, 0.0, 1),
new Vertex(2.0, 1.0, 1),
new Vertex(2.0, 2.0, 1),
new Vertex(0.0, 2.0, 1),
new Vertex(1.5, 1.6, 1),
new Vertex(2.0, 0.0, 1) // duplicate
};
poly.Points.AddRange(p);
poly.Add(new Segment(p[0], p[1], 1));
poly.Add(new Segment(p[1], p[2], 1));
poly.Add(new Segment(p[2], p[3], 1));
poly.Add(new Segment(p[3], p[4], 1));
poly.Add(new Segment(p[4], p[0], 1));
poly.Add(new Segment(p[2], p[5], 2));
return poly;
}
}
}
+1 -1
View File
@@ -383,7 +383,7 @@ namespace TriangleNet
{
numbering = NodeNumbering.None;
undeads = 0; // No eliminated input vertices yet.
//undeads = 0; // No eliminated input vertices yet.
checksegments = false; // There are no segments in the triangulation yet.
checkquality = false; // The quality triangulation stage has not begun.
+22 -8
View File
@@ -52,17 +52,17 @@ namespace TriangleNet.Voronoi
/// Generate the Voronoi diagram from given triangle mesh..
/// </summary>
/// <param name="mesh"></param>
/// <param name="bounded"></param>
protected void Generate(Mesh mesh)
{
mesh.Renumber();
base.edges = new List<HalfEdge>();
this.rays = new List<HalfEdge>();
// Undead vertices cannot be Voronoi cell generators.
int count = mesh.vertices.Count - mesh.undeads;
// Allocate space for Voronoi diagram.
var vertices = new Vertex[mesh.triangles.Count + mesh.hullsize];
var faces = new Face[mesh.vertices.Count];
var faces = new Face[count];
if (factory == null)
{
@@ -74,10 +74,21 @@ namespace TriangleNet.Voronoi
// Compute triangles circumcenters.
var map = ComputeVertices(mesh, vertices);
// Create all Voronoi faces.
// Ensure linear numbering of vertices (excluding undeads).
int vid = 0;
// Create all Voronoi faces, skipping undead vertices.
foreach (var vertex in mesh.vertices.Values)
{
faces[vertex.id] = factory.CreateFace(vertex);
if (vertex.type == VertexType.UndeadVertex)
{
vertex.id = count++;
}
else
{
vertex.id = vid++;
faces[vertex.id] = factory.CreateFace(vertex);
}
}
ComputeEdges(mesh, vertices, faces, map);
@@ -93,13 +104,16 @@ namespace TriangleNet.Voronoi
/// Compute the Voronoi vertices (the circumcenters of the triangles).
/// </summary>
/// <returns>An empty map, which will map all vertices to a list of leaving edges.</returns>
/// <remarks>
/// This method will also change triangle ids (to ensure linear numbering of triangles).
/// </remarks>
protected List<HalfEdge>[] ComputeVertices(Mesh mesh, Vertex[] vertices)
{
Otri tri = default(Otri);
double xi = 0, eta = 0;
Vertex vertex;
Point pt;
int id;
int id, i = 0;
// Maps all vertices to a list of leaving edges.
var map = new List<HalfEdge>[mesh.triangles.Count];
@@ -107,7 +121,7 @@ namespace TriangleNet.Voronoi
// Compute triangle circumcenters
foreach (var t in mesh.triangles)
{
id = t.id;
t.id = id = i++;
tri.tri = t;
pt = predicates.FindCircumcenter(tri.Org(), tri.Dest(), tri.Apex(), ref xi, ref eta);