/// <summary> /// Form a Delaunay triangulation by incrementally inserting vertices. /// </summary> /// <returns>Returns the number of edges on the convex hull of the /// triangulation.</returns> public IMesh Triangulate(IList <Vertex> points, Configuration config) { _TriangleNetMesh = new TriangleNetMesh(config); _TriangleNetMesh.TransferNodes(points); Otri starttri = new Otri(); // Create a triangular bounding box. GetBoundingBox(); foreach (var v in _TriangleNetMesh.vertices.Values) { starttri.tri = _TriangleNetMesh.dummytri; Osub tmp = default(Osub); if (_TriangleNetMesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate) { if (Log.Verbose) { Log.Instance.Warning("A duplicate vertex appeared and was ignored.", "Incremental.Triangulate()"); } v.type = VertexType.UndeadVertex; _TriangleNetMesh.undeads++; } } // Remove the bounding box. _TriangleNetMesh.hullsize = RemoveBox(); return(_TriangleNetMesh); }
/// <summary> /// Form a Delaunay triangulation by the divide-and-conquer method. /// </summary> /// <returns></returns> /// <remarks> /// Sorts the vertices, calls a recursive procedure to triangulate them, and /// removes the bounding box, setting boundary markers as appropriate. /// </remarks> public IMesh Triangulate(IList <Vertex> points, Configuration config) { predicates = config.Predicates(); _TriangleNetMesh = new TriangleNetMesh(config); _TriangleNetMesh.TransferNodes(points); Otri hullleft = default(Otri), hullright = default(Otri); int i, j, n = points.Count; // Allocate an array of pointers to vertices for sorting. sortarray = new Vertex[n]; i = 0; foreach (var v in points) { sortarray[i++] = v; } // Sort the vertices. VertexSorter.Sort(sortarray); // Discard duplicate vertices, which can really mess up the algorithm. i = 0; for (j = 1; j < n; j++) { if ((sortarray[i].x == sortarray[j].x) && (sortarray[i].y == sortarray[j].y)) { if (Log.Verbose) { Log.Instance.Warning( String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].id), "Dwyer.Triangulate()"); } sortarray[j].type = VertexType.UndeadVertex; _TriangleNetMesh.undeads++; } else { i++; sortarray[i] = sortarray[j]; } } i++; if (UseDwyer) { // Re-sort the array of vertices to accommodate alternating cuts. VertexSorter.Alternate(sortarray, i); } // Form the Delaunay triangulation. DivconqRecurse(0, i - 1, 0, ref hullleft, ref hullright); _TriangleNetMesh.hullsize = RemoveGhosts(ref hullleft); return(_TriangleNetMesh); }
/// <summary> /// Reconstruct a triangulation from its raw data representation. /// </summary> public static TriangleNetMesh ToMesh(Polygon polygon, ITriangle[] triangles) { Otri tri = default(Otri); Osub subseg = default(Osub); int i = 0; int elements = triangles == null ? 0 : triangles.Length; int segments = polygon.Segments.Count; // TODO: Configuration should be a function argument. var mesh = new TriangleNetMesh(new Configuration()); mesh.TransferNodes(polygon.Points); mesh.regions.AddRange(polygon.Regions); mesh.behavior.useRegions = polygon.Regions.Count > 0; if (polygon.Segments.Count > 0) { mesh.behavior.Poly = true; mesh.holes.AddRange(polygon.Holes); } // Create the triangles. for (i = 0; i < elements; i++) { mesh.MakeTriangle(ref tri); } if (mesh.behavior.Poly) { mesh.insegments = segments; // Create the subsegments. for (i = 0; i < segments; i++) { mesh.MakeSegment(ref subseg); } } var vertexarray = SetNeighbors(mesh, triangles); SetSegments(mesh, polygon, vertexarray); return(mesh); }
public IMesh Triangulate(IList <Vertex> points, Configuration config) { predicates = config.Predicates(); _TriangleNetMesh = new TriangleNetMesh(config); _TriangleNetMesh.TransferNodes(points); // Nonexistent x value used as a flag to mark circle events in sweepline // Delaunay algorithm. xminextreme = 10 * _TriangleNetMesh.bounds.Left - 9 * _TriangleNetMesh.bounds.Right; SweepEvent[] eventheap; SweepEvent nextevent; SweepEvent newevent; SplayNode splayroot; Otri bottommost = default(Otri); Otri searchtri = default(Otri); Otri fliptri; Otri lefttri = default(Otri); Otri righttri = default(Otri); Otri farlefttri = default(Otri); Otri farrighttri = default(Otri); Otri inserttri = default(Otri); Vertex firstvertex, secondvertex; Vertex nextvertex, lastvertex; Vertex connectvertex; Vertex leftvertex, midvertex, rightvertex; float lefttest, righttest; int heapsize; bool check4events, farrightflag = false; splaynodes = new List <SplayNode>(); splayroot = null; heapsize = points.Count; CreateHeap(out eventheap, heapsize);//, out events, out freeevents); _TriangleNetMesh.MakeTriangle(ref lefttri); _TriangleNetMesh.MakeTriangle(ref righttri); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref righttri); firstvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; do { if (heapsize == 0) { Log.Instance.Error("Input vertices are all identical.", "SweepLine.Triangulate()"); throw new Exception("Input vertices are all identical."); } secondvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; if ((firstvertex.x == secondvertex.x) && (firstvertex.y == secondvertex.y)) { if (Log.Verbose) { Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + secondvertex.id + ").", "SweepLine.Triangulate().1"); } secondvertex.type = VertexType.UndeadVertex; _TriangleNetMesh.undeads++; } } while ((firstvertex.x == secondvertex.x) && (firstvertex.y == secondvertex.y)); lefttri.SetOrg(firstvertex); lefttri.SetDest(secondvertex); righttri.SetOrg(secondvertex); righttri.SetDest(firstvertex); lefttri.Lprev(ref bottommost); lastvertex = secondvertex; while (heapsize > 0) { nextevent = eventheap[0]; HeapDelete(eventheap, heapsize, 0); heapsize--; check4events = true; if (nextevent.xkey < _TriangleNetMesh.bounds.Left) { fliptri = nextevent.otriEvent; fliptri.Oprev(ref farlefttri); Check4DeadEvent(ref farlefttri, eventheap, ref heapsize); fliptri.Onext(ref farrighttri); Check4DeadEvent(ref farrighttri, eventheap, ref heapsize); if (farlefttri.Equals(bottommost)) { fliptri.Lprev(ref bottommost); } _TriangleNetMesh.Flip(ref fliptri); fliptri.SetApex(null); fliptri.Lprev(ref lefttri); fliptri.Lnext(ref righttri); lefttri.Sym(ref farlefttri); if (randomnation(SAMPLERATE) == 0) { fliptri.Sym(); leftvertex = fliptri.Dest(); midvertex = fliptri.Apex(); rightvertex = fliptri.Org(); splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey); } } else { nextvertex = nextevent.vertexEvent; if ((nextvertex.x == lastvertex.x) && (nextvertex.y == lastvertex.y)) { if (Log.Verbose) { Log.Instance.Warning("A duplicate vertex appeared and was ignored (ID " + nextvertex.id + ").", "SweepLine.Triangulate().2"); } nextvertex.type = VertexType.UndeadVertex; _TriangleNetMesh.undeads++; check4events = false; } else { lastvertex = nextvertex; splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag); //bottommost.Copy(ref searchtri); //farrightflag = false; //while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex)) //{ // searchtri.OnextSelf(); // farrightflag = searchtri.Equal(bottommost); //} Check4DeadEvent(ref searchtri, eventheap, ref heapsize); searchtri.Copy(ref farrighttri); searchtri.Sym(ref farlefttri); _TriangleNetMesh.MakeTriangle(ref lefttri); _TriangleNetMesh.MakeTriangle(ref righttri); connectvertex = farrighttri.Dest(); lefttri.SetOrg(connectvertex); lefttri.SetDest(nextvertex); righttri.SetOrg(nextvertex); righttri.SetDest(connectvertex); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref farlefttri); righttri.Bond(ref farrighttri); if (!farrightflag && farrighttri.Equals(bottommost)) { lefttri.Copy(ref bottommost); } if (randomnation(SAMPLERATE) == 0) { splayroot = SplayInsert(splayroot, lefttri, nextvertex); } else if (randomnation(SAMPLERATE) == 0) { righttri.Lnext(ref inserttri); splayroot = SplayInsert(splayroot, inserttri, nextvertex); } } } if (check4events) { leftvertex = farlefttri.Apex(); midvertex = lefttri.Dest(); rightvertex = lefttri.Apex(); lefttest = predicates.CounterClockwise(leftvertex, midvertex, rightvertex); if (lefttest > 0.0f) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest); newevent.otriEvent = lefttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; lefttri.SetOrg(new SweepEventVertex(newevent)); } leftvertex = righttri.Apex(); midvertex = righttri.Org(); rightvertex = farrighttri.Apex(); righttest = predicates.CounterClockwise(leftvertex, midvertex, rightvertex); if (righttest > 0.0f) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest); newevent.otriEvent = farrighttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; farrighttri.SetOrg(new SweepEventVertex(newevent)); } } } splaynodes.Clear(); bottommost.Lprev(); _TriangleNetMesh.hullsize = RemoveGhosts(ref bottommost); return(_TriangleNetMesh); }