/// <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(); }