/// <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.tri) && (borg == badtri.org) && (bdest == badtri.dest) && (bapex == badtri.apex)) { 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 = predicates.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 (Log.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 #if USE_ATTRIBS , mesh.nextras #endif ); newvertex.type = VertexType.FreeVertex; // 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.Lprev(); } // Assign triangle for attributes interpolation. newvertex.tri.tri = newvertex_tri; // Insert the circumcenter, searching from the edge of the triangle, // and maintain the Delaunay property of the triangulation. Osub tmp = default(Osub); success = _TriangleNetMesh.InsertVertex(newvertex, ref badotri, ref tmp, true, true); if (success == InsertVertexResult.Successful) { newvertex.hash = _TriangleNetMesh.hash_vtx++; newvertex.id = newvertex.hash; #if USE_ATTRIBS if (mesh.nextras > 0) { Interpolation.InterpolateAttributes(newvertex, newvertex.tri.tri, mesh.nextras); } #endif #if USE_Z Interpolation.InterpolateZ(newvertex, newvertex.tri.tri); #endif _TriangleNetMesh.vertices.Add(newvertex.hash, newvertex); if (_TriangleNetMesh.steinerleft > 0) { _TriangleNetMesh.steinerleft--; } } else if (success == InsertVertexResult.Encroaching) { // If the newly inserted vertex encroaches upon a subsegment, // delete the new vertex. _TriangleNetMesh.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 (Log.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."); } } }