/// <summary>
/// Inserts a vertex at the circumcenter of a triangle. Deletes
/// the newly inserted vertex if it encroaches upon a segment.
/// </summary>
/// <param name="badtri"></param>
private void SplitTriangle(BadTriangle badtri)
{
Otri badotri = default(Otri);
Vertex borg, bdest, bapex;
Point newloc; // Location of the new vertex
float xi = 0, eta = 0;
InsertVertexResult success;
bool errorflag;
badotri = badtri.poortri;
borg = badotri.Org();
bdest = badotri.Dest();
bapex = badotri.Apex();
// Make sure that this triangle is still the same triangle it was
// when it was tested and determined to be of bad quality.
// Subsequent transformations may have made it a different triangle.
if (!Otri.IsDead(badotri.triangle) && (borg == badtri.triangorg) &&
(bdest == badtri.triangdest) && (bapex == badtri.triangapex))
{
errorflag = false;
// Create a new vertex at the triangle's circumcenter.
// Using the original (simpler) Steiner point location method
// for mesh refinement.
// TODO: NewLocation doesn't work for refinement. Why? Maybe
// reset VertexType?
if (behavior.fixedArea || behavior.VarArea)
{
newloc = Primitives.FindCircumcenter(borg, bdest, bapex, ref xi, ref eta, behavior.offconstant);
}
else
{
newloc = newLocation.FindLocation(borg, bdest, bapex, ref xi, ref eta, true, badotri);
}
// Check whether the new vertex lies on a triangle vertex.
if (((newloc.x == borg.x) && (newloc.y == borg.y)) ||
((newloc.x == bdest.x) && (newloc.y == bdest.y)) ||
((newloc.x == bapex.x) && (newloc.y == bapex.y)))
{
if (Behavior.Verbose)
{
logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
errorflag = true;
}
}
else
{
// The new vertex must be in the interior, and therefore is a
// free vertex with a marker of zero.
Vertex newvertex = new Vertex(newloc.x, newloc.y, 0, mesh.nextras);
newvertex.type = VertexType.FreeVertex;
for (int i = 0; i < mesh.nextras; i++)
{
// Interpolate the vertex attributes at the circumcenter.
newvertex.attributes[i] = borg.attributes[i]
+ xi * (bdest.attributes[i] - borg.attributes[i])
+ eta * (bapex.attributes[i] - borg.attributes[i]);
}
// Ensure that the handle 'badotri' does not represent the longest
// edge of the triangle. This ensures that the circumcenter must
// fall to the left of this edge, so point location will work.
// (If the angle org-apex-dest exceeds 90 degrees, then the
// circumcenter lies outside the org-dest edge, and eta is
// negative. Roundoff error might prevent eta from being
// negative when it should be, so I test eta against xi.)
if (eta < xi)
{
badotri.LprevSelf();
}
// Insert the circumcenter, searching from the edge of the triangle,
// and maintain the Delaunay property of the triangulation.
Osub tmp = default(Osub);
success = mesh.InsertVertex(newvertex, ref badotri, ref tmp, true, true);
if (success == InsertVertexResult.Successful)
{
newvertex.hash = mesh.hash_vtx++;
newvertex.id = newvertex.hash;
mesh.vertices.Add(newvertex.hash, newvertex);
if (mesh.steinerleft > 0)
{
mesh.steinerleft--;
}
}
else if (success == InsertVertexResult.Encroaching)
{
// If the newly inserted vertex encroaches upon a subsegment,
// delete the new vertex.
mesh.UndoVertex();
}
else if (success == InsertVertexResult.Violating)
{
// Failed to insert the new vertex, but some subsegment was
// marked as being encroached.
}
else
{ // success == DUPLICATEVERTEX
// Couldn't insert the new vertex because a vertex is already there.
if (Behavior.Verbose)
{
logger.Warning("New vertex falls on existing vertex.", "Quality.SplitTriangle()");
errorflag = true;
}
}
}
if (errorflag)
{
logger.Error("The new vertex is at the circumcenter of triangle: This probably "
+ "means that I am trying to refine triangles to a smaller size than can be "
+ "accommodated by the finite precision of floating point arithmetic.",
"Quality.SplitTriangle()");
throw new Exception("The new vertex is at the circumcenter of triangle.");
}
}
}