private int RemoveGhosts(ref Otri startghost) { Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); bool poly = !this.mesh.behavior.Poly; startghost.Lprev(ref otri); otri.SymSelf(); Mesh.dummytri.neighbors[0] = otri; startghost.Copy(ref otri1); int num = 0; do { num++; otri1.Lnext(ref otri2); otri1.LprevSelf(); otri1.SymSelf(); if (poly && otri1.triangle != Mesh.dummytri) { Vertex vertex = otri1.Org(); if (vertex.mark == 0) { vertex.mark = 1; } } otri1.Dissolve(); otri2.Sym(ref otri1); this.mesh.TriangleDealloc(otri2.triangle); }while (!otri1.Equal(startghost)); return(num); }
private int RemoveBox() { Otri otri = new Otri(); Otri otri1 = new Otri(); Otri otri2 = new Otri(); Otri otri3 = new Otri(); Otri otri4 = new Otri(); Otri otri5 = new Otri(); bool poly = !this.mesh.behavior.Poly; otri3.triangle = Mesh.dummytri; otri3.orient = 0; otri3.SymSelf(); otri3.Lprev(ref otri4); otri3.LnextSelf(); otri3.SymSelf(); otri3.Lprev(ref otri1); otri1.SymSelf(); otri3.Lnext(ref otri2); otri2.SymSelf(); if (otri2.triangle == Mesh.dummytri) { otri1.LprevSelf(); otri1.SymSelf(); } Mesh.dummytri.neighbors[0] = otri1; int num = -2; while (!otri3.Equal(otri4)) { num++; otri3.Lprev(ref otri5); otri5.SymSelf(); if (poly && otri5.triangle != Mesh.dummytri) { Vertex vertex = otri5.Org(); if (vertex.mark == 0) { vertex.mark = 1; } } otri5.Dissolve(); otri3.Lnext(ref otri); otri.Sym(ref otri3); this.mesh.TriangleDealloc(otri.triangle); if (otri3.triangle != Mesh.dummytri) { continue; } otri5.Copy(ref otri3); } this.mesh.TriangleDealloc(otri4.triangle); return(num); }
public void TestDissolve() { // Outer space triangle. var dummy = new Triangle() { id = -1 }; var triangles = CreateExampleMesh(); Otri s = default; Otri t = default; Otri tmp = default; // The bottom left triangle with edge 1 -> 3. s.tri = triangles[0]; s.orient = 1; // The center triangle with edge 3 -> 1. t.tri = triangles[1]; t.orient = 2; // 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 neighbors are properly set. s.Sym(ref tmp); Assert.AreEqual(1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(0, tmp.tri.ID); // Now dissolve the bond from one side. s.Dissolve(dummy); // Check neighbors. s.Sym(ref tmp); Assert.AreEqual(-1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(0, tmp.tri.ID); // And dissolve the bond from the other side. t.Dissolve(dummy); // Check neighbors. s.Sym(ref tmp); Assert.AreEqual(-1, tmp.tri.ID); t.Sym(ref tmp); Assert.AreEqual(-1, tmp.tri.ID); }
/// <summary> /// Removes ghost triangles. /// </summary> /// <param name="startghost"></param> /// <returns>Number of vertices on the hull.</returns> int RemoveGhosts(ref Otri startghost) { Otri searchedge = default(Otri); Otri dissolveedge = default(Otri); Otri deadtriangle = default(Otri); Vertex markorg; int hullsize; bool noPoly = !mesh.behavior.Poly; var dummytri = mesh.dummytri; // Find an edge on the convex hull to start point location from. startghost.Lprev(ref searchedge); searchedge.Sym(); dummytri.neighbors[0] = searchedge; // Remove the bounding box and count the convex hull edges. startghost.Copy(ref dissolveedge); hullsize = 0; do { hullsize++; dissolveedge.Lnext(ref deadtriangle); dissolveedge.Lprev(); dissolveedge.Sym(); // If no PSLG is involved, set the boundary markers of all the vertices // on the convex hull. If a PSLG is used, this step is done later. if (noPoly) { // Watch out for the case where all the input vertices are collinear. if (dissolveedge.tri.id != Mesh.DUMMY) { markorg = dissolveedge.Org(); if (markorg.label == 0) { markorg.label = 1; } } } // Remove a bounding triangle from a convex hull triangle. dissolveedge.Dissolve(dummytri); // Find the next bounding triangle. deadtriangle.Sym(ref dissolveedge); // Delete the bounding triangle. mesh.TriangleDealloc(deadtriangle.tri); } while (!dissolveedge.Equals(startghost)); return(hullsize); }
/// <summary> /// Remove the "infinite" bounding triangle, setting boundary markers as appropriate. /// </summary> /// <returns>Returns the number of edges on the convex hull of the triangulation.</returns> /// <remarks> /// The triangular bounding box has three boundary triangles (one for each /// side of the bounding box), and a bunch of triangles fanning out from /// the three bounding box vertices (one triangle for each edge of the /// convex hull of the inner mesh). This routine removes these triangles. /// </remarks> int RemoveBox() { Otri deadtriangle = default(Otri); Otri searchedge = default(Otri); Otri checkedge = default(Otri); Otri nextedge = default(Otri), finaledge = default(Otri), dissolveedge = default(Otri); Vertex markorg; int hullsize; bool noPoly = !mesh.behavior.Poly; // Find a boundary triangle. nextedge.triangle = Mesh.dummytri; nextedge.orient = 0; nextedge.SymSelf(); // Mark a place to stop. nextedge.Lprev(ref finaledge); nextedge.LnextSelf(); nextedge.SymSelf(); // Find a triangle (on the boundary of the vertex set) that isn't // a bounding box triangle. nextedge.Lprev(ref searchedge); searchedge.SymSelf(); // Check whether nextedge is another boundary triangle // adjacent to the first one. nextedge.Lnext(ref checkedge); checkedge.SymSelf(); if (checkedge.triangle == Mesh.dummytri) { // Go on to the next triangle. There are only three boundary // triangles, and this next triangle cannot be the third one, // so it's safe to stop here. searchedge.LprevSelf(); searchedge.SymSelf(); } // Find a new boundary edge to search from, as the current search // edge lies on a bounding box triangle and will be deleted. Mesh.dummytri.neighbors[0] = searchedge; hullsize = -2; while (!nextedge.Equal(finaledge)) { hullsize++; nextedge.Lprev(ref dissolveedge); dissolveedge.SymSelf(); // If not using a PSLG, the vertices should be marked now. // (If using a PSLG, markhull() will do the job.) if (noPoly) { // Be careful! One must check for the case where all the input // vertices are collinear, and thus all the triangles are part of // the bounding box. Otherwise, the setvertexmark() call below // will cause a bad pointer reference. if (dissolveedge.triangle != Mesh.dummytri) { markorg = dissolveedge.Org(); if (markorg.mark == 0) { markorg.mark = 1; } } } // Disconnect the bounding box triangle from the mesh triangle. dissolveedge.Dissolve(); nextedge.Lnext(ref deadtriangle); deadtriangle.Sym(ref nextedge); // Get rid of the bounding box triangle. mesh.TriangleDealloc(deadtriangle.triangle); // Do we need to turn the corner? if (nextedge.triangle == Mesh.dummytri) { // Turn the corner. dissolveedge.Copy(ref nextedge); } } mesh.TriangleDealloc(finaledge.triangle); return(hullsize); }
/// <summary> /// Spread the virus from all infected triangles to any neighbors not /// protected by subsegments. Delete all infected triangles. /// </summary> /// <remarks> /// This is the procedure that actually creates holes and concavities. /// /// This procedure operates in two phases. The first phase identifies all /// the triangles that will die, and marks them as infected. They are /// marked to ensure that each triangle is added to the virus pool only /// once, so the procedure will terminate. /// /// The second phase actually eliminates the infected triangles. It also /// eliminates orphaned vertices. /// </remarks> void Plague() { Otri testtri = default(Otri); Otri neighbor = default(Otri); Osub neighborsubseg = default(Osub); Vertex testvertex; Vertex norg, ndest; bool killorg; // Loop through all the infected triangles, spreading the virus to // their neighbors, then to their neighbors' neighbors. for (int i = 0; i < viri.Count; i++) { // WARNING: Don't use foreach, mesh.viri list may get modified. testtri.triangle = viri[i]; // A triangle is marked as infected by messing with one of its pointers // to subsegments, setting it to an illegal value. Hence, we have to // temporarily uninfect this triangle so that we can examine its // adjacent subsegments. // TODO: Not true in the C# version (so we could skip this). testtri.Uninfect(); // Check each of the triangle's three neighbors. for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { // Find the neighbor. testtri.Sym(ref neighbor); // Check for a subsegment between the triangle and its neighbor. testtri.SegPivot(ref neighborsubseg); // Check if the neighbor is nonexistent or already infected. if ((neighbor.triangle == Mesh.dummytri) || neighbor.IsInfected()) { if (neighborsubseg.seg != Mesh.dummysub) { // There is a subsegment separating the triangle from its // neighbor, but both triangles are dying, so the subsegment // dies too. mesh.SubsegDealloc(neighborsubseg.seg); if (neighbor.triangle != Mesh.dummytri) { // Make sure the subsegment doesn't get deallocated again // later when the infected neighbor is visited. neighbor.Uninfect(); neighbor.SegDissolve(); neighbor.Infect(); } } } else { // The neighbor exists and is not infected. if (neighborsubseg.seg == Mesh.dummysub) { // There is no subsegment protecting the neighbor, so // the neighbor becomes infected. neighbor.Infect(); // Ensure that the neighbor's neighbors will be infected. viri.Add(neighbor.triangle); } else { // The neighbor is protected by a subsegment. // Remove this triangle from the subsegment. neighborsubseg.TriDissolve(); // The subsegment becomes a boundary. Set markers accordingly. if (neighborsubseg.seg.boundary == 0) { neighborsubseg.seg.boundary = 1; } norg = neighbor.Org(); ndest = neighbor.Dest(); if (norg.mark == 0) { norg.mark = 1; } if (ndest.mark == 0) { ndest.mark = 1; } } } } // Remark the triangle as infected, so it doesn't get added to the // virus pool again. testtri.Infect(); } foreach (var virus in viri) { testtri.triangle = virus; // Check each of the three corners of the triangle for elimination. // This is done by walking around each vertex, checking if it is // still connected to at least one live triangle. for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { testvertex = testtri.Org(); // Check if the vertex has already been tested. if (testvertex != null) { killorg = true; // Mark the corner of the triangle as having been tested. testtri.SetOrg(null); // Walk counterclockwise about the vertex. testtri.Onext(ref neighbor); // Stop upon reaching a boundary or the starting triangle. while ((neighbor.triangle != Mesh.dummytri) && (!neighbor.Equal(testtri))) { if (neighbor.IsInfected()) { // Mark the corner of this triangle as having been tested. neighbor.SetOrg(null); } else { // A live triangle. The vertex survives. killorg = false; } // Walk counterclockwise about the vertex. neighbor.OnextSelf(); } // If we reached a boundary, we must walk clockwise as well. if (neighbor.triangle == Mesh.dummytri) { // Walk clockwise about the vertex. testtri.Oprev(ref neighbor); // Stop upon reaching a boundary. while (neighbor.triangle != Mesh.dummytri) { if (neighbor.IsInfected()) { // Mark the corner of this triangle as having been tested. neighbor.SetOrg(null); } else { // A live triangle. The vertex survives. killorg = false; } // Walk clockwise about the vertex. neighbor.OprevSelf(); } } if (killorg) { // Deleting vertex testvertex.type = VertexType.UndeadVertex; mesh.undeads++; } } } // Record changes in the number of boundary edges, and disconnect // dead triangles from their neighbors. for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { testtri.Sym(ref neighbor); if (neighbor.triangle == Mesh.dummytri) { // There is no neighboring triangle on this edge, so this edge // is a boundary edge. This triangle is being deleted, so this // boundary edge is deleted. mesh.hullsize--; } else { // Disconnect the triangle from its neighbor. neighbor.Dissolve(); // There is a neighboring triangle on this edge, so this edge // becomes a boundary edge when this triangle is deleted. mesh.hullsize++; } } // Return the dead triangle to the pool of triangles. mesh.TriangleDealloc(testtri.triangle); } // Empty the virus pool. viri.Clear(); }
private void Plague() { Otri item = new Otri(); Otri otri = new Otri(); Osub osub = new Osub(); for (int i = 0; i < this.viri.Count; i++) { item.triangle = this.viri[i]; item.Uninfect(); item.orient = 0; while (item.orient < 3) { item.Sym(ref otri); item.SegPivot(ref osub); if (otri.triangle != Mesh.dummytri && !otri.IsInfected()) { if (osub.seg != Mesh.dummysub) { osub.TriDissolve(); if (osub.seg.boundary == 0) { osub.seg.boundary = 1; } Vertex vertex = otri.Org(); Vertex vertex1 = otri.Dest(); if (vertex.mark == 0) { vertex.mark = 1; } if (vertex1.mark == 0) { vertex1.mark = 1; } } else { otri.Infect(); this.viri.Add(otri.triangle); } } else if (osub.seg != Mesh.dummysub) { this.mesh.SubsegDealloc(osub.seg); if (otri.triangle != Mesh.dummytri) { otri.Uninfect(); otri.SegDissolve(); otri.Infect(); } } item.orient = item.orient + 1; } item.Infect(); } foreach (Triangle virus in this.viri) { item.triangle = virus; item.orient = 0; while (item.orient < 3) { Vertex vertex2 = item.Org(); if (vertex2 != null) { bool flag = true; item.SetOrg(null); item.Onext(ref otri); while (otri.triangle != Mesh.dummytri && !otri.Equal(item)) { if (!otri.IsInfected()) { flag = false; } else { otri.SetOrg(null); } otri.OnextSelf(); } if (otri.triangle == Mesh.dummytri) { item.Oprev(ref otri); while (otri.triangle != Mesh.dummytri) { if (!otri.IsInfected()) { flag = false; } else { otri.SetOrg(null); } otri.OprevSelf(); } } if (flag) { vertex2.type = VertexType.UndeadVertex; Mesh mesh = this.mesh; mesh.undeads = mesh.undeads + 1; } } item.orient = item.orient + 1; } item.orient = 0; while (item.orient < 3) { item.Sym(ref otri); if (otri.triangle != Mesh.dummytri) { otri.Dissolve(); Mesh mesh1 = this.mesh; mesh1.hullsize = mesh1.hullsize + 1; } else { Mesh mesh2 = this.mesh; mesh2.hullsize = mesh2.hullsize - 1; } item.orient = item.orient + 1; } this.mesh.TriangleDealloc(item.triangle); } this.viri.Clear(); }