/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPolyhedron.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkPolyhedron.h"

#include "vtkCellArray.h"
#include "vtkIdTypeArray.h"
#include "vtkDoubleArray.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkOrderedTriangulator.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkTetra.h"
#include "vtkTriangle.h"
#include "vtkQuad.h"
#include "vtkPolygon.h"
#include "vtkLine.h"
#include "vtkEdgeTable.h"
#include "vtkPolyData.h"
#include "vtkCellLocator.h"
#include "vtkGenericCell.h"
#include "vtkPointLocator.h"
#include "vtkMeanValueCoordinatesInterpolator.h"
#include "vtkSmartPointer.h"
#include "vtkMergePoints.h"
#include "vtkCellData.h"
#include "vtkDataArray.h"
#include "vtkType.h"

#include <map>
#include <vector>
#include <set>
#include <list>
#include <limits>

vtkStandardNewMacro(vtkPolyhedron);

// Special typedef
typedef std::vector<vtkIdType>                 vtkIdVectorType;
class vtkPointIdMap : public std::map<vtkIdType,vtkIdType>{};
class vtkIdToIdMapType : public std::map<vtkIdType, vtkIdType>{};
class vtkIdToIdVectorMapType : public std::map<vtkIdType, vtkIdVectorType>{};
typedef std::map<vtkIdType,vtkIdType*>::iterator PointIdMapIterator;
typedef vtkIdToIdVectorMapType::iterator          vtkIdToIdVectorMapIteratorType;
typedef std::pair<vtkIdType, vtkIdVectorType>  vtkIdToIdVectorPairType;
typedef std::pair<vtkIdType, vtkIdType>        vtkIdToIdPairType;
typedef std::set<vtkIdType>                    vtkIdSetType;

// Special class for iterating through polyhedron faces
//----------------------------------------------------------------------------
class vtkPolyhedronFaceIterator
{
public:
  vtkIdType CurrentPolygonSize;
  vtkIdType *Polygon;
  vtkIdType *Current;
  vtkIdType NumberOfPolygons;
  vtkIdType Id;

  vtkPolyhedronFaceIterator(vtkIdType numFaces, vtkIdType *t)
  {
      this->CurrentPolygonSize = t[0];
      this->Polygon = t;
      this->Current = t+1;
      this->NumberOfPolygons = numFaces;
      this->Id = 0;
  }
  vtkIdType* operator++()
  {
      this->Current += this->CurrentPolygonSize + 1;
      this->Polygon = this->Current - 1;
      this->Id++;
      if (this->Id < this->NumberOfPolygons)
      {
        this->CurrentPolygonSize = this->Polygon[0];
      }
      else
      {
        this->CurrentPolygonSize = VTK_ID_MAX;
      }
      return this->Current;
  }
};


// Special class for iterating through vertices on a polygon face
//----------------------------------------------------------------------------
class vtkPolygonVertexIterator
{
public:
  vtkIdType *Current;
  vtkIdType NumberOfVertices;
  vtkIdType Id;
  // 1 or 0 for iterating along its original direction or reverse
  vtkIdType IterDirection;

  vtkPolygonVertexIterator(vtkIdType numVertices, vtkIdType startVertex,
                           vtkIdType *startVertexPointer, vtkIdType nextVertex)
  {
    this->Current = startVertexPointer;
    this->NumberOfVertices = numVertices;
    this->Id = startVertex;
    this->IterDirection = 1;
    vtkIdType nextId = this->Id + 1;
    vtkIdType *next = this->Current + 1;
    if (nextId == this->NumberOfVertices)
    {
      next -= this->NumberOfVertices;
    }
    if (*next != nextVertex)
    {
      this->IterDirection = 0;
    }
  }

  vtkIdType* operator++()
  {
    if (this->IterDirection)
    {
      this->Id++;
      this->Current++;
      if (this->Id == this->NumberOfVertices)
      {
        this->Id = 0;
        this->Current -= this->NumberOfVertices;
      }
    }
    else
    {
      this->Id--;
      this->Current--;
      if (this->Id == -1)
      {
        this->Id = this->NumberOfVertices - 1;
        this->Current += this->NumberOfVertices;
      }
    }
    return this->Current;
  }
};

//----------------------------------------------------------------------------
class vtkPolyhedron::vtkInternal
{
public:
  vtkIdTypeArray * FacesBackup;
  vtkEdgeTable * EdgeTableBackup;

vtkInternal()
{
  this->FacesBackup = NULL;
  this->EdgeTableBackup = NULL;
}

~vtkInternal()
{
  this->FacesBackup = NULL;
  this->EdgeTableBackup = NULL;
}

//----------------------------------------------------------------------------
// Here we use a point merger to try to prevent the problem of duplicated
// points in the input.
void RemoveDuplicatedPointsFromFaceArrayAndEdgeTable(vtkPoints * points,
                                                     vtkIdTypeArray * & faces,
                                                     vtkEdgeTable * & edgeTable,
                                                     double *bounds)
{
  double coordTolerance = 0.000001; // initial value
  if (bounds)
  {
    // scale coordTolerance with length of the bounds diagonal if < 1.0
    double bbDiag = sqrt((bounds[1] - bounds[0])*(bounds[1] - bounds[0]) +
                         (bounds[3] - bounds[2])*(bounds[3] - bounds[2]) +
                         (bounds[5] - bounds[4])*(bounds[5] - bounds[4]));
    coordTolerance = std::min(coordTolerance, coordTolerance*bbDiag);
  }

  vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
  vtkSmartPointer<vtkPointLocator> merge = vtkSmartPointer<vtkPointLocator>::New();
  merge->SetTolerance(coordTolerance);
  merge->InitPointInsertion(newPoints, bounds);
  bool foundDupPoint = false;
  vtkIdType pid = -1;
  vtkIdToIdMapType pidMap0;
  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); i++)
  {
    if (!merge->InsertUniquePoint(points->GetPoint(i), pid))
    {
      foundDupPoint = true;
    }
    if (pidMap0.find(pid) == pidMap0.end())
    {
      pidMap0.insert(vtkIdToIdPairType(pid,i));
    }
  }

  // update face array and edge table if necessary.
  if (foundDupPoint)
  {
    vtkIdToIdMapType pidMap;
    for (vtkIdType i = 0; i < points->GetNumberOfPoints(); i++)
    {
      pid = merge->IsInsertedPoint(points->GetPoint(i));
      pidMap.insert(vtkIdToIdPairType(i, pidMap0.find(pid)->second));
    }

    this->FacesBackup = faces;
    this->EdgeTableBackup = edgeTable;

    vtkIdType nfaces = 0;
    vtkIdType insertId = 0;

    faces = vtkIdTypeArray::New();
    faces->SetNumberOfTuples(points->GetNumberOfPoints()*10);
    faces->InsertComponent(insertId++, 0, 0); // allocate space for nfaces
    edgeTable = vtkEdgeTable::New();
    edgeTable->InitEdgeInsertion(points->GetNumberOfPoints());

    vtkPolyhedronFaceIterator
      faceIter(this->FacesBackup->GetValue(0), this->FacesBackup->GetPointer(1));
    while (faceIter.Id < faceIter.NumberOfPolygons)
    {
      vtkIdVectorType vVector;
      for (vtkIdType i = 0; i < faceIter.CurrentPolygonSize; i++)
      {
        pid = pidMap.find(faceIter.Current[i])->second;
        vVector.push_back(pid);
      }
      bool dupPointRemoved = true;
      while (dupPointRemoved && vVector.size() > 2)
      {
        dupPointRemoved = false;
        if (vVector[0] == vVector[vVector.size()-1])
        {
          vVector.erase(vVector.begin()+vVector.size()-1);
          dupPointRemoved = true;
        }
        for (size_t i = 1; i < vVector.size(); i++)
        {
          if (vVector[i] == vVector[i-1])
          {
            vVector.erase(vVector.begin()+i);
            dupPointRemoved = true;
          }
        }
      }
      if (vVector.size() < 3)
      {
        ++faceIter;
        continue;
      }

      nfaces++;

      faces->InsertComponent(insertId++, 0, vVector.size());
      for (size_t i = 0; i < vVector.size(); i++)
      {
        faces->InsertComponent(insertId++, 0, vVector[i]);
      }
      if (edgeTable->IsEdge(vVector[0],vVector[vVector.size()-1]) == (-1))
      {
        edgeTable->InsertEdge(vVector[0],vVector[vVector.size()-1]);
      }
      for (size_t i = 1; i < vVector.size(); i++)
      {
        if (edgeTable->IsEdge(vVector[i],vVector[i-1]) == (-1))
        {
          edgeTable->InsertEdge(vVector[i],vVector[i-1]);
        }
      }

      ++faceIter;
    }

    faces->SetComponent(0,0,nfaces);
  }
  else
  {
    this->FacesBackup = NULL;
    this->EdgeTableBackup = NULL;
  }
}

//----------------------------------------------------------------------------
// Here we use a point merger to try to prevent the problem of duplicated
// points in the input.
void RestoreFaceArrayAndEdgeTable(vtkIdTypeArray * & faces,
                                  vtkEdgeTable * & edgeTable)
{
  if (this->FacesBackup)
  {
    faces->Delete();
    faces = this->FacesBackup;
  }
  if (this->EdgeTableBackup)
  {
    edgeTable->Delete();
    edgeTable = this->EdgeTableBackup;
  }
}

//----------------------------------------------------------------------------
// insert new id element in between two existing adjacent id elements.
// this is a convenient function. no check whether the input elements
// exist in the vector. no check for element adjacency.
int InsertNewIdToIdVector(vtkIdVectorType & idVector, vtkIdType id,
                          vtkIdType id0, vtkIdType id1)
{
  if (idVector.size() < 2)
  {
    return 0;
  }

  size_t num = idVector.size();
  if ((idVector[0] == id0 && idVector[num-1] == id1)
    ||(idVector[0] == id1 && idVector[num-1] == id0))
  {
    idVector.push_back(id);
    return 1;
  }

  vtkIdVectorType::iterator iter = idVector.begin();
  for (; iter != idVector.end(); ++iter)
  {
    if (*iter == id0 || *iter == id1)
    {
      ++iter;
      idVector.insert(iter, id);
      return 1;
    }
  }

  return 0;
};

// Convinient function used by clip. The id is the vector index of the positive
// point, id0 is the vector index of the start point, and id1 is the vector index
// of the end point.
//----------------------------------------------------------------------------
int EraseSegmentFromIdVector(vtkIdVectorType & idVector, vtkIdType id,
                             vtkIdType id0, vtkIdType id1)
{
  // three possible cases
  // first case: 0 -- id0 -- id -- id1 -- size-1
  if (id0 < id && id < id1)
  {
    idVector.erase(idVector.begin() + id0 + 1, idVector.begin() + id1);
  }
  // second case: 0 -- id1 -- id0 -- id -- size-1
  // third case: 0 -- id -- id1 -- id0 -- size-1
  else if (id1 < id0 && (id0 < id || id < id1))
  {
    idVector.erase(idVector.begin() + id0 + 1, idVector.end());
    idVector.erase(idVector.begin(), idVector.begin() + id1);
  }
  else
  {
    // we should never get here.
    return 0;
  }
  return 1;
};

// convert the point ids from map.first to map.second
//----------------------------------------------------------------------------
int ConvertPointIds(vtkIdType npts, vtkIdType * pts,
                    vtkIdToIdMapType & map, vtkIdType reverse = 0)
{
  for (vtkIdType i = 0; i < npts; i++)
  {
    vtkIdType id = reverse ? npts-1-i : i;
    vtkIdToIdMapType::iterator iter = map.find(pts[id]);
    if (iter == map.end())
    {
      return 0;
    }
    pts[id] = iter->second;
  }
  return 1;
};

//----------------------------------------------------------------------------
// The connected contour points are found by (1) locating the current
// contour point in the face loop, (2) looping through face point:
//  meet a positive point, keep going.
//  meet a contour point, store it and stop marching in this direction.
//  meet a negative point, stop marching in this direction.
//  meet the same point from both directions, stop.
// This loop may find zero, one or two connected contour points.
void FindConnectedContourPointsOnFace(vtkIdVectorType & facePtsVector,
                                      vtkIdVectorType & faceContourPtsVec,
                                      vtkIdType currContourPoint,
                                      vtkIdVectorType & pointLabelVec,
                                      vtkIdSetType & connectedContourPtsSet,
                                      vtkIdSetType & unConnectedContourPtsSet)
{
  vtkIdType numFacePoints = static_cast<vtkIdType>(facePtsVector.size());
  if (numFacePoints < 3)
  {
    return;
  }
  if (faceContourPtsVec.size() < 2)
  {
    return;
  }
  // locate the id of the startContourPt inside the face loop
  vtkIdType startPt = -1;
  for (vtkIdType i = 0; i < numFacePoints; i++)
  {
    if (currContourPoint == facePtsVector[i])
    {
      startPt = i;
      break;
    }
  }

  if (startPt < 0 || startPt >= numFacePoints)
  {
    return;
  }

  vtkIdType leftEndPt = -1; // face loop index
  vtkIdType rightEndPt = -1; // face loop index
  vtkIdType leftEndPoint = -1; // point id
  vtkIdType rightEndPoint = -1; // point id
  vtkIdType leftEndPassPositivePoint = 0;
  vtkIdType rightEndPassPositivePoint = 0;
  // search in one direction.
  vtkIdType endPt = startPt - 1;
  for (; endPt != startPt; endPt--)
  {
    if (endPt < 0)
    {
      endPt = numFacePoints - 1;
      if (endPt == startPt)
      {
        break;
      }
    }
    if (pointLabelVec[facePtsVector[endPt]] == -1)//negative point reached. stop
    {
      break;
    }
    else if (pointLabelVec[facePtsVector[endPt]] == 0)//contour pt reached. stop
    {
      leftEndPt = endPt;
      leftEndPoint = facePtsVector[endPt];
      break;
    }
    else
    {
      leftEndPassPositivePoint = 1;
    }
    // positive pt reached. continue.
  }

  // check if already loop through the entire face
  if (endPt != startPt)
  {
    vtkIdType prevEndPt = endPt;

    // search in the other direction
    for (endPt = startPt + 1; endPt != prevEndPt; endPt++)
    {
      if (endPt > numFacePoints - 1)
      {
        endPt = 0;
        if (endPt == prevEndPt)
        {
          break;
        }
        if (endPt == startPt)
        {
          break;
        }
      }
      if (pointLabelVec[facePtsVector[endPt]] == -1)//negative point reached. stop
      {
        break;
      }
      else if (pointLabelVec[facePtsVector[endPt]] == 0)//contour pt reached. stop
      {
        rightEndPt = endPt;
        rightEndPoint = facePtsVector[endPt];
        break;
      }
      else
      {
        rightEndPassPositivePoint = 1;
      }
    }
  }

  // need to check a special case where startPt, leftEndPoint and rightEndPoint
  // are directly connected or connected by a series of other contour points,
  // and startPt is at one end of the contour strip. We can check this situation
  // using leftEndPassPositivePoint and leftEndPassPositivePoint. If both are
  // 1, then the three points are not on a contour strip. If both are 0, then
  // startPt is not at one end of the contour strip.
  if (leftEndPoint >= 0 && rightEndPoint >=0 && leftEndPoint != rightEndPoint)
  {
    if (leftEndPassPositivePoint != rightEndPassPositivePoint)
    {
      bool foundNonContourPoint = false;
      for (endPt = leftEndPt - 1; endPt != rightEndPt; endPt--)
      {
        if (endPt < 0)
        {
          endPt = numFacePoints - 1;
          if (endPt == rightEndPt)
          {
            break;
          }
        }
        if (pointLabelVec[facePtsVector[endPt]] != 0)
        {
          foundNonContourPoint = true;
          break;
        }
      }
      if (!foundNonContourPoint)// startPt on one end of the contour strip
      {
        if (leftEndPassPositivePoint)
        {
          leftEndPoint = -1;
        }
        else
        {
          rightEndPoint = -1;
        }
      }
    }
  }

  if (leftEndPoint >= 0)
  {
    connectedContourPtsSet.insert(leftEndPoint);
  }
  if (rightEndPoint >= 0)
  {
    connectedContourPtsSet.insert(rightEndPoint);
  }
  for (size_t i = 0; i < faceContourPtsVec.size(); i++)
  {
    if (faceContourPtsVec[i] != leftEndPoint &&
        faceContourPtsVec[i] != rightEndPoint &&
        faceContourPtsVec[i] != currContourPoint)
    {
      unConnectedContourPtsSet.insert(faceContourPtsVec[i]);
    }
  }
};

//----------------------------------------------------------------------------
void RemoveIdFromIdToIdVectorMap(vtkIdToIdVectorMapType & map, vtkIdType id)
{
  vtkIdToIdVectorMapIteratorType mit = map.begin();
  for (; mit != map.end(); ++mit)
  {
    vtkIdVectorType::iterator vit = mit->second.begin();
    for (; vit != mit->second.end(); ++vit)
    {
      if ((*vit) == id)
      {
        mit->second.erase(vit);
        break;
      }
    }
  }
};

//----------------------------------------------------------------------------
// For each contour point, extract its adjacent faces, then extract other
// contour points on the same face that can be connected to the current
// points.
// The connected contour points are found by (1) locating the current
// contour point in the face loop, (2) looping through face point:
//  meet a positive point, keep going.
//  meet a contour point, store it and stop marching in this direction.
//  meet a negative point, stop marching in this direction.
//  meet the same point from both directions, stop.
// This loop may find zero, one or two connected contour points.
int  ExtractContourConnectivities(
                 vtkIdToIdVectorMapType & ceMap,
                 vtkIdSetType & cpSet,
                 vtkIdVectorType & pointLabelVector,
                 vtkIdToIdVectorMapType & pointToFacesMap,
                 vtkIdToIdVectorMapType & faceToPointsMap,
                 vtkIdToIdVectorMapType & faceToContourPointsMap)
{
  int maxConnectivity = 0;
  if (cpSet.empty())
  {
    return 0;
  }

  vtkIdSetType contourBranchesSet;
  vtkIdSetType nonContourBranchesSet;
  vtkIdVectorType contourBranchesVector;
  vtkIdSetType::iterator cpSetIt;
  vtkIdToIdVectorMapType::iterator fcpMapIt, fvMapIt, ceMapIt, ceMapIt1;
  for (cpSetIt = cpSet.begin(); cpSetIt != cpSet.end(); /*manual increment*/)
  {
    contourBranchesSet.clear();
    nonContourBranchesSet.clear();
    contourBranchesVector.clear();
    vtkIdType pid = *cpSetIt;
    vtkIdVectorType fVector = pointToFacesMap.find(pid)->second;
    for (size_t i = 0; i < fVector.size(); i++)
    {
      // find adjacent faces that contain contour points
      fcpMapIt = faceToContourPointsMap.find(fVector[i]);
      if (fcpMapIt == faceToContourPointsMap.end())
      {
        continue;
      }
      fvMapIt = faceToPointsMap.find(fVector[i]);
      if (fvMapIt == faceToPointsMap.end())
      {
        cout << "Cannot find point ids of a face. We should never get "
          "here. Contouring aborted." << endl;
        return 0;
      }


      // find connected contour points and store them in the set. Notice that
      // some weird topology will classify a point as a connected contour point
      // in one face and a non-connected contour point in some other face. we
      // will extract the union.
      FindConnectedContourPointsOnFace(
                  fvMapIt->second, fcpMapIt->second, pid,
                  pointLabelVector, contourBranchesSet, nonContourBranchesSet);
    }

    if (!contourBranchesSet.empty())
    {
      vtkIdSetType::iterator ccpSetIt = contourBranchesSet.begin();
      for (; ccpSetIt != contourBranchesSet.end(); ++ccpSetIt)
      {
        if (nonContourBranchesSet.find(*ccpSetIt) == nonContourBranchesSet.end())
        {
          contourBranchesVector.push_back(*ccpSetIt);
        }
      }
    }

    if (contourBranchesVector.size() >= 2)
    {
      ceMap.insert(
        vtkIdToIdVectorPairType(pid, contourBranchesVector));
      ++cpSetIt;
    }
    else // throw away point contour or edge contour.
    {
      if (cpSetIt != cpSet.begin())
      {
        vtkIdSetType::iterator tempIt = cpSetIt;
        --cpSetIt;
        cpSet.erase(tempIt);
        ++cpSetIt;
      }
      else
      {
        cpSet.erase(cpSetIt);
        cpSetIt = cpSet.begin();
      }
    }
  }

  // sanity check, all edges should be listed twice
  for (ceMapIt = ceMap.begin(); ceMapIt != ceMap.end(); ++ceMapIt)
  {
    vtkIdVectorType edges = ceMapIt->second;
    for (size_t i = 0; i < edges.size(); i++)
    {
      bool foundMatch = false;
      ceMapIt1 = ceMap.find(edges[i]);
      if (ceMapIt1 != ceMap.end())
      {
        for (size_t j = 0; j < ceMapIt1->second.size(); j++)
        {
          if (ceMapIt->first == ceMapIt1->second[j])
          {
            foundMatch = true;
            break;
          }
        }
      }
      if (!foundMatch)
      {
        edges.erase(edges.begin()+i);
        i--;
      }
    }
    ceMapIt->second = edges;
  }

  // clean 0 or 1-connected contour from ceMap
  for (ceMapIt = ceMap.begin(); ceMapIt != ceMap.end(); /*manual increment*/)
  {
    if (ceMapIt->second.size() >= 2)
    {
      ++ceMapIt;
      continue;
    }

    cpSetIt = cpSet.find(ceMapIt->first);
    if (cpSetIt != cpSet.end())
    {
      cpSet.erase(cpSetIt);
    }

    if (ceMapIt != ceMap.begin())
    {
      vtkIdToIdVectorMapType::iterator tempIt = ceMapIt;
      --ceMapIt;
      ceMap.erase(tempIt);
      ++ceMapIt;
    }
    else
    {
      ceMap.erase(ceMapIt);
      ceMapIt = ceMap.begin();
    }
  }

  // set maxConnectivity.
  for (ceMapIt = ceMap.begin(); ceMapIt != ceMap.end(); ++ceMapIt)
  {
    if (static_cast<int>(ceMapIt->second.size()) > maxConnectivity)
    {
      maxConnectivity = static_cast<int>(ceMapIt->second.size());
    }
  }

  return maxConnectivity;
};

//----------------------------------------------------------------------------
// Use eigenvalues to determine the dimension of the input contour points.
// This chunk of code is mostly copied from vtkOBBTree::ComputeOBB()
// Function returns 0 if input is a single point, 1 if co-linear,
// 2 if co-planar, 3 if 3D. It also returns the center as well as the normal
// (the eigenvector with the smallest eigenvalue) of the input contour pointset.
static int CheckContourDimensions(vtkPoints* points, vtkIdType npts,
                                  const vtkIdType * ptIds,
                                  double * normal, double * center)
{
  static const double eigenvalueRatioThresh = 1e-12; // was 0.001, but 1e-12 seems better: https://gitlab.kitware.com/paraview/paraview/issues/13490
  if (npts < 3)
  {
    // Defensively return zeros here for normal and center.
    if (normal)
    {
      normal[0] = 0.0;
      normal[1] = 0.0;
      normal[2] = 0.0;
    }
    if (center)
    {
      center[0] = 0.0;
      center[1] = 0.0;
      center[2] = 0.0;
    }
    return npts - 1;
  }

  vtkIdType i, j;
  double x[3], mean[3], xp[3], *v[3], v0[3], v1[3], v2[3];
  double *a[3], a0[3], a1[3], a2[3], eigValue[3];

  // Compute mean
  mean[0] = mean[1] = mean[2] = 0.0;
  for (i=0; i < npts; i++ )
  {
    points->GetPoint(ptIds[i], x);
    mean[0] += x[0];
    mean[1] += x[1];
    mean[2] += x[2];
  }
  for (i=0; i < 3; i++)
  {
    mean[i] /= npts;
  }

  // Compute covariance matrix
  a[0] = a0; a[1] = a1; a[2] = a2;
  for (i=0; i < 3; i++)
  {
    a0[i] = a1[i] = a2[i] = 0.0;
  }

  for (j = 0; j < npts; j++ )
  {
    points->GetPoint(ptIds[j], x);
    xp[0] = x[0] - mean[0]; xp[1] = x[1] - mean[1]; xp[2] = x[2] - mean[2];
    for (i = 0; i < 3; i++)
    {
      a0[i] += xp[0] * xp[i];
      a1[i] += xp[1] * xp[i];
      a2[i] += xp[2] * xp[i];
    }
  }//for all points

  for (i=0; i < 3; i++)
  {
    a0[i] /= npts;
    a1[i] /= npts;
    a2[i] /= npts;
  }

  // Extract axes (i.e., eigenvectors) from covariance matrix.
  v[0] = v0; v[1] = v1; v[2] = v2;
  vtkMath::Jacobi(a,eigValue,v);

  int ret = 3;

  if ((eigValue[2] / eigValue[0]) < eigenvalueRatioThresh)
  {
    ret--;
  }
  if ((eigValue[1] / eigValue[0]) < eigenvalueRatioThresh)
  {
    ret--;
  }

  if (normal)
  {
    for (i =0; i < 3; i++)
    {
      double norm = vtkMath::Norm(a[i], 3);
      if (norm > 0.000001)
      {
        break;
      }
    }
    if (i < 3)
    {
      normal[0] = v2[0];
      normal[1] = v2[1];
      normal[2] = v2[2];
    }
    else
    {
      points->GetPoint(ptIds[0], v0);
      points->GetPoint(ptIds[1], v1);
      v0[0] = v0[0] - mean[0];
      v0[1] = v0[1] - mean[1];
      v0[2] = v0[2] - mean[2];
      v1[0] = v1[0] - mean[0];
      v1[1] = v1[1] - mean[1];
      v1[2] = v1[2] - mean[2];
      vtkMath::Normalize(v0);
      vtkMath::Normalize(v1);
      vtkMath::Cross(v0, v1, normal);
      vtkMath::Normalize(normal);
    }
  }
  if (center)
  {
    center[0] = mean[0];
    center[1] = mean[1];
    center[2] = mean[2];
  }

  return ret;
};

//----------------------------------------------------------------------------
// For each contour point, compute the normal (pointing to the positive side),
// then sort the other contour points connected to it, such that the connecting
// edges are ordered contour-clockwise when viewed from the normal direction.

// Input ceMap shows that a contour point (map->first) is connected to a number
// of other contour points (map->second). It does not distinguish boundary
// edges from internal edges. The following function also update ceMap such that
// a boundary edge a-->b (assuming traversing from the counter-clockwise
// direction) is only stored once ({a, [b, ...]}). an internal edge a<-->b is
// stored twice ({a, [b, ...] and {b, [a, ...]}}.

// Current implementation of this function assumes planar contours, we only
// compute normal once and reuse it for all other contour points.
// TODO: for non-planar cut, need to compute normal for each contour point. We
// then project edges onto a tangent plane and sort them.
static void OrderMultiConnectedContourPoints(vtkIdToIdVectorMapType & cpMap,
                                             vtkIdToIdVectorMapType & cpBackupMap,
                                             vtkIdSetType & cpSet,
                                             vtkPoints * points)
{
  double p[3], x0[3], x1[3], e0[3], e1[3], nn[3];
  vtkIdSetType::iterator setIt;
  vtkIdVectorType pids;
  for (setIt = cpSet.begin(); setIt != cpSet.end(); ++setIt)
  {
    pids.push_back(*setIt);
  }

  // return if the input contour points are 1D. Note: the function also
  // computes normal n and center o.
  double o[3], n[3];
  if (CheckContourDimensions(
        points, static_cast<vtkIdType>(pids.size()), &(pids[0]), n, o) < 2)
  {
    return;
  }
  vtkMath::Normalize(n);

  // locate an extreme point in a direction normal to the normal. this
  // extreme point is a convex vertex.
  vtkIdToIdVectorMapType::iterator mapIt = cpMap.begin();
  points->GetPoint(mapIt->first, p);
  e0[0] = p[0] - o[0];
  e0[1] = p[1] - o[1];
  e0[2] = p[2] - o[2];
  vtkMath::Normalize(e0);
  vtkMath::Cross(e0, n, nn);
  vtkMath::Normalize(nn);

  double maxDistance = VTK_DOUBLE_MIN;
  vtkIdType maxPid = -1;
  for (; mapIt != cpMap.end(); ++mapIt)
  {
    points->GetPoint(mapIt->first, p);
    e0[0] = p[0] - o[0];
    e0[1] = p[1] - o[1];
    e0[2] = p[2] - o[2];
    double distance = vtkMath::Dot(nn, e0);
    if (distance > maxDistance)
    {
      maxDistance = distance;
      maxPid = mapIt->first;
    }
  }

  // Order edges of the contour point contour-clockwise. Note that a boundary
  // point has two boundary edges. We will remove the incoming boundary edge
  // and store the outgoing boundary edge at the end (after all internal edges).
  // incoming and outgoing boudnary edges are defined when they are traversed
  // counter-clockwisely.
  std::vector<double> extremePointAngles; // record the angles of extreme point
  vtkIdVectorType edges;
  size_t edgesSize = 0;
  const double angleTolerance = 0.0000001;
  for (mapIt = cpMap.begin(); mapIt != cpMap.end(); ++mapIt)
  {
    edges = mapIt->second;
    edgesSize = edges.size();

    // If the contour point is 2-connected we don't need to order them.
    if (edgesSize >=3 || mapIt->first == maxPid)
    {
      // get the current first edge
      points->GetPoint(mapIt->first, p);
      points->GetPoint(edges[0], x0);
      e0[0] = x0[0] - p[0];
      e0[1] = x0[1] - p[1];
      e0[2] = x0[2] - p[2];
      vtkMath::Normalize(e0);
      vtkMath::Cross(e0, n, x0);
      vtkMath::Cross(n, x0, e0);
      vtkMath::Normalize(e0);

      // compute the angles from other edges to the first edge
      std::vector<double> angles;
      angles.push_back(0);
      const double maxDotProduct = 0.95;
      for (size_t i = 1; i < edgesSize; i++)
      {
        points->GetPoint(edges[i], x1);
        e1[0] = x1[0] - p[0];
        e1[1] = x1[1] - p[1];
        e1[2] = x1[2] - p[2];
        vtkMath::Normalize(e1);
        vtkMath::Cross(e1, n, x1);
        vtkMath::Cross(n, x1, e1);
        vtkMath::Normalize(e1);
        double dotproduct = vtkMath::Dot(e0, e1);
        double angle = acos(dotproduct);
        if (dotproduct < maxDotProduct && dotproduct > -maxDotProduct)
        {
          vtkMath::Cross(e0, e1, nn);
          if (vtkMath::Dot(n, nn) < 0)
          {
            angle = 2.0*vtkMath::Pi() - angle;
          }
        }
        else if (dotproduct > maxDotProduct)
        {
          vtkMath::Cross(e0, n, nn);
          angle = acos(vtkMath::Dot(nn, e1)) - vtkMath::Pi()/2.0;
        }
        else if (dotproduct < -maxDotProduct)
        {
          vtkMath::Cross(n, e0, nn);
          angle = acos(vtkMath::Dot(nn, e1)) + vtkMath::Pi()/2.0;
        }
        if (angle < -angleTolerance)
        {
          angle += 2.0*vtkMath::Pi();
        }
        if (angle > 2.0*vtkMath::Pi()+angleTolerance)
        {
          angle -= 2.0*vtkMath::Pi();
        }
        angles.push_back(angle);
      }

      // sort edges
      for (size_t i = 1; i < edgesSize-1; i++)
      {
        for (size_t j = i+1; j < edgesSize; j++)
        {
          if (angles[i] > angles[j])
          {
            vtkIdType temp = edges[i];
            edges[i] = edges[j];
            edges[j] = temp;
            double angle = angles[i];
            angles[i] = angles[j];
            angles[j] = angle;
          }
        }
      }

      mapIt->second = edges;

      if (mapIt->first == maxPid)
      {
        extremePointAngles = angles;
      }
    }
  }

  // store the sorted map.
  cpBackupMap = cpMap;

  // find the incoming and outgoing boundary edges of the extreme point. we use
  // the observation: if the outgoing boundary edge is chosen as the reference
  // edge. the angle between all other edges and the outgoing boundary edges
  // will be in [0, pi]. the incoming boundary edge will be the one that is
  // previous to the outgoing boundary edge.
  mapIt = cpMap.find(maxPid);
  edges = mapIt->second;
  edgesSize = edges.size();
  if (extremePointAngles.size() != edgesSize)
  {
    cout << "The size of the edge array does not match the size of the "
      "angle array. We should never get here." << endl;
    return;
  }
  vtkIdType outBoundary = -1;
  vtkIdType inBoundary = -1;
  for (size_t i = 0; i < edgesSize; i++)
  {
    double angle0 = extremePointAngles[i];
    size_t j = 0;
    for (; j < edgesSize; j++)
    {
      double angle = extremePointAngles[j] - angle0;
      if (angle < 0)
      {
        angle = angle + 2.0*vtkMath::Pi();
      }
      if (angle > vtkMath::Pi())
      {
        break;
      }
    }
    if (j == edgesSize)
    {
      outBoundary = static_cast<vtkIdType>(i);
      inBoundary = outBoundary - 1 < 0 ?
                     static_cast<vtkIdType>(edgesSize) - 1 : outBoundary - 1;
      break;
    }
  }

  vtkIdType prevPid = maxPid;
  vtkIdType currPid = edges[outBoundary];

  // remove incoming boundary edge.
  edges.erase(edges.begin() + inBoundary);
  cpMap.find(maxPid)->second = edges;

  // traverse the contour graph to remove all incoming boundary edges.
  while (currPid != maxPid)
  {
    edges = cpMap.find(currPid)->second;
    edgesSize = edges.size();
    size_t i;
    bool foundPrevPid = false;
    for (i = 0; i < edgesSize; i++)
    {
      if (edges[i] == prevPid)
      {
        inBoundary = static_cast<vtkIdType>(i);
        outBoundary = inBoundary + 1 >= static_cast<vtkIdType>(edgesSize) ?
                        0 : inBoundary + 1;
        foundPrevPid = true;
        break;
      }
    }
    if (!foundPrevPid) // traversing failed.
    {
      return;
    }
    prevPid = currPid;
    currPid = edges[outBoundary];
    edges.erase(edges.begin() + inBoundary);
    cpMap.find(prevPid)->second = edges;
  }
};

//-----------------------------------------------------------------------------
void OrderTwoConnectedContourPoints(vtkIdToIdVectorMapType & cpMap,
                                   vtkIdToIdVectorMapType & cpBackupMap)
{
  // backup the map.
  cpBackupMap = cpMap;

  // traverse edges
  vtkIdToIdVectorMapType::iterator mapIt = cpMap.begin();
  vtkIdVectorType edges = mapIt->second;
  vtkIdType startPid = mapIt->first;

  // choose one as incoming edge and one as outgoing edge
  vtkIdType outBoundary = 0;
  vtkIdType inBoundary = 1;

  // find next point
  vtkIdType prevPid = mapIt->first;
  vtkIdType currPid = edges[outBoundary];

  // remove incoming boundary edge.
  edges.erase(edges.begin() + inBoundary);
  cpMap.find(startPid)->second = edges;

  // traverse the edge graph to remove all incoming boundary edges.
  while (currPid != startPid)
  {
    mapIt = cpMap.find(currPid);
    if (mapIt == cpMap.end())
    {
      cout << "Find an unexpected case. The input polyhedron cell may not be a "
        << "water tight or the polygonal faces may not be planar. Contouring "
        << "will continue, but this cell may not be processed correctly." << endl;
      break;
    }
    edges = mapIt->second;
    if (edges[0] == prevPid)
    {
      inBoundary = 0;
      outBoundary = 1;
    }
    else
    {
      inBoundary = 1;
      outBoundary = 0;
    }
    prevPid = currPid;
    currPid = edges[outBoundary];
    edges.erase(edges.begin() + inBoundary);
    cpMap.find(prevPid)->second = edges;
  }
};

//----------------------------------------------------------------------------
// This function is called when InternalContour() finds an unexpected case
// (typically caused by a non-watertight cell). In this case, we will ignore
// the existing edges between contours. Instead, simply order them as a polygon
// around the center point.
static int OrderDisconnectedContourPoints(vtkIdSetType & cpSet,
                                          vtkPoints * points,
                                          vtkIdVectorType & pointLabelVector,
                                          vtkIdVectorType & polygon)
{
  polygon.clear();
  if (cpSet.empty())
  {
    return 0;
  }

  double x[3], e0[3], e[3], nn[3];
  vtkIdSetType::iterator setIt;
  for (setIt = cpSet.begin(); setIt != cpSet.end(); ++setIt)
  {
    polygon.push_back(*setIt);
  }

  // return if the input contour points are 1D. Note: the function also
  // computes normal n and center o.
  double o[3], n[3];
  if (CheckContourDimensions(
        points, static_cast<vtkIdType>(polygon.size()), &(polygon[0]), n, o) < 2)
  {
    return 0;
  }

  // make sure normal n points to the positive side
  vtkIdType numPoints = static_cast<vtkIdType>(pointLabelVector.size());
  for (vtkIdType i = 0; i < numPoints; i++)
  {
    if (pointLabelVector[i] == 1)
    {
      points->GetPoint(i, x);
      e[0] = x[0] - o[0];
      e[1] = x[1] - o[1];
      e[2] = x[2] - o[2];
      if (vtkMath::Dot(e, n) < 0)
      {
        n[0] = -n[0];
        n[1] = -n[1];
        n[2] = -n[2];
      }
      break;
    }
    else if (pointLabelVector[i] == -1)
    {
      points->GetPoint(i, x);
      e[0] = x[0] - o[0];
      e[1] = x[1] - o[1];
      e[2] = x[2] - o[2];
      if (vtkMath::Dot(e, n) > 0)
      {
        n[0] = -n[0];
        n[1] = -n[1];
        n[2] = -n[2];
      }
      break;
    }
  }

  // now loop over contour points to order them.
  std::vector<double> angles;
  angles.push_back(0.0);

  // choose to start from the first point
  points->GetPoint(polygon[0], x);
  e0[0] = x[0] - o[0];
  e0[1] = x[1] - o[1];
  e0[2] = x[2] - o[2];
  vtkMath::Cross(e0, n, nn);
  vtkMath::Cross(n, nn, e0);
  vtkMath::Normalize(e0);

  // compute the angles from other edges to the first edge
  for (size_t i = 1; i < polygon.size(); i++)
  {
    points->GetPoint(polygon[i], x);
    e[0] = x[0] - o[0];
    e[1] = x[1] - o[1];
    e[2] = x[2] - o[2];
    vtkMath::Cross(e, n, nn);
    vtkMath::Cross(n, nn, e);
    vtkMath::Normalize(e);

    const double maxDotProduct = 0.95;
    double dotproduct = vtkMath::Dot(e0, e);
    double angle = acos(dotproduct);
    if (dotproduct < maxDotProduct && dotproduct > -maxDotProduct)
    {
      vtkMath::Cross(e0, e, nn);
      if (vtkMath::Dot(n, nn) < 0)
      {
        angle += vtkMath::Pi();
      }
    }
    else if (dotproduct > maxDotProduct)
    {
      vtkMath::Cross(e0, n, nn);
      angle = acos(vtkMath::Dot(nn, e)) - vtkMath::Pi()/2.0;
    }
    else
    {
      vtkMath::Cross(n, e0, nn);
      angle = acos(vtkMath::Dot(nn, e)) + vtkMath::Pi()/2.0;
    }
    angles.push_back(angle);
  }

  // sort contour points
  for (size_t i = 1; i < polygon.size(); i++)
  {
    for (size_t j = i+1; j < polygon.size(); j++)
    {
      if (angles[i] > angles[j])
      {
        vtkIdType temp = polygon[i];
        polygon[i] = polygon[j];
        polygon[j] = temp;
        double angle = angles[i];
        angles[i] = angles[j];
        angles[j] = angle;
      }
    }
  }

  return 1;
}

//----------------------------------------------------------------------------
// Note: the triangulation results are inserted into the input cellArray, which
// does not need to be empty.
void Triangulate3DContour(vtkIdType npts, vtkIdType * pts,
                          vtkCellArray *cellArray)
{
  vtkIdType start = 0;
  vtkIdType end = npts-1;
  vtkIdType ids[3];

  while (start < end)
  {
    ids[0] = pts[start++];
    ids[1] = pts[start];
    ids[2] = pts[end];
    cellArray->InsertNextCell(3, ids);

    if (start >= end - 1)
    {
      return;
    }

    ids[0] = pts[end];
    ids[1] = pts[start];
    ids[2] = pts[--end];
    cellArray->InsertNextCell(3, ids);
  }
};

}; //end vtkInternal class


//----------------------------------------------------------------------------
// Construct the hexahedron with eight points.
vtkPolyhedron::vtkPolyhedron()
{
  this->Line = vtkLine::New();
  this->Triangle = vtkTriangle::New();
  this->Quad = vtkQuad::New();
  this->Polygon = vtkPolygon::New();
  this->Tetra = vtkTetra::New();
  this->GlobalFaces = vtkIdTypeArray::New();
  this->FaceLocations = vtkIdTypeArray::New();
  this->PointIdMap = new vtkPointIdMap;

  this->EdgesGenerated = 0;
  this->EdgeTable = vtkEdgeTable::New();
  this->Edges = vtkIdTypeArray::New();
  this->Edges->SetNumberOfComponents(2);
  this->EdgeFaces = vtkIdTypeArray::New();
  this->EdgeFaces->SetNumberOfComponents(2);

  this->FacesGenerated = 0;
  this->Faces = vtkIdTypeArray::New();

  this->BoundsComputed = 0;

  this->PolyDataConstructed = 0;
  this->PolyData = vtkPolyData::New();
  this->Polys = vtkCellArray::New();
  //this->Polys->Register(this);
  //this->Polys->Delete();
  this->PolyConnectivity = vtkIdTypeArray::New();
  this->LocatorConstructed = 0;
  this->CellLocator = vtkCellLocator::New();
  this->CellIds = vtkIdList::New();
  this->Cell = vtkGenericCell::New();

  this->Internal = new vtkInternal();
}

//----------------------------------------------------------------------------
vtkPolyhedron::~vtkPolyhedron()
{
  this->Line->Delete();
  this->Triangle->Delete();
  this->Quad->Delete();
  this->Polygon->Delete();
  this->Tetra->Delete();
  this->GlobalFaces->Delete();
  this->FaceLocations->Delete();
  delete this->PointIdMap;
  this->EdgeTable->Delete();
  this->Edges->Delete();
  this->EdgeFaces->Delete();
  this->Faces->Delete();
  this->PolyData->Delete();
  this->Polys->Delete();
  this->PolyConnectivity->Delete();
  this->CellLocator->Delete();
  this->CellIds->Delete();
  this->Cell->Delete();
  delete this->Internal;
}

//----------------------------------------------------------------------------
void vtkPolyhedron::ComputeBounds()
{
  if ( this->BoundsComputed )
  {
    return;
  }

  this->Superclass::GetBounds(); //stored in this->Bounds
  this->BoundsComputed = 1;
}

//----------------------------------------------------------------------------
void vtkPolyhedron::ConstructPolyData()
{
  if (this->PolyDataConstructed)
  {
    return;
  }

  // Here's a trick, we're going to use the Faces array as the connectivity
  // array. Note that the Faces have an added nfaces value at the beginning
  // of the array. Other than that,it's a vtkCellArray. So we play games
  // with the pointers.
  this->GenerateFaces();

  if (this->Faces->GetNumberOfTuples() == 0)
  {
    return;
  }

  this->PolyConnectivity->SetNumberOfTuples(this->Faces->GetMaxId()-1);
  this->PolyConnectivity->
    SetArray(this->Faces->GetPointer(1), this->Faces->GetMaxId()-1, 1);
  this->Polys->SetNumberOfCells(*(this->Faces->GetPointer(0)));
  this->Polys->
    SetCells(*(this->Faces->GetPointer(0)), this->PolyConnectivity);

  // Standard setup
  this->PolyData->Initialize();
  this->PolyData->SetPoints(this->Points);
  this->PolyData->SetPolys(this->Polys);

  this->PolyDataConstructed = 1;
}

vtkPolyData* vtkPolyhedron::GetPolyData()
{
  if (!this->PolyDataConstructed)
  {
    this->ConstructPolyData();
  }

  return this->PolyData;
}
//----------------------------------------------------------------------------
void vtkPolyhedron::ConstructLocator()
{
  if (this->LocatorConstructed)
  {
    return;
  }

  this->ConstructPolyData();

  // With the polydata set up, we can assign it to the  locator
  this->CellLocator->Initialize();
  this->CellLocator->SetDataSet(this->PolyData);
  this->CellLocator->BuildLocator();

  this->LocatorConstructed = 1;
}


//----------------------------------------------------------------------------
void vtkPolyhedron::ComputeParametricCoordinate(double x[3], double pc[3])
{
  this->ComputeBounds();
  double *bounds = this->Bounds;

  pc[0] = (x[0] - bounds[0]) / (bounds[1] - bounds[0]);
  pc[1] = (x[1] - bounds[2]) / (bounds[3] - bounds[2]);
  pc[2] = (x[2] - bounds[4]) / (bounds[5] - bounds[4]);
}

//----------------------------------------------------------------------------
void vtkPolyhedron::
ComputePositionFromParametricCoordinate(double pc[3], double x[3])
{
  this->ComputeBounds();
  double *bounds = this->Bounds;
  x[0] = ( 1 - pc[0] )* bounds[0] + pc[0] * bounds[1];
  x[1] = ( 1 - pc[1] )* bounds[2] + pc[1] * bounds[3];
  x[2] = ( 1 - pc[2] )* bounds[4] + pc[2] * bounds[5];
}

//----------------------------------------------------------------------------
// Should be called by GetCell() prior to any other method invocation and after the
// points, point ids, and faces have been loaded.
void vtkPolyhedron::Initialize()
{
  // Clear out any remaining memory.
  this->PointIdMap->clear();

  // We need to create a reverse map from the point ids to their canonical cell
  // ids. This is a fancy way of saying that we have to be able to rapidly go
  // from a PointId[i] to the location i in the cell.
  vtkIdType i, id, numPointIds = this->PointIds->GetNumberOfIds();
  for (i=0; i < numPointIds; ++i)
  {
    id = this->PointIds->GetId(i);
    (*this->PointIdMap)[id] = i;
  }

  // Edges have to be reset
  this->EdgesGenerated = 0;
  this->EdgeTable->Reset();
  this->Edges->Reset();
  this->EdgeFaces->Reset();
  this->Faces->Reset();

  // Polys have to be reset
  this->Polys->Reset();
  this->PolyConnectivity->Reset();

  // Faces may need renumbering later. This means converting the face ids from
  // global ids to local, canonical ids.
  this->FacesGenerated = 0;

  // No bounds have been computed as of yet.
  this->BoundsComputed = 0;

  // No supplemental geometric stuff created
  this->PolyDataConstructed = 0;
  this->LocatorConstructed = 0;
}

//----------------------------------------------------------------------------
int vtkPolyhedron::GetNumberOfEdges()
{
  // Make sure edges have been generated.
  if ( ! this->EdgesGenerated )
  {
    this->GenerateEdges();
  }

  return static_cast<int>(this->Edges->GetNumberOfTuples());
}

//----------------------------------------------------------------------------
// This method requires that GenerateEdges() is invoked beforehand.
vtkCell *vtkPolyhedron::GetEdge(int edgeId)
{
  // Make sure edges have been generated.
  if ( ! this->EdgesGenerated )
  {
    this->GenerateEdges();
  }

  // Make sure requested edge is within range
  vtkIdType numEdges = this->Edges->GetNumberOfTuples();

  if ( edgeId < 0 || edgeId >= numEdges )
  {
    return NULL;
  }

  // Return the requested edge
  vtkIdType edge[2];
  this->Edges->GetTypedTuple(edgeId,edge);

  // Recall that edge tuples are stored in canonical numbering
  for (int i=0; i<2; i++)
  {
    this->Line->PointIds->SetId(i,this->PointIds->GetId(edge[i]));
    this->Line->Points->SetPoint(i,this->Points->GetPoint(edge[i]));
  }

  return this->Line;
}

//----------------------------------------------------------------------------
int vtkPolyhedron::GenerateEdges()
{
  if ( this->EdgesGenerated )
  {
    return this->Edges->GetNumberOfTuples();
  }

  //check the number of faces and return if there aren't any
  if ( this->GlobalFaces->GetNumberOfTuples() == 0 ||
       this->GlobalFaces->GetValue(0) <= 0 )
  {
    return 0;
  }

  // Loop over all faces, inserting edges into the table
  vtkIdType *faces = this->GlobalFaces->GetPointer(0);
  vtkIdType nfaces = faces[0];
  vtkIdType *face = faces + 1;
  vtkIdType fid, i, edge[2], npts, edgeFaces[2], edgeId;
  edgeFaces[1] = -1;

  this->EdgeTable->InitEdgeInsertion(this->Points->GetNumberOfPoints(),1);
  for (fid=0; fid < nfaces; ++fid)
  {
    npts = face[0];
    for (i=1; i <= npts; ++i)
    {
      edge[0] = (*this->PointIdMap)[face[i]];
      edge[1] = (*this->PointIdMap)[(i != npts ? face[i+1] : face[1])];
      edgeFaces[0] = fid;
      if ( (edgeId = this->EdgeTable->IsEdge(edge[0],edge[1])) == (-1) )
      {
        edgeId = this->EdgeTable->InsertEdge(edge[0],edge[1]);
        this->Edges->InsertNextTypedTuple(edge);
        this->EdgeFaces->InsertTypedTuple(edgeId,edgeFaces);
      }
      else
      {
        this->EdgeFaces->SetComponent(edgeId,1,fid);
      }
    }
    face += face[0] + 1;
  } //for all faces

  // Okay all done
  this->EdgesGenerated = 1;
  return this->Edges->GetNumberOfTuples();
}

//----------------------------------------------------------------------------
int vtkPolyhedron::GetNumberOfFaces()
{
  // Make sure faces have been generated.
  if ( ! this->FacesGenerated )
  {
    this->GenerateFaces();
  }

  if (this->GlobalFaces->GetNumberOfTuples() == 0)
  {
    return 0;
  }

  return static_cast<int>(this->GlobalFaces->GetValue(0));
}

//----------------------------------------------------------------------------
void vtkPolyhedron::GenerateFaces()
{
  if ( this->FacesGenerated )
  {
    return;
  }

  if (this->GlobalFaces->GetNumberOfTuples() == 0)
  {
    return;
  }

  // Basically we just run through the faces and change the global ids to the
  // canonical ids using the PointIdMap.
  this->Faces->SetNumberOfTuples(this->GlobalFaces->GetNumberOfTuples());
  vtkIdType *gFaces = this->GlobalFaces->GetPointer(0);
  vtkIdType *faces = this->Faces->GetPointer(0);
  vtkIdType nfaces = gFaces[0]; faces[0] = nfaces;
  vtkIdType *gFace = gFaces + 1;
  vtkIdType *face = faces + 1;
  vtkIdType fid, i, id, npts;

  for (fid=0; fid < nfaces; ++fid)
  {
    npts = gFace[0];
    face[0] = npts;
    for (i=1; i <= npts; ++i)
    {
      id = (*this->PointIdMap)[gFace[i]];
      face[i] = id;
    }
    gFace += gFace[0] + 1;
    face += face[0] + 1;
  } //for all faces


  // Okay we've done the deed
  this->FacesGenerated = 1;
}

//----------------------------------------------------------------------------
vtkCell *vtkPolyhedron::GetFace(int faceId)
{
  if ( faceId < 0 || faceId >= this->GlobalFaces->GetValue(0) )
  {
    return NULL;
  }

  this->GenerateFaces();

  // Okay load up the polygon
  vtkIdType i, p, loc = this->FaceLocations->GetValue(faceId);
  vtkIdType *face = this->GlobalFaces->GetPointer(loc);

  this->Polygon->PointIds->SetNumberOfIds(face[0]);
  this->Polygon->Points->SetNumberOfPoints(face[0]);

  // grab faces in global id space
  for (i=0; i < face[0]; ++i)
  {
    this->Polygon->PointIds->SetId(i,face[i+1]);
    p = (*this->PointIdMap)[face[i+1]];
    this->Polygon->Points->SetPoint(i,this->Points->GetPoint(p));
  }

  return this->Polygon;
}

//----------------------------------------------------------------------------
// Specify the faces for this cell.
void vtkPolyhedron::SetFaces(vtkIdType *faces)
{
  // Set up face structure
  this->GlobalFaces->Reset();
  this->FaceLocations->Reset();

  if (!faces)
  {
    return;
  }

  vtkIdType nfaces = faces[0];
  this->FaceLocations->SetNumberOfValues(nfaces);

  this->GlobalFaces->InsertNextValue(nfaces);
  vtkIdType *face = faces + 1;
  vtkIdType faceLoc = 1;
  vtkIdType i, fid, npts;

  for (fid=0; fid < nfaces; ++fid)
  {
    npts = face[0];
    this->GlobalFaces->InsertNextValue(npts);
    for (i=1; i<=npts; ++i)
    {
      this->GlobalFaces->InsertNextValue(face[i]);
    }
    this->FaceLocations->SetValue(fid,faceLoc);

    faceLoc += face[0] + 1;
    face = faces + faceLoc;
  } //for all faces
}

//----------------------------------------------------------------------------
// Return the list of faces for this cell.
vtkIdType *vtkPolyhedron::GetFaces()
{
  if (!this->GlobalFaces->GetNumberOfTuples())
  {
    return NULL;
  }

  return this->GlobalFaces->GetPointer(0);
}

//----------------------------------------------------------------------------
int vtkPolyhedron::IntersectWithLine(double p1[3], double p2[3], double tol,
                                     double& tMin, double xMin[3],
                                     double pc[3], int& subId)
{
  // It's easiest if this is done in canonical space
  this->GenerateFaces();

  // Loop over all the faces, intersecting them in turn.
  vtkIdType *face = this->Faces->GetPointer(0);
  vtkIdType nfaces = *face++;
  vtkIdType npts, i, fid, numHits=0;
  double t=VTK_FLOAT_MAX;
  double x[3];

  tMin=VTK_FLOAT_MAX;
  for (fid=0; fid < nfaces; ++fid)
  {
    npts = face[0];
    vtkIdType hit = 0;
    switch (npts)
    {
      case 3: //triangle
        for (i=0; i<3; i++)
        {
          this->Triangle->Points->SetPoint(i,this->Points->GetPoint(face[i+1]));
          this->Triangle->PointIds->SetId(i,face[i+1]);
        }
        hit = this->Triangle->IntersectWithLine(p1,p2,tol,t,x,pc,subId);
        break;
      case 4: //quad
        for (i=0; i<4; i++)
        {
          this->Quad->Points->SetPoint(i,this->Points->GetPoint(face[i+1]));
          this->Quad->PointIds->SetId(i,face[i+1]);
        }
        hit = this->Quad->IntersectWithLine(p1,p2,tol,t,x,pc,subId);
        break;
      default: //general polygon
        this->Polygon->GetPoints()->SetNumberOfPoints(npts);
        this->Polygon->GetPointIds()->SetNumberOfIds(npts);
        for (i=0; i<npts; i++)
        {
          this->Polygon->Points->SetPoint(i,this->Points->GetPoint(face[i+1]));
          this->Polygon->PointIds->SetId(i,face[i+1]);
        }
        hit = this->Polygon->IntersectWithLine(p1,p2,tol,t,x,pc,subId);
        break;
    }

    // Update minimum hit
    if ( hit )
    {
      numHits++;
      if ( t < tMin )
      {
        tMin = t;
        xMin[0] = x[0]; xMin[1] = x[1]; xMin[2] = x[2];
      }
    }

    face += face[0] + 1;
  }//for all faces

  // Compute parametric coordinates
  this->ComputeParametricCoordinate(xMin,pc);

  return numHits;
}

#define VTK_MAX_ITER 10    //Maximum iterations for ray-firing
#define VTK_VOTE_THRESHOLD 3

//----------------------------------------------------------------------------
// Shoot random rays and count the number of intersections
int vtkPolyhedron::IsInside(double x[3], double tolerance)
{
  // do a quick bounds check
  this->ComputeBounds();
  double *bounds = this->Bounds;
  if ( x[0] < bounds[0] || x[0] > bounds[1] ||
       x[1] < bounds[2] || x[1] > bounds[3] ||
       x[2] < bounds[4] || x[2] > bounds[5])
  {
    return 0;
  }

  // It's easiest if these computations are done in canonical space
  this->GenerateFaces();

  // This algorithm is adaptive; if there are enough faces in this
  // polyhedron, a cell locator is built to accelerate intersections.
  // Otherwise brute force looping over cells is used.
  vtkIdType *faceArray = this->Faces->GetPointer(0);
  vtkIdType nfaces = *faceArray++;
  if ( nfaces > 25 )
  {
    this->ConstructLocator();
  }

  // We need a length to normalize the computations
  double length = sqrt( this->Superclass::GetLength2() );

  //  Perform in/out by shooting random rays. Multiple rays are fired
  //  to improve accuracy of the result.
  //
  //  The variable iterNumber counts the number of rays fired and is
  //  limited by the defined variable VTK_MAX_ITER.
  //
  //  The variable deltaVotes keeps track of the number of votes for
  //  "in" versus "out" of the surface.  When deltaVotes > 0, more votes
  //  have counted for "in" than "out".  When deltaVotes < 0, more votes
  //  have counted for "out" than "in".  When the delta_vote exceeds or
  //  equals the defined variable VTK_VOTE_THRESHOLD, then the
  //  appropriate "in" or "out" status is returned.
  //
  double rayMag, ray[3], xray[3], t, pcoords[3], xint[3];
  int i, numInts, iterNumber, deltaVotes, subId;
  vtkIdType idx, numCells;
  double tol = tolerance * length;

  for (deltaVotes = 0, iterNumber = 1;
       (iterNumber < VTK_MAX_ITER) && (abs(deltaVotes) < VTK_VOTE_THRESHOLD);
       iterNumber++)
  {
    //  Define a random ray to fire.
    do
    {
      for (i=0; i<3; i++)
      {
        ray[i] = vtkMath::Random(-1.0,1.0);
      }
      rayMag = vtkMath::Norm(ray);
    }
    while (rayMag == 0.0);

    // The ray must be appropriately sized wrt the bounding box. (It has to go
    // all the way through the bounding box.)
    for (i=0; i<3; i++)
    {
      xray[i] = x[i] + (length/rayMag)*ray[i];
    }

    // Intersect the line with each of the candidate cells
    numInts = 0;

    if ( this->LocatorConstructed )
    {
      // Retrieve the candidate cells from the locator
      this->CellLocator->FindCellsAlongLine(x,xray,tol,this->CellIds);
      numCells = this->CellIds->GetNumberOfIds();

      for ( idx=0; idx < numCells; idx++ )
      {
        this->PolyData->GetCell(this->CellIds->GetId(idx), this->Cell);
        if ( this->Cell->IntersectWithLine(x, xray, tol, t, xint, pcoords, subId) )
        {
          // Check for vertex, edge or face intersections
          // count the number of 0 or 1 pcoords
          int pcount = 0;
          for (int p = 0; p < 3; ++p)
          {
            if (pcoords[p] == 0.0 || pcoords[p] == 1.0)
            {
              pcount++;
            }
          }
          // pcount = 1, exact face intersection
          // pcount = 2, exact edge intersection
          // pcount = 3, exact vertex intersection
          if (pcount == 0)
          {
            numInts++;
          }
        }
      } //for all candidate cells
    }
    else
    {
      numCells = nfaces;
      this->ConstructPolyData();

      for ( idx=0; idx < numCells; idx++ )
      {
        this->PolyData->GetCell(idx, this->Cell);
        if ( this->Cell->IntersectWithLine(x, xray, tol, t, xint, pcoords, subId) )
        {
          // Check for vertex, edge or face intersections
          // count the number of 0 or 1 pcoords
          int pcount = 0;
          for (int p = 0; p < 3; ++p)
          {
            if (pcoords[p] == 0.0 || pcoords[p] == 1.0)
            {
              pcount++;
            }
          }
          // pcount = 1, exact face intersection
          // pcount = 2, exact edge intersection
          // pcount = 3, exact vertex intersection
          if (pcount == 0)
          {
            numInts++;
          }
        }
      } //for all candidate cells
    }

    // Count the result
    if ( numInts != 0 && (numInts % 2) == 0)
    {
      --deltaVotes;
    }
    else
    {
      ++deltaVotes;
    }
  } //try another ray

  //   If the number of votes is positive, the point is inside
  //
  return ( deltaVotes < 0 ? 0 : 1 );
}

#undef VTK_MAX_ITER
#undef VTK_VOTE_THRESHOLD


//----------------------------------------------------------------------------
// Determine whether or not a polyhedron is convex. This method is adapted
// from Devillers et al., "Checking the Convexity of Polytopes and the
// Planarity of Subdivisions", Computational Geometry, Volume 11, Issues 3 – 4,
// December 1998, Pages 187 – 208.
bool vtkPolyhedron::IsConvex()
{
  double x[2][3], n[3], c[3], c0[3], c1[3], c0p[3], c1p[3], n0[3], n1[3];
  double n0p[3], n1p[3], np[3], tmp0, tmp1;
  vtkIdType i, w[2], p0, p1, edgeId, edgeFaces[2], loc, v, *face, r=0;
  const double eps = FLT_EPSILON;

  std::vector<double> p(this->PointIds->GetNumberOfIds());
  vtkIdVectorType d(this->PointIds->GetNumberOfIds(),0);

  // initialization
  this->GenerateEdges();
  this->GenerateFaces();
  this->ConstructPolyData();
  this->ComputeBounds();

  // loop over all edges in the polyhedron
  this->EdgeTable->InitTraversal();
  while ((edgeId = this->EdgeTable->GetNextEdge(w[0], w[1])) >= 0)
  {
    // get the global point ids
    p0 = this->PointIds->GetId(w[0]);
    p1 = this->PointIds->GetId(w[1]);

    // get the edge points
    this->Points->GetPoint(p0, x[0]);
    this->Points->GetPoint(p1, x[1]);

    // get the local face ids
    this->EdgeFaces->GetTypedTuple(edgeId,edgeFaces);

    // get the face vertex ids for the first face
    loc = this->FaceLocations->GetValue(edgeFaces[0]);
    face = this->GlobalFaces->GetPointer(loc);

    // compute the centroid and normal for the first face
    vtkPolygon::ComputeCentroid(this->Points, face[0], face + 1, c0);
    vtkPolygon::ComputeNormal(this->Points, face[0], face + 1, n0);

    // get the face vertex ids for the second face
    loc = this->FaceLocations->GetValue(edgeFaces[1]);
    face = this->GlobalFaces->GetPointer(loc);

    // compute the centroid and normal for the second face
    vtkPolygon::ComputeCentroid(this->Points, face[0], face + 1, c1);
    vtkPolygon::ComputeNormal(this->Points, face[0], face + 1, n1);

    // check for local convexity (the average of the two centroids must be
    // "below" both faces, as defined by their outward normals).
    for (i=0;i<3;i++)
    {
      c[i] = (c1[i] + c0[i])*.5;
      c0p[i] = c[i] - c0[i];
      c1p[i] = c[i] - c1[i];
    }

    if (vtkMath::Dot(n0,c0p) > 0. || vtkMath::Dot(n1,c1p) > 0.)
    {
      return false;
    }

    // check if the edge is a seam edge
    // 1. the edge must not be vertical
    // 2. the two faces must lie on the same side of a vertical plane
    // 3. the upper face must not be vertical

    // 1. simply check that the unit normal along the seam has x or y
    //    components
    for (i=0;i<3;i++)
    {
      n[i] = x[1][i] - x[0][i];
    }
    vtkMath::Normalize(n);
    if (std::abs(n[0]) < eps && std::abs(n[1]) < eps)
    {
      continue;
    }

    // 2. we need a plane through the seam and through a vector parallel to the
    //    z axis (or, more accurately, we need a vector perpendicular to this
    //    plane). So, we take a vector pointing from the centroid of the seam
    //    to the centroid of "higher" plane and remove the seam- and
    //    z-components from it.
    for (i=0;i<3;i++)
    {
      c[i] = (x[1][i] + x[0][i])*.5;
      n0p[i] = c0[i] - c[i];
      n1p[i] = c1[i] - c[i];
    }
    vtkMath::Normalize(n0p);
    vtkMath::Normalize(n1p);

    memcpy(np, (n0p[2] > n1p[2] ? n0p : n1p), sizeof(np));

    tmp0 = vtkMath::Dot(np,n);
    np[0] -= n[0]*tmp0;
    np[1] -= n[1]*tmp0;
    np[2] = 0.;

    // 3. if np has zero magnitude, then condition 3 is violated. Otherwise,
    //    we can use it to ensure condition 2.
    if (std::abs(np[0]) < eps && std::abs(np[1]) < eps)
    {
      continue;
    }

    // if the vectors from the seam centroid to the face centroid are in the
    // same direction relative to the plane, then condition 2 is satisfied.
    tmp0 = vtkMath::Dot(np,n0p);
    tmp1 = vtkMath::Dot(np,n1p);

    if ((tmp0 < 0.) != (tmp1 < 0.))
    {
      continue;
    }

    // at this point, we know we have a seam edge. We now look at each vertex
    // in the seam and determine whether or not it is a right-2-seam vertex. A
    // convex polytope has exactly one right-2-seam vertex.
    for (i = 0; i < 2; i++)
    {
      v = w[i];

      // are there already 2 seams associated with this vertex? If so, then the
      // projection of the polytope onto the x-y plane would have multiple seams
      // emanating from the vertex => non-convex.
      if (d[v] == 2)
      {
        return false;
      }

      // is this the first time that this vertex has been associated with a
      // seam? If so, increment its seam count and record the x-coordinate of
      // the adjacent edge vertex.
      if (d[v] == 0)
      {
        d[v]++;
        p[v] = x[(i+1)%2][0];
      }
      else
      {
        d[v]++;
        // is v a right-2-seam vertex (i.e. is the x-value of v larger than the
        // x-values of both u and p[v])?
        if (x[i][0] > x[(i+1)%2][0] && x[i][0] > p[v])
        {
          // is this the first right-2-seam vertex?
          if (r == 0)
          {
            r++;
          }
          else
          {
            return false;
          }
        }
      }

    }
  }

  return true;
}

//----------------------------------------------------------------------------
int vtkPolyhedron::CellBoundary(int vtkNotUsed(subId), double pcoords[3],
                                    vtkIdList *pts)
{
  double x[3], n[3], o[3], v[3];
  double dist, minDist = VTK_DOUBLE_MAX;
  vtkIdType numFacePts = -1;
  vtkIdType * facePts = 0;

  // compute coordinates
  this->ComputePositionFromParametricCoordinate(pcoords, x);

  vtkPolyhedronFaceIterator
    faceIter(this->GetNumberOfFaces(), this->Faces->GetPointer(1));
  while (faceIter.Id < faceIter.NumberOfPolygons)
  {
    if (faceIter.CurrentPolygonSize < 3)
    {
      vtkErrorMacro("Find a face with " << faceIter.CurrentPolygonSize <<
        " vertices. Cannot return CellBoundary due to this degenerate case.");
      break;
    }

    vtkPolygon::ComputeNormal(this->Points, faceIter.CurrentPolygonSize,
                              faceIter.Current, n);
    vtkMath::Normalize(n);
    this->Points->GetPoint(faceIter.Current[0], o);
    v[0] = x[0] - o[0];
    v[1] = x[1] - o[1];
    v[2] = x[2] - o[2];
    dist = fabs(vtkMath::Dot(v, n));
    if (dist < minDist)
    {
      minDist = dist;
      numFacePts = faceIter.CurrentPolygonSize;
      facePts = faceIter.Current;
    }

    ++faceIter;
  }

  pts->Reset();
  if (numFacePts > 0)
  {
    for (vtkIdType i = 0; i < numFacePts; i++)
    {
      pts->InsertNextId(this->PointIds->GetId(facePts[i]));
    }
  }

  // determine whether point is inside of polygon
  if ( pcoords[0] >= 0.0 && pcoords[0] <= 1.0 &&
       pcoords[1] >= 0.0 && pcoords[1] <= 1.0 &&
       pcoords[2] >= 0.0 && pcoords[2] <= 1.0 &&
       (this->IsInside(x, std::numeric_limits<double>::infinity())) )
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

//----------------------------------------------------------------------------
int vtkPolyhedron::EvaluatePosition( double x[3], double * closestPoint,
                                     int & vtkNotUsed(subId), double pcoords[3],
                                     double & minDist2, double * weights )
{
  // compute parametric coordinates
  this->ComputeParametricCoordinate(x, pcoords);

  // construct polydata, the result is stored in this->PolyData,
  // the cell array is stored in this->Polys
  this->ConstructPolyData();

  // Construct cell locator
  this->ConstructLocator();

  // find closest point and store the squared distance
  vtkIdType cellId;
  int id;
  double cp[3];
  this->Cell->Initialize();
  this->CellLocator->FindClosestPoint(
    x, cp, this->Cell, cellId, id, minDist2 );

  if (closestPoint)
  {
    closestPoint[0] = cp[0];
    closestPoint[1] = cp[1];
    closestPoint[2] = cp[2];
  }

  // get the MVC weights
  this->InterpolateFunctions(x, weights);

  // set distance to be zero, if point is inside
  int isInside = this->IsInside(x, std::numeric_limits<double>::infinity());
  if (isInside)
  {
    minDist2 = 0.0;
  }

  return isInside;
}

//----------------------------------------------------------------------------
void vtkPolyhedron::EvaluateLocation( int & vtkNotUsed(subId), double pcoords[3],
                                      double x[3],  double * weights )
{
  this->ComputePositionFromParametricCoordinate(pcoords, x);

  this->InterpolateFunctions(x, weights);
}

//----------------------------------------------------------------------------
void vtkPolyhedron::Derivatives(int vtkNotUsed(subId), double pcoords[3],
                                double *values, int dim, double *derivs)
{
  int i, j, k, idx;
  for ( j = 0; j < dim; j++ )
  {
    for ( i = 0; i < 3; i++ )
    {
      derivs[j*dim + i] = 0.0;
    }
  }

  static const double Sample_Offset_In_Parameter_Space = 0.01;

  double x[4][3];
  double coord[3];

  //compute positions of point and three offset sample points
  coord[0] = pcoords[0];
  coord[1] = pcoords[1];
  coord[2] = pcoords[2];
  this->ComputePositionFromParametricCoordinate(coord, x[0]);

  coord[0] += Sample_Offset_In_Parameter_Space;
  this->ComputePositionFromParametricCoordinate(coord, x[1]);
  coord[0] = pcoords[0];

  coord[1] += Sample_Offset_In_Parameter_Space;
  this->ComputePositionFromParametricCoordinate(coord, x[2]);
  coord[1] = pcoords[1];

  coord[2] += Sample_Offset_In_Parameter_Space;
  this->ComputePositionFromParametricCoordinate(coord, x[3]);
  coord[2] = pcoords[2];

  this->ConstructPolyData();
  int numVerts = this->PolyData->GetNumberOfPoints();

  double *weights = new double[numVerts];
  double *sample = new double[dim*4];
  //for each sample point, sample data values
  for ( idx = 0, k = 0; k < 4; k++ ) //loop over three sample points
  {
    this->InterpolateFunctions(x[k],weights);
    for ( j = 0; j < dim; j++, idx++) //over number of derivates requested
    {
      sample[idx] = 0.0;
      for ( i = 0; i < numVerts; i++ )
      {
        sample[idx] += weights[i] * values[j + i*dim];
      }
    }
  }

  double v1[3], v2[3], v3[3];
  double l1, l2, l3;
  //compute differences along the two axes
  for ( i = 0; i < 3; i++ )
  {
    v1[i] = x[1][i] - x[0][i];
    v2[i] = x[2][i] - x[0][i];
    v3[i] = x[3][i] - x[0][i];
  }
  l1 = vtkMath::Normalize(v1);
  l2 = vtkMath::Normalize(v2);
  l3 = vtkMath::Normalize(v3);


  //compute derivatives along x-y-z axes
  double ddx, ddy, ddz;
  for ( j = 0; j < dim; j++ )
  {
    ddx = (sample[  dim+j] - sample[j]) / l1;
    ddy = (sample[2*dim+j] - sample[j]) / l2;
    ddz = (sample[3*dim+j] - sample[j]) / l3;

    //project onto global x-y-z axes
    derivs[3*j]     = ddx*v1[0] + ddy*v2[0] + ddz*v3[0];
    derivs[3*j + 1] = ddx*v1[1] + ddy*v2[1] + ddz*v3[1];
    derivs[3*j + 2] = ddx*v1[2] + ddy*v2[2] + ddz*v3[2];
  }

  delete [] weights;
  delete [] sample;
}

//----------------------------------------------------------------------------
double *vtkPolyhedron::GetParametricCoords()
{
  return NULL;
}

//----------------------------------------------------------------------------
void vtkPolyhedron::InterpolateFunctions(double x[3], double *sf)
{
  // construct polydata, the result is stored in this->PolyData,
  // the cell array is stored in this->Polys
  this->ConstructPolyData();

  // compute the weights
  if (!this->PolyData->GetPoints())
  {
    return;
  }
  vtkMeanValueCoordinatesInterpolator::ComputeInterpolationWeights(
    x, this->PolyData->GetPoints(), this->Polys, sf);
}

//----------------------------------------------------------------------------
void vtkPolyhedron::InterpolateDerivs(double x[3], double *derivs)
{
  (void)x;
  (void)derivs;
}

//----------------------------------------------------------------------------
int vtkPolyhedron::Triangulate(int vtkNotUsed(index), vtkIdList *ptIds,
                               vtkPoints *pts)
{
  ptIds->Reset();
  pts->Reset();

  if (!this->GetPoints() || !this->GetNumberOfPoints())
  {
    return 0;
  }

  this->ComputeBounds();

  // use ordered triangulator to triangulate the polyhedron.
  vtkSmartPointer<vtkOrderedTriangulator> triangulator =
    vtkSmartPointer<vtkOrderedTriangulator>::New();

  triangulator->InitTriangulation(this->Bounds, this->GetNumberOfPoints());
  triangulator->PreSortedOff();

  double point[3];
  for (vtkIdType i = 0; i < this->GetNumberOfPoints(); i++)
  {
    this->GetPoints()->GetPoint(i, point);
    triangulator->InsertPoint(i, point, point, 0);
  }
  triangulator->Triangulate();

  triangulator->AddTetras(0, ptIds, pts);

  // convert to global Ids
  vtkIdType* ids = ptIds->GetPointer(0);
  for (vtkIdType i = 0; i < ptIds->GetNumberOfIds(); i++)
  {
    ids[i] = this->PointIds->GetId(ids[i]);
  }

  return 1;
}

//----------------------------------------------------------------------------
int vtkPolyhedron::IntersectWithContour(double value,
                                        int insideOut,
                                        vtkDataArray *inScalars)
{
  bool allPositive = true;
  bool allNegative = true;

  // make the valueTolerance dependent on the range of
  // values that is being contoured
  double vMin(DBL_MAX), vMax(-DBL_MAX);
  for (vtkIdType pid = 0; pid < this->Points->GetNumberOfPoints(); ++pid)
  {
    double v = inScalars->GetComponent(pid,0);
    vMin = std::min(vMin, v);
    vMax = std::max(vMax, v);
  }

  double valueTolerance = std::min(1e-6, 1e-6*(vMax - vMin));

  for (vtkIdType pid = 0; pid < this->Points->GetNumberOfPoints(); ++pid)
  {
    double v = inScalars->GetComponent(pid,0);
    if (v < value + valueTolerance)
    {
      allPositive = false;
    }
    else if (v > value - valueTolerance)
    {
      allNegative = false;
    }
  }

  if ((allPositive && insideOut) || (allNegative && !insideOut))
  {
    return 2;
  }

  if (allPositive || allNegative)
  {
    return 1;
  }

  return 0;
}

//----------------------------------------------------------------------------
// Internal implementation of contouring algorithm
// NOTE: inScalars are in canonoical id space. while inPd are in global id space.
int vtkPolyhedron::InternalContour(double value,
                                   int insideOut,
                                   vtkIncrementalPointLocator *locator,
                                   vtkDataArray *inScalars,
                                   vtkDataArray *outScalars,
                                   vtkPointData *inPd,
                                   vtkPointData *outPd,
                                   vtkCellArray *contourPolys,
                                   vtkIdToIdVectorMapType & faceToPointsMap,
                                   vtkIdToIdVectorMapType & pointToFacesMap,
                                   vtkIdToIdMapType & pointIdMap)
{
  // make the valueTolerance dependent on the range of
  // values that is being contoured
  double vMin(DBL_MAX), vMax(-DBL_MAX);
  for (vtkIdType pid = 0; pid < this->Points->GetNumberOfPoints(); ++pid)
  {
    double v = inScalars->GetComponent(pid,0);
    vMin = std::min(vMin, v);
    vMax = std::max(vMax, v);
  }

  double valueTolerance = std::min(1e-6, 1e-6*(vMax - vMin));

  double x0[3], x1[3], x[3];
  double v0, v1, v, t;

  vtkIdType p0, p1, pid, fid, outPid, globalP0, globalP1;
  void * ptr = NULL;

  pointToFacesMap.clear();
  faceToPointsMap.clear();
  pointIdMap.clear();

  vtkIdVectorType pointLabelVector;
  for (pid = 0; pid < this->Points->GetNumberOfPoints(); pid++)
  {
    v = inScalars->GetComponent(pid,0);
    if (v < value + valueTolerance)
    {
      if (v > value - valueTolerance)
      {
        pointLabelVector.push_back(0);
      }
      else
      {
        pointLabelVector.push_back(-1);
      }
    }
    else if (v > value - valueTolerance)
    {
      if (v < value + valueTolerance)
      {
        pointLabelVector.push_back(0);
      }
      else
      {
        pointLabelVector.push_back(1);
      }
    }
  }

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  points->DeepCopy(this->Points);

  if (outScalars)
  {
    for (vtkIdType i = 0; i < inScalars->GetNumberOfTuples(); i++)
    {
      outScalars->InsertNextTuple1(inScalars->GetTuple1(i));
    }
  }

  // construct a face to contour points map
  vtkIdToIdVectorMapType faceToContourPointsMap;

  vtkIdToIdVectorMapIteratorType vfMapIt, vfMapIt0, vfMapIt1;
  vtkIdToIdVectorMapIteratorType fvMapIt, fcpMapIt, fcpMapItTemp;

  // loop through all faces to construct PointToFacesMap and FaceToPointsMap
  vtkPolyhedronFaceIterator
    faceIter(this->Faces->GetValue(0), this->Faces->GetPointer(1));
  while (faceIter.Id < faceIter.NumberOfPolygons)
  {
    // the rest code of this function assumes that a face contains at least
    // three vertices. return if find a single-vertex or double-vertex face.
    if (faceIter.CurrentPolygonSize < 3)
    {
      vtkErrorMacro("Find a face with " << faceIter.CurrentPolygonSize <<
        " vertices. Contouring aborted due to this degenrate case.");
      return -1;
    }

    fid = faceIter.Id;
    vtkIdVectorType vVector;
    for (vtkIdType i = 0; i < faceIter.CurrentPolygonSize; i++)
    {
      pid = faceIter.Current[i];
      vfMapIt = pointToFacesMap.find(pid);
      if (vfMapIt != pointToFacesMap.end())
      {
        vfMapIt->second.push_back(fid);
      }
      else
      {
        vtkIdVectorType fVector;
        fVector.push_back(fid);
        pointToFacesMap.insert(vtkIdToIdVectorPairType(pid, fVector));
      }
      vVector.push_back(pid);
    }

    faceToPointsMap.insert(vtkIdToIdVectorPairType(fid, vVector));
    ++faceIter;
  }

  // loop through all edges to find contour points and store them in the point
  // locator. if the contour points are new (not overlap with any of original
  // vertex), update PointToFacesMap, FaceToPointsMap and FaceToContourPointsMap.
  vtkIdSetType cpSet; // contour point set
  this->EdgeTable->InitTraversal();
  while (this->EdgeTable->GetNextEdge(p0, p1, ptr))
  {
    // If both vertices are positive or negative, we do nothing and continue;
    if ((pointLabelVector[p0] == 1 && pointLabelVector[p1] == 1) ||
        (pointLabelVector[p0] == -1 && pointLabelVector[p1] == -1))
    {
      continue;
    }

    globalP0 = this->PointIds->GetId(p0);
    globalP1 = this->PointIds->GetId(p1);

    v0 = inScalars->GetComponent(p0,0);
    v1 = inScalars->GetComponent(p1,0);

    points->GetPoint(p0, x0);
    points->GetPoint(p1, x1);

    // If one or two of the vertices are contour points, we maintain the face
    // to contour point map then continue
    if (!pointLabelVector[p0] || !pointLabelVector[p1])
    {
      vtkIdType contourVertexIds[2];
      contourVertexIds[0] = -1;
      contourVertexIds[1] = -1;
      if (pointLabelVector[p0] == 0)
      {
        if (cpSet.insert(p0).second) // check if the point already exist in set
        {
          if (locator->InsertUniquePoint(x0, outPid))
          {
            outPd->CopyData(inPd, globalP0, outPid);
          }
          pointIdMap.insert(vtkIdToIdPairType(p0, outPid));
          contourVertexIds[0] = p0;
        }
      }
      if (pointLabelVector[p1] == 0)
      {
        if (cpSet.insert(p1).second) // check if the point already exist in set
        {
          if (locator->InsertUniquePoint(x1, outPid))
          {
            outPd->CopyData(inPd, globalP1, outPid);
          }
          pointIdMap.insert(vtkIdToIdPairType(p1, outPid));
          contourVertexIds[1] = p1;
        }
      }

      for (int i = 0; i < 2; i++)
      {
        if (contourVertexIds[i] < 0)
        {
          continue;
        }

        vfMapIt = pointToFacesMap.find(contourVertexIds[i]);
        if (vfMapIt == pointToFacesMap.end())
        {
          vtkErrorMacro("Cannot locate adjacent faces of a vertex. We should "
            "never get here. Contouring continue but result maybe wrong.");
          continue;
        }

        for (size_t k = 0; k < vfMapIt->second.size(); k++)
        {
          vtkIdType contourFaceId = vfMapIt->second[k];
          fcpMapIt = faceToContourPointsMap.find(contourFaceId);
          if (fcpMapIt != faceToContourPointsMap.end())
          {
            fcpMapIt->second.push_back(contourVertexIds[i]);
          }
          else
          {
            vtkIdVectorType contourPointVector;
            contourPointVector.push_back(contourVertexIds[i]);
            faceToContourPointsMap.insert(
              vtkIdToIdVectorPairType(contourFaceId, contourPointVector));
          }
        }
      }

      continue;
    }

   // If two edge vertices are one positive and one negative. We need to
   // insert new contour points on this edge.

    t = (value - v0)/(v1 - v0);
    x[0] = (1 - t) * x0[0] + t * x1[0];
    x[1] = (1 - t) * x0[1] + t * x1[1];
    x[2] = (1 - t) * x0[2] + t * x1[2];

    pid = points->InsertNextPoint(x);
    // update pointLabelVector: we know the pid will be the number of existing
    // point (original verices plus previously inserted contour points)
    pointLabelVector.push_back(0);

    // update PointToFacesMap: there should be two and only two faces adjacent
    // to the newly inserted contour point.
    vfMapIt0 = pointToFacesMap.find(p0);
    vfMapIt1 = pointToFacesMap.find(p1);
    vtkIdVectorType fVector;
    vtkIdVectorType fVector0 = vfMapIt0->second;
    vtkIdVectorType fVector1 = vfMapIt1->second;
    for (size_t i = 0; i < fVector0.size(); i++)
    {
      for (size_t j = 0; j < fVector1.size(); j++)
      {
        if (fVector0[i] == fVector1[j])
        {
          fVector.push_back(fVector0[i]);
        }
      }
    }
    if (fVector.size() != 2)
    {
      continue;
    }
    pointToFacesMap.insert(vtkIdToIdVectorPairType(pid, fVector));

    // update FaceToPointsMap: insert the new point to the adjacent faces,
    // but still need to keep the order
    for (int k = 0; k < 2; k++)
    {
      fvMapIt = faceToPointsMap.find(fVector[k]);
      this->Internal->InsertNewIdToIdVector(fvMapIt->second, pid, p0, p1);
    }

    // update FaceToContourPointsMap: insert the new point to the adjacent faces
    for (int k = 0; k < 2; k++)
    {
      fcpMapIt = faceToContourPointsMap.find(fVector[k]);
      if (fcpMapIt != faceToContourPointsMap.end())
      {
        fcpMapIt->second.push_back(pid);
      }
      else
      {
        vtkIdVectorType contourPointVector;
        contourPointVector.push_back(pid);
        faceToContourPointsMap.insert(
          vtkIdToIdVectorPairType(fVector[k], contourPointVector));
      }
    }

    // Maintain point data. only add to locator when it has never been added
    // as contour point of previous processed cells.
    if (locator->InsertUniquePoint(x, outPid) && outPd)
    {
      outPd->InterpolateEdge(inPd,outPid,globalP0,globalP1,t);
    }

    // A point unique to merge may not be unique to locator, since it may have
    // been inserted to locator as contour point of previous processed cells.
    if (outScalars)
    {
      outScalars->InsertTuple1(pid, value);
    }

    pointIdMap.insert(vtkIdToIdPairType(pid, outPid));

    cpSet.insert(pid);
  }

  // Extract valid edges between contour points. We store edge information in a
  // edge map ceMap. The key (first field) of ceMap is contour point Pd. The
  // second field of ceMap is a vector of Ids of connected contour points. This
  // process may remove point from cpSet if that point is only connected to one
  // other contour point and therefore form a edge face.
  vtkIdToIdVectorMapType ceMap; // edge map
  int maxConnectivity = this->Internal->ExtractContourConnectivities(
                             ceMap, cpSet, pointLabelVector, pointToFacesMap,
                             faceToPointsMap, faceToContourPointsMap);

  // special handling of point or line cases.
  if (cpSet.size() < 3 || ceMap.size() < 3)
  {
    for (size_t i = 0; i < pointLabelVector.size(); i++)
    {
      if (pointLabelVector[i] == 1)
      {
        return insideOut ? 2 : 1;
      }
      if (pointLabelVector[i] == -1)
      {
        return insideOut ? 1 : 2;
      }
    }
    return -1;
  }

  // The following process needs to know whether a contour point is boundary
  // point and therefore contain two boundary edges.
  // This information is important. As we traverse the edges to extract polygons
  // contour edges only need to be traversed once, while internal edges need to
  // be traversed twice.
  // Note that in the simple case, where all contour points are 2-connected and
  // all contour edges are boundary edges. The result contour only contains one
  // single polygon. Otherwise, there are both boundary points (connected to two
  // boundary edges and zero or one or multiple internal edges) and internal
  // points (only connected to internal edges). The result contour contains
  // multiple polygons. In the latter case, we will need to distinguish boundary
  // contour points and interior contour points.

  // ceMap only shows that a contour point (map->first) is connected to a number
  // of other contour points (map->second). the following function computes
  // the normal of the contour point (map->first) and then sorts the connected
  // contour points (map->second) such that the connected edges are ordered
  // counter-clockwise. the sorted edge graph is stored in ceBackupMap.
  // the following function also distinguishes boundary edges from internal ones
  // a boundary edge a-->b (assuming traversing from the counter-clockwise
  // direction) is only stored once ({a, [b, ...]}). an internal edge a<-->b is
  // stored twice ({a, [b, ...] and {b, [a, ...]}}. this graph is stored in
  // the updated ceMap.
  vtkIdToIdVectorMapType ceBackupMap;
  if (maxConnectivity > 2)
  {
    this->Internal->OrderMultiConnectedContourPoints(ceMap, ceBackupMap,
                                                     cpSet, points);
  }
  else
  {
    this->Internal->OrderTwoConnectedContourPoints(ceMap, ceBackupMap);
  }

  // cpSet and ceMap defines the contour graph. We now need to travel through
  // the graph to extract non-overlapping polygons. The polygons can share
  // edges but none of them is a subset of another one.
  // Here we use the order of the edges. Specifically, when a contour point
  // is visited, we will choose the outgoing edge to be the edge previous to the
  // incoming edge in the ceBackupMap.
  std::vector<vtkIdVectorType> polygonVector;
  vtkIdToIdVectorMapType::iterator ceMapIt, ceBackupMapIt;
  vtkIdSetType::iterator cpSetIt = cpSet.end();

  // backup ceMap. During graph travasal, we will remove edges from contour point
  // which can mess up the ordering.
  vtkIdSetType cpBackupSet = cpSet;
  bool unexpectedCell = false;
  while (!cpSet.empty())
  {
    vtkIdType startPid = *(cpSet.begin());

    // check if the point still have untravelled outgoing edges.
    ceMapIt = ceMap.find(startPid);
    if (ceMapIt == ceMap.end())
    {
      cpSet.erase(cpSetIt);
      continue;
    }

    vtkIdType currPid = startPid;
    vtkIdType prevPid = -1;
    vtkIdType nextPid = -1;

    // vector to record points on a contour polygon
    vtkIdVectorType cpLoop;

    // continue to find the next contour point.
    while (!cpLoop.empty() || prevPid == -1)
    {

      // when back to the start point, break the loop.
      if (!cpLoop.empty() && currPid == startPid)
      {
        break;
      }

      cpSetIt = cpSet.find(currPid);
      ceMapIt = ceMap.find(currPid);

      // we should never arrive to a deadend.
      if (ceMapIt == ceMap.end() || cpSetIt == cpSet.end())
      {
        unexpectedCell = true;
        break;
      }

      // add current point to the polygon loop
      cpLoop.push_back(currPid);

      // get the current available outgoing edges
      vtkIdVectorType edges = ceMapIt->second;

      // choose the next point to travel. the outgoing edge is chosen to be the
      // one previous to the incoming edge.
      if (prevPid == -1)
      {
        nextPid = edges[0];
      }
      else
      {
        if (edges.size() == 1)
        {
          nextPid = edges[0];
        }
        else if (edges.size() == 2)
        {
          nextPid = edges[0] == prevPid ? edges[1] : edges[0];
        }
        else
        {
          vtkIdVectorType backupEdges = ceBackupMap.find(currPid)->second;
          for (size_t i = 0; i < backupEdges.size(); i++)
          {
            if (backupEdges[i] == prevPid)
            {
              if (i == 0)
              {
                nextPid = backupEdges[backupEdges.size() - 1];
              }
              else
              {
                nextPid = backupEdges[i-1];
              }
              break;
            }
          }
        }
      }

      // remove the outgoing edge
      bool foundEdge = false;
      for (size_t i = 0; i < edges.size(); i++)
      {
        if (edges[i] == nextPid)
        {
          foundEdge = true;
          edges.erase(edges.begin()+i);
        }
      }

      // the next edge shouldn't have been travelled and thus been removed
      if (!foundEdge)
      {
        unexpectedCell = true;
        break;
      }

      // removing point from ceMap and cpSet if all its edges have been visited.
      if (edges.empty())
      {
        ceMap.erase(ceMapIt);
        cpSet.erase(cpSetIt);
      }
      else
      {
        ceMapIt->second = edges;
      }

      // move on
      prevPid = currPid;
      currPid = nextPid;
      nextPid = -1;

    }// end_inner_while_loop

    if (unexpectedCell)
    {
      //vtkWarningMacro("Find an unexpected case. The input polyhedron cell may "
      //"not be a water tight cell. Or the contouring function is non-planar and "
      //"intersects more than two edges and/or vertices on one face of the input "
      //"polyhedron cell. Contouring will continue, but this cell will be not be "
      //"processed.");

      polygonVector.clear();
      vtkIdVectorType polygon;
      if (this->Internal->OrderDisconnectedContourPoints(cpBackupSet,
                               points, pointLabelVector, polygon))
      {
         polygonVector.push_back(polygon);
      }
      break;
    }

    if (!cpLoop.empty())
    {
      // record polygon loop.
      polygonVector.push_back(cpLoop);
    }
  } // end_outer_while_loop

  //
  // Finally, add contour polygons to the output
  for (size_t i = 0; i < polygonVector.size(); i++)
  {
    vtkIdVectorType polygon = polygonVector[i];

    vtkIdType npts = static_cast<vtkIdType>(polygon.size());
    vtkIdType *pts = &(polygon[0]);

    if (npts < 3) // skip point or line contour
    {
      continue;
    }

    // check the dimensionality of the contour
    int ret = this->Internal->
      CheckContourDimensions(points, npts, pts, NULL, NULL);

    if (ret <= 1) // skip single point or co-linear points
    {
    }
    else if (ret == 2) // planar polygon, add directly
    {
      contourPolys->InsertNextCell(npts, pts);
    }
    else  // 3D points, need to triangulate the original polygon
    {
      this->Internal->Triangulate3DContour(npts, pts, contourPolys);
    }
  }

  return 0;
}

//----------------------------------------------------------------------------
void vtkPolyhedron::Contour(double value,
                            vtkDataArray *pointScalars,
                            vtkIncrementalPointLocator *locator,
                            vtkCellArray *verts,
                            vtkCellArray *lines,
                            vtkCellArray *polys,
                            vtkPointData *inPd, vtkPointData *outPd,
                            vtkCellData *inCd, vtkIdType cellId,
                            vtkCellData *outCd)
{
  vtkIdToIdVectorMapType faceToPointsMap;
  vtkIdToIdVectorMapType pointToFacesMap;
  vtkIdToIdMapType       pointIdMap;  //local one, not this->PointIdMap
  vtkIdType offset = 0;
  if (verts)
  {
    offset += verts->GetNumberOfCells();
  }
  if (lines)
  {
    offset += lines->GetNumberOfCells();
  }

  // initialization
  this->GenerateEdges();
  this->GenerateFaces();
  this->ConstructPolyData();
  this->ComputeBounds();

  if (this->IntersectWithContour(value, 0, pointScalars))
  {
    return;
  }

  this->Internal->RemoveDuplicatedPointsFromFaceArrayAndEdgeTable(
    this->Points, this->Faces, this->EdgeTable, this->Bounds);

  vtkSmartPointer<vtkCellArray> contourPolys =
    vtkSmartPointer<vtkCellArray>::New();

  int ret = this->InternalContour(value, 0, locator, pointScalars,
                    NULL, inPd, outPd, contourPolys,
                    faceToPointsMap, pointToFacesMap, pointIdMap);
  if (ret != 0)
  {
    this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
    return;
  }

  vtkIdType npts = 0;
  vtkIdType *pts = 0;
  contourPolys->InitTraversal();
  while (contourPolys->GetNextCell(npts, pts))
  {
    if (!this->Internal->ConvertPointIds(npts, pts, pointIdMap))
    {
      vtkErrorMacro("Cannot find the id of an output point. We should never "
        "get here. Contouring aborted.");
      this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
      return;
    }

    vtkIdType newCellId = offset + polys->InsertNextCell(npts, pts);
    outCd->CopyData(inCd, cellId, newCellId);
  }

  this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
}

//----------------------------------------------------------------------------
void vtkPolyhedron::Clip(double value,
                         vtkDataArray *pointScalars,
                         vtkIncrementalPointLocator *locator,
                         vtkCellArray *connectivity,
                         vtkPointData *inPd, vtkPointData *outPd,
                         vtkCellData *inCd, vtkIdType cellId,
                         vtkCellData *outCd, int insideOut)
{
  vtkIdToIdVectorMapType faceToPointsMap;
  vtkIdToIdVectorMapType pointToFacesMap;
  vtkIdToIdMapType       pointIdMap; //local one, not this->PointIdMap
  vtkIdType newPid, newCellId;

  vtkIdType npts = 0;
  vtkIdType *pts = 0;

  // initialization
  this->GenerateEdges();
  this->GenerateFaces();
  this->ConstructPolyData();
  this->ComputeBounds();

  // vector to store cell connectivity
  vtkIdVectorType cellVector;

  // check if polyhedron is all in
  if (this->IntersectWithContour(value, insideOut, pointScalars) == 1)
  {
    cellVector.push_back(this->Faces->GetValue(0));

    // loop through all faces to add them into cellVector
    vtkPolyhedronFaceIterator
      faceIter(this->Faces->GetValue(0), this->Faces->GetPointer(1));
    while (faceIter.Id < faceIter.NumberOfPolygons)
    {
      vtkIdVectorType pids;
      for (vtkIdType i = 0; i < faceIter.CurrentPolygonSize; i++)
      {
        vtkIdType pid = faceIter.Current[i];
        if (locator->InsertUniquePoint(this->Points->GetPoint(pid), newPid))
        {
          vtkIdType globalPid = this->PointIds->GetId(pid);
          outPd->CopyData(inPd, globalPid, newPid);
        }
        pids.push_back(pid);
        pointIdMap.insert(vtkIdToIdPairType(pid, newPid));
      }

      npts = static_cast<vtkIdType>(pids.size());
      if (npts == 0)
      {
        ++faceIter;
        continue;
      }
      pts = &(pids[0]);
      if (!this->Internal->ConvertPointIds(npts, pts, pointIdMap))
      {
        vtkErrorMacro("Cannot find the id of an output point. We should never "
          "get here. Clipping aborted.");
        this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
        return;
      }
      cellVector.push_back(npts);
      cellVector.insert(cellVector.end(), pts, pts+npts);

      ++faceIter;
    }
    if (!cellVector.empty())
    {
      newCellId = connectivity->InsertNextCell(
        static_cast<vtkIdType>(cellVector.size()), &(cellVector[0]));
      outCd->CopyData(inCd, cellId, newCellId);
    }
    return;
  }

  this->Internal->RemoveDuplicatedPointsFromFaceArrayAndEdgeTable(
    this->Points, this->Faces, this->EdgeTable, this->Bounds);

  vtkSmartPointer<vtkDoubleArray> contourScalars =
    vtkSmartPointer<vtkDoubleArray>::New();
  vtkSmartPointer<vtkCellArray> contourPolys =
    vtkSmartPointer<vtkCellArray>::New();

  int ret = this->InternalContour(value, insideOut, locator, pointScalars,
                    contourScalars, inPd, outPd, contourPolys,
                    faceToPointsMap, pointToFacesMap, pointIdMap);

  // error occurs
  if (ret == -1)
  {
    this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
    return;
  }

  // polyhedron is all outside
  if (ret == 2)
  {
    this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
    return;
  }

  // polyhedron is all inside
  // FIXME: Documentation needed:
  // 1. How this can ever happen given the IntersectWithContour call above?
  // 2. If it can happen, how+why is it different than the code above that
  //    copies the cell to the output?
  if (ret == 1)
  {
    cellVector.push_back(this->Faces->GetValue(0));

    // loop through all faces to add them into cellVector
    vtkPolyhedronFaceIterator
      faceIter(this->Faces->GetValue(0), this->Faces->GetPointer(1));
    while (faceIter.Id < faceIter.NumberOfPolygons)
    {
      vtkIdVectorType pids;
      for (vtkIdType i = 0; i < faceIter.CurrentPolygonSize; i++)
      {
        vtkIdType pid = faceIter.Current[i];
        if (locator->InsertUniquePoint(this->Points->GetPoint(pid), newPid))
        {
          vtkIdType globalPid = this->PointIds->GetId(pid);
          outPd->CopyData(inPd, globalPid, newPid);
        }
        pids.push_back(pid);
        pointIdMap.insert(vtkIdToIdPairType(pid, newPid));
      }

      npts = static_cast<vtkIdType>(pids.size());
      if (npts == 0)
      {
        if (faceIter.Id < faceIter.NumberOfPolygons - 1)
        {
          ++faceIter;
          continue;
        }
        else
        {
          break;
        }
      }
      pts = &(pids[0]);
      if (!this->Internal->ConvertPointIds(npts, pts, pointIdMap))
      {
        vtkErrorMacro("Cannot find the id of an output point. We should never "
          "get here. Clipping aborted.");
        this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
        return;
      }
      cellVector.push_back(npts);
      cellVector.insert(cellVector.end(), pts, pts+npts);

      ++faceIter;
    }
    if (!cellVector.empty())
    {
      newCellId = connectivity->InsertNextCell(
        static_cast<vtkIdType>(cellVector.size()), &(cellVector[0]));
      outCd->CopyData(inCd, cellId, newCellId);
    }
    this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
    return;
  }

  // prepare visited array for all faces
  bool* visited = new bool [this->Faces->GetValue(0)];
  for (int i = 0; i < this->Faces->GetValue(0); i++)
  {
    visited[i] = false;
  }

  // make the valueTolerance dependent on the range of
  // values that is being contoured
  double vMin(DBL_MAX), vMax(-DBL_MAX);
  for (vtkIdType pid = 0; pid < this->Points->GetNumberOfPoints(); ++pid)
  {
    double v = contourScalars->GetComponent(pid,0);
    vMin = std::min(vMin, v);
    vMax = std::max(vMax, v);
  }

  double valueTolerance = std::min(1e-6, 1e-6*(vMax - vMin));

  // Main algorithm: go through all positive points (points on the right side
  // of the contour).  These do not include contour points.
  // For each point on the right side, find all of its adjacent faces. There
  // maybe two types of faces, (1) faces with all positive points, or
  // (2) faces with positive negative and contour points. For case (1), we will
  // keep the original face and add it into the result polyhedron. For case (2),
  // we will subdivide the original face, and add the subface that includes
  // positive points into the result polyhedron.
  std::vector<vtkIdVectorType> faces;
  vtkIdToIdVectorMapIteratorType pfMapIt, fpMapIt;
  for (vtkIdType pid = 0; pid < this->Points->GetNumberOfPoints(); pid++)
  {
    // find if a point is a positive point
    double v = contourScalars->GetComponent(pid,0);
    if ( (insideOut && (v > value-valueTolerance)) || ((!insideOut) && (v < value+valueTolerance)) )
    {
      continue;
    }

    // find adjacent faces of the positive point
    pfMapIt = pointToFacesMap.find(pid);
    if (pfMapIt == pointToFacesMap.end())
    {
      continue;
    }
    vtkIdVectorType fids = pfMapIt->second;

    // for each adjacent face
    for (size_t i = 0; i < fids.size(); i++)
    {
      vtkIdType fid = fids[i];
      if (visited[fid])
      {
        continue;
      }

      fpMapIt = faceToPointsMap.find(fid);
      if (fpMapIt == faceToPointsMap.end())
      {
        vtkErrorMacro("Cannot locate points on a face. We should "
          "never get here. Clipping continues but may generate wrong result.");
        continue;
      }
      vtkIdVectorType pids = fpMapIt->second;
      vtkIdType numFacePoints = static_cast<vtkIdType>(pids.size());

      // locate the positive point inside the id vector.
      vtkIdType positivePt = -1;
      for (vtkIdType j = 0; j < numFacePoints; j++)
      {
        if (pid == pids[j])
        {
          positivePt = j;
          break;
        }
      }

      // positive point not found: this can happen when the current face
      // has been partially visited before, and some points have been removed from
      // its point vector.
      if (positivePt < 0 || positivePt >= numFacePoints)
      {
        continue;
      }

      // a new id vector to hold ids of points on new surface patch
      vtkIdVectorType newpids;
      newpids.push_back(pid);

      // step through the ajacent points on both sides of the positive point.
      // stop when a contour point or a negative point is hit.
      bool startFound = false;
      bool endFound = false;

      vtkIdType startPt = positivePt - 1;
      vtkIdType endPt = positivePt + 1;
      for (vtkIdType k = 0; k < numFacePoints; k++)
      {
        if (startFound && endFound)
        {
          break;
        }

        if (!startFound)
        {
          if (startPt < 0)
          {
            startPt = numFacePoints - 1;
          }

          newpids.insert(newpids.begin(), pids[startPt]);
          v = contourScalars->GetComponent(pids[startPt],0);
          if ((insideOut && (v > value-valueTolerance)) || ((!insideOut) && (v < value+valueTolerance)))
          {
            startFound = true;
            if ((insideOut && (v > value+valueTolerance)) || ((!insideOut) && (v < value-valueTolerance)))
            {
              vtkWarningMacro("A positive point is directly connected to a "
                "negative point with no contour point in between. We should "
                "never get here.");
              if (startPt == numFacePoints-1)
              {
                startPt = 0;
              }
              else
              {
                startPt++;
              }
              newpids.erase(newpids.begin());
            }
          }
          else
          {
            startPt--;
          }
        }

        if (!endFound)
        {
          if (endPt > numFacePoints - 1)
          {
            endPt = 0;
          }

          newpids.push_back(pids[endPt]);
          v = contourScalars->GetComponent(pids[endPt],0);
          if ((insideOut && (v > value-valueTolerance)) || ((!insideOut) && (v < value+valueTolerance)))
          {
            endFound = true;
            if ((insideOut && (v > value+valueTolerance)) || ((!insideOut) && (v < value-valueTolerance)))
            {
              vtkWarningMacro("A positive point is directly connected to a "
                "negative point with no contour point in between. We should "
                "never get here.");
              if (endPt == 0)
              {
                endPt = numFacePoints-1;
              }
              else
              {
                endPt--;
              }
              newpids.pop_back();
            }
          }
          else
          {
            endPt++;
          }
        }
      }// end inner for loop for finding start and end points

      // if face are entirely positive, add it directly into the face list
      if (!startFound && !endFound)
      {
        visited[fid] = true;
        faces.push_back(pids);
      }

      // if face contain contour points
      else if (startFound && endFound)
      {
        // a point or a line
        if (newpids.size() < 3)
        {
          visited[fid] = true;
        }
        // if face only contains one contour point, this is a special case that
        // may only happen when one of the original vertex is a contour point.
        // we will add this face to the result polyhedron.
        else if (startPt == endPt)
        {
          visited[fid] = true;
          faces.push_back(pids);
        }
        // Face contain at least two contour points. In this case, we will create
        // a new face patch whose close boundary is start point -->contour point
        // --> end point --> start point. Notice that the face may contain other
        // positive points and contour points. So we will not label the face as
        // visited. Instead, we will erase the chunk from start point to end
        // point from the point id vector of the face. So that the other part
        // can still be visited in the future.
        else
        {
          if (!this->Internal->EraseSegmentFromIdVector(
                     pids, positivePt, startPt, endPt))
          {
            vtkErrorMacro("Erase segment from Id vector failed. We should "
              "never get here.");
            visited[fid] = true;
            continue;
          }
          if (pids.size()<=2) // all but two contour points are left
          {
            pids.clear();
            visited[fid] = true;
          }
          fpMapIt->second = pids;
          faces.push_back(newpids);
        }
      }

      // only find start or only find end. this should never happen
      else
      {
        visited[fid] = true;
        vtkErrorMacro("We should never get here. Locating contour points failed. "
          "Clipping continues but may generate wrong result.");
      }
    } // end for each face

  } // end for_pid

  delete [] visited;

  // not a valid output when the clip plane passes through the cell boundary
  // faces.
  if (faces.empty())
  {
    this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
    return;
  }

  vtkIdType numAllFaces = contourPolys->GetNumberOfCells() +
                          static_cast<vtkIdType>(faces.size());
  cellVector.push_back(numAllFaces);

  // add contour faces
  contourPolys->InitTraversal();
  while (contourPolys->GetNextCell(npts, pts))
  {
    if (!this->Internal->ConvertPointIds(npts, pts, pointIdMap, insideOut))
    {
      vtkErrorMacro("Cannot find the id of an output point. We should never "
        "get here. Clipping aborted.");
      this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
      return;
    }
    cellVector.push_back(npts);
    cellVector.insert(cellVector.end(), pts, pts+npts);
  }

  // add other faces
  for (size_t i = 0; i < faces.size(); i++)
  {
    vtkIdVectorType pids = faces[i];
    for (size_t j = 0; j < pids.size(); j++)
    {
      vtkIdType pid = pids[j];
      vtkIdToIdMapType::iterator iter = pointIdMap.find(pid);
      if (iter == pointIdMap.end()) // must be original points
      {
        if (locator->InsertUniquePoint(this->Points->GetPoint(pid), newPid))
        {
          vtkIdType globalPid = this->PointIds->GetId(pid);
          outPd->CopyData(inPd, globalPid, newPid);
        }
        pointIdMap.insert(vtkIdToIdPairType(pid, newPid));
      }
    }

    npts = static_cast<vtkIdType>(pids.size());
    pts = &(pids[0]);
    if (!this->Internal->ConvertPointIds(npts, pts, pointIdMap))
    {
      vtkErrorMacro("Cannot find the id of an output point. We should never "
        "get here. Clipping aborted.");
      this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
      return;
    }
    cellVector.push_back(npts);
    cellVector.insert(cellVector.end(), pts, pts+npts);
  }

  newCellId = connectivity->InsertNextCell(
    static_cast<vtkIdType>(cellVector.size()), &(cellVector[0]));
  outCd->CopyData(inCd, cellId, newCellId);

  this->Internal->RestoreFaceArrayAndEdgeTable(this->Faces, this->EdgeTable);
}

//----------------------------------------------------------------------------
void vtkPolyhedron::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Triangle:\n";
  this->Triangle->PrintSelf(os,indent.GetNextIndent());

  os << indent << "Polygon:\n";
  this->Polygon->PrintSelf(os,indent.GetNextIndent());

  os << indent << "Tetra:\n";
  this->Tetra->PrintSelf(os,indent.GetNextIndent());

  os << indent << "Faces:\n";
  this->GlobalFaces->PrintSelf(os,indent.GetNextIndent());

}
