public void TestBond() { Otri s = default; Otri t = default; Otri tmp = default; s.tri = Helper.CreateTriangle(0, vertices[0], vertices[1], vertices[3]); t.tri = Helper.CreateTriangle(1, vertices[1], vertices[4], vertices[3]); s.orient = 1; // Edge 1 -> 3. t.orient = 2; // Edge 3 -> 1. // Make sure we're on the correct edges. Assert.AreEqual(1, s.Org().ID); Assert.AreEqual(3, s.Dest().ID); Assert.AreEqual(3, t.Org().ID); Assert.AreEqual(1, t.Dest().ID); // Check that the triangles don't have neighbors. s.Sym(ref tmp); //Assert.AreEqual(-1, tmp.tri.ID); Assert.IsNull(tmp.tri); t.Sym(ref tmp); //Assert.AreEqual(-1, tmp.tri.ID); Assert.IsNull(tmp.tri); // Bond the two triangles. s.Bond(ref t); // Check that neighbors are properly set. s.Sym(ref tmp); Assert.AreEqual(1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(0, tmp.tri.ID); }
/// <summary> /// Recursively form a Delaunay triangulation by the divide-and-conquer method. /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <param name="axis"></param> /// <param name="farleft"></param> /// <param name="farright"></param> /// <remarks> /// Recursively breaks down the problem into smaller pieces, which are /// knitted together by mergehulls(). The base cases (problems of two or /// three vertices) are handled specially here. /// /// On completion, 'farleft' and 'farright' are bounding triangles such that /// the origin of 'farleft' is the leftmost vertex (breaking ties by /// choosing the highest leftmost vertex), and the destination of /// 'farright' is the rightmost vertex (breaking ties by choosing the /// lowest rightmost vertex). /// </remarks> void DivconqRecurse(int left, int right, int axis, ref Otri farleft, ref Otri farright) { Otri midtri = default(Otri); Otri tri1 = default(Otri); Otri tri2 = default(Otri); Otri tri3 = default(Otri); Otri innerleft = default(Otri), innerright = default(Otri); double area; int vertices = right - left + 1; int divider; if (vertices == 2) { // The triangulation of two vertices is an edge. An edge is // represented by two bounding triangles. mesh.MakeTriangle(ref farleft); farleft.SetOrg(sortarray[left]); farleft.SetDest(sortarray[left + 1]); // The apex is intentionally left NULL. mesh.MakeTriangle(ref farright); farright.SetOrg(sortarray[left + 1]); farright.SetDest(sortarray[left]); // The apex is intentionally left NULL. farleft.Bond(ref farright); farleft.LprevSelf(); farright.LnextSelf(); farleft.Bond(ref farright); farleft.LprevSelf(); farright.LnextSelf(); farleft.Bond(ref farright); // Ensure that the origin of 'farleft' is sortarray[0]. farright.Lprev(ref farleft); return; } else if (vertices == 3) { // The triangulation of three vertices is either a triangle (with // three bounding triangles) or two edges (with four bounding // triangles). In either case, four triangles are created. mesh.MakeTriangle(ref midtri); mesh.MakeTriangle(ref tri1); mesh.MakeTriangle(ref tri2); mesh.MakeTriangle(ref tri3); area = Primitives.CounterClockwise(sortarray[left], sortarray[left + 1], sortarray[left + 2]); if (area == 0.0) { // Three collinear vertices; the triangulation is two edges. midtri.SetOrg(sortarray[left]); midtri.SetDest(sortarray[left + 1]); tri1.SetOrg(sortarray[left + 1]); tri1.SetDest(sortarray[left]); tri2.SetOrg(sortarray[left + 2]); tri2.SetDest(sortarray[left + 1]); tri3.SetOrg(sortarray[left + 1]); tri3.SetDest(sortarray[left + 2]); // All apices are intentionally left NULL. midtri.Bond(ref tri1); tri2.Bond(ref tri3); midtri.LnextSelf(); tri1.LprevSelf(); tri2.LnextSelf(); tri3.LprevSelf(); midtri.Bond(ref tri3); tri1.Bond(ref tri2); midtri.LnextSelf(); tri1.LprevSelf(); tri2.LnextSelf(); tri3.LprevSelf(); midtri.Bond(ref tri1); tri2.Bond(ref tri3); // Ensure that the origin of 'farleft' is sortarray[0]. tri1.Copy(ref farleft); // Ensure that the destination of 'farright' is sortarray[2]. tri2.Copy(ref farright); } else { // The three vertices are not collinear; the triangulation is one // triangle, namely 'midtri'. midtri.SetOrg(sortarray[left]); tri1.SetDest(sortarray[left]); tri3.SetOrg(sortarray[left]); // Apices of tri1, tri2, and tri3 are left NULL. if (area > 0.0) { // The vertices are in counterclockwise order. midtri.SetDest(sortarray[left + 1]); tri1.SetOrg(sortarray[left + 1]); tri2.SetDest(sortarray[left + 1]); midtri.SetApex(sortarray[left + 2]); tri2.SetOrg(sortarray[left + 2]); tri3.SetDest(sortarray[left + 2]); } else { // The vertices are in clockwise order. midtri.SetDest(sortarray[left + 2]); tri1.SetOrg(sortarray[left + 2]); tri2.SetDest(sortarray[left + 2]); midtri.SetApex(sortarray[left + 1]); tri2.SetOrg(sortarray[left + 1]); tri3.SetDest(sortarray[left + 1]); } // The topology does not depend on how the vertices are ordered. midtri.Bond(ref tri1); midtri.LnextSelf(); midtri.Bond(ref tri2); midtri.LnextSelf(); midtri.Bond(ref tri3); tri1.LprevSelf(); tri2.LnextSelf(); tri1.Bond(ref tri2); tri1.LprevSelf(); tri3.LprevSelf(); tri1.Bond(ref tri3); tri2.LnextSelf(); tri3.LprevSelf(); tri2.Bond(ref tri3); // Ensure that the origin of 'farleft' is sortarray[0]. tri1.Copy(ref farleft); // Ensure that the destination of 'farright' is sortarray[2]. if (area > 0.0) { tri2.Copy(ref farright); } else { farleft.Lnext(ref farright); } } return; } else { // Split the vertices in half. divider = vertices >> 1; // Recursively triangulate each half. DivconqRecurse(left, left + divider - 1, 1 - axis, ref farleft, ref innerleft); //DebugWriter.Session.Write(mesh, true); DivconqRecurse(left + divider, right, 1 - axis, ref innerright, ref farright); //DebugWriter.Session.Write(mesh, true); // Merge the two triangulations into one. MergeHulls(ref farleft, ref innerleft, ref innerright, ref farright, axis); //DebugWriter.Session.Write(mesh, true); } }
/// <summary> /// Merge two adjacent Delaunay triangulations into a single Delaunay triangulation. /// </summary> /// <param name="farleft">Bounding triangles of the left triangulation.</param> /// <param name="innerleft">Bounding triangles of the left triangulation.</param> /// <param name="innerright">Bounding triangles of the right triangulation.</param> /// <param name="farright">Bounding triangles of the right triangulation.</param> /// <param name="axis"></param> /// <remarks> /// This is similar to the algorithm given by Guibas and Stolfi, but uses /// a triangle-based, rather than edge-based, data structure. /// /// The algorithm walks up the gap between the two triangulations, knitting /// them together. As they are merged, some of their bounding triangles /// are converted into real triangles of the triangulation. The procedure /// pulls each hull's bounding triangles apart, then knits them together /// like the teeth of two gears. The Delaunay property determines, at each /// step, whether the next "tooth" is a bounding triangle of the left hull /// or the right. When a bounding triangle becomes real, its apex is /// changed from NULL to a real vertex. /// /// Only two new triangles need to be allocated. These become new bounding /// triangles at the top and bottom of the seam. They are used to connect /// the remaining bounding triangles (those that have not been converted /// into real triangles) into a single fan. /// /// On entry, 'farleft' and 'innerleft' are bounding triangles of the left /// triangulation. The origin of 'farleft' is the leftmost vertex, and /// the destination of 'innerleft' is the rightmost vertex of the /// triangulation. Similarly, 'innerright' and 'farright' are bounding /// triangles of the right triangulation. The origin of 'innerright' and /// destination of 'farright' are the leftmost and rightmost vertices. /// /// On completion, the origin of 'farleft' is the leftmost vertex of the /// merged triangulation, and the destination of 'farright' is the rightmost /// vertex. /// </remarks> void MergeHulls(ref Otri farleft, ref Otri innerleft, ref Otri innerright, ref Otri farright, int axis) { Otri leftcand = default(Otri), rightcand = default(Otri); Otri nextedge = default(Otri); Otri sidecasing = default(Otri), topcasing = default(Otri), outercasing = default(Otri); Otri checkedge = default(Otri); Otri baseedge = default(Otri); Vertex innerleftdest; Vertex innerrightorg; Vertex innerleftapex, innerrightapex; Vertex farleftpt, farrightpt; Vertex farleftapex, farrightapex; Vertex lowerleft, lowerright; Vertex upperleft, upperright; Vertex nextapex; Vertex checkvertex; bool changemade; bool badedge; bool leftfinished, rightfinished; innerleftdest = innerleft.Dest(); innerleftapex = innerleft.Apex(); innerrightorg = innerright.Org(); innerrightapex = innerright.Apex(); // Special treatment for horizontal cuts. if (useDwyer && (axis == 1)) { farleftpt = farleft.Org(); farleftapex = farleft.Apex(); farrightpt = farright.Dest(); farrightapex = farright.Apex(); // The pointers to the extremal vertices are shifted to point to the // topmost and bottommost vertex of each hull, rather than the // leftmost and rightmost vertices. while (farleftapex.y < farleftpt.y) { farleft.LnextSelf(); farleft.SymSelf(); farleftpt = farleftapex; farleftapex = farleft.Apex(); } innerleft.Sym(ref checkedge); checkvertex = checkedge.Apex(); while (checkvertex.y > innerleftdest.y) { checkedge.Lnext(ref innerleft); innerleftapex = innerleftdest; innerleftdest = checkvertex; innerleft.Sym(ref checkedge); checkvertex = checkedge.Apex(); } while (innerrightapex.y < innerrightorg.y) { innerright.LnextSelf(); innerright.SymSelf(); innerrightorg = innerrightapex; innerrightapex = innerright.Apex(); } farright.Sym(ref checkedge); checkvertex = checkedge.Apex(); while (checkvertex.y > farrightpt.y) { checkedge.Lnext(ref farright); farrightapex = farrightpt; farrightpt = checkvertex; farright.Sym(ref checkedge); checkvertex = checkedge.Apex(); } } // Find a line tangent to and below both hulls. do { changemade = false; // Make innerleftdest the "bottommost" vertex of the left hull. if (Primitives.CounterClockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) { innerleft.LprevSelf(); innerleft.SymSelf(); innerleftdest = innerleftapex; innerleftapex = innerleft.Apex(); changemade = true; } // Make innerrightorg the "bottommost" vertex of the right hull. if (Primitives.CounterClockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) { innerright.LnextSelf(); innerright.SymSelf(); innerrightorg = innerrightapex; innerrightapex = innerright.Apex(); changemade = true; } } while (changemade); // Find the two candidates to be the next "gear tooth." innerleft.Sym(ref leftcand); innerright.Sym(ref rightcand); // Create the bottom new bounding triangle. mesh.MakeTriangle(ref baseedge); // Connect it to the bounding boxes of the left and right triangulations. baseedge.Bond(ref innerleft); baseedge.LnextSelf(); baseedge.Bond(ref innerright); baseedge.LnextSelf(); baseedge.SetOrg(innerrightorg); baseedge.SetDest(innerleftdest); // Apex is intentionally left NULL. // Fix the extreme triangles if necessary. farleftpt = farleft.Org(); if (innerleftdest == farleftpt) { baseedge.Lnext(ref farleft); } farrightpt = farright.Dest(); if (innerrightorg == farrightpt) { baseedge.Lprev(ref farright); } // The vertices of the current knitting edge. lowerleft = innerleftdest; lowerright = innerrightorg; // The candidate vertices for knitting. upperleft = leftcand.Apex(); upperright = rightcand.Apex(); // Walk up the gap between the two triangulations, knitting them together. while (true) { // Have we reached the top? (This isn't quite the right question, // because even though the left triangulation might seem finished now, // moving up on the right triangulation might reveal a new vertex of // the left triangulation. And vice-versa.) leftfinished = Primitives.CounterClockwise(upperleft, lowerleft, lowerright) <= 0.0; rightfinished = Primitives.CounterClockwise(upperright, lowerleft, lowerright) <= 0.0; if (leftfinished && rightfinished) { // Create the top new bounding triangle. mesh.MakeTriangle(ref nextedge); nextedge.SetOrg(lowerleft); nextedge.SetDest(lowerright); // Apex is intentionally left NULL. // Connect it to the bounding boxes of the two triangulations. nextedge.Bond(ref baseedge); nextedge.LnextSelf(); nextedge.Bond(ref rightcand); nextedge.LnextSelf(); nextedge.Bond(ref leftcand); // Special treatment for horizontal cuts. if (useDwyer && (axis == 1)) { farleftpt = farleft.Org(); farleftapex = farleft.Apex(); farrightpt = farright.Dest(); farrightapex = farright.Apex(); farleft.Sym(ref checkedge); checkvertex = checkedge.Apex(); // The pointers to the extremal vertices are restored to the // leftmost and rightmost vertices (rather than topmost and // bottommost). while (checkvertex.x < farleftpt.x) { checkedge.Lprev(ref farleft); farleftapex = farleftpt; farleftpt = checkvertex; farleft.Sym(ref checkedge); checkvertex = checkedge.Apex(); } while (farrightapex.x > farrightpt.x) { farright.LprevSelf(); farright.SymSelf(); farrightpt = farrightapex; farrightapex = farright.Apex(); } } return; } // Consider eliminating edges from the left triangulation. if (!leftfinished) { // What vertex would be exposed if an edge were deleted? leftcand.Lprev(ref nextedge); nextedge.SymSelf(); nextapex = nextedge.Apex(); // If nextapex is NULL, then no vertex would be exposed; the // triangulation would have been eaten right through. if (nextapex != null) { // Check whether the edge is Delaunay. badedge = Primitives.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0; while (badedge) { // Eliminate the edge with an edge flip. As a result, the // left triangulation will have one more boundary triangle. nextedge.LnextSelf(); nextedge.Sym(ref topcasing); nextedge.LnextSelf(); nextedge.Sym(ref sidecasing); nextedge.Bond(ref topcasing); leftcand.Bond(ref sidecasing); leftcand.LnextSelf(); leftcand.Sym(ref outercasing); nextedge.LprevSelf(); nextedge.Bond(ref outercasing); // Correct the vertices to reflect the edge flip. leftcand.SetOrg(lowerleft); leftcand.SetDest(null); leftcand.SetApex(nextapex); nextedge.SetOrg(null); nextedge.SetDest(upperleft); nextedge.SetApex(nextapex); // Consider the newly exposed vertex. upperleft = nextapex; // What vertex would be exposed if another edge were deleted? sidecasing.Copy(ref nextedge); nextapex = nextedge.Apex(); if (nextapex != null) { // Check whether the edge is Delaunay. badedge = Primitives.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0; } else { // Avoid eating right through the triangulation. badedge = false; } } } } // Consider eliminating edges from the right triangulation. if (!rightfinished) { // What vertex would be exposed if an edge were deleted? rightcand.Lnext(ref nextedge); nextedge.SymSelf(); nextapex = nextedge.Apex(); // If nextapex is NULL, then no vertex would be exposed; the // triangulation would have been eaten right through. if (nextapex != null) { // Check whether the edge is Delaunay. badedge = Primitives.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0; while (badedge) { // Eliminate the edge with an edge flip. As a result, the // right triangulation will have one more boundary triangle. nextedge.LprevSelf(); nextedge.Sym(ref topcasing); nextedge.LprevSelf(); nextedge.Sym(ref sidecasing); nextedge.Bond(ref topcasing); rightcand.Bond(ref sidecasing); rightcand.LprevSelf(); rightcand.Sym(ref outercasing); nextedge.LnextSelf(); nextedge.Bond(ref outercasing); // Correct the vertices to reflect the edge flip. rightcand.SetOrg(null); rightcand.SetDest(lowerright); rightcand.SetApex(nextapex); nextedge.SetOrg(upperright); nextedge.SetDest(null); nextedge.SetApex(nextapex); // Consider the newly exposed vertex. upperright = nextapex; // What vertex would be exposed if another edge were deleted? sidecasing.Copy(ref nextedge); nextapex = nextedge.Apex(); if (nextapex != null) { // Check whether the edge is Delaunay. badedge = Primitives.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0; } else { // Avoid eating right through the triangulation. badedge = false; } } } } if (leftfinished || (!rightfinished && (Primitives.InCircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) { // Knit the triangulations, adding an edge from 'lowerleft' // to 'upperright'. baseedge.Bond(ref rightcand); rightcand.Lprev(ref baseedge); baseedge.SetDest(lowerleft); lowerright = upperright; baseedge.Sym(ref rightcand); upperright = rightcand.Apex(); } else { // Knit the triangulations, adding an edge from 'upperleft' // to 'lowerright'. baseedge.Bond(ref leftcand); leftcand.Lnext(ref baseedge); baseedge.SetOrg(lowerright); lowerleft = upperleft; baseedge.Sym(ref leftcand); upperleft = leftcand.Apex(); } } }
/// <summary> /// Reconstruct a triangulation from its raw data representation. /// </summary> /// <param name="mesh"></param> /// <param name="input"></param> /// <returns></returns> /// <remarks> /// Reads an .ele file and reconstructs the original mesh. If the -p switch /// is used, this procedure will also read a .poly file and reconstruct the /// subsegments of the original mesh. If the -a switch is used, this /// procedure will also read an .area file and set a maximum area constraint /// on each triangle. /// /// Vertices that are not corners of triangles, such as nodes on edges of /// subparametric elements, are discarded. /// /// This routine finds the adjacencies between triangles (and subsegments) /// by forming one stack of triangles for each vertex. Each triangle is on /// three different stacks simultaneously. Each triangle's subsegment /// pointers are used to link the items in each stack. This memory-saving /// feature makes the code harder to read. The most important thing to keep /// in mind is that each triangle is removed from a stack precisely when /// the corresponding pointer is adjusted to refer to a subsegment rather /// than the next triangle of the stack. /// </remarks> public static int Reconstruct(Mesh mesh, InputGeometry input, ITriangle[] triangles) { int hullsize = 0; Otri tri = default(Otri); Otri triangleleft = default(Otri); Otri checktri = default(Otri); Otri checkleft = default(Otri); Otri checkneighbor = default(Otri); Osub subseg = default(Osub); List <Otri>[] vertexarray; // Triangle Otri prevlink; // Triangle Otri nexttri; // Triangle Vertex tdest, tapex; Vertex checkdest, checkapex; Vertex shorg; Vertex segmentorg, segmentdest; int[] corner = new int[3]; int[] end = new int[2]; //bool segmentmarkers = false; int boundmarker; int aroundvertex; bool notfound; int i = 0; int elements = triangles == null ? 0 : triangles.Length; int numberofsegments = input.segments.Count; mesh.inelements = elements; mesh.regions.AddRange(input.regions); // Create the triangles. for (i = 0; i < mesh.inelements; i++) { mesh.MakeTriangle(ref tri); // Mark the triangle as living. //tri.triangle.neighbors[0].triangle = tri.triangle; } if (mesh.behavior.Poly) { mesh.insegments = numberofsegments; // Create the subsegments. for (i = 0; i < mesh.insegments; i++) { mesh.MakeSegment(ref subseg); // Mark the subsegment as living. //subseg.ss.subsegs[0].ss = subseg.ss; } } // Allocate a temporary array that maps each vertex to some adjacent // triangle. I took care to allocate all the permanent memory for // triangles and subsegments first. vertexarray = new List <Otri> [mesh.vertices.Count]; // Each vertex is initially unrepresented. for (i = 0; i < mesh.vertices.Count; i++) { Otri tmp = default(Otri); tmp.triangle = Mesh.dummytri; vertexarray[i] = new List <Otri>(3); vertexarray[i].Add(tmp); } i = 0; // Read the triangles from the .ele file, and link // together those that share an edge. foreach (var item in mesh.triangles.Values) { tri.triangle = item; corner[0] = triangles[i].P0; corner[1] = triangles[i].P1; corner[2] = triangles[i].P2; // Copy the triangle's three corners. for (int j = 0; j < 3; j++) { if ((corner[j] < 0) || (corner[j] >= mesh.invertices)) { SimpleLog.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Triangle has an invalid vertex index."); } } // Read the triangle's attributes. tri.triangle.region = triangles[i].Region; // TODO: VarArea if (mesh.behavior.VarArea) { tri.triangle.area = triangles[i].Area; } // Set the triangle's vertices. tri.orient = 0; tri.SetOrg(mesh.vertices[corner[0]]); tri.SetDest(mesh.vertices[corner[1]]); tri.SetApex(mesh.vertices[corner[2]]); // Try linking the triangle to others that share these vertices. for (tri.orient = 0; tri.orient < 3; tri.orient++) { // Take the number for the origin of triangleloop. aroundvertex = corner[tri.orient]; int index = vertexarray[aroundvertex].Count - 1; // Look for other triangles having this vertex. nexttri = vertexarray[aroundvertex][index]; // Link the current triangle to the next one in the stack. //tri.triangle.neighbors[tri.orient] = nexttri; // Push the current triangle onto the stack. vertexarray[aroundvertex].Add(tri); checktri = nexttri; if (checktri.triangle != Mesh.dummytri) { tdest = tri.Dest(); tapex = tri.Apex(); // Look for other triangles that share an edge. do { checkdest = checktri.Dest(); checkapex = checktri.Apex(); if (tapex == checkdest) { // The two triangles share an edge; bond them together. tri.Lprev(ref triangleleft); triangleleft.Bond(ref checktri); } if (tdest == checkapex) { // The two triangles share an edge; bond them together. checktri.Lprev(ref checkleft); tri.Bond(ref checkleft); } // Find the next triangle in the stack. index--; nexttri = vertexarray[aroundvertex][index]; checktri = nexttri; } while (checktri.triangle != Mesh.dummytri); } } i++; } // Prepare to count the boundary edges. hullsize = 0; if (mesh.behavior.Poly) { // Read the segments from the .poly file, and link them // to their neighboring triangles. boundmarker = 0; i = 0; foreach (var item in mesh.subsegs.Values) { subseg.seg = item; end[0] = input.segments[i].P0; end[1] = input.segments[i].P1; boundmarker = input.segments[i].Boundary; for (int j = 0; j < 2; j++) { if ((end[j] < 0) || (end[j] >= mesh.invertices)) { SimpleLog.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Segment has an invalid vertex index."); } } // set the subsegment's vertices. subseg.orient = 0; segmentorg = mesh.vertices[end[0]]; segmentdest = mesh.vertices[end[1]]; subseg.SetOrg(segmentorg); subseg.SetDest(segmentdest); subseg.SetSegOrg(segmentorg); subseg.SetSegDest(segmentdest); subseg.seg.boundary = boundmarker; // Try linking the subsegment to triangles that share these vertices. for (subseg.orient = 0; subseg.orient < 2; subseg.orient++) { // Take the number for the destination of subsegloop. aroundvertex = end[1 - subseg.orient]; int index = vertexarray[aroundvertex].Count - 1; // Look for triangles having this vertex. prevlink = vertexarray[aroundvertex][index]; nexttri = vertexarray[aroundvertex][index]; checktri = nexttri; shorg = subseg.Org(); notfound = true; // Look for triangles having this edge. Note that I'm only // comparing each triangle's destination with the subsegment; // each triangle's apex is handled through a different vertex. // Because each triangle appears on three vertices' lists, each // occurrence of a triangle on a list can (and does) represent // an edge. In this way, most edges are represented twice, and // every triangle-subsegment bond is represented once. while (notfound && (checktri.triangle != Mesh.dummytri)) { checkdest = checktri.Dest(); if (shorg == checkdest) { // We have a match. Remove this triangle from the list. //prevlink = vertexarray[aroundvertex][index]; vertexarray[aroundvertex].Remove(prevlink); // Bond the subsegment to the triangle. checktri.SegBond(ref subseg); // Check if this is a boundary edge. checktri.Sym(ref checkneighbor); if (checkneighbor.triangle == Mesh.dummytri) { // The next line doesn't insert a subsegment (because there's // already one there), but it sets the boundary markers of // the existing subsegment and its vertices. mesh.InsertSubseg(ref checktri, 1); hullsize++; } notfound = false; } index--; // Find the next triangle in the stack. prevlink = vertexarray[aroundvertex][index]; nexttri = vertexarray[aroundvertex][index]; checktri = nexttri; } } i++; } } // Mark the remaining edges as not being attached to any subsegment. // Also, count the (yet uncounted) boundary edges. for (i = 0; i < mesh.vertices.Count; i++) { // Search the stack of triangles adjacent to a vertex. int index = vertexarray[i].Count - 1; nexttri = vertexarray[i][index]; checktri = nexttri; while (checktri.triangle != Mesh.dummytri) { // Find the next triangle in the stack before this // information gets overwritten. index--; nexttri = vertexarray[i][index]; // No adjacent subsegment. (This overwrites the stack info.) checktri.SegDissolve(); checktri.Sym(ref checkneighbor); if (checkneighbor.triangle == Mesh.dummytri) { mesh.InsertSubseg(ref checktri, 1); hullsize++; } checktri = nexttri; } } return(hullsize); }
public IMesh Triangulate(IList <Vertex> points, Configuration config) { this.predicates = config.Predicates(); this.mesh = new Mesh(config); this.mesh.TransferNodes(points); // Nonexistent x value used as a flag to mark circle events in sweepline // Delaunay algorithm. xminextreme = 10 * mesh.bounds.Left - 9 * mesh.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; double 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); mesh.MakeTriangle(ref lefttri); mesh.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; mesh.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 < mesh.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); } mesh.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; mesh.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); mesh.MakeTriangle(ref lefttri); mesh.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.0) { 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.0) { 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(); this.mesh.hullsize = RemoveGhosts(ref bottommost); return(this.mesh); }
public int Triangulate(Mesh mesh) { SweepLine.SweepEvent[] sweepEventArray; SweepLine.SweepEvent sweepEvent; Vertex vertex; Vertex vertex1; Vertex vertex2; Vertex vertex3; this.mesh = mesh; this.xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax; Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Otri otri3 = new Otri(); Otri otri4 = new Otri(); Otri otri5 = new Otri(); Otri otri6 = new Otri(); bool i = false; this.splaynodes = new List <SweepLine.SplayNode>(); SweepLine.SplayNode splayNode = null; this.CreateHeap(out sweepEventArray); int num = mesh.invertices; mesh.MakeTriangle(ref otri2); mesh.MakeTriangle(ref otri3); otri2.Bond(ref otri3); otri2.LnextSelf(); otri3.LprevSelf(); otri2.Bond(ref otri3); otri2.LnextSelf(); otri3.LprevSelf(); otri2.Bond(ref otri3); Vertex vertex4 = sweepEventArray[0].vertexEvent; this.HeapDelete(sweepEventArray, num, 0); num--; do { if (num == 0) { SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()"); throw new Exception("Input vertices are all identical."); } vertex = sweepEventArray[0].vertexEvent; this.HeapDelete(sweepEventArray, num, 0); num--; if (vertex4.x != vertex.x || vertex4.y != vertex.y) { continue; } if (Behavior.Verbose) { SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().1"); } vertex.type = VertexType.UndeadVertex; Mesh mesh1 = mesh; mesh1.undeads = mesh1.undeads + 1; }while (vertex4.x == vertex.x && vertex4.y == vertex.y); otri2.SetOrg(vertex4); otri2.SetDest(vertex); otri3.SetOrg(vertex); otri3.SetDest(vertex4); otri2.Lprev(ref otri); Vertex vertex5 = vertex; while (num > 0) { SweepLine.SweepEvent sweepEvent1 = sweepEventArray[0]; this.HeapDelete(sweepEventArray, num, 0); num--; bool flag = true; if (sweepEvent1.xkey >= mesh.bounds.Xmin) { Vertex vertex6 = sweepEvent1.vertexEvent; if (vertex6.x != vertex5.x || vertex6.y != vertex5.y) { vertex5 = vertex6; splayNode = this.FrontLocate(splayNode, otri, vertex6, ref otri1, ref i); otri.Copy(ref otri1); for (i = false; !i && this.RightOfHyperbola(ref otri1, vertex6); i = otri1.Equal(otri)) { otri1.OnextSelf(); } this.Check4DeadEvent(ref otri1, sweepEventArray, ref num); otri1.Copy(ref otri5); otri1.Sym(ref otri4); mesh.MakeTriangle(ref otri2); mesh.MakeTriangle(ref otri3); Vertex vertex7 = otri5.Dest(); otri2.SetOrg(vertex7); otri2.SetDest(vertex6); otri3.SetOrg(vertex6); otri3.SetDest(vertex7); otri2.Bond(ref otri3); otri2.LnextSelf(); otri3.LprevSelf(); otri2.Bond(ref otri3); otri2.LnextSelf(); otri3.LprevSelf(); otri2.Bond(ref otri4); otri3.Bond(ref otri5); if (!i && otri5.Equal(otri)) { otri2.Copy(ref otri); } if (this.randomnation(SweepLine.SAMPLERATE) == 0) { splayNode = this.SplayInsert(splayNode, otri2, vertex6); } else if (this.randomnation(SweepLine.SAMPLERATE) == 0) { otri3.Lnext(ref otri6); splayNode = this.SplayInsert(splayNode, otri6, vertex6); } } else { if (Behavior.Verbose) { SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().2"); } vertex6.type = VertexType.UndeadVertex; Mesh mesh2 = mesh; mesh2.undeads = mesh2.undeads + 1; flag = false; } } else { Otri otri7 = sweepEvent1.otriEvent; otri7.Oprev(ref otri4); this.Check4DeadEvent(ref otri4, sweepEventArray, ref num); otri7.Onext(ref otri5); this.Check4DeadEvent(ref otri5, sweepEventArray, ref num); if (otri4.Equal(otri)) { otri7.Lprev(ref otri); } mesh.Flip(ref otri7); otri7.SetApex(null); otri7.Lprev(ref otri2); otri7.Lnext(ref otri3); otri2.Sym(ref otri4); if (this.randomnation(SweepLine.SAMPLERATE) == 0) { otri7.SymSelf(); vertex1 = otri7.Dest(); vertex2 = otri7.Apex(); vertex3 = otri7.Org(); splayNode = this.CircleTopInsert(splayNode, otri2, vertex1, vertex2, vertex3, sweepEvent1.ykey); } } if (!flag) { continue; } vertex1 = otri4.Apex(); vertex2 = otri2.Dest(); vertex3 = otri2.Apex(); double num1 = Primitives.CounterClockwise(vertex1, vertex2, vertex3); if (num1 > 0) { sweepEvent = new SweepLine.SweepEvent() { xkey = this.xminextreme, ykey = this.CircleTop(vertex1, vertex2, vertex3, num1), otriEvent = otri2 }; this.HeapInsert(sweepEventArray, num, sweepEvent); num++; otri2.SetOrg(new SweepLine.SweepEventVertex(sweepEvent)); } vertex1 = otri3.Apex(); vertex2 = otri3.Org(); vertex3 = otri5.Apex(); double num2 = Primitives.CounterClockwise(vertex1, vertex2, vertex3); if (num2 <= 0) { continue; } sweepEvent = new SweepLine.SweepEvent() { xkey = this.xminextreme, ykey = this.CircleTop(vertex1, vertex2, vertex3, num2), otriEvent = otri5 }; this.HeapInsert(sweepEventArray, num, sweepEvent); num++; otri5.SetOrg(new SweepLine.SweepEventVertex(sweepEvent)); } this.splaynodes.Clear(); otri.LprevSelf(); return(this.RemoveGhosts(ref otri)); }
/// <summary> /// Finds the adjacencies between triangles by forming a stack of triangles for /// each vertex. Each triangle is on three different stacks simultaneously. /// </summary> private static List <Otri>[] SetNeighbors(Mesh mesh, ITriangle[] triangles) { Otri tri = default(Otri); Otri triangleleft = default(Otri); Otri checktri = default(Otri); Otri checkleft = default(Otri); Otri nexttri; TVertex tdest, tapex; TVertex checkdest, checkapex; int[] corner = new int[3]; int aroundvertex; int i; // Allocate a temporary array that maps each vertex to some adjacent triangle. var vertexarray = new List <Otri> [mesh.vertices.Count]; // Each vertex is initially unrepresented. for (i = 0; i < mesh.vertices.Count; i++) { Otri tmp = default(Otri); tmp.tri = mesh.dummytri; vertexarray[i] = new List <Otri>(3); vertexarray[i].Add(tmp); } i = 0; // Read the triangles from the .ele file, and link // together those that share an edge. foreach (var item in mesh.triangles) { tri.tri = item; // Copy the triangle's three corners. for (int j = 0; j < 3; j++) { corner[j] = triangles[i].GetVertexID(j); if ((corner[j] < 0) || (corner[j] >= mesh.invertices)) { Log.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Triangle has an invalid vertex index."); } } // Read the triangle's attributes. tri.tri.label = triangles[i].Label; // TODO: VarArea if (mesh.behavior.VarArea) { tri.tri.area = triangles[i].Area; } // Set the triangle's vertices. tri.orient = 0; tri.SetOrg(mesh.vertices[corner[0]]); tri.SetDest(mesh.vertices[corner[1]]); tri.SetApex(mesh.vertices[corner[2]]); // Try linking the triangle to others that share these vertices. for (tri.orient = 0; tri.orient < 3; tri.orient++) { // Take the number for the origin of triangleloop. aroundvertex = corner[tri.orient]; int index = vertexarray[aroundvertex].Count - 1; // Look for other triangles having this vertex. nexttri = vertexarray[aroundvertex][index]; // Push the current triangle onto the stack. vertexarray[aroundvertex].Add(tri); checktri = nexttri; if (checktri.tri.id != Mesh.DUMMY) { tdest = tri.Dest(); tapex = tri.Apex(); // Look for other triangles that share an edge. do { checkdest = checktri.Dest(); checkapex = checktri.Apex(); if (tapex == checkdest) { // The two triangles share an edge; bond them together. tri.Lprev(ref triangleleft); triangleleft.Bond(ref checktri); } if (tdest == checkapex) { // The two triangles share an edge; bond them together. checktri.Lprev(ref checkleft); tri.Bond(ref checkleft); } // Find the next triangle in the stack. index--; nexttri = vertexarray[aroundvertex][index]; checktri = nexttri; }while (checktri.tri.id != Mesh.DUMMY); } } i++; } return(vertexarray); }
private void DivconqRecurse(int left, int right, int axis, ref Otri farleft, ref Otri farright) { Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Otri otri3 = new Otri(); Otri otri4 = new Otri(); Otri otri5 = new Otri(); int num = right - left + 1; if (num == 2) { this.mesh.MakeTriangle(ref farleft); farleft.SetOrg(this.sortarray[left]); farleft.SetDest(this.sortarray[left + 1]); this.mesh.MakeTriangle(ref farright); farright.SetOrg(this.sortarray[left + 1]); farright.SetDest(this.sortarray[left]); farleft.Bond(ref farright); farleft.LprevSelf(); farright.LnextSelf(); farleft.Bond(ref farright); farleft.LprevSelf(); farright.LnextSelf(); farleft.Bond(ref farright); farright.Lprev(ref farleft); return; } if (num != 3) { int num1 = num >> 1; this.DivconqRecurse(left, left + num1 - 1, 1 - axis, ref farleft, ref otri4); this.DivconqRecurse(left + num1, right, 1 - axis, ref otri5, ref farright); this.MergeHulls(ref farleft, ref otri4, ref otri5, ref farright, axis); return; } this.mesh.MakeTriangle(ref otri); this.mesh.MakeTriangle(ref otri1); this.mesh.MakeTriangle(ref otri2); this.mesh.MakeTriangle(ref otri3); double num2 = Primitives.CounterClockwise(this.sortarray[left], this.sortarray[left + 1], this.sortarray[left + 2]); if (num2 == 0) { otri.SetOrg(this.sortarray[left]); otri.SetDest(this.sortarray[left + 1]); otri1.SetOrg(this.sortarray[left + 1]); otri1.SetDest(this.sortarray[left]); otri2.SetOrg(this.sortarray[left + 2]); otri2.SetDest(this.sortarray[left + 1]); otri3.SetOrg(this.sortarray[left + 1]); otri3.SetDest(this.sortarray[left + 2]); otri.Bond(ref otri1); otri2.Bond(ref otri3); otri.LnextSelf(); otri1.LprevSelf(); otri2.LnextSelf(); otri3.LprevSelf(); otri.Bond(ref otri3); otri1.Bond(ref otri2); otri.LnextSelf(); otri1.LprevSelf(); otri2.LnextSelf(); otri3.LprevSelf(); otri.Bond(ref otri1); otri2.Bond(ref otri3); otri1.Copy(ref farleft); otri2.Copy(ref farright); return; } otri.SetOrg(this.sortarray[left]); otri1.SetDest(this.sortarray[left]); otri3.SetOrg(this.sortarray[left]); if (num2 <= 0) { otri.SetDest(this.sortarray[left + 2]); otri1.SetOrg(this.sortarray[left + 2]); otri2.SetDest(this.sortarray[left + 2]); otri.SetApex(this.sortarray[left + 1]); otri2.SetOrg(this.sortarray[left + 1]); otri3.SetDest(this.sortarray[left + 1]); } else { otri.SetDest(this.sortarray[left + 1]); otri1.SetOrg(this.sortarray[left + 1]); otri2.SetDest(this.sortarray[left + 1]); otri.SetApex(this.sortarray[left + 2]); otri2.SetOrg(this.sortarray[left + 2]); otri3.SetDest(this.sortarray[left + 2]); } otri.Bond(ref otri1); otri.LnextSelf(); otri.Bond(ref otri2); otri.LnextSelf(); otri.Bond(ref otri3); otri1.LprevSelf(); otri2.LnextSelf(); otri1.Bond(ref otri2); otri1.LprevSelf(); otri3.LprevSelf(); otri1.Bond(ref otri3); otri2.LnextSelf(); otri3.LprevSelf(); otri2.Bond(ref otri3); otri1.Copy(ref farleft); if (num2 > 0) { otri2.Copy(ref farright); return; } farleft.Lnext(ref farright); }
private void MergeHulls(ref Otri farleft, ref Otri innerleft, ref Otri innerright, ref Otri farright, int axis) { Vertex vertex; Vertex vertex1; Vertex vertex2; Vertex vertex3; Vertex vertex4; Vertex i; bool flag; bool flag1; Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Otri otri3 = new Otri(); Otri otri4 = new Otri(); Otri otri5 = new Otri(); Otri otri6 = new Otri(); Otri otri7 = new Otri(); Vertex vertex5 = innerleft.Dest(); Vertex vertex6 = innerleft.Apex(); Vertex vertex7 = innerright.Org(); Vertex vertex8 = innerright.Apex(); if (this.useDwyer && axis == 1) { vertex = farleft.Org(); vertex2 = farleft.Apex(); vertex1 = farright.Dest(); vertex3 = farright.Apex(); while (vertex2.y < vertex.y) { farleft.LnextSelf(); farleft.SymSelf(); vertex = vertex2; vertex2 = farleft.Apex(); } innerleft.Sym(ref otri6); for (i = otri6.Apex(); i.y > vertex5.y; i = otri6.Apex()) { otri6.Lnext(ref innerleft); vertex6 = vertex5; vertex5 = i; innerleft.Sym(ref otri6); } while (vertex8.y < vertex7.y) { innerright.LnextSelf(); innerright.SymSelf(); vertex7 = vertex8; vertex8 = innerright.Apex(); } farright.Sym(ref otri6); for (i = otri6.Apex(); i.y > vertex1.y; i = otri6.Apex()) { otri6.Lnext(ref farright); vertex3 = vertex1; vertex1 = i; farright.Sym(ref otri6); } } do { flag = false; if (Primitives.CounterClockwise(vertex5, vertex6, vertex7) > 0) { innerleft.LprevSelf(); innerleft.SymSelf(); vertex5 = vertex6; vertex6 = innerleft.Apex(); flag = true; } if (Primitives.CounterClockwise(vertex8, vertex7, vertex5) <= 0) { continue; } innerright.LnextSelf(); innerright.SymSelf(); vertex7 = vertex8; vertex8 = innerright.Apex(); flag = true; }while (flag); innerleft.Sym(ref otri); innerright.Sym(ref otri1); this.mesh.MakeTriangle(ref otri7); otri7.Bond(ref innerleft); otri7.LnextSelf(); otri7.Bond(ref innerright); otri7.LnextSelf(); otri7.SetOrg(vertex7); otri7.SetDest(vertex5); vertex = farleft.Org(); if (vertex5 == vertex) { otri7.Lnext(ref farleft); } vertex1 = farright.Dest(); if (vertex7 == vertex1) { otri7.Lprev(ref farright); } Vertex vertex9 = vertex5; Vertex vertex10 = vertex7; Vertex vertex11 = otri.Apex(); Vertex vertex12 = otri1.Apex(); while (true) { bool flag2 = Primitives.CounterClockwise(vertex11, vertex9, vertex10) <= 0; bool flag3 = Primitives.CounterClockwise(vertex12, vertex9, vertex10) <= 0; if (flag2 & flag3) { break; } if (!flag2) { otri.Lprev(ref otri2); otri2.SymSelf(); vertex4 = otri2.Apex(); if (vertex4 != null) { flag1 = Primitives.InCircle(vertex9, vertex10, vertex11, vertex4) > 0; while (flag1) { otri2.LnextSelf(); otri2.Sym(ref otri4); otri2.LnextSelf(); otri2.Sym(ref otri3); otri2.Bond(ref otri4); otri.Bond(ref otri3); otri.LnextSelf(); otri.Sym(ref otri5); otri2.LprevSelf(); otri2.Bond(ref otri5); otri.SetOrg(vertex9); otri.SetDest(null); otri.SetApex(vertex4); otri2.SetOrg(null); otri2.SetDest(vertex11); otri2.SetApex(vertex4); vertex11 = vertex4; otri3.Copy(ref otri2); vertex4 = otri2.Apex(); flag1 = (vertex4 == null ? false : Primitives.InCircle(vertex9, vertex10, vertex11, vertex4) > 0); } } } if (!flag3) { otri1.Lnext(ref otri2); otri2.SymSelf(); vertex4 = otri2.Apex(); if (vertex4 != null) { flag1 = Primitives.InCircle(vertex9, vertex10, vertex12, vertex4) > 0; while (flag1) { otri2.LprevSelf(); otri2.Sym(ref otri4); otri2.LprevSelf(); otri2.Sym(ref otri3); otri2.Bond(ref otri4); otri1.Bond(ref otri3); otri1.LprevSelf(); otri1.Sym(ref otri5); otri2.LnextSelf(); otri2.Bond(ref otri5); otri1.SetOrg(null); otri1.SetDest(vertex10); otri1.SetApex(vertex4); otri2.SetOrg(vertex12); otri2.SetDest(null); otri2.SetApex(vertex4); vertex12 = vertex4; otri3.Copy(ref otri2); vertex4 = otri2.Apex(); flag1 = (vertex4 == null ? false : Primitives.InCircle(vertex9, vertex10, vertex12, vertex4) > 0); } } } if (flag2 || !flag3 && Primitives.InCircle(vertex11, vertex9, vertex10, vertex12) > 0) { otri7.Bond(ref otri1); otri1.Lprev(ref otri7); otri7.SetDest(vertex9); vertex10 = vertex12; otri7.Sym(ref otri1); vertex12 = otri1.Apex(); } else { otri7.Bond(ref otri); otri.Lnext(ref otri7); otri7.SetOrg(vertex10); vertex9 = vertex11; otri7.Sym(ref otri); vertex11 = otri.Apex(); } } this.mesh.MakeTriangle(ref otri2); otri2.SetOrg(vertex9); otri2.SetDest(vertex10); otri2.Bond(ref otri7); otri2.LnextSelf(); otri2.Bond(ref otri1); otri2.LnextSelf(); otri2.Bond(ref otri); if (this.useDwyer && axis == 1) { vertex = farleft.Org(); vertex2 = farleft.Apex(); vertex1 = farright.Dest(); vertex3 = farright.Apex(); farleft.Sym(ref otri6); for (i = otri6.Apex(); i.x < vertex.x; i = otri6.Apex()) { otri6.Lprev(ref farleft); vertex2 = vertex; vertex = i; farleft.Sym(ref otri6); } while (vertex3.x > vertex1.x) { farright.LprevSelf(); farright.SymSelf(); vertex1 = vertex3; vertex3 = farright.Apex(); } } }
public static int Reconstruct(Mesh mesh, InputGeometry input, ITriangle[] triangles) { Otri item; int num; int num1 = 0; Otri region = new Otri(); Otri otri = new Otri(); Otri l = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Osub osub = new Osub(); int[] p0 = new int[3]; int[] p1 = new int[2]; int i = 0; int num2 = (triangles == null ? 0 : (int)triangles.Length); int count = input.segments.Count; mesh.inelements = num2; mesh.regions.AddRange(input.regions); for (i = 0; i < mesh.inelements; i++) { mesh.MakeTriangle(ref region); } if (mesh.behavior.Poly) { mesh.insegments = count; for (i = 0; i < mesh.insegments; i++) { mesh.MakeSegment(ref osub); } } List <Otri>[] otris = new List <Otri> [mesh.vertices.Count]; for (i = 0; i < mesh.vertices.Count; i++) { Otri otri3 = new Otri() { triangle = Mesh.dummytri }; otris[i] = new List <Otri>(3); otris[i].Add(otri3); } i = 0; foreach (Triangle value in mesh.triangles.Values) { region.triangle = value; p0[0] = triangles[i].P0; p0[1] = triangles[i].P1; p0[2] = triangles[i].P2; for (int j = 0; j < 3; j++) { if (p0[j] < 0 || p0[j] >= mesh.invertices) { SimpleLog.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Triangle has an invalid vertex index."); } } region.triangle.region = triangles[i].Region; if (mesh.behavior.VarArea) { region.triangle.area = triangles[i].Area; } region.orient = 0; region.SetOrg(mesh.vertices[p0[0]]); region.SetDest(mesh.vertices[p0[1]]); region.SetApex(mesh.vertices[p0[2]]); region.orient = 0; while (region.orient < 3) { num = p0[region.orient]; int count1 = otris[num].Count - 1; item = otris[num][count1]; otris[num].Add(region); l = item; if (l.triangle != Mesh.dummytri) { Vertex vertex = region.Dest(); Vertex vertex1 = region.Apex(); do { Vertex vertex2 = l.Dest(); Vertex vertex3 = l.Apex(); if (vertex1 == vertex2) { region.Lprev(ref otri); otri.Bond(ref l); } if (vertex == vertex3) { l.Lprev(ref otri1); region.Bond(ref otri1); } count1--; item = otris[num][count1]; l = item; }while (l.triangle != Mesh.dummytri); } region.orient = region.orient + 1; } i++; } num1 = 0; if (mesh.behavior.Poly) { int boundary = 0; i = 0; foreach (Segment segment in mesh.subsegs.Values) { osub.seg = segment; p1[0] = input.segments[i].P0; p1[1] = input.segments[i].P1; boundary = input.segments[i].Boundary; for (int k = 0; k < 2; k++) { if (p1[k] < 0 || p1[k] >= mesh.invertices) { SimpleLog.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()"); throw new Exception("Segment has an invalid vertex index."); } } osub.orient = 0; Vertex item1 = mesh.vertices[p1[0]]; Vertex item2 = mesh.vertices[p1[1]]; osub.SetOrg(item1); osub.SetDest(item2); osub.SetSegOrg(item1); osub.SetSegDest(item2); osub.seg.boundary = boundary; osub.orient = 0; while (osub.orient < 2) { num = p1[1 - osub.orient]; int count2 = otris[num].Count - 1; Otri item3 = otris[num][count2]; item = otris[num][count2]; l = item; Vertex vertex4 = osub.Org(); bool flag = true; while (flag && l.triangle != Mesh.dummytri) { if (vertex4 == l.Dest()) { otris[num].Remove(item3); l.SegBond(ref osub); l.Sym(ref otri2); if (otri2.triangle == Mesh.dummytri) { mesh.InsertSubseg(ref l, 1); num1++; } flag = false; } count2--; item3 = otris[num][count2]; item = otris[num][count2]; l = item; } osub.orient = osub.orient + 1; } i++; } } for (i = 0; i < mesh.vertices.Count; i++) { int count3 = otris[i].Count - 1; item = otris[i][count3]; for (l = item; l.triangle != Mesh.dummytri; l = item) { count3--; item = otris[i][count3]; l.SegDissolve(); l.Sym(ref otri2); if (otri2.triangle == Mesh.dummytri) { mesh.InsertSubseg(ref l, 1); num1++; } } } return(num1); }