//@ Include files, #define's, etc.
#include <queue>

#include <math.h>
#include "GR_assert.h"
#include "GR_Cell.h"
#include "GR_Face.h"
#include "GR_BFace.h"
#include "GR_Vertex.h"
#include "GR_Geometry.h"
#include "GR_Mesh.h"
#include "GR_Mesh2D.h"
#include "GR_Vec.h"

//@ Swap away iFace if this is legal and improves the mesh quality measure
// Swapping typically propagates through the mesh, and the return value from
// iFaceSwap is the total number of swaps done during this invocation.
int Mesh2D::
iFaceSwap (Face* const pF)
{
  if (!pF->iFullCheck ())
    return (0);
  // Never swap a face that divides two regions in a multi-region mesh.
  if (pF->iFaceLoc () == Face::eBdryTwoSide ||
      pF->eType() == Face::eMultiEdge)
    return (0);
  assert (eSwapType () != eNone);

  //@@ Case: one or both cells is not a tri, including boundaries
  Cell *pCLeft = pF->pCCellLeft ();
  Cell *pCRight = pF->pCCellRight ();
  if (!pCLeft->qValid () || !pCRight->qValid ())
    return (0);
  if (pCLeft->eType () != Cell::eTriCell ||
      pCRight->eType () != Cell::eTriCell)
    return (0);

  Vert *pVVertA = pF->pVVert (0);
  Vert *pVVertB = pF->pVVert (1);
  TriCell *pTCLeft = dynamic_cast<TriCell*>(pCLeft);
  TriCell *pTCRight = dynamic_cast<TriCell*>(pCRight);
  assert(pTCLeft != NULL);
  assert(pTCRight != NULL);
  
  Vert *pVVertC = pTCLeft->pVVertOpposite (pF);
  Vert *pVVertD = pTCRight->pVVertOpposite (pF);

  int iOrientA = iOrient2D (pVVertA, pVVertD, pVVertC);
  int iOrientB = iOrient2D (pVVertB, pVVertC, pVVertD);
  if (iOrientA == -1 || iOrientB == -1 ||
      (iOrientA == 0 && iOrientB == 0))
    return 0;

  if (qDoSwap (pVVertA, pVVertB, pVVertC, pVVertD)) {
    return iReconfigure (pF);
  }
  else
    return (0);
}

//@ Swap away iFace if this is legal and improves the mesh quality measure
// Swapping typically propagates through the mesh, and the return value from
// iFaceSwap is the total number of swaps done during this invocation.
bool Mesh2D::
qRemoveEdge (Face * const pF)
{
  if (!pF->qValid () || pF->qDeleted ())
    return (false);
  assert (pF->iFullCheck ());

  //@@ Case: one or both cells is not a tet, including boundaries
  Cell *pCL = pF->pCCellLeft ();
  Cell *pCR = pF->pCCellRight ();
  if (!pCL->qValid () || !pCR->qValid ())
    return (false);
  if (pCL->eType () != Cell::eTriCell ||
      pCR->eType () != Cell::eTriCell)
    return (false);

  TriCell *pTCL = dynamic_cast<TriCell*>(pCL);
  TriCell *pTCR = dynamic_cast<TriCell*>(pCR);
  assert(pTCL != NULL);
  assert(pTCR != NULL);

  Vert *pVVertA = pF->pVVert (0);
  Vert *pVVertB = pF->pVVert (1);
  Vert *pVVertC = pTCL->pVVertOpposite (pF);
  Vert *pVVertD = pTCR->pVVertOpposite (pF);

  if (iOrient2D (pVVertA, pVVertD, pVVertC) != 1 ||
      iOrient2D (pVVertB, pVVertC, pVVertD) != 1)
    return false;

  vDisallowSwapRecursion ();
  iReconfigure (pF);
  vAllowSwapRecursion ();
  return true;
}

// This tie breaker is used only to pick a unique configuration in the
// event that a tie occurs trying to decide  how to swap.  The only
// thing which this choice of tiebreaker has to recommend it is that it
// gives a unique answer for any two pairs of verts (AB and CD).
static bool
qTieBreak (const Vert * pVVertA, const Vert * pVVertB,
	   const Vert * pVVertC, const Vert * pVVertD)
{
  unsigned long ulA = reinterpret_cast<unsigned long> (pVVertA);
  unsigned long ulB = reinterpret_cast<unsigned long> (pVVertB);
  unsigned long ulC = reinterpret_cast<unsigned long> (pVVertC);
  unsigned long ulD = reinterpret_cast<unsigned long> (pVVertD);
  if (min (ulA, ulB) > min (ulC, ulD))
    return true;
  else
    return false;
}

//@@ Determines whether swapping is needed for local Delaunay-ness.
static bool
qDoSwapDelaunay (const Vert * pVVertA, const Vert * pVVertB,
		 const Vert * pVVertC, const Vert * pVVertD)
{
  switch (iIncircle (pVVertA, pVVertB, pVVertC, pVVertD)) {
  case -1:
    return false;		// pVVertD is outside

  case 1:
    return true;		// pVVertD is inside

  case 0:			// Need some sort of tie-breaker for uniqueness
    return false;		// Tie breaker design is a little tricky....
    //     return qTieBreak(pVVertA, pVVertB, pVVertC, pVVertD);

  default:
    assert2 (0, "Illegal return value from iIncircle");
    return false;
  }
}

//@@ Determines whether swapping will improve the maximum face angle.
static bool
qDoSwapMaxDihed (const Vert * pVVertA, const Vert * pVVertB,
		 const Vert * pVVertC, const Vert * pVVertD)
{
  // This algorithm finds face angles between adjacent faces by dotting
  // their unit normals.  The largest magnitude loses.
  //
  // To prevent pairs from flopping back and forth, the tie-breaker is
  // invoked if the inequality is small.

  double dEps = 1.e-12;
  // All of these normals are intended to point inwards.
  double adNormDA[2], adNormBD[2], adNormCB[2], adNormAC[2];
  vNormal (pVVertA->adCoords (), pVVertD->adCoords (), adNormDA);
  vNormal (pVVertD->adCoords (), pVVertB->adCoords (), adNormBD);
  vNormal (pVVertB->adCoords (), pVVertC->adCoords (), adNormCB);
  vNormal (pVVertC->adCoords (), pVVertA->adCoords (), adNormAC);

  vNORMALIZE2D (adNormDA);
  vNORMALIZE2D (adNormBD);
  vNORMALIZE2D (adNormCB);
  vNORMALIZE2D (adNormAC);

  double dDotBDA = dDOT2D (adNormBD, adNormDA);
  double dDotACB = dDOT2D (adNormAC, adNormCB);
  double dDotDAC = dDOT2D (adNormDA, adNormAC);
  double dDotCBD = dDOT2D (adNormCB, adNormBD);

  double dMaxThis = max (dDotBDA, dDotACB);
  double dMaxOther = max (dDotDAC, dDotCBD);

//   // Use the commented code only to create bad meshes to test swapping.
// #warning Deliberately broken swapping decision
//   if (dMaxThis > 0.97 || dMaxOther > 0.97) {
//     //     // This is the -right- decision
    if (dMaxThis > dMaxOther + dEps)
      return true;
    else if (dMaxThis + dEps < dMaxOther)
      return false;
    else
      return qTieBreak (pVVertA, pVVertB, pVVertC, pVVertD);
//     // Use the following clause only to create bad meshes to test swapping.
//   }
//   else {
//     if (dMaxThis < dMaxOther - dEps)
//       return true;
//     else if (dMaxThis - dEps > dMaxOther)
//       return false;
//     else
//       return qTieBreak (pVVertA, pVVertB, pVVertC, pVVertD);
//   }
}

bool
Mesh2D::qDoSwap (const Vert* const pVVertA, const Vert* const pVVertB,
		 const Vert* const pVVertL, const Vert* const pVVertR,
		 const Vert* const pVVertE) const
{
  assert (pVVertA->qValid ());
  assert (pVVertB->qValid ());
  assert (pVVertL->qValid ());
  assert (pVVertR->qValid ());
  assert(!pVVertE->qValid ());


  switch (eSwapType()) {
  case eMinSine:
  case eDelaunay:
    return qDoSwapDelaunay (pVVertA, pVVertB, pVVertL, pVVertR);
  case eMaxDihed:
    return qDoSwapMaxDihed (pVVertA, pVVertB, pVVertL, pVVertR);
  case eFromQual:
    {
      assert(pQ != NULL);
      TriCellCV TCCV11(const_cast<Vert*>(pVVertA),
		       const_cast<Vert*>(pVVertB),
		       const_cast<Vert*>(pVVertL));
      TriCellCV TCCV12(const_cast<Vert*>(pVVertB),
		       const_cast<Vert*>(pVVertA),
		       const_cast<Vert*>(pVVertR));
      double dQual11 = pQ->dEvaluate(&TCCV11);
      double dQual12 = pQ->dEvaluate(&TCCV12);

      TriCellCV TCCV21(const_cast<Vert*>(pVVertL),
		       const_cast<Vert*>(pVVertR),
		       const_cast<Vert*>(pVVertB));
      TriCellCV TCCV22(const_cast<Vert*>(pVVertR),
		       const_cast<Vert*>(pVVertL),
		       const_cast<Vert*>(pVVertA));
      double dQual21 = pQ->dEvaluate(&TCCV21);
      double dQual22 = pQ->dEvaluate(&TCCV22);

      bool qMaximize = pQ->qMaximizeMinValue();
      if (qMaximize) {
	double dQual1 = min(dQual11, dQual12);
	double dQual2 = min(dQual21, dQual22);
	if (dQual1 > dQual2) return true;
	else                 return false;
      }
      else {
	double dQual1 = max(dQual11, dQual12);
	double dQual2 = max(dQual21, dQual22);
	if (dQual1 < dQual2) return true;
	else                 return false;
      }
    }
  default:
    return (false);
  }
}

int Mesh2D::
iReconfigure (Face * const pFEdge)
{
  assert (pFEdge->iFullCheck ());
  assert (!((eSwapMeasure == eNone) && qSwapRecur));
  if (pFEdge->iFaceLoc () == Face::eBdryTwoSide)
    return (0);

  // Identify all the parts
  TriCell *pC0 = dynamic_cast<TriCell*>(pFEdge->pCCellLeft ());
  TriCell *pC1 = dynamic_cast<TriCell*>(pFEdge->pCCellRight());
  Vert *pVA = pFEdge->pVVert (0);
  Vert *pVB = pFEdge->pVVert (1);
  Vert *pV0 = pC0->pVVertOpposite (pFEdge);
  Vert *pV1 = pC1->pVVertOpposite (pFEdge);

  Face *pFA = pC0->pFFaceOpposite (pVB);
  Face *pFB = pC0->pFFaceOpposite (pVA);
  Face *pFC = pC1->pFFaceOpposite (pVA);
  Face *pFD = pC1->pFFaceOpposite (pVB);

  // Realign the diagonal edge
  pFEdge->vReplaceVert (pVA, pV1);	// sic

  pFEdge->vReplaceVert (pVB, pV0);	// sic

  // Correct the edge-cell pointers
  assert (pFB->qHasCell (pC0));
  pFB->vReplaceCell (pC0, pC1);

  assert (pFD->qHasCell (pC1));
  pFD->vReplaceCell (pC1, pC0);

  // Make sure the vertex hints are correct.
  pVA->vSetHintFace (pFA);
  pVB->vSetHintFace (pFB);

  // Tag these verts for smoothing
  pV0->vMarkIllShaped ();
  pV1->vMarkIllShaped ();
  pVA->vMarkIllShaped ();
  pVB->vMarkIllShaped ();

  // Set up new face-edge lists for the faces involved.
  pC0->vAssign (pFD, pFA, pFEdge);
  pC1->vAssign (pFB, pFC, pFEdge);
  assert (pC0->iFullCheck ());
  assert (pC1->iFullCheck ());

  int iRetVal = 1;
  if (qSwapRecur) {
    iRetVal += iFaceSwap(pFA);
    iRetVal += iFaceSwap(pFB);
    iRetVal += iFaceSwap(pFC);
    iRetVal += iFaceSwap(pFD);
  }
  return iRetVal;
}

//@ Make certain that a particular edge is included in a 2D mesh.
bool Mesh2D::
qRecoverEdge (const int iV0, const int iV1)
     // Force swaps of all edges that are crossed by the edge between
     // the verts indicated by iV0 and iV1.
{
  assert (iV0 != iV1);
  Vert *pV0 = pVVert (iV0);
  Vert *pV1 = pVVert (iV1);
  Face *pFDummy;
  return qRecoverEdge(pV0, pV1, pFDummy);
}

bool Mesh2D::
qRecoverEdge (Vert* const pV0, Vert* const pV1, Face*& pFRet)
// Force swaps of all edges that are crossed by the edge between
// the verts indicated by pV0 and pV1.
{
  assert (pV0->qValid ());
  assert (pV1->qValid ());
  bool qOldRecursion = qSwapRecursionAllowed ();
  vDisallowSwapRecursion ();
  pFRet = pFInvalidFace;

//  vMessage(3, "Inside qRecoverEdge: %d, %d : (%f, %f) - (%f, %f)\n",
//	   iV0, iV1, pV0->dX (), pV0->dY (), pV1->dX (), pV1->dY ());

  // Find the cell across which to begin walking from pV0 to pV1.
  std::set<Cell*> spCInc;
  std::set<Vert*> spVNeigh;
  vNeighborhood(pV0, spCInc, spVNeigh);

  // For each cell, find out which, if any, of its non-incident faces
  // are crossed by pV0, pV1.  In the process, identify the face
  // connecting pV0 to pV1 if it exists.
  std::set<Cell*>::iterator iter;
  Face *pFToCross = pFInvalidFace;
  Cell *pC = pCInvalidCell;
  bool qGotIt = false;
  for (iter = spCInc.begin(); !qGotIt && (iter != spCInc.end()); iter++) {
    Cell *pCCand = *iter;
    assert(pCCand->qHasVert(pV0));
    for (int iF = pCCand->iNumFaces() - 1; iF >= 0; iF--) {
      Face *pFCand = pCCand->pFFace(iF);
      if (pFCand->qHasVert(pV0)) {
	if (pFCand->qHasVert(pV1)) {
	  pFRet = pFCand;
	  return true;
	}
	// If a face incident on pV0 isn't also incident on pV1, then
	// don't bother.
      }

      else if ((iOrient2D(pV0, pV1, pFCand->pVVert(0)) ==
		iOrient2D(pV1, pV0, pFCand->pVVert(1))) &&
	       (iOrient2D(pFCand->pVVert(0), pFCand->pVVert(1), pV0) ==
		iOrient2D(pFCand->pVVert(1), pFCand->pVVert(0), pV1))) {
	// This edge crosses the segment pV0, pV1; it's the place to
	// start.
	pFToCross = pFCand;
	pC = pCCand;
	qGotIt = true;
	break;
      }
    }
  }
  assert(spVNeigh.find(pV1) == spVNeigh.end());
  assert(pFToCross != pFInvalidFace);
  assert(pC != pCInvalidCell);
  if (pC->eType() != Cell::eTriCell) {
    // Needed to swap an edge that bounds a quad.
    return false;
  }

  // Walk from pV0 to pV1, listing all the edges that cross (pV0, pV1).
  // The walk should always succeed, hitting no vertices square on and
  // running into no boundaries.
  std::queue<Face*> qpFBadEdges;
  Face *pF = pFToCross;
  Vert *pV = pVInvalidVert;
  Vert *pVLeft, *pVRight;
  if (iOrient2D(pV0, pV1, pF->pVVert(0)) == 1) {
    pVLeft = pF->pVVert(0);
    pVRight = pF->pVVert(1);
  }
  else {
    pVLeft = pF->pVVert(1);
    pVRight = pF->pVVert(0);
  }
  assert(iOrient2D(pV0, pV1, pVLeft) == 1);
  assert(iOrient2D(pV1, pV0, pVRight) == 1);
  assert(iOrient2D(pVLeft, pVRight, pV1) == 1);
  assert(iOrient2D(pVRight, pVLeft, pV0) == 1);

  do {
    // Add the current to the list of those which need removing
    qpFBadEdges.push(pF);
    // Grab the next cell and vertex
    pC = pF->pCCellOpposite (pC);
    if (pC->eType () != Cell::eTriCell) {
      return false;
    }

    // This cast will succeed; all other cases just exited.
    TriCell* pTC = dynamic_cast<TriCell*>(pC);
    assert(pTC != NULL);
    pV = pTC->pVVertOpposite (pF);
    int iOrient = iOrient2D (pV, pV0, pV1);
    switch (iOrient) {
    case 1:
      pF = pTC->pFFaceOpposite (pVLeft);
      pVLeft = pV;
      break;			// end left side case

    case -1:
      pF = pTC->pFFaceOpposite (pVRight);
      pVRight = pV;
      break;			// end right side case

    default:
      // This assertion fails if a vert lies exactly on the segment
      // connecting pV0 and pV1.  This is an error in the existing
      // triangulation, or in the edge recovery request.
      assert2 (pV == pV1, "Ties should be impossible in forced edge swapping");
    }				// end switch

  }
  while (pV != pV1);		// end walk across mesh

  // Attempt to swap each edge in turn.  If the replacement would cross
  // the edge to be recovered, don't bother.  Also don't swap in convex
  // quad cases.  Eventually, the list of bad edges will be empty.
  while (!qpFBadEdges.empty()) {
    pF = qpFBadEdges.front();
    qpFBadEdges.pop();

    Cell *pCL = pF->pCCellLeft ();
    Cell *pCR = pF->pCCellRight ();
    // These assertions should be okay, even for mixed-element meshes,
    // because all pipes with quads in them should have returned before
    // this. 
    assert (pCL->eType () == Cell::eTriCell);
    assert (pCR->eType () == Cell::eTriCell);
    TriCell* pTCL = dynamic_cast<TriCell*>(pCL);
    assert(pTCL != NULL);
    TriCell* pTCR = dynamic_cast<TriCell*>(pCR);
    assert(pTCR != NULL);
    
    Vert *pVA = pF->pVVert (0);
    Vert *pVB = pF->pVVert (1);
    Vert *pVC = pTCL->pVVertOpposite (pF);
    Vert *pVD = pTCR->pVVertOpposite (pF);
    assert (iOrient2D (pVA, pVB, pVC) == 1);
    assert (iOrient2D (pVA, pVB, pVD) == -1);
    assert (pF->eType () == Face::eEdgeFace);
    if (iOrient2D (pVA, pVD, pVC) == 1 &&
	iOrient2D (pVB, pVC, pVD) == 1) {
      iReconfigure(pF);	// No swap recursion
      // If the new diagonal crosses the line connecting pV0 and pV1,
      // pF still needs to be forced out, but it needs a different
      // hull around it.  In this case, leave pF in the list and  go
      // on to the next edge.
      // This test passes if pVC or pVD is identical to pV0 or pV1, or
      // if pVC and pVD are on the same side of pV0-pV1.

      if (iOrient2D (pV0, pV1, pVC) * iOrient2D (pV0, pV1, pVD) == -1) {
	qpFBadEdges.push(pF);
      }
    }
    else {
      // Re-queue this one so that you can try it again when it's turn
      // comes up.
      qpFBadEdges.push(pF);
    }
  }
  if (qOldRecursion)
    vAllowSwapRecursion ();
  pFRet = pF;
  return true;
}

// bool Mesh2D::
// qRecoverEdge (Vert* const pV0, Vert* const pV1, Face*& pFRet)
//      // Force swaps of all edges that are crossed by the edge between
//      // the verts indicated by pV0 and pV1.
// {
//   assert (pV0->qValid ());
//   assert (pV1->qValid ());
//   bool qOldRecursion = qSwapRecursionAllowed ();
//   vDisallowSwapRecursion ();
//   pFRet = pFInvalidFace;

// //  vMessage(3, "Inside qRecoverEdge: %d, %d : (%f, %f) - (%f, %f)\n",
// //	   iV0, iV1, pV0->dX (), pV0->dY (), pV1->dX (), pV1->dY ());

//   // Find the cell across which to begin walking from pV0 to pV1.
//   Cell *pC;
//   Vert *pVLeft = pVInvalidVert;
//   Vert *pVRight = pVInvalidVert;
//   {
//     int iNBdryHits = 0;
//     Face *pF = pV0->pFHintFace ();
//     if (pF == pFInvalidFace) {
//       pF = pV0->pFSetHintFace (this);
//     }
//     assert (pF->qValid () && pF->qHasVert (pV0));
//     pC = pF->pCCellLeft ();
//     if ((pC->eType () == Cell:: eBdryEdge) ||
// 	(pC->eType () == Cell::eIntBdryEdge)) {
//       pC = pF->pCCellRight ();
//       iNBdryHits = 1;
//     }
//     if ((pF->pVVert(0) == pV0 && pF->pVVert(1) == pV1) ||
// 	(pF->pVVert(1) == pV0 && pF->pVVert(0) == pV1)) {
//       pFRet = pF;
//       return true;
//     }

//     if (pC->qHasVert(pV1)) {
//       // We know we're going to get a hit, so let's just find the face,
//       // which is known not to be the current pF.
//       for (int iF = 0; iF < pC->iNumFaces(); iF++) {
// 	Face *pFCand = pC->pFFace(iF);
// 	if (pFCand == pF) continue;
// 	if ((pFCand->pVVert(0) == pV0 && pFCand->pVVert(1) == pV1) ||
// 	    (pFCand->pVVert(1) == pV0 && pFCand->pVVert(0) == pV1)) {
// 	  pFRet = pFCand;
// 	  return true;
// 	}
//       }
//     }
      
//     // Set up pVPrev and pV to be the other two verts in this cell,
//     // along with pV0.
//     Vert *pV = pF->pVVert (0);
//     if (pV == pV0) {
//       pV = pF->pVVert (1);
//     }
//     Vert *pVPrev = pV;
//     TriCell * pTC = dynamic_cast<TriCell*>(pC);
//     assert(pTC != NULL);
//     pV = pTC->pVVertOpposite (pF);
//     assert(pV != pV1 && pVPrev != pV1);

//     // Walk around pV0 until either: you find an edge that connects to
//     // pV1; you find a cell containing the line towards pV1; or you hit
//     // a boundary.  If you hit a boundary, reverse directions and keep
//     // going.  The second time you hit a boundary, you've demonstrated
//     // that there's no plausible way to reach pV1 from pV0.  Even this
//     // brute force approach fails for multiply-connected regions.
//     while (iOrient2D (pV0, pVPrev, pV1) != -iOrient2D (pV0, pV, pV1)
// 	   ||
// 	   iOrient2D (pVPrev, pV, pV1) != -iOrient2D (pVPrev, pV, pV0)) {
//       pF = pC->pFFaceOpposite (pVPrev);
//       assert(pF->qHasVert(pV0) && pF->qHasVert(pV));
//       pC = pF->pCCellOpposite (pC);
//       if ((pC->eType () == Cell:: eBdryEdge) ||
// 	  (pC->eType () == Cell::eIntBdryEdge)) {
// 	pC = pF->pCCellOpposite (pC);
// 	iNBdryHits++;
// 	assert (iNBdryHits == 1);
//       }
//       pVPrev = pV;
//       pTC = dynamic_cast<TriCell*>(pC);
//       assert(pTC != NULL);
//       pV = pC->pVVertOpposite (pF);
//       if (pV == pV1) {
// 	pFRet = pC->pFFaceOpposite(pVPrev);
// 	return true;
//       }
//     }
//     int iFinalOrient = iOrient2D (pV0, pV1, pV);
//     if (iFinalOrient == 1) {
//       pVLeft = pV;
//       pVRight = pVPrev;
//     }
//     else if (iFinalOrient == -1) {
//       pVRight = pV;
//       pVLeft = pVPrev;
//     }
//     else {
//       assert2 (0, "Collinear point hit while recovering edges");
//     }
//   }

//   // Walk from pV0 to pV1, listing all the edges that cross (pV0, pV1).
//   // The walk should always succeed, hitting no vertices square on and
//   // running into no boundaries.
//   std::queue<Face*> qpFBadEdges;
//   Face *pF = pC->pFFaceOpposite (pV0);
//   Vert *pV = pVInvalidVert;
//   do {
//     // Add the current to the list of those which need removing
//     qpFBadEdges.push(pF);
//     // Grab the next cell and vertex
//     pC = pF->pCCellOpposite (pC);
//     // This assertion will fail if a boundary is hit.
//     assert (pC->eType () == Cell::eTriCell);
//     if (pC->eType () != Cell::eTriCell) {
//       return false;
//     }

//     TriCell* pTC = dynamic_cast<TriCell*>(pC);
//     assert(pTC != NULL);
//     pV = pC->pVVertOpposite (pF);
//     int iOrient = iOrient2D (pV, pV0, pV1);
//     switch (iOrient) {
//     case 1:
//       pF = pC->pFFaceOpposite (pVLeft);
//       pVLeft = pV;
//       break;			// end left side case

//     case -1:
//       pF = pC->pFFaceOpposite (pVRight);
//       pVRight = pV;
//       break;			// end right side case

//     default:
//       // This assertion fails if a vert lies exactly on the segment
//       // connecting pV0 and pV1.  This is an error in the existing
//       // triangulation.
//       assert2 (pV == pV1, "Ties should be impossible in forced edge swapping");
//     }				// end switch

//   }
//   while (pV != pV1);		// end walk across mesh

//   // Attempt to swap each edge in turn.  If the replacement would cross
//   // the edge to be recovered, don't bother.  Also don't swap in convex
//   // quad cases.  Eventually, the list of bad edges will be empty.
//   while (!qpFBadEdges.empty()) {
//     pF = qpFBadEdges.front();
//     qpFBadEdges.pop();

//     Cell *pCL = pF->pCCellLeft ();
//     Cell *pCR = pF->pCCellRight ();
//     // These assertions may turn out to be inappropriate for mixed meshes.
//     assert (pCL->eType () == Cell::eTriCell);
//     assert (pCR->eType () == Cell::eTriCell);
//     TriCell* pTCL = dynamic_cast<TriCell*>(pCL);
//     assert(pTCL != NULL);
//     TriCell* pTCR = dynamic_cast<TriCell*>(pCR);
//     assert(pTCR != NULL);
    
//     Vert *pVA = pF->pVVert (0);
//     Vert *pVB = pF->pVVert (1);
//     Vert *pVC = pTCL->pVVertOpposite (pF);
//     Vert *pVD = pTCR->pVVertOpposite (pF);
//     assert (iOrient2D (pVA, pVB, pVC) == 1);
//     assert (iOrient2D (pVA, pVB, pVD) == -1);
//     assert (pF->eType () == Face::eEdgeFace);
//     if (iOrient2D (pVA, pVD, pVC) == 1 &&
// 	iOrient2D (pVB, pVC, pVD) == 1) {
//       iReconfigure(pF);	// No swap recursion
//       // If the new diagonal crosses the line connecting pV0 and pV1,
//       // pF still needs to be forced out, but it needs a different
//       // hull around it.  In this case, leave pF in the list and  go
//       // on to the next edge.
//       // This test passes if pVC or pVD is identical to pV0 or pV1, or
//       // if pVC and pVD are on the same side of pV0-pV1.

//       if (iOrient2D (pV0, pV1, pVC) * iOrient2D (pV0, pV1, pVD) == -1) {
// 	qpFBadEdges.push(pF);
//       }
//     }
//     else {
//       // Re-queue this one so that you can try it again when it's turn
//       // comes up.
//       qpFBadEdges.push(pF);
//     }
//   }
//   if (qOldRecursion)
//     vAllowSwapRecursion ();
//   pFRet = pF;
//   return true;
// }
