/// <summary>
/// Find the holes and infect them. Find the area constraints and infect
/// them. Infect the convex hull. Spread the infection and kill triangles.
/// Spread the area constraints.
/// </summary>
public void CarveHoles()
{
Otri searchtri = default(Otri);
Vertex searchorg, searchdest;
LocateResult intersect;
Triangle[] regionTris = null;
if (!mesh.behavior.Convex)
{
// Mark as infected any unprotected triangles on the boundary.
// This is one way by which concavities are created.
InfectHull();
}
if (!mesh.behavior.NoHoles)
{
// Infect each triangle in which a hole lies.
foreach (var hole in mesh.holes)
{
// Ignore holes that aren't within the bounds of the mesh.
if (mesh.bounds.Contains(hole))
{
// Start searching from some triangle on the outer boundary.
searchtri.triangle = Mesh.dummytri;
searchtri.orient = 0;
searchtri.SymSelf();
// Ensure that the hole is to the left of this boundary edge;
// otherwise, locate() will falsely report that the hole
// falls within the starting triangle.
searchorg = searchtri.Org();
searchdest = searchtri.Dest();
if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0)
{
// Find a triangle that contains the hole.
intersect = mesh.locator.Locate(hole, ref searchtri);
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
{
// Infect the triangle. This is done by marking the triangle
// as infected and including the triangle in the virus pool.
searchtri.Infect();
viri.Add(searchtri.triangle);
}
}
}
}
}
// Now, we have to find all the regions BEFORE we carve the holes, because locate() won't
// work when the triangulation is no longer convex. (Incidentally, this is the reason why
// regional attributes and area constraints can't be used when refining a preexisting mesh,
// which might not be convex; they can only be used with a freshly triangulated PSLG.)
if (mesh.regions.Count > 0)
{
int i = 0;
regionTris = new Triangle[mesh.regions.Count];
// Find the starting triangle for each region.
foreach (var region in mesh.regions)
{
regionTris[i] = Mesh.dummytri;
// Ignore region points that aren't within the bounds of the mesh.
if (mesh.bounds.Contains(region.point))
{
// Start searching from some triangle on the outer boundary.
searchtri.triangle = Mesh.dummytri;
searchtri.orient = 0;
searchtri.SymSelf();
// Ensure that the region point is to the left of this boundary
// edge; otherwise, locate() will falsely report that the
// region point falls within the starting triangle.
searchorg = searchtri.Org();
searchdest = searchtri.Dest();
if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0)
{
// Find a triangle that contains the region point.
intersect = mesh.locator.Locate(region.point, ref searchtri);
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
{
// Record the triangle for processing after the
// holes have been carved.
regionTris[i] = searchtri.triangle;
regionTris[i].region = region.id;
}
}
}
i++;
}
}
if (viri.Count > 0)
{
// Carve the holes and concavities.
Plague();
}
if (regionTris != null)
{
var iterator = new RegionIterator(mesh);
for (int i = 0; i < regionTris.Length; i++)
{
if (regionTris[i] != Mesh.dummytri)
{
// Make sure the triangle under consideration still exists.
// It may have been eaten by the virus.
if (!Otri.IsDead(regionTris[i]))
{
// Apply one region's attribute and/or area constraint.
iterator.Process(regionTris[i]);
}
}
}
}
// Free up memory (virus pool should be empty anyway).
viri.Clear();
}