/// <summary> /// incremental insert Delaunay triangulation based on Bowyer/Watson's algorithm /// </summary> public static void TriangulateDelaunay(List <Vector2f> points, out List <Vector2f> outPoints, out List <int> outTris) { var mesh = new DelaunayTriangulation(); mesh.Triangulate(points); int vertCount = mesh.Vertices.Count; int triCount = mesh.Triangles.Count; outPoints = new List <Vector2f>(vertCount); outTris = new List <int>(triCount * 3); int offset = 0; for (int i = offset; i < vertCount; ++i) { outPoints.Add(mesh.Vertices[i]); } for (int i = 0; i < triCount; ++i) { var t = mesh.Triangles[i]; // throw away tris connected to the initial bounding box if (t.i0 < offset || t.i1 < offset || t.i2 < offset) { continue; } outTris.Add(t.i0 - offset); outTris.Add(t.i1 - offset); outTris.Add(t.i2 - offset); } }
/// <summary> /// iterative optimisation algoirthm based on Variational Tetrahedral Meshing /// </summary> public static void TriangulateVariational(List <Vector2f> inPoints, List <Vector2f> bPoints, int iterations, out List <Vector2f> outPoints, out List <int> outTris) { Vector2f[] points = new Vector2f[inPoints.Count]; float[] weights = new float[inPoints.Count]; for (int i = 0; i < points.Length; ++i) { points[i] = inPoints[i]; } var mesh = new DelaunayTriangulation(); for (int k = 0; k < iterations; ++k) { mesh.Triangulate(points); Array.Clear(points, 0, points.Length); Array.Clear(weights, 0, weights.Length); // optimize boundary points for (int i = 0; i < bPoints.Count; ++i) { int closest = 0; float closestDistSq = float.PositiveInfinity; Vector2f b = bPoints[i]; // find closest point (todo: use spatial hash) for (int j = 0; j < mesh.Vertices.Count; ++j) { float dSq = (mesh.Vertices[j] - b).SqrMagnitude; if (dSq < closestDistSq) { closest = j; closestDistSq = dSq; } } points[closest] -= b; weights[closest] -= 1.0f; } // optimize interior points by moving them to the centroid of their 1-ring for (int i = 0; i < mesh.Triangles.Count; ++i) { var t = mesh.Triangles[i]; float w = t.TriArea(mesh.Vertices); for (int v = 0; v < 3; ++v) { int s = t[v]; if (weights[s] >= 0.0f) { points[s] += w * t.CircumCenter; weights[s] += w; } } } for (int i = 0; i < points.Length; ++i) { points[i] /= weights[i]; } } mesh.Triangulate(points); /* * points.resize(0); * points.assign(mesh.vertices.begin()+3, mesh.vertices.end()); * * // remove any sliver tris on the boundary * for (uint32_t i = 0; i<mesh.triangles.size();) * { * real q = mesh.TriangleQuality(i); * * if (q > 3.0f) * mesh.triangles.erase(mesh.triangles.begin() + i); * else ++i; * } */ outPoints = new List <Vector2f>(mesh.Vertices); outTris = new List <int>(mesh.Triangles.Count * 3); for (int i = 0; i < mesh.Triangles.Count; ++i) { var t = mesh.Triangles[i]; outTris.Add(t.i0); outTris.Add(t.i1); outTris.Add(t.i2); } }