// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-FileCopyrightText: Copyright (c) Sandia Corporation
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkBoxClipDataSet.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkExecutive.h"
#include "vtkFloatArray.h"
#include "vtkGenericCell.h"
#include "vtkIdList.h"
#include "vtkImageData.h"
#include "vtkIncrementalPointLocator.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkMergePoints.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkUnsignedCharArray.h"
#include "vtkUnstructuredGrid.h"

#include <cmath>
#include <vector>

VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkBoxClipDataSet);
vtkCxxSetObjectMacro(vtkBoxClipDataSet, Locator, vtkIncrementalPointLocator);
//------------------------------------------------------------------------------
vtkBoxClipDataSet::vtkBoxClipDataSet()
{
  this->Locator = nullptr;
  this->GenerateClipScalars = 0;

  this->GenerateClippedOutput = 0;
  // this->MergeTolerance = 0.01;

  this->SetNumberOfOutputPorts(2);

  this->Orientation = 1;

  this->PlaneNormal[0][0] = -1.0;
  this->PlaneNormal[0][1] = 0.0;
  this->PlaneNormal[0][2] = 0.0;

  this->PlaneNormal[1][0] = 1.0;
  this->PlaneNormal[1][1] = 0.0;
  this->PlaneNormal[1][2] = 0.0;

  this->PlaneNormal[2][0] = 0.0;
  this->PlaneNormal[2][1] = -1.0;
  this->PlaneNormal[2][2] = 0.0;

  this->PlaneNormal[3][0] = 0.0;
  this->PlaneNormal[3][1] = 1.0;
  this->PlaneNormal[3][2] = 0.0;

  this->PlaneNormal[4][0] = 0.0;
  this->PlaneNormal[4][1] = 0.0;
  this->PlaneNormal[4][2] = -1.0;

  this->PlaneNormal[5][0] = 0.0;
  this->PlaneNormal[5][1] = 0.0;
  this->PlaneNormal[5][2] = 1.0;

  this->PlanePoint[0][0] = 0.0;
  this->PlanePoint[0][1] = 0.0;
  this->PlanePoint[0][2] = 0.0;

  this->PlanePoint[1][0] = 1.0;
  this->PlanePoint[1][1] = 0.0;
  this->PlanePoint[1][2] = 0.0;

  this->PlanePoint[2][0] = 0.0;
  this->PlanePoint[2][1] = 0.0;
  this->PlanePoint[2][2] = 0.0;

  this->PlanePoint[3][0] = 0.0;
  this->PlanePoint[3][1] = 1.0;
  this->PlanePoint[3][2] = 0.0;

  this->PlanePoint[4][0] = 0.0;
  this->PlanePoint[4][1] = 0.0;
  this->PlanePoint[4][2] = 0.0;

  this->PlanePoint[5][0] = 0.0;
  this->PlanePoint[5][1] = 0.0;
  this->PlanePoint[5][2] = 1.0;

  int i = 0;
  while (i < 3)
  {
    this->BoundBoxClip[i][0] = 0.0;
    this->BoundBoxClip[i][1] = 1.0;
    ++i;
  }

  // by default process active point scalars
  this->SetInputArrayToProcess(
    0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS);
}

//------------------------------------------------------------------------------
vtkBoxClipDataSet::~vtkBoxClipDataSet()
{
  this->SetLocator(nullptr);
}

//------------------------------------------------------------------------------
// Do not say we have two outputs unless we are generating the clipped output.
int vtkBoxClipDataSet::GetNumberOfOutputs()
{
  if (this->GenerateClippedOutput)
  {
    return 2;
  }
  return 1;
}

//------------------------------------------------------------------------------
// Overload standard modified time function. If Clip functions is modified,
// then this object is modified as well.
vtkMTimeType vtkBoxClipDataSet::GetMTime()
{
  vtkMTimeType mTime = this->Superclass::GetMTime();
  vtkMTimeType time;

  if (this->Locator != nullptr)
  {
    time = this->Locator->GetMTime();
    mTime = (time > mTime ? time : mTime);
  }

  return mTime;
}

//------------------------------------------------------------------------------
vtkUnstructuredGrid* vtkBoxClipDataSet::GetClippedOutput()
{
  if (this->GetNumberOfOutputPorts() < 2)
  {
    return nullptr;
  }

  return vtkUnstructuredGrid::SafeDownCast(this->GetExecutive()->GetOutputData(1));
}

//------------------------------------------------------------------------------
//
// Clip by box
//
int vtkBoxClipDataSet::RequestData(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector, vtkInformationVector* outputVector)
{
  // get the info objects
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation* outInfo = outputVector->GetInformationObject(0);

  // get the input and output
  vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkUnstructuredGrid* output =
    vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkUnstructuredGrid* clippedOutput = this->GetClippedOutput();

  vtkIdType i;
  vtkIdType npts;
  const vtkIdType* pts;
  vtkIdType estimatedSize;
  vtkIdType newCellId;
  vtkIdType numPts = input->GetNumberOfPoints();
  vtkIdType numCells = input->GetNumberOfCells();
  vtkPointData* inPD = input->GetPointData();
  vtkPointData* outPD[2];
  vtkCellData* inCD = input->GetCellData();
  vtkCellData* outCD[2];
  vtkPoints* newPoints;
  vtkPoints* cellPts;
  vtkDebugMacro(<< "Clip by Box\n");
  vtkUnsignedCharArray* types[2];

  int j;
  int cellType = 0;
  int numOutputs = 1;

  // Initialize self; create output objects
  //
  if (numPts < 1)
  {
    vtkDebugMacro(<< "No data to clip");
    return 1;
  }

  // allocate the output and associated helper classes
  estimatedSize = numCells;
  estimatedSize = estimatedSize / 1024 * 1024; // multiple of 1024
  estimatedSize = std::max<vtkIdType>(estimatedSize, 1024);
  vtkCellArray* conn[2];
  conn[0] = vtkCellArray::New();
  conn[0]->AllocateEstimate(estimatedSize, 1);
  conn[0]->InitTraversal();
  types[0] = vtkUnsignedCharArray::New();
  types[0]->Allocate(estimatedSize, estimatedSize / 2);

  if (this->GenerateClippedOutput)
  {
    numOutputs = 2;
    conn[1] = vtkCellArray::New();
    conn[1]->AllocateEstimate(estimatedSize, 1);
    conn[1]->InitTraversal();
    types[1] = vtkUnsignedCharArray::New();
    types[1]->Allocate(estimatedSize, estimatedSize / 2);
  }

  newPoints = vtkPoints::New();
  newPoints->Allocate(numPts, numPts / 2);

  // locator used to merge potentially duplicate points
  if (this->Locator == nullptr)
  {
    this->CreateDefaultLocator();
  }
  this->Locator->InitPointInsertion(newPoints, input->GetBounds());

  outPD[0] = output->GetPointData();
  if (this->GenerateClippedOutput)
  {
    outPD[1] = output->GetPointData();
  }

  vtkDataArray* scalars = this->GetInputArrayToProcess(0, inputVector);
  if (!this->GenerateClipScalars && !scalars)
  {
    outPD[0]->CopyScalarsOff();
    if (this->GenerateClippedOutput)
    {
      outPD[1]->CopyScalarsOff();
    }
  }
  else
  {
    outPD[0]->CopyScalarsOn();
    if (this->GenerateClippedOutput)
    {
      outPD[1]->CopyScalarsOn();
    }
  }
  outPD[0]->InterpolateAllocate(inPD, estimatedSize, estimatedSize / 2);
  outCD[0] = output->GetCellData();
  outCD[0]->CopyAllocate(inCD, estimatedSize, estimatedSize / 2);
  if (this->GenerateClippedOutput)
  {
    outPD[1] = clippedOutput->GetPointData();
    outPD[1]->InterpolateAllocate(inPD, estimatedSize, estimatedSize / 2);
    outCD[1] = clippedOutput->GetCellData();
    outCD[1]->CopyAllocate(inCD, estimatedSize, estimatedSize / 2);
  }

  // Process all cells and clip each in turn

  vtkIdType updateTime = numCells / 20 + 1; // update roughly every 5%
  vtkGenericCell* cell = vtkGenericCell::New();
  vtkIdType cellId;

  bool abort = false;
  int num[2];
  int numNew[2];

  num[0] = num[1] = 0;
  numNew[0] = numNew[1] = 0;

  unsigned int orientation = this->GetOrientation(); // Test if there is a transformation

  // clock_t init_tmp = clock();
  for (cellId = 0; cellId < numCells && !abort; cellId++)
  {
    if (!(cellId % updateTime))
    {
      this->UpdateProgress(static_cast<float>(cellId) / numCells);
      abort = this->CheckAbort();
    }

    input->GetCell(cellId, cell);
    cellPts = cell->GetPoints();
    npts = cellPts->GetNumberOfPoints();

    if (this->GenerateClippedOutput)
    {
      if ((cell->GetCellDimension()) == 3)
      {
        if (orientation)
        {
          this->ClipHexahedronInOut(
            newPoints, cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        else
        {
          this->ClipBoxInOut(
            newPoints, cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }

        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        numNew[1] = conn[1]->GetNumberOfCells() - num[1];
        num[0] = conn[0]->GetNumberOfCells();
        num[1] = conn[1]->GetNumberOfCells();
      }
      else if ((cell->GetCellDimension()) == 2)
      {
        if (orientation)
        {
          this->ClipHexahedronInOut2D(
            newPoints, cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        else
        {
          this->ClipBoxInOut2D(
            newPoints, cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        numNew[1] = conn[1]->GetNumberOfCells() - num[1];
        num[0] = conn[0]->GetNumberOfCells();
        num[1] = conn[1]->GetNumberOfCells();
      }
      else if (cell->GetCellDimension() == 1)
      {
        if (orientation)
        {
          this->ClipHexahedronInOut1D(
            newPoints, cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        else
        {
          this->ClipBoxInOut1D(
            newPoints, cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        numNew[1] = conn[1]->GetNumberOfCells() - num[1];
        num[0] = conn[0]->GetNumberOfCells();
        num[1] = conn[1]->GetNumberOfCells();
      }
      else if (cell->GetCellDimension() == 0)
      {
        if (orientation)
        {
          this->ClipHexahedronInOut0D(cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        else
        {
          this->ClipBoxInOut0D(cell, this->Locator, conn, inPD, outPD, inCD, cellId, outCD);
        }
        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        numNew[1] = conn[1]->GetNumberOfCells() - num[1];
        num[0] = conn[0]->GetNumberOfCells();
        num[1] = conn[1]->GetNumberOfCells();
      }
      else
      {
        vtkErrorMacro(<< "Do not support cells of dimension " << cell->GetCellDimension());
      }
    }
    else
    {
      if ((cell->GetCellDimension()) == 3)
      {
        if (orientation)
        {
          this->ClipHexahedron(
            newPoints, cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        else
        {
          this->ClipBox(
            newPoints, cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }

        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        num[0] = conn[0]->GetNumberOfCells();
      }
      else if ((cell->GetCellDimension()) == 2)
      {
        if (orientation)
        {
          this->ClipHexahedron2D(
            newPoints, cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        else
        {
          this->ClipBox2D(
            newPoints, cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        num[0] = conn[0]->GetNumberOfCells();
      }
      else if (cell->GetCellDimension() == 1)
      {
        if (orientation)
        {
          this->ClipHexahedron1D(
            newPoints, cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        else
        {
          this->ClipBox1D(
            newPoints, cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        num[0] = conn[0]->GetNumberOfCells();
      }
      else if (cell->GetCellDimension() == 0)
      {
        if (orientation)
        {
          this->ClipHexahedron0D(
            cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        else
        {
          this->ClipBox0D(cell, this->Locator, conn[0], inPD, outPD[0], inCD, cellId, outCD[0]);
        }
        numNew[0] = conn[0]->GetNumberOfCells() - num[0];
        num[0] = conn[0]->GetNumberOfCells();
      }
      else
      {
        vtkErrorMacro(<< "Do not support cells of dimension " << cell->GetCellDimension());
      }
    }

    for (i = 0; i < numOutputs; i++) // for both outputs
    {
      for (j = 0; j < numNew[i]; j++)
      {
        conn[i]->GetNextCell(npts, pts);

        // For each new cell added, got to set the type of the cell
        switch (cell->GetCellDimension())
        {
          case 0: // points are generated-------------------------------
            cellType = (npts > 1 ? VTK_POLY_VERTEX : VTK_VERTEX);
            break;

          case 1: // lines are generated----------------------------------
            cellType = (npts > 2 ? VTK_POLY_LINE : VTK_LINE);
            break;

          case 2: // polygons are generated------------------------------
                  // NOLINTNEXTLINE(readability-avoid-nested-conditional-operator)
            cellType = (npts == 3 ? VTK_TRIANGLE : (npts == 4 ? VTK_QUAD : VTK_POLYGON));
            break;

          case 3: // tetrahedra are generated------------------------------
            cellType = VTK_TETRA;
            break;
        } // switch

        newCellId = types[i]->InsertNextValue(cellType);
        outCD[i]->CopyData(inCD, cellId, newCellId);
      } // for each new cell
    }   // for both outputs
  }     // for each cell

  cell->Delete();

  output->SetPoints(newPoints);
  output->SetCells(types[0], conn[0]);

  conn[0]->Delete();
  types[0]->Delete();

  if (this->GenerateClippedOutput)
  {
    clippedOutput->SetPoints(newPoints);
    clippedOutput->SetCells(types[1], conn[1]);
    conn[1]->Delete();
    types[1]->Delete();
  }
  newPoints->Delete();
  this->Locator->Initialize(); // release any extra memory
  output->Squeeze();

  return 1;
}

//------------------------------------------------------------------------------
// Specify a spatial locator for merging points. By default,
// an instance of vtkMergePoints is used.
void vtkBoxClipDataSet::CreateDefaultLocator()
{
  if (this->Locator == nullptr)
  {
    this->Locator = vtkMergePoints::New();
    this->Locator->Register(this);
    this->Locator->Delete();
  }
}

//------------------------------------------------------------------------------
// Set the box for clipping
// for each plane, specify the normal and one vertex on the plane.
//
void vtkBoxClipDataSet::SetBoxClip(const double* n0, const double* o0, const double* n1,
  const double* o1, const double* n2, const double* o2, const double* n3, const double* o3,
  const double* n4, const double* o4, const double* n5, const double* o5)
{
  if ((this->Orientation == 1)

    && (this->PlaneNormal[0][0] == n0[0]) && (this->PlaneNormal[0][1] == n0[1]) &&
    (this->PlaneNormal[0][2] == n0[2])

    && (this->PlaneNormal[1][0] == n1[0]) && (this->PlaneNormal[1][1] == n1[1]) &&
    (this->PlaneNormal[1][2] == n1[2])

    && (this->PlaneNormal[2][0] == n2[0]) && (this->PlaneNormal[2][1] == n2[1]) &&
    (this->PlaneNormal[2][2] == n2[2])

    && (this->PlaneNormal[3][0] == n3[0]) && (this->PlaneNormal[3][1] == n3[1]) &&
    (this->PlaneNormal[3][2] == n3[2])

    && (this->PlaneNormal[4][0] == n4[0]) && (this->PlaneNormal[4][1] == n4[1]) &&
    (this->PlaneNormal[4][2] == n4[2])

    && (this->PlaneNormal[5][0] == n5[0]) && (this->PlaneNormal[5][1] == n5[1]) &&
    (this->PlaneNormal[5][2] == n5[2])

    && (this->PlanePoint[0][0] == o0[0]) && (this->PlanePoint[0][1] == o0[1]) &&
    (this->PlanePoint[0][2] == o0[2])

    && (this->PlanePoint[1][0] == o1[0]) && (this->PlanePoint[1][1] == o1[1]) &&
    (this->PlanePoint[1][2] == o1[2])

    && (this->PlanePoint[2][0] == o2[0]) && (this->PlanePoint[2][1] == o2[1]) &&
    (this->PlanePoint[2][2] == o2[2])

    && (this->PlanePoint[3][0] == o3[0]) && (this->PlanePoint[3][1] == o3[1]) &&
    (this->PlanePoint[3][2] == o3[2])

    && (this->PlanePoint[4][0] == o4[0]) && (this->PlanePoint[4][1] == o4[1]) &&
    (this->PlanePoint[4][2] == o4[2])

    && (this->PlanePoint[5][0] == o5[0]) && (this->PlanePoint[5][1] == o5[1]) &&
    (this->PlanePoint[5][2] == o5[2]))
  {
    return;
  }

  this->SetOrientation(1);

  this->PlaneNormal[0][0] = n0[0];
  this->PlaneNormal[0][1] = n0[1];
  this->PlaneNormal[0][2] = n0[2];

  this->PlaneNormal[1][0] = n1[0];
  this->PlaneNormal[1][1] = n1[1];
  this->PlaneNormal[1][2] = n1[2];

  this->PlaneNormal[2][0] = n2[0];
  this->PlaneNormal[2][1] = n2[1];
  this->PlaneNormal[2][2] = n2[2];

  this->PlaneNormal[3][0] = n3[0];
  this->PlaneNormal[3][1] = n3[1];
  this->PlaneNormal[3][2] = n3[2];

  this->PlaneNormal[4][0] = n4[0];
  this->PlaneNormal[4][1] = n4[1];
  this->PlaneNormal[4][2] = n4[2];

  this->PlaneNormal[5][0] = n5[0];
  this->PlaneNormal[5][1] = n5[1];
  this->PlaneNormal[5][2] = n5[2];

  this->PlanePoint[0][0] = o0[0];
  this->PlanePoint[0][1] = o0[1];
  this->PlanePoint[0][2] = o0[2];

  this->PlanePoint[1][0] = o1[0];
  this->PlanePoint[1][1] = o1[1];
  this->PlanePoint[1][2] = o1[2];

  this->PlanePoint[2][0] = o2[0];
  this->PlanePoint[2][1] = o2[1];
  this->PlanePoint[2][2] = o2[2];

  this->PlanePoint[3][0] = o3[0];
  this->PlanePoint[3][1] = o3[1];
  this->PlanePoint[3][2] = o3[2];

  this->PlanePoint[4][0] = o4[0];
  this->PlanePoint[4][1] = o4[1];
  this->PlanePoint[4][2] = o4[2];

  this->PlanePoint[5][0] = o5[0];
  this->PlanePoint[5][1] = o5[1];
  this->PlanePoint[5][2] = o5[2];

  this->Modified();
}

//------------------------------------------------------------------------------
// Specify the bounding box for clipping

void vtkBoxClipDataSet::SetBoxClip(
  double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
{
  if ((this->Orientation == 0) && (this->BoundBoxClip[0][0] == xmin) &&
    (this->BoundBoxClip[0][1] == xmax) && (this->BoundBoxClip[1][0] == ymin) &&
    (this->BoundBoxClip[1][1] == ymax) && (this->BoundBoxClip[2][0] == zmin) &&
    (this->BoundBoxClip[2][1] == zmax))
  {
    return;
  }

  this->SetOrientation(0);
  this->BoundBoxClip[0][0] = xmin;
  this->BoundBoxClip[0][1] = xmax;
  this->BoundBoxClip[1][0] = ymin;
  this->BoundBoxClip[1][1] = ymax;
  this->BoundBoxClip[2][0] = zmin;
  this->BoundBoxClip[2][1] = zmax;

  this->Modified();
}

//------------------------------------------------------------------------------
int vtkBoxClipDataSet::FillInputPortInformation(int, vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
  return 1;
}

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

  // os << indent << "Merge Tolerance: " << this->MergeTolerance << "\n";
  os << indent << "Orientation: " << this->Orientation << "\n";

  if (this->Locator)
  {
    os << indent << "Locator: " << this->Locator << "\n";
  }
  else
  {
    os << indent << "Locator: (none)\n";
  }

  os << indent << "Generate Clipped Output: " << (this->GenerateClippedOutput ? "Yes\n" : "Off\n");
  os << indent << "Generate Clip Scalars: " << (this->GenerateClipScalars ? "On\n" : "Off\n");
}

//------------------------------------------------------------------------------
// InterpolateEdge: Interpolate the data in a vtkDataSetAttributes along a line
//
// This method works very much like vtkDataSetAttributes::InterpolateEdge
// except that rather than take the interpolation information from an
// input and copy it to an output, the values to interpolate are already
// placed in the output arrays.  This is necessary because vtkBoxClipDataSet
// will continually cut (and consequently interpolate) the input until it
// fits within the bounds.
void vtkBoxClipDataSet::InterpolateEdge(
  vtkDataSetAttributes* attributes, vtkIdType toId, vtkIdType fromId1, vtkIdType fromId2, double t)
{
  int numArrays = attributes->GetNumberOfArrays();
  for (int i = 0; i < numArrays; i++)
  {
    vtkAbstractArray* array = attributes->GetAbstractArray(i);

    // We are ignoring any special interpolate flags (such as nearest neighbor
    // interpolation).  That kind of interpolation is not linear and could be
    // incorrect when multiple cuts are performed on the same primitive (which
    // can happen).

    array->InterpolateTuple(toId, fromId1, array, fromId2, array, t);
  }
}

//------------------------------------------------------------------------------
// CellGrid: Subdivide cells in consistent tetrahedra.
// Case : Voxel(11) or Hexahedron(12).
//
// MinEdgF search the smallest vertex index in linear order of a face(4 vertices)
//
void vtkBoxClipDataSet::MinEdgeF(
  const unsigned int* id_v, const vtkIdType* cellIds, unsigned int* edgF)
{

  int i;
  unsigned int id;
  int ids;
  int min_f;

  ids = 0;
  id = id_v[0]; // Face index
  min_f = cellIds[id_v[0]];

  for (i = 1; i < 4; i++)
  {
    if (min_f > cellIds[id_v[i]])
    {
      min_f = cellIds[id_v[i]];
      id = id_v[i];
      ids = i;
    }
  }

  switch (ids)
  {
    case 0:
      if (id < id_v[2])
      {
        edgF[0] = id;
        edgF[1] = id_v[2];
      }
      else
      {
        edgF[0] = id_v[2];
        edgF[1] = id;
      }
      break;
    case 1:
      if (id < id_v[3])
      {
        edgF[0] = id;
        edgF[1] = id_v[3];
      }
      else
      {
        edgF[0] = id_v[3];
        edgF[1] = id;
      }
      break;
    case 2:
      if (id < id_v[0])
      {
        edgF[0] = id;
        edgF[1] = id_v[0];
      }
      else
      {
        edgF[0] = id_v[0];
        edgF[1] = id;
      }
      break;
    case 3:
      if (id < id_v[1])
      {
        edgF[0] = id;
        edgF[1] = id_v[1];
      }
      else
      {
        edgF[0] = id_v[1];
        edgF[1] = id;
      }
      break;
  }
}

//------------------------------------------------------------------------------
// CellGrid: Subdivide cells in consistent tetrahedra.
//
// Case : Voxel or Hexahedron:
//       if ( subdivide voxel in 6 tetrahedra)
//           voxel : 2 wedges (*)
//       else
//           voxel : 5 tetrahedra
//
// Case : Wedge (*)
//
// ------------------------------------------------
//
//(*) WedgeToTetra: subdivide one wedge in 3 tetrahedra
//
//        wedge : 1 tetrahedron + 1 pyramid = 3 tetrahedra.
//
void vtkBoxClipDataSet::WedgeToTetra(
  const vtkIdType* wedgeId, const vtkIdType* cellIds, vtkCellArray* newCellArray)
{
  int i;
  int id;
  vtkIdType xmin;
  vtkIdType tab[4];
  vtkIdType tabpyram[5];

  constexpr vtkIdType vwedge[6][4] = {
    { 0, 4, 3, 5 },
    { 1, 4, 3, 5 },
    { 2, 4, 3, 5 },
    { 3, 0, 1, 2 },
    { 4, 0, 1, 2 },
    { 5, 0, 1, 2 },
  };

  // the table 'vwedge' set 6 possibilities of the smallest index
  //
  //             v5
  //             /\       .
  //         v3 /..\ v4
  //           /   /
  //        v2/\  /
  //       v0/__\/v1
  //   if(v0 index ) is the smallest index:
  //   wedge is subdivided in:
  //         1 tetrahedron-> vwedge[0]: {v0,v4,v3,v5}
  //     and 1 pyramid    -> vert[0]  : {v1,v2,v5,v4,v0}
  //

  id = 0;
  xmin = cellIds[wedgeId[0]];
  for (i = 1; i < 6; i++)
  {
    if (xmin > cellIds[wedgeId[i]])
    {
      xmin = cellIds[wedgeId[i]]; // the smallest global index
      id = i;                     // local index
    }
  }
  for (i = 0; i < 4; i++)
  {
    tab[i] = wedgeId[vwedge[id][i]];
  }
  newCellArray->InsertNextCell(4, tab);

  // Pyramid :create 2 tetrahedra
  constexpr vtkIdType vert[6][5] = {
    { 1, 2, 5, 4, 0 },
    { 2, 0, 3, 5, 1 },
    { 3, 0, 1, 4, 2 },
    { 1, 2, 5, 4, 3 },
    { 2, 0, 3, 5, 4 },
    { 3, 0, 1, 4, 5 },
  };
  for (i = 0; i < 5; i++)
  {
    tabpyram[i] = wedgeId[vert[id][i]];
  }
  this->PyramidToTetra(tabpyram, cellIds, newCellArray);
}

//------------------------------------------------------------------------------
// CellGrid: Subdivide cells in consistent tetrahedra.
//
// PyramidToTetra :Subdivide the pyramid in consistent tetrahedra.
//        Pyramid : 2 tetrahedra.
//
void vtkBoxClipDataSet::PyramidToTetra(
  const vtkIdType* pyramId, const vtkIdType* cellIds, vtkCellArray* newCellArray)
{
  vtkIdType xmin;
  unsigned int i, j, idpy;
  vtkIdType tab[4];

  // the table 'vpy' set 3 possibilities of the smallest index
  // vertices{v0,v1,v2,v3,v4}. {v0,v1,v2,v3} is a square face of pyramid
  //
  //                v4
  //                ^
  //
  //
  //           v3 _ _ __ _  v2
  //           /         /
  //        v0/_ _ _ _ _/v1
  //
  //   if(v0 index ) is the smallest index:
  //   the pyramid is subdivided in:
  //         2 tetrahedra-> vpy[0]: {v0,v1,v2,v4}
  //                        vpy[1]: {v0,v2,v3,v4}
  //
  constexpr vtkIdType vpy[8][4] = {
    { 0, 1, 2, 4 },
    { 0, 2, 3, 4 },
    { 1, 2, 3, 4 },
    { 1, 3, 0, 4 },
    { 2, 3, 0, 4 },
    { 2, 0, 1, 4 },
    { 3, 0, 1, 4 },
    { 3, 1, 2, 4 },
  };

  xmin = cellIds[pyramId[0]];
  idpy = 0;
  for (i = 1; i < 4; i++)
  {
    if (xmin > cellIds[pyramId[i]])
    {
      xmin = cellIds[pyramId[i]]; // global index
      idpy = i;                   // local index
    }
  }
  for (j = 0; j < 4; j++)
  {
    tab[j] = pyramId[vpy[2 * idpy][j]];
  }
  newCellArray->InsertNextCell(4, tab);

  for (j = 0; j < 4; j++)
  {
    tab[j] = pyramId[vpy[2 * idpy + 1][j]];
  }
  newCellArray->InsertNextCell(4, tab);
}

//------------------------------------------------------------------------------
// Tetra Grid : Subdivide cells in  consistent tetrahedra.
//             For each cell, search the smallest global index.
//
//  Case Tetrahedron(10): Just insert this cell in the newCellArray
//
//  Case Voxel(11) or Hexahedron(12):
//       - for each face: looking for the diagonal edge with the smallest index
//       - 2 possibilities: subdivide a cell in 5 or 6 tetrahedra
//
//         (I)Case 6 tetrahedra:
//                  - 6 possibilities: subdivide de cell in 2 wedges:
//                   (1) diagonal edges (v0,v5),(v2,v7)
//                       vwedge[0]={0,5,4,2,7,6},
//                       vwedge[1]={0,1,5,2,3,7},
//                   (2) diagonal edges (v4,v7),(v0,v3)
//                       vwedge[2]={4,7,6,0,3,2},
//                       vwedge[3]={4,5,7,0,1,3},
//                   (3) diagonal edges (v0,v6),(v1,v7)
//        vwedge[4]= {1,7,5,0,6,4},
//                       vwedge[5]{1,3,7,0,2,6},
//                       subdivide de cell in 2 wedges:
//                   (4) diagonal edges (v1,v2),(v5,v6)
//                       vwedge[6]={4,5,6,0,1,2},
//                       vwedge[7]={6,5,7,2,1,3},
//                   (5) diagonal edges (v2,v4),(v3,v5)
//                       vwedge[8]={3,7,5,2,6,4},
//                       vwedge[9]={1,3,5,0,2,4},
//                   (6) diagonal edges (v1,v4),(v3,v6)
//                       vwedge[10]={0,1,4,2,3,6}
//                       vwedge[11]={1,5,4,3,7,6}
//         v6 _ _ __ _  v7
//           /|        /|           VOXEL
//        v4/_|_ _ _ _/ |           opposite vertex of v0 is v7 and vice-versa
//          | |     v5| |           diagonal edges Edg_f[i]
//          |v2 _ _ _ |_|  v3
//          |/        |/
//        v0/_ _ _ _ _|/v1
//
//
//     (II)Case 5 tetrahedra:
//       - search the smallest vertex vi
//       - verify if the opposite vertices of vi do not belong to any diagonal edges Edg_f
//       - 2 possibilities: create 5 tetraedra
//           - if vi is ( 0 or 3 or 5 or 6)
//             vtetra[]={v0,v5,v3,v6},{v0,v4,v5,v6},{v0,v1,v3,v5},{v5,v3,v6,v7},{v0,v3,v2,v6}};
//           - if vi is ( 1 or 2 or 4 or 7)
//             vtetra[]={v1,v2,v4,v7},{v0,v1,v2,v4},{v1,v4,v5,v7},{v1,v3,v2,v7},{v2,v6,v4,v7}};
//  Case Wedge (13):
//       the table 'vwedge' set 6 possibilities of the smallest index
//
//                 v5
//               /\            .
//           v3 /..\ v4
//             /   /
//          v2/\  /
//         v0/__\/v1
//
//        if(v0 index ) is the smallest index:
//         wedge is subdivided in:
//              1 tetrahedron-> vwedge[0]: {v0,v4,v3,v5}
//               and 1 pyramid-> vert[0] : {v1,v2,v5,v4,v0}
//
//  Case Pyramid (14):
//       the table 'vpy' set 3 possibilities of the smallest index
//       vertices{v0,v1,v2,v3,v4}. {v0,v1,v2,v3} is a square face of pyramid
//
//                v4  (opposite vertex of face with 4 vertices)
//                ^
//
//
//          v3 _ _ __ _  v2
//           /         /
//        v0/_ _ _ _ _/v1
//
//        if(v0 index ) is the smallest index:
//        the pyramid is subdivided in:
//        2 tetrahedra-> vpyram[0]: {v0,v1,v2,v4}
//                       vpyram[1]: {v0,v2,v3,v4}
//
//
//------------------------------------------------------------------------------
void vtkBoxClipDataSet::CellGrid(
  vtkIdType typeobj, vtkIdType npts, const vtkIdType* cellIds, vtkCellArray* newCellArray)
{
  vtkIdType tab[4];
  vtkIdType tabp[5];
  vtkIdType ptstriangle = 3;
  vtkIdType ptstetra = 4;
  vtkIdType xmin;
  vtkIdType idt;
  int i, j;
  unsigned int id = 0;
  unsigned int idpy = 0;

  unsigned int Edg_f[6][2]; // edge selected of each face
  unsigned int idv[4];

  unsigned int idopos;
  unsigned int numbertetra;

  constexpr vtkIdType triPassThrough[3] = { 0, 1, 2 };
  vtkIdType tri[3];
  vtkIdType line[2];

  switch (typeobj)
  {
    case VTK_VERTEX:
    case VTK_POLY_VERTEX:
      for (idt = 0; idt < npts; idt++)
      {
        newCellArray->InsertNextCell(1, &idt);
      }
      break;

    case VTK_LINE:
    case VTK_POLY_LINE:
      for (idt = 0; idt < npts - 1; idt++)
      {
        line[0] = idt;
        line[1] = idt + 1;
        newCellArray->InsertNextCell(2, line);
      }
      break;

    case VTK_TRIANGLE: // 5
    case VTK_QUADRATIC_TRIANGLE:
    case VTK_BIQUADRATIC_TRIANGLE:
      newCellArray->InsertNextCell(ptstriangle, triPassThrough);
      break;

    case VTK_TRIANGLE_STRIP: // 6
      for (idt = 0; idt < npts - 2; idt++)
      {
        if (idt % 2 == 0)
        {
          tri[0] = idt;
          tri[1] = idt + 1;
          tri[2] = idt + 2;
        }
        else
        {
          tri[0] = idt;
          tri[1] = idt + 2;
          tri[2] = idt + 1;
        }
        newCellArray->InsertNextCell(3, tri);
      }
      break;

    case VTK_POLYGON: // 7 (Convex case)
      tri[0] = 0;
      for (idt = 2; idt < npts; idt++)
      {
        tri[1] = idt - 1;
        tri[2] = idt;
        newCellArray->InsertNextCell(3, tri);
      }
      break;

    case VTK_PIXEL: // 8
    {
      constexpr vtkIdType vtrip[2][3] = {
        { 0, 1, 3 },
        { 0, 3, 2 },
      };
      newCellArray->InsertNextCell(3, vtrip[0]);
      newCellArray->InsertNextCell(3, vtrip[1]);
    }
    break;

    case VTK_QUAD: // 9
    case VTK_QUADRATIC_QUAD:
    case VTK_BIQUADRATIC_QUAD:
    case VTK_QUADRATIC_LINEAR_QUAD:
    {
      constexpr vtkIdType vtriq[2][3] = {
        { 0, 1, 2 },
        { 0, 2, 3 },
      };
      newCellArray->InsertNextCell(3, vtriq[0]);
      newCellArray->InsertNextCell(3, vtriq[1]);
    }
    break;

    case VTK_TETRA: // 10
    case VTK_QUADRATIC_TETRA:
    {
      constexpr vtkIdType tetra[4] = { 0, 1, 2, 3 };
      newCellArray->InsertNextCell(ptstetra, tetra);
    }
    break;

    case VTK_VOXEL: // 11
      // each face: search edge with smallest global index
      // face 0 (0,1,5,4)
      idv[0] = 0;
      idv[1] = 1;
      idv[2] = 5;
      idv[3] = 4;
      this->MinEdgeF(idv, cellIds, Edg_f[0]);

      // face 1 (0,1,3,2)
      idv[0] = 0;
      idv[1] = 1;
      idv[2] = 3;
      idv[3] = 2;
      this->MinEdgeF(idv, cellIds, Edg_f[1]);
      // face 2 (0,2,6,4)
      idv[0] = 0;
      idv[1] = 2;
      idv[2] = 6;
      idv[3] = 4;
      this->MinEdgeF(idv, cellIds, Edg_f[2]);
      // face 3 (4,5,7,6)
      idv[0] = 4;
      idv[1] = 5;
      idv[2] = 7;
      idv[3] = 6;
      this->MinEdgeF(idv, cellIds, Edg_f[3]);
      // face 4 (2,3,7,6)
      idv[0] = 2;
      idv[1] = 3;
      idv[2] = 7;
      idv[3] = 6;
      this->MinEdgeF(idv, cellIds, Edg_f[4]);
      // face 5 (1,3,7,5)
      idv[0] = 1;
      idv[1] = 3;
      idv[2] = 7;
      idv[3] = 5;
      this->MinEdgeF(idv, cellIds, Edg_f[5]);

      // search the smallest global index of voxel
      xmin = cellIds[0];
      id = 0;
      for (i = 1; i < 8; i++)
      {
        if (xmin > cellIds[i])
        {
          xmin = cellIds[i]; // the smallest global index
          id = i;            // local index
        }
      }
      // two cases:
      idopos = 7 - id;
      numbertetra = 5;
      for (i = 0; i < 6; i++)
      {
        j = 0;
        if (idopos == Edg_f[i][j])
        {
          numbertetra = 6;
          break;
        }
        j = 1;
        if (idopos == Edg_f[i][j])
        {
          numbertetra = 6;
          break;
        }
      }

      if (numbertetra == 5)
      {
        // case 1: create  5 tetraedra
        if ((id == 0) || (id == 3) || (id == 5) || (id == 6))
        {
          constexpr vtkIdType vtetra[5][4] = {
            { 0, 5, 3, 6 },
            { 0, 4, 5, 6 },
            { 0, 1, 3, 5 },
            { 5, 3, 6, 7 },
            { 0, 3, 2, 6 },
          };
          for (i = 0; i < 5; i++)
          {
            newCellArray->InsertNextCell(4, vtetra[i]);
          }
        }
        else
        {
          constexpr vtkIdType vtetra[5][4] = {
            { 1, 2, 4, 7 },
            { 0, 1, 2, 4 },
            { 1, 4, 5, 7 },
            { 1, 3, 2, 7 },
            { 2, 6, 4, 7 },
          };

          for (i = 0; i < 5; i++)
          {
            newCellArray->InsertNextCell(4, vtetra[i]);
          }
        }
      }
      else
      {
        // case 2: create 2 wedges-> 6 tetrahedra
        constexpr vtkIdType vwedge[12][6] = {
          { 0, 5, 4, 2, 7, 6 },
          { 0, 1, 5, 2, 3, 7 },
          { 4, 7, 6, 0, 3, 2 },
          { 4, 5, 7, 0, 1, 3 },
          { 1, 7, 5, 0, 6, 4 },
          { 1, 3, 7, 0, 2, 6 },
          { 4, 5, 6, 0, 1, 2 },
          { 6, 5, 7, 2, 1, 3 },
          { 3, 7, 5, 2, 6, 4 },
          { 1, 3, 5, 0, 2, 4 },
          { 0, 1, 4, 2, 3, 6 },
          { 1, 5, 4, 3, 7, 6 },
        };
        unsigned int edgeId = 10 * Edg_f[i][0] + Edg_f[i][1];
        switch (edgeId)
        {
          case 5:  // edge(v0,v5):10*0 + 5
          case 27: // edge(v2,v7):10*2 + 7
            this->WedgeToTetra(vwedge[0], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[1], cellIds, newCellArray);
            break;
          case 3:  // edge(v0,v2)
          case 47: // edge(v4,v6)
            this->WedgeToTetra(vwedge[2], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[3], cellIds, newCellArray);
            break;
          case 6:
          case 17:
            this->WedgeToTetra(vwedge[4], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[5], cellIds, newCellArray);
            break;
          case 12:
          case 56:
            this->WedgeToTetra(vwedge[6], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[7], cellIds, newCellArray);
            break;
          case 24:
          case 35:
            this->WedgeToTetra(vwedge[8], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[9], cellIds, newCellArray);
            break;
          case 14:
          case 36:
            this->WedgeToTetra(vwedge[10], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[11], cellIds, newCellArray);
            break;
        }
      }
      break;

    case VTK_HEXAHEDRON: // 12
    case VTK_QUADRATIC_HEXAHEDRON:
    case VTK_TRIQUADRATIC_HEXAHEDRON:
    case VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON:
    {
      // each face: search edge with smallest global index
      // face 0 (0,1,5,4)
      idv[0] = 0;
      idv[1] = 1;
      idv[2] = 5;
      idv[3] = 4;
      this->MinEdgeF(idv, cellIds, Edg_f[0]);

      // face 1 (0,1,2,3)
      idv[0] = 0;
      idv[1] = 1;
      idv[2] = 2;
      idv[3] = 3;
      this->MinEdgeF(idv, cellIds, Edg_f[1]);
      // face 2 (0,3,7,4)
      idv[0] = 0;
      idv[1] = 3;
      idv[2] = 7;
      idv[3] = 4;
      this->MinEdgeF(idv, cellIds, Edg_f[2]);
      // face 3 (4,5,6,7)
      idv[0] = 4;
      idv[1] = 5;
      idv[2] = 6;
      idv[3] = 7;
      this->MinEdgeF(idv, cellIds, Edg_f[3]);
      // face 4 (3,2,6,7)
      idv[0] = 3;
      idv[1] = 2;
      idv[2] = 6;
      idv[3] = 7;
      this->MinEdgeF(idv, cellIds, Edg_f[4]);
      // face 5 (1,2,6,5)
      idv[0] = 1;
      idv[1] = 2;
      idv[2] = 6;
      idv[3] = 5;
      this->MinEdgeF(idv, cellIds, Edg_f[5]);

      // search the smallest global index of voxel
      xmin = cellIds[0];
      id = 0;
      for (i = 1; i < 8; i++)
      {
        if (xmin > cellIds[i])
        {
          xmin = cellIds[i]; // the smallest global index
          id = i;            // local index
        }
      }

      // two cases:
      constexpr unsigned int tabopos[8] = { 6, 7, 4, 5, 2, 3, 0, 1 };
      idopos = tabopos[id];
      numbertetra = 5;
      for (i = 0; i < 6; i++)
      {
        j = 0;
        if (idopos == Edg_f[i][j])
        {
          numbertetra = 6;
          break;
        }
        j = 1;
        if (idopos == Edg_f[i][j])
        {
          numbertetra = 6;
          break;
        }
      }

      if (numbertetra == 5)
      {
        // case 1: create  5 tetraedra
        if ((id == 0) || (id == 2) || (id == 5) || (id == 7))
        {
          constexpr vtkIdType vtetra[5][4] = {
            { 0, 5, 2, 7 },
            { 0, 4, 5, 7 },
            { 0, 1, 2, 5 },
            { 5, 2, 7, 6 },
            { 0, 2, 3, 7 },
          };
          for (i = 0; i < 5; i++)
          {
            newCellArray->InsertNextCell(4, vtetra[i]);
          }
        }
        else
        {
          constexpr vtkIdType vtetra[5][4] = {
            { 1, 3, 4, 6 },
            { 0, 1, 3, 4 },
            { 1, 4, 5, 6 },
            { 1, 2, 3, 6 },
            { 3, 7, 4, 6 },
          };

          for (i = 0; i < 5; i++)
          {
            newCellArray->InsertNextCell(4, vtetra[i]);
          }
        }
      }
      else
      {
        // case 2: create 2 wedges-> 6 tetrahedra
        constexpr vtkIdType vwedge[12][6] = {
          { 0, 5, 4, 3, 6, 7 },
          { 0, 1, 5, 3, 2, 6 },
          { 4, 6, 7, 0, 2, 3 },
          { 4, 5, 6, 0, 1, 2 },
          { 1, 6, 5, 0, 7, 4 },
          { 1, 2, 6, 0, 3, 7 },
          { 4, 5, 7, 0, 1, 3 },
          { 7, 5, 6, 3, 1, 2 },
          { 2, 6, 5, 3, 7, 4 },
          { 1, 2, 5, 0, 3, 4 },
          { 0, 1, 4, 3, 2, 7 },
          { 1, 5, 4, 2, 6, 7 },
        };
        unsigned int edgeId = 10 * Edg_f[i][0] + Edg_f[i][1];

        switch (edgeId)
        {
          case 5:  // edge(v0,v5):10*0 + 5
          case 36: // edge(v3,v6):10*3 + 6
            this->WedgeToTetra(vwedge[0], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[1], cellIds, newCellArray);
            break;
          case 2:  // edge(v0,v2)
          case 46: // edge(v4,v6)
            this->WedgeToTetra(vwedge[2], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[3], cellIds, newCellArray);
            break;
          case 7:
          case 16:
            this->WedgeToTetra(vwedge[4], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[5], cellIds, newCellArray);
            break;
          case 13:
          case 57:
            this->WedgeToTetra(vwedge[6], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[7], cellIds, newCellArray);
            break;
          case 34:
          case 25:
            this->WedgeToTetra(vwedge[8], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[9], cellIds, newCellArray);
            break;
          case 14:
          case 27:
            this->WedgeToTetra(vwedge[10], cellIds, newCellArray);
            this->WedgeToTetra(vwedge[11], cellIds, newCellArray);
            break;
        }
      }
    }
    break;

    case VTK_WEDGE:
    case VTK_QUADRATIC_WEDGE:
    case VTK_QUADRATIC_LINEAR_WEDGE:
    case VTK_BIQUADRATIC_QUADRATIC_WEDGE:
      if (npts == 6) // create 3 tetrahedra
      {
        // first tetrahedron
        constexpr vtkIdType vwedge[6][4] = {
          { 0, 4, 3, 5 },
          { 1, 4, 3, 5 },
          { 2, 4, 3, 5 },
          { 3, 0, 1, 2 },
          { 4, 0, 1, 2 },
          { 5, 0, 1, 2 },
        };
        xmin = cellIds[0];
        id = 0;
        for (i = 1; i < 6; i++)
        {
          if (xmin > cellIds[i])
          {
            xmin = cellIds[i]; // the smallest global index
            id = i;            // local index
          }
        }
        newCellArray->InsertNextCell(4, vwedge[id]);

        // Pyramid :create 2 tetrahedra

        constexpr vtkIdType vert[6][5] = {
          { 1, 2, 5, 4, 0 },
          { 2, 0, 3, 5, 1 },
          { 3, 0, 1, 4, 2 },
          { 1, 2, 5, 4, 3 },
          { 2, 0, 3, 5, 4 },
          { 3, 0, 1, 4, 5 },
        };
        constexpr vtkIdType vpy[8][4] = {
          { 0, 1, 2, 4 },
          { 0, 2, 3, 4 },
          { 1, 2, 3, 4 },
          { 1, 3, 0, 4 },
          { 2, 3, 0, 4 },
          { 2, 0, 1, 4 },
          { 3, 0, 1, 4 },
          { 3, 1, 2, 4 },
        };
        xmin = cellIds[vert[id][0]];
        tabp[0] = vert[id][0];
        idpy = 0;
        for (i = 1; i < 4; i++)
        {
          tabp[i] = vert[id][i];
          if (xmin > cellIds[vert[id][i]])
          {
            xmin = cellIds[vert[id][i]]; // global index
            idpy = i;                    // local index
          }
        }
        tabp[4] = vert[id][4];
        for (j = 0; j < 4; j++)
        {
          tab[j] = tabp[vpy[2 * idpy][j]];
        }
        newCellArray->InsertNextCell(4, tab);

        for (j = 0; j < 4; j++)
        {
          tab[j] = tabp[vpy[2 * idpy + 1][j]];
        }
        newCellArray->InsertNextCell(4, tab);
      }
      else
      {
        vtkErrorMacro(<< " This cell is not a wedge\n");
        return;
      }
      break;

    case VTK_PYRAMID: // Create 2 tetrahedra
    case VTK_QUADRATIC_PYRAMID:
    case VTK_TRIQUADRATIC_PYRAMID:
      if (npts == 5)
      {
        // note: the first element vpyram[][0] is the smallest index of pyramid
        constexpr vtkIdType vpyram[8][4] = {
          { 0, 1, 2, 4 },
          { 0, 2, 3, 4 },
          { 1, 2, 3, 4 },
          { 1, 3, 0, 4 },
          { 2, 3, 0, 4 },
          { 2, 0, 1, 4 },
          { 3, 0, 1, 4 },
          { 3, 1, 2, 4 },
        };
        xmin = cellIds[0];
        id = 0;
        for (i = 1; i < 4; i++)
        {
          if (xmin > cellIds[i])
          {
            xmin = cellIds[i]; // the smallest global index of square face
            id = i;            // local index
          }
        }
        newCellArray->InsertNextCell(4, vpyram[2 * id]);
        newCellArray->InsertNextCell(4, vpyram[2 * id + 1]);
      }
      else
      {
        vtkErrorMacro(<< " This cell is not a pyramid\n");
        return;
      }
      break;
  }
}

//------------------------------------------------------------------------------
// The new cell created in intersection between tetrahedron and plane
// are tetrahedron or wedges or pyramids.
//
// CreateTetra is used to subdivide wedges and pyramids in tetrahedron.  The
// proper vertex ordering for wedges and pyramids can be found in "The
// Visualization Toolkit."  In the third edition, they are in Figure 5-2 on page
// 115 in section 5.4 ("Cell Types") in the "Basic Data Representation" chapter.
//
void vtkBoxClipDataSet::CreateTetra(
  vtkIdType npts, const vtkIdType* cellIds, vtkCellArray* newCellArray)
{
  vtkIdType tabp[5];
  vtkIdType tab[3][4];

  unsigned int i, j;
  unsigned int id = 0;
  unsigned int idpy;

  vtkIdType xmin;

  if (npts == 6)
  {
    // VTK_WEDGE: Create 3 tetrahedra
    // first tetrahedron
    constexpr vtkIdType vwedge[6][4] = {
      { 0, 4, 3, 5 },
      { 1, 4, 3, 5 },
      { 2, 4, 3, 5 },
      { 3, 0, 1, 2 },
      { 4, 0, 1, 2 },
      { 5, 0, 1, 2 },
    };
    xmin = cellIds[0];
    id = 0;
    for (i = 1; i < 6; i++)
    {
      if (xmin > cellIds[i])
      {
        xmin = cellIds[i]; // the smallest global index
        id = i;            // local index
      }
    }
    for (j = 0; j < 4; j++)
    {
      tab[0][j] = cellIds[vwedge[id][j]];
    }
    newCellArray->InsertNextCell(4, tab[0]);

    // Pyramid: create 2 tetrahedra

    constexpr vtkIdType vert[6][5] = {
      { 1, 2, 5, 4, 0 },
      { 2, 0, 3, 5, 1 },
      { 3, 0, 1, 4, 2 },
      { 1, 2, 5, 4, 3 },
      { 2, 0, 3, 5, 4 },
      { 3, 0, 1, 4, 5 },
    };
    constexpr vtkIdType vpy[8][4] = {
      { 0, 1, 2, 4 },
      { 0, 2, 3, 4 },
      { 1, 2, 3, 4 },
      { 1, 3, 0, 4 },
      { 2, 3, 0, 4 },
      { 2, 0, 1, 4 },
      { 3, 0, 1, 4 },
      { 3, 1, 2, 4 },
    };
    xmin = cellIds[vert[id][0]];
    tabp[0] = vert[id][0];
    idpy = 0;
    for (i = 1; i < 4; i++)
    {
      tabp[i] = vert[id][i];
      if (xmin > cellIds[vert[id][i]])
      {
        xmin = cellIds[vert[id][i]]; // global index
        idpy = i;                    // local index
      }
    }
    tabp[4] = vert[id][4];
    for (j = 0; j < 4; j++)
    {
      tab[1][j] = cellIds[tabp[vpy[2 * idpy][j]]];
    }
    newCellArray->InsertNextCell(4, tab[1]);

    for (j = 0; j < 4; j++)
    {
      tab[2][j] = cellIds[tabp[vpy[2 * idpy + 1][j]]];
    }
    newCellArray->InsertNextCell(4, tab[2]);
  }
  else
  {
    // VTK_PYRAMID: Create 2 tetrahedra
    // The first element in each set is the smallest index of pyramid
    constexpr vtkIdType vpyram[8][4] = {
      { 0, 1, 2, 4 },
      { 0, 2, 3, 4 },
      { 1, 2, 3, 4 },
      { 1, 3, 0, 4 },
      { 2, 3, 0, 4 },
      { 2, 0, 1, 4 },
      { 3, 0, 1, 4 },
      { 3, 1, 2, 4 },
    };
    xmin = cellIds[0];
    id = 0;
    for (i = 1; i < 4; i++)
    {
      if (xmin > cellIds[i])
      {
        xmin = cellIds[i]; // the smallest global index of face with 4 vertices
        id = i;            // local index
      }
    }
    for (j = 0; j < 4; j++)
    {
      tab[0][j] = cellIds[vpyram[2 * id][j]];
    }
    newCellArray->InsertNextCell(4, tab[0]);

    for (j = 0; j < 4; j++)
    {
      tab[1][j] = cellIds[vpyram[2 * id + 1][j]];
    }
    newCellArray->InsertNextCell(4, tab[1]);
  }
}

//------------------------------------------------------------------------------
// Clip each cell of an unstructured grid.
//
//------------------------------------------------------------------------------
//(1) How decide when the cell is NOT outside
//
//    Explaining with an example in 2D.
//    Look at 9 region in the picture and the triangle represented there.
//    v0,v1,v2 are vertices of triangle T.
//
//              |         |
//        1     |   2     |     3
//     _ _ _ _ _ _ _ _ _  _ _ _ _ _ ymax
//              |         | v1
//        4     |   5     |/\   6
//              |         /  \             .
//     _ _ _ _ _ _ _ _ _ /| _ \_ _ _ymin
//              |     v2/_|_ _ \v0
//        7     |   8     |     9
//            xmin       xmax
//
// set test={1,1,1,1} (one test for each plane: test={xmin,xmax,ymin,ymax} )
//    for each vertex, if the test is true set 0 in the test table:
//    vO > xmin ?, v0 < xmax ?, v0 > ymin ?, v0 < ymax ?
//    In the example: test={0,1,1,0}
//    v1 > xmin ?, v1 < xmax ?, v1 > ymin ?, v1 < ymax ?
//    In the example: test={0,1,0,0}
//    v2 > xmin ?, v2 < xmax ?, v2 > ymin ?, v2 < ymax ?
//    In the Example: test={0,0,0,0} -> triangle is NOT outside.
//
//
//    In general, look at the possibilities of each region
//
//    (1,0,0,1)  | (0,0,0,1)  | (0,1,0,1)
//    - - - - - - - - - - - - - - - - - -
//    (1,0,0,0)  | (0,0,0,0)  | (0,1,0,0)
//    - - - - - - - - - - - - - - - - - -
//    (1,0,1,0)  | (0,0,1,0)  | (0,1,1,0)
//
//    In the case above we have:(v0,v1,v2)
//    (1,1,1,1)->(0,1,1,0)->(0,1,0,0)->(0,0,0,0)
//
//    If you have one vertex in region 5, this triangle is NOT outside
//    The triangle IS outside if (v0,v1,v2) are in region like
//    (1,2,3): (1,0,0,1)->(0,0,0,1)->(0,0,0,1)
//    (1,4,7): (1,0,0,1)->(1,0,0,0)->(1,0,0,0)
//    (7,8,9): (1,0,1,0)->(0,0,1,0)->(0,0,1,0)
//    (9,6,3): (0,1,1,0)->(0,1,0,0)->(0,1,0,0)
//
//    Note that if the triangle T is on the region 5, T is NOT outside
//    In fact, T is inside
//
//    You can extend this idea to 3D.
//
//    Note: xmin = this->BoundBoxClip[0][0], xmax=  this->BoundBoxClip[0][1],...
//
//------------------------------------------------------------------------------
// (2) Intersection between Tetrahedron and Plane:
//     Description:
//         vertices of tetrahedron {v0,v1,v2,v3}
//         edge e1 : (v0,v1),   edge e2 : (v1,v2)
//         edge e3 : (v2,v0),   edge e4 : (v0,v3)
//         edge e5 : (v1,v3),   edge e6 : (v2,v3)
//
//         intersecting points p0, pi, ...
//
//         Note: The algorithm search intersection
//               points with these edge order.
//
//          v3                        v3
//       e6/|\ e5                     |
//        / | \            e2         |
//     v2/_ |_ \ v1    v2 - - -v1     |e4
//       \  |  /                      |
//      e3\ | /e1                     |
//         \|/                        |
//          v0                        v0
//
//    (a) Intersecting  4 edges: see tab4[]
//                    -> create: 2 wedges
//                    -> 3 cases
//                    ------------------------------------------
//        case 1246:
//                   if (plane intersecting  edges {e1,e2,e4,e6})
//                   then  p0 belongs to e1, p1 belongs to e2,
//                         p2 belongs to e4, p3 belongs to e6.
//
//                                    v3
//                                     |            v3
//                                     |            /
//                v1    v2 - *- -v1    |           * p3
//              /            p1        * p2       /
//             *p0                     |       v2/
//           /                         |
//          v0                        v0
//          (e1)          (e2)       (e4)        (e6)
//
//                   So, there are two wedges:
//                   {p0,v1,p1,p2,v3,p3}  {p2,v0,p0,p3,v2,p1}
//
//                   Note: if e1 and e2 are intersected by plane,
//                         and the plane intersects 4 edges,
//                         the edge e5 could not be intersected
//                         (skew lines, do not create a planar face)
//                         neither the edge e3((e1,e2,e3) is a face)
//
//                    ------------------------------------------
//        case 2345:
//                   if (plane intersecting  edges {e2,e3,e4,e5})
//                   The two wedges are:
//                   {p3,v3,p2,p0,v2,p1}, {p1,v0,p2,p0,v1,p3}
//
//                    ------------------------------------------
//        case 1356:
//                   if (plane intersecting  edges {e1,e3,e5,e6})
//                   The two wedges are:
//                   {p0,v0,p1,p2,v3,p3}, {p0,v1,p2,p1,v2,p3}
//
//                    -----------------------------------------
//
//    (b) Intersecting  3 edges: tab3[]
//                    ->create: 1 tetrahedron + 1 wedge
//                    -> 4 cases
//                    ------------------------------------------
//    case 134:
//                   if (plane intersecting  edges {e1,e3,e4})
//                   then  p0 belongs to e1, p1 belongs to e3,
//                         p2 belongs to e4.
//
//                           v3
//                           |
//                           |
//                     v2   *p2   v1
//                       \   |   /
//                      p1*  |  *p0
//                          \|/
//                          v0
//
//
//                   So, there are:
//                       1 tetrahedron {v0,p0,p2,p1)
//                       and 1 wedge:  {p0,p2,p1,v1,v3,v2}: tab3[0]
//
//                   Note:(a)if e1 and e3 are intersected by plane,
//                            and the plane intersects 3 edges,
//                            the edges e5 could not be intersected,
//                            if so, e6 be intersected too and the
//                            plane intersect 4 edges.
//                        (b) tetrahedron vertices:
//                            Use the first three indices of tab3:
//                            {v0,p(0),p(2),p(1)}
//
//                    ------------------------------------------
//        case 125:
//                   if (plane intersecting  edges {e1,e2,e5})
//         There are :
//                      1 tetrahedron: {v1,p0,p2,p1}
//                      1 wedge      : {p0,p2,p1,v0,v3,v2},
//                    ------------------------------------------
//    case 236:
//                   if (plane intersecting  edges {e2,e3,e6})
//         There are :
//                      1 tetrahedron: {v2,p0,p1,p2}
//                      1 wedge      : {p0,p1,p2,v1,v0,v3},
//                    ------------------------------------------
//        case 456:
//                  if (plane intersecting  edges {e4,e5,e6})
//         There are :
//                      1 tetrahedron: {v3,p0,p1,p2}
//                      1 wedge      : {p0,p1,p2,v0,v1,v2},
//                    ------------------------------------------
//
//    (c) Intersecting  2 edges and 1 vertex: tab2[]
//                      -> create: 1 tetrahedron + 1 pyramid
//      -> 12 cases
//                    ------------------------------------------
//        case 12:        v3        indexes:{0,0,1,2,3},
//                        *                  0 1 2 3 4
//                    e6/ | \ e5
//                     /  |p1\         tetrahedron: indices(*,4,1,2)
//                  v2/_ _|_*_\ v1
//                    \   |   /
//                   e3\  |p0*
//                      \ | /e1
//                        v0
//
//                  if (plane intersecting  edges {e1,e2}
//                      and one vertex)
//           There are
//                      1 tetrahedron: {v1,v3,p0,p1}
//                      1 pyramid    : {v0,p0,p1,v2,v3},
//
//                  Note:  if e1 and e2 are intersected by plane,
//                            and the plane intersects 2 edges,
//                            then the vertex is v3.
//                    ------------------------------------------
//
//        case 13:                   indexes{2,1,0,1,3}
//                      Intersecting edges {e1,e3}
//                      Intersectinf vertes v3,
//
//                      1 tetrahedron: {v0,v3,p1,p0}
//                      1 pyramid    : {v2,p1,p0,v1,v3},
//                    ------------------------------------------
//        all cases see tab2[]
//                    ------------------------------------------
//    (d) Intersecting  1 edges and 2 vertices: tab1[]
//                      -> create: 2 tetrahedra
//                      -> 6 cases
//
//        - edge e1, vertices {v2,v3}(e6)
//
//                        v3
//                        *              tetrahedra: {p0,v2,v3,v1},{p0,v3,v2,v0}
//                    e6/ | \ e5
//                     /  |  \                  .
//                 v2 *_ _|_ _\ v1
//                    \   |   /
//                   e3\  |p0*
//                      \ | /e1
//                        v0
//         - other cases see tab1[]
//------------------------------------------------------------------------------
//
void vtkBoxClipDataSet::ClipBox(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray* tets, vtkPointData* inPD, vtkPointData* outPD,
  vtkCellData* inCD, vtkIdType cellId, vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytetra = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[4];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType tab_id[6];
  vtkIdType ptstetra = 4;

  vtkIdType i, j;
  unsigned int allInside;
  unsigned int idcellnew;
  unsigned int cutInd;

  /* Edges Tetrahedron */
  vtkIdType edges[6][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
    { 0, 3 },
    { 1, 3 },
    { 2, 3 },
  };
  double value, deltaScalar;
  double t;
  double *p1, *p2;
  double x[3], v[3];
  double v_tetra[4][3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all volume cells to tetrahedra
  this->CellGrid(cellType, npts, cellptId.data(), arraytetra);
  unsigned int totalnewtetra = arraytetra->GetNumberOfCells();
  unsigned int idtetranew;

  for (idtetranew = 0; idtetranew < totalnewtetra; idtetranew++)
  {
    arraytetra->GetNextCell(ptstetra, v_id);

    for (allInside = 1, i = 0; i < 4; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      if (!(((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
            (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
            (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1]))))
      {
        // outside,its type might change later (nearby intersection)
        allInside = 0;
      }
    } // for all points of the tetrahedron.

    // Test Outside: see(1)
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 4; i++)
      {
        cellPts->GetPoint(v_id[i], v);

        if (v[0] > this->BoundBoxClip[0][0])
        {
          test[0] = 0;
        }
        if (v[0] < this->BoundBoxClip[0][1])
        {
          test[1] = 0;
        }
        if (v[1] > this->BoundBoxClip[1][0])
        {
          test[2] = 0;
        }
        if (v[1] < this->BoundBoxClip[1][1])
        {
          test[3] = 0;
        }
        if (v[2] > this->BoundBoxClip[2][0])
        {
          test[4] = 0;
        }
        if (v[2] < this->BoundBoxClip[2][1])
        {
          test[5] = 0;
        }

      } // for all points of the cell.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        continue; // Tetrahedron is outside.
      }
    } // if not all inside.

    for (i = 0; i < 4; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);
      // Currently all points are injected because of the possibility
      // of intersection point merging.
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD->CopyData(inPD, ptId, iid[i]);
      }

    } // for all points of the tetrahedron.

    if (allInside)
    {
      // Tetrahedron inside.
      vtkIdType newCellId = tets->InsertNextCell(4, iid);
      outCD->CopyData(inCD, cellId, newCellId);
      continue;
    }

    double *pedg1, *pedg2;

    // Tetrahedron Intersection Cases
    constexpr unsigned int tab4[6][6] = {
      { 1, 1, 0, 3, 3, 2 },
      { 2, 0, 0, 3, 2, 1 },
      { 3, 3, 2, 0, 2, 1 },
      { 1, 0, 2, 0, 1, 3 },
      { 0, 0, 1, 2, 3, 3 },
      { 0, 1, 2, 1, 2, 3 },
    };
    constexpr unsigned int tab3[4][6] = {
      { 0, 2, 1, 1, 3, 2 },
      { 0, 1, 2, 0, 2, 3 },
      { 0, 1, 2, 1, 0, 3 },
      { 0, 1, 2, 0, 1, 2 },
    };
    constexpr unsigned int tab2[12][5] = {
      { 0, 0, 1, 2, 3 },
      { 2, 1, 0, 1, 3 },
      { 1, 0, 1, 0, 3 },
      { 2, 0, 1, 3, 0 },
      { 3, 1, 0, 1, 0 },
      { 1, 0, 1, 2, 0 },
      { 3, 1, 0, 2, 1 },
      { 2, 1, 0, 0, 1 },
      { 0, 0, 1, 3, 1 },
      { 1, 0, 1, 3, 2 },
      { 3, 1, 0, 0, 2 },
      { 0, 0, 1, 1, 2 },
    };
    constexpr unsigned int tab1[12][3] = {
      { 2, 3, 1 },
      { 3, 2, 0 },
      { 3, 0, 1 },
      { 0, 3, 2 },
      { 1, 3, 0 },
      { 3, 1, 2 },
      { 2, 1, 0 },
      { 1, 2, 3 },
      { 2, 0, 3 },
      { 0, 2, 1 },
      { 0, 1, 3 },
      { 1, 0, 2 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkIdType newCellId = cellarray->InsertNextCell(4, iid);
    unsigned int planes;

    // Test Cell intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      // The index of the dimension of the cut plane (x == 0, y == 1, z == 2).
      cutInd = planes / 2;

      // The plane is always parallel to unitary cube.
      value = this->BoundBoxClip[cutInd][planes % 2];

      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();
      int edgeNum;

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        unsigned int i0, i1;
        vtkIdType p_id[4];
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_tetra[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_tetra[1]);
        newPoints->GetPoint(v_id[2], v_tetra[2]);
        newPoints->GetPoint(v_id[3], v_tetra[3]);

        for (edgeNum = 0; edgeNum < 6; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_tetra[verts[0]];
          p2 = v_tetra[verts[1]];

          if ((p1[cutInd] < value && value < p2[cutInd]) ||
            (p2[cutInd] < value && value < p1[cutInd]))
          {
            deltaScalar = p2[cutInd] - p1[cutInd];

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (value - pedg1[cutInd]) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);
            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD, p_id[num_inter], v_id[v1], v_id[v2], t);
            }
            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 4; i++)
          {
            if (((v_tetra[i][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[i][cutInd] > value) && ((planes % 2) == 1)))

            // If only one vertex is outside, so the tetrahedron is outside
            // because there is not intersection.
            {
              outside = 1;
              break;
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(4, v_id);
          }
          continue;
        }
        switch (num_inter)
        {
          case 4: // We have two wedges
            switch (edges_inter)
            {
              case 1246:
                i0 = 0;
                break;
              case 2345:
                i0 = 2;
                break;
              case 1356:
                i0 = 4;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }

            if (((v_tetra[3][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[3][cutInd] > value) && ((planes % 2) == 1)))
            {

              // The v_tetra[3] is outside box, so the first wedge is outside

              tab_id[0] = p_id[tab4[i0 + 1][0]];
              // ps: v_tetra[3] is always in first wedge (see tab)

              tab_id[1] = v_id[tab4[i0 + 1][1]];
              tab_id[2] = p_id[tab4[i0 + 1][2]];
              tab_id[3] = p_id[tab4[i0 + 1][3]];
              tab_id[4] = v_id[tab4[i0 + 1][4]];
              tab_id[5] = p_id[tab4[i0 + 1][5]];
              this->CreateTetra(6, tab_id, newcellArray);
            }
            else
            {
              tab_id[0] = p_id[tab4[i0][0]];
              tab_id[1] = v_id[tab4[i0][1]];
              tab_id[2] = p_id[tab4[i0][2]];
              tab_id[3] = p_id[tab4[i0][3]];
              tab_id[4] = v_id[tab4[i0][4]];
              tab_id[5] = p_id[tab4[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);
            }
            break;
          case 3: // We have one tetrahedron and one wedge
            // i0 gets the vertex on the tetrahedron.
            switch (edges_inter)
            {
              case 134:
                i0 = 0;
                break;
              case 125:
                i0 = 1;
                break;
              case 236:
                i0 = 2;
                break;
              case 456:
                i0 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }

            if (((v_tetra[i0][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[i0][cutInd] > value) && ((planes % 2) == 1)))
            {

              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = p_id[tab3[i0][0]];
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[tab3[i0][3]];
              tab_id[4] = v_id[tab3[i0][4]];
              tab_id[5] = v_id[tab3[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);
            }
            else
            {
              tab_id[0] = p_id[tab3[i0][0]];
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[i0];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            break;

          case 2:                // We have one tetrahedron and one pyramid
            switch (edges_inter) // i1 = vertex of the tetrahedron
            {
              case 12:
                i0 = 0;
                i1 = 1;
                break;
              case 13:
                i0 = 1;
                i1 = 0;
                break;
              case 23:
                i0 = 2;
                i1 = 2;
                break;
              case 25:
                i0 = 3;
                i1 = 1;
                break;
              case 26:
                i0 = 4;
                i1 = 2;
                break;
              case 56:
                i0 = 5;
                i1 = 3;
                break;
              case 34:
                i0 = 6;
                i1 = 0;
                break;
              case 46:
                i0 = 7;
                i1 = 3;
                break;
              case 36:
                i0 = 8;
                i1 = 2;
                break;
              case 14:
                i0 = 9;
                i1 = 0;
                break;
              case 15:
                i0 = 10;
                i1 = 1;
                break;
              case 45:
                i0 = 11;
                i1 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_tetra[i1][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[i1][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = v_id[tab2[i0][0]];
              tab_id[1] = p_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = v_id[tab2[i0][3]];
              tab_id[4] = v_id[tab2[i0][4]];
              this->CreateTetra(5, tab_id, newcellArray);
            }
            else
            {
              tab_id[0] = v_id[i1];
              tab_id[1] = v_id[tab2[i0][4]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = p_id[tab2[i0][1]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            break;

          case 1: // We have two tetrahedron.
            if ((edges_inter > 6) || (edges_inter < 1))
            {
              vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                            << " Edges_inter = " << edges_inter);
              continue;
            }
            if (((v_tetra[tab1[2 * edges_inter - 1][2]][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[tab1[2 * edges_inter - 1][2]][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = p_id[0];
              tab_id[1] = v_id[tab1[2 * edges_inter - 2][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 2][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 2][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = p_id[0];
              tab_id[1] = v_id[tab1[2 * edges_inter - 1][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 1][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 1][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            break;
        }
      } // for all new cells

      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells();

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets->InsertNextCell(npts, v_id);
      outCD->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();
  }
  arraytetra->Delete();
}

//------------------------------------------------------------------------------
// ClipHexahedron: Box is like hexahedron.
//
// The difference between ClipBox and ClipHexahedron is the outside test.
// The ClipHexahedron use plane equation to decide who is outside.
//
void vtkBoxClipDataSet::ClipHexahedron(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray* tets, vtkPointData* inPD, vtkPointData* outPD,
  vtkCellData* inCD, vtkIdType cellId, vtkCellData* outCD)
{
  vtkIdType idcellnew;
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytetra = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[4];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType tab_id[6];
  vtkIdType ptstetra = 4;

  vtkIdType i, j;
  unsigned int allInside, k;
  unsigned int planes;

  /* Edges Tetrahedron */
  vtkIdType edges[6][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
    { 0, 3 },
    { 1, 3 },
    { 2, 3 },
  };
  double deltaScalar;
  double t;
  double *p1, *p2;
  double v[3], x[3];
  double p[6];
  double v_tetra[4][3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  this->CellGrid(
    cellType, npts, cellptId.data(), arraytetra); // Convert all volume cells to tetrahedra

  unsigned int totalnewtetra = arraytetra->GetNumberOfCells();
  unsigned int idtetranew;

  for (idtetranew = 0; idtetranew < totalnewtetra; idtetranew++)
  {
    arraytetra->GetNextCell(ptstetra, v_id);

    for (allInside = 1, i = 0; i < 4; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]);
      }

      if (!((p[0] <= 0) && (p[1] <= 0) && (p[2] <= 0) && (p[3] <= 0) && (p[4] <= 0) && (p[5] <= 0)))
      {
        allInside = 0;
      }
    } // for all points of the cell.

    // Test Outside
    unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
    for (i = 0; i < 4; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      // Use plane equation
      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]);
      }

      for (k = 0; k < 3; k++)
      {
        if (p[2 * k] < 0)
        {
          test[2 * k] = 0;
        }
        if (p[2 * k + 1] < 0)
        {
          test[2 * k + 1] = 0;
        }
      }

    } // for all points of the cell.

    if (!allInside &&
      ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1)))
    {
      continue; // Tetrahedron is outside.
    }

    for (i = 0; i < 4; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      // Currently all points are injected because of the possibility
      // of intersection point merging.
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD->CopyData(inPD, ptId, iid[i]);
      }
    } // for all points of the tetrahedron.

    if (allInside)
    {
      vtkIdType newCellId = tets->InsertNextCell(4, iid); // Tetrahedron inside.
      outCD->CopyData(inCD, cellId, newCellId);
      continue;
    }

    double *pedg1, *pedg2;

    // Tetrahedron Intersection Cases
    constexpr unsigned int tab4[6][6] = {
      { 1, 1, 0, 3, 3, 2 },
      { 2, 0, 0, 3, 2, 1 },
      { 3, 3, 2, 0, 2, 1 },
      { 1, 0, 2, 0, 1, 3 },
      { 0, 0, 1, 2, 3, 3 },
      { 0, 1, 2, 1, 2, 3 },
    };
    constexpr unsigned int tab3[4][6] = {
      { 0, 2, 1, 1, 3, 2 },
      { 0, 1, 2, 0, 2, 3 },
      { 0, 1, 2, 1, 0, 3 },
      { 0, 1, 2, 0, 1, 2 },
    };
    constexpr unsigned int tab2[12][5] = {
      { 0, 0, 1, 2, 3 },
      { 2, 1, 0, 1, 3 },
      { 1, 0, 1, 0, 3 },
      { 2, 0, 1, 3, 0 },
      { 3, 1, 0, 1, 0 },
      { 1, 0, 1, 2, 0 },
      { 3, 1, 0, 2, 1 },
      { 2, 1, 0, 0, 1 },
      { 0, 0, 1, 3, 1 },
      { 1, 0, 1, 3, 2 },
      { 3, 1, 0, 0, 2 },
      { 0, 0, 1, 1, 2 },
    };
    constexpr unsigned int tab1[12][3] = {
      { 2, 3, 1 },
      { 3, 2, 0 },
      { 3, 0, 1 },
      { 0, 3, 2 },
      { 1, 3, 0 },
      { 3, 1, 2 },
      { 2, 1, 0 },
      { 1, 2, 3 },
      { 2, 0, 3 },
      { 0, 2, 1 },
      { 0, 1, 3 },
      { 1, 0, 2 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkIdType newCellId = cellarray->InsertNextCell(4, iid);

    // Test Cell intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      vtkIdType totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int i0, i1;
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        vtkIdType p_id[4];

        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_tetra[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_tetra[1]);
        newPoints->GetPoint(v_id[2], v_tetra[2]);
        newPoints->GetPoint(v_id[3], v_tetra[3]);

        p[0] = this->PlaneNormal[planes][0] * (v_tetra[0][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[0][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[0][2] - this->PlanePoint[planes][2]);
        p[1] = this->PlaneNormal[planes][0] * (v_tetra[1][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[1][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[1][2] - this->PlanePoint[planes][2]);
        p[2] = this->PlaneNormal[planes][0] * (v_tetra[2][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[2][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[2][2] - this->PlanePoint[planes][2]);
        p[3] = this->PlaneNormal[planes][0] * (v_tetra[3][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[3][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[3][2] - this->PlanePoint[planes][2]);

        for (int edgeNum = 0; edgeNum < 6; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_tetra[verts[0]];
          p2 = v_tetra[verts[1]];
          double s1 = p[verts[0]];
          double s2 = p[verts[1]];
          if ((s1 * s2) < 0)
          {
            deltaScalar = s2 - s1;

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
              t = s1;
              s1 = s2;
              s2 = t;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (-s1) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);

            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD, p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges
        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 4; i++)
          {
            if (p[i] > 0)
            {
              // If only one vertex is outside, so the tetrahedron is outside
              // because there is not intersection.
              // some vertex could be on plane, so you need to test all vertex

              outside = 1;
              break;
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane

            newCellId = newcellArray->InsertNextCell(4, v_id);
          }
          continue;
        }
        switch (num_inter)
        {
          case 4: // We have two wedges
            switch (edges_inter)
            {
              case 1246:
                i0 = 0;
                break;
              case 2345:
                i0 = 2;
                break;
              case 1356:
                i0 = 4;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }

            if (p[3] > 0)
            {
              // The v_tetra[3] is outside box, so the first wedge is outside
              // ps: v_tetra[3] is always in first wedge (see tab)

              tab_id[0] = p_id[tab4[i0 + 1][0]];
              tab_id[1] = v_id[tab4[i0 + 1][1]];
              tab_id[2] = p_id[tab4[i0 + 1][2]];
              tab_id[3] = p_id[tab4[i0 + 1][3]];
              tab_id[4] = v_id[tab4[i0 + 1][4]];
              tab_id[5] = p_id[tab4[i0 + 1][5]];
              this->CreateTetra(6, tab_id, newcellArray);
            }
            else
            {
              tab_id[0] = p_id[tab4[i0][0]];
              tab_id[1] = v_id[tab4[i0][1]];
              tab_id[2] = p_id[tab4[i0][2]];
              tab_id[3] = p_id[tab4[i0][3]];
              tab_id[4] = v_id[tab4[i0][4]];
              tab_id[5] = p_id[tab4[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);
            }
            break;
          case 3: // We have one tetrahedron and one wedge
            switch (edges_inter)
            {
              case 134:
                i0 = 0;
                break;
              case 125:
                i0 = 1;
                break;
              case 236:
                i0 = 2;
                break;
              case 456:
                i0 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }

            if (p[i0] > 0)
            {
              // Isolate vertex is outside box, so the tetrahedron is outside

              tab_id[0] = p_id[tab3[i0][0]];
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[tab3[i0][3]];
              tab_id[4] = v_id[tab3[i0][4]];
              tab_id[5] = v_id[tab3[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);
            }
            else
            {
              tab_id[0] = p_id[tab3[i0][0]];
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[i0];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            break;
          case 2:                // We have one tetrahedron and one pyramid
            switch (edges_inter) // i1 = vertex of the tetrahedron
            {
              case 12:
                i0 = 0;
                i1 = 1;
                break;
              case 13:
                i0 = 1;
                i1 = 0;
                break;
              case 23:
                i0 = 2;
                i1 = 2;
                break;
              case 25:
                i0 = 3;
                i1 = 1;
                break;
              case 26:
                i0 = 4;
                i1 = 2;
                break;
              case 56:
                i0 = 5;
                i1 = 3;
                break;
              case 34:
                i0 = 6;
                i1 = 0;
                break;
              case 46:
                i0 = 7;
                i1 = 3;
                break;
              case 36:
                i0 = 8;
                i1 = 2;
                break;
              case 14:
                i0 = 9;
                i1 = 0;
                break;
              case 15:
                i0 = 10;
                i1 = 1;
                break;
              case 45:
                i0 = 11;
                i1 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (p[i1] > 0)
            {
              // Isolate vertex is outside box, so the tetrahedron is outside

              tab_id[0] = v_id[tab2[i0][0]];
              tab_id[1] = p_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = v_id[tab2[i0][3]];
              tab_id[4] = v_id[tab2[i0][4]];
              this->CreateTetra(5, tab_id, newcellArray);
            }
            else
            {
              tab_id[0] = v_id[i1];
              tab_id[1] = v_id[tab2[i0][4]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = p_id[tab2[i0][1]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            break;
          case 1: // We have two tetrahedron.
            if ((edges_inter > 6) || (edges_inter < 1))
            {
              vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                            << " Edges_inter = " << edges_inter);
              continue;
            }
            if (p[tab1[2 * edges_inter - 1][2]] > 0)
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = p_id[0];
              tab_id[1] = v_id[tab1[2 * edges_inter - 2][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 2][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 2][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = p_id[0];
              tab_id[1] = v_id[tab1[2 * edges_inter - 1][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 1][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 1][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    vtkIdType totalnewcells = cellarray->GetNumberOfCells();

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets->InsertNextCell(npts, v_id);
      outCD->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();
  }
  arraytetra->Delete();
}
//------------------------------------------------------------------------------
// ClipBoxInOut
//
// The difference between ClipBox and ClipBoxInOut is the outputs.
// The ClipBoxInOut generate both outputs: inside and outside the clip box.
//
void vtkBoxClipDataSet::ClipBoxInOut(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** tets, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytetra = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[4];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType ptIdout[4];
  vtkIdType tab_id[6];
  vtkIdType ptstetra = 4;

  int i, j;
  int allInside;
  int cutInd;

  unsigned int planes;
  unsigned int idcellnew;
  unsigned int idtetranew;

  /* Edges Tetrahedron */
  vtkIdType edges[6][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
    { 0, 3 },
    { 1, 3 },
    { 2, 3 },
  };
  double value, deltaScalar;
  double t;
  double v[3], x[3];
  double v_tetra[4][3];
  double *p1, *p2;

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all volume cells to tetrahedra
  this->CellGrid(cellType, npts, cellptId.data(), arraytetra);
  unsigned int totalnewtetra = arraytetra->GetNumberOfCells();

  for (idtetranew = 0; idtetranew < totalnewtetra; idtetranew++)
  {
    arraytetra->GetNextCell(ptstetra, v_id);

    for (allInside = 1, i = 0; i < 4; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      if (!(((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
            (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
            (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1]))))
      {
        // outside,its type might change later (nearby intersection)
        allInside = 0;
      }
    } // for all points of the cell.

    // Test Outside: see(1)
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 4; i++)
      {
        ptIdout[i] = cellIds->GetId(v_id[i]);
        cellPts->GetPoint(v_id[i], v_tetra[i]);

        if (v_tetra[i][0] > this->BoundBoxClip[0][0])
        {
          test[0] = 0;
        }
        if (v_tetra[i][0] < this->BoundBoxClip[0][1])
        {
          test[1] = 0;
        }
        if (v_tetra[i][1] > this->BoundBoxClip[1][0])
        {
          test[2] = 0;
        }
        if (v_tetra[i][1] < this->BoundBoxClip[1][1])
        {
          test[3] = 0;
        }
        if (v_tetra[i][2] > this->BoundBoxClip[2][0])
        {
          test[4] = 0;
        }
        if (v_tetra[i][2] < this->BoundBoxClip[2][1])
        {
          test[5] = 0;
        }
      } // for all points of the cell.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        for (i = 0; i < 4; i++)
        {
          if (locator->InsertUniquePoint(v_tetra[i], iid[i]))
          {
            outPD[0]->CopyData(inPD, ptIdout[i], iid[i]);
            outPD[1]->CopyData(inPD, ptIdout[i], iid[i]);
          }
        }
        int newCellId = tets[1]->InsertNextCell(4, iid);
        outCD[1]->CopyData(inCD, cellId, newCellId);
        continue; // Tetrahedron is outside.
      }
    } // if not allinside.

    for (i = 0; i < 4; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      // Currently all points are injected because of the possibility
      // of intersection point merging.
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD[0]->CopyData(inPD, ptId, iid[i]);
        outPD[1]->CopyData(inPD, ptId, iid[i]);
      }

    } // for all points of the tetrahedron.

    if (allInside)
    {
      // Tetrahedron inside.
      int newCellId = tets[0]->InsertNextCell(4, iid);
      outCD[0]->CopyData(inCD, cellId, newCellId);
      continue;
    }

    double *pedg1, *pedg2;

    // Tetrahedron Intersection Cases
    constexpr unsigned int tab4[6][6] = {
      { 1, 1, 0, 3, 3, 2 },
      { 2, 0, 0, 3, 2, 1 },
      { 3, 3, 2, 0, 2, 1 },
      { 1, 0, 2, 0, 1, 3 },
      { 0, 0, 1, 2, 3, 3 },
      { 0, 1, 2, 1, 2, 3 },
    };
    constexpr unsigned int tab3[4][6] = {
      { 0, 2, 1, 1, 3, 2 },
      { 0, 1, 2, 0, 2, 3 },
      { 0, 1, 2, 1, 0, 3 },
      { 0, 1, 2, 0, 1, 2 },
    };
    constexpr unsigned int tab2[12][5] = {
      { 0, 0, 1, 2, 3 },
      { 2, 1, 0, 1, 3 },
      { 1, 0, 1, 0, 3 },
      { 2, 0, 1, 3, 0 },
      { 3, 1, 0, 1, 0 },
      { 1, 0, 1, 2, 0 },
      { 3, 1, 0, 2, 1 },
      { 2, 1, 0, 0, 1 },
      { 0, 0, 1, 3, 1 },
      { 1, 0, 1, 3, 2 },
      { 3, 1, 0, 0, 2 },
      { 0, 0, 1, 1, 2 },
    };
    constexpr unsigned int tab1[12][3] = {
      { 2, 3, 1 },
      { 3, 2, 0 },
      { 3, 0, 1 },
      { 0, 3, 2 },
      { 1, 3, 0 },
      { 3, 1, 2 },
      { 2, 1, 0 },
      { 1, 2, 3 },
      { 2, 0, 3 },
      { 0, 2, 1 },
      { 0, 1, 3 },
      { 1, 0, 2 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkCellArray* cellarrayout = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(4, iid);

    // Test Cell intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      // The index of the dimension of the cut plane (x == 0, y == 1, z == 2).
      cutInd = planes / 2;

      value =
        this->BoundBoxClip[cutInd][planes % 2]; // The plane is always parallel to unitary cube.

      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        unsigned int i0, i1;
        vtkIdType p_id[4];
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_tetra[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_tetra[1]);
        newPoints->GetPoint(v_id[2], v_tetra[2]);
        newPoints->GetPoint(v_id[3], v_tetra[3]);
        for (int edgeNum = 0; edgeNum < 6; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_tetra[verts[0]];
          p2 = v_tetra[verts[1]];

          if ((p1[cutInd] < value && value < p2[cutInd]) ||
            (p2[cutInd] < value && value < p1[cutInd]))
          {
            deltaScalar = p2[cutInd] - p1[cutInd];

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (value - pedg1[cutInd]) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);
            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD[0], p_id[num_inter], v_id[v1], v_id[v2], t);
              this->InterpolateEdge(outPD[1], p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 4; i++)
          {
            if (((v_tetra[i][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[i][cutInd] > value) && ((planes % 2) == 1)))
            {
              // If only one vertex is outside, so the tetrahedron is outside
              // because there is not intersection.
              outside = 1;
              break;
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(4, v_id);
          }
          else
          {
            newCellId = tets[1]->InsertNextCell(4, v_id);
            outCD[1]->CopyData(inCD, cellId, newCellId);
          }
          continue;
        }
        switch (num_inter)
        {
          case 4: // We have two wedges
            switch (edges_inter)
            {
              case 1246:
                i0 = 0;
                break;
              case 2345:
                i0 = 2;
                break;
              case 1356:
                i0 = 4;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_tetra[3][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[3][cutInd] > value) && ((planes % 2) == 1)))
            {
              // The v_tetra[3] is outside box, so
              // the first wedge is outside
              // ps: v_tetra[3] is always in first wedge (see tab)

              tab_id[0] = p_id[tab4[i0 + 1][0]]; // Inside
              tab_id[1] = v_id[tab4[i0 + 1][1]];
              tab_id[2] = p_id[tab4[i0 + 1][2]];
              tab_id[3] = p_id[tab4[i0 + 1][3]];
              tab_id[4] = v_id[tab4[i0 + 1][4]];
              tab_id[5] = p_id[tab4[i0 + 1][5]];
              this->CreateTetra(6, tab_id, newcellArray);

              tab_id[0] = p_id[tab4[i0][0]]; // Outside
              tab_id[1] = v_id[tab4[i0][1]];
              tab_id[2] = p_id[tab4[i0][2]];
              tab_id[3] = p_id[tab4[i0][3]];
              tab_id[4] = v_id[tab4[i0][4]];
              tab_id[5] = p_id[tab4[i0][5]];
              this->CreateTetra(6, tab_id, cellarrayout);
            }
            else
            {
              tab_id[0] = p_id[tab4[i0][0]]; // Inside
              tab_id[1] = v_id[tab4[i0][1]];
              tab_id[2] = p_id[tab4[i0][2]];
              tab_id[3] = p_id[tab4[i0][3]];
              tab_id[4] = v_id[tab4[i0][4]];
              tab_id[5] = p_id[tab4[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);

              tab_id[0] = p_id[tab4[i0 + 1][0]]; // Outside
              tab_id[1] = v_id[tab4[i0 + 1][1]];
              tab_id[2] = p_id[tab4[i0 + 1][2]];
              tab_id[3] = p_id[tab4[i0 + 1][3]];
              tab_id[4] = v_id[tab4[i0 + 1][4]];
              tab_id[5] = p_id[tab4[i0 + 1][5]];
              this->CreateTetra(6, tab_id, cellarrayout);
            }
            break;
          case 3: // We have one tetrahedron and one wedge
            switch (edges_inter)
            {
              case 134:
                i0 = 0;
                break;
              case 125:
                i0 = 1;
                break;
              case 236:
                i0 = 2;
                break;
              case 456:
                i0 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_tetra[i0][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[i0][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Isolate vertex is outside box, so/ the tetrahedron is outside
              tab_id[0] = p_id[tab3[i0][0]]; // Inside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[tab3[i0][3]];
              tab_id[4] = v_id[tab3[i0][4]];
              tab_id[5] = v_id[tab3[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);

              tab_id[0] = p_id[tab3[i0][0]]; // Outside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[i0];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = p_id[tab3[i0][0]];
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]]; // Inside
              tab_id[3] = v_id[i0];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = p_id[tab3[i0][0]]; // Outside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[tab3[i0][3]];
              tab_id[4] = v_id[tab3[i0][4]];
              tab_id[5] = v_id[tab3[i0][5]];
              this->CreateTetra(6, tab_id, cellarrayout);
            }
            break;
          case 2:                // We have one tetrahedron and one pyramid
            switch (edges_inter) // i1 = vertex of the tetrahedron
            {
              case 12:
                i0 = 0;
                i1 = 1;
                break;
              case 13:
                i0 = 1;
                i1 = 0;
                break;
              case 23:
                i0 = 2;
                i1 = 2;
                break;
              case 25:
                i0 = 3;
                i1 = 1;
                break;
              case 26:
                i0 = 4;
                i1 = 2;
                break;
              case 56:
                i0 = 5;
                i1 = 3;
                break;
              case 34:
                i0 = 6;
                i1 = 0;
                break;
              case 46:
                i0 = 7;
                i1 = 3;
                break;
              case 36:
                i0 = 8;
                i1 = 2;
                break;
              case 14:
                i0 = 9;
                i1 = 0;
                break;
              case 15:
                i0 = 10;
                i1 = 1;
                break;
              case 45:
                i0 = 11;
                i1 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_tetra[i1][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[i1][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = v_id[tab2[i0][0]]; // Inside
              tab_id[1] = p_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = v_id[tab2[i0][3]];
              tab_id[4] = v_id[tab2[i0][4]];
              this->CreateTetra(5, tab_id, newcellArray);

              tab_id[0] = v_id[i1]; // Outside
              tab_id[1] = v_id[tab2[i0][4]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = p_id[tab2[i0][1]];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = v_id[i1]; // Inside
              tab_id[1] = v_id[tab2[i0][4]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = p_id[tab2[i0][1]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = v_id[tab2[i0][0]]; // Outside
              tab_id[1] = p_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = v_id[tab2[i0][3]];
              tab_id[4] = v_id[tab2[i0][4]];
              this->CreateTetra(5, tab_id, cellarrayout);
            }
            break;
          case 1: // We have two tetrahedron.
            if ((edges_inter > 6) || (edges_inter < 1))
            {
              vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                            << " Edges_inter = " << edges_inter);
              continue;
            }
            if (((v_tetra[tab1[2 * edges_inter - 1][2]][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_tetra[tab1[2 * edges_inter - 1][2]][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Isolate vertex is outside box, so the tetrahedron is outside

              tab_id[0] = p_id[0]; // Inside
              tab_id[1] = v_id[tab1[2 * edges_inter - 2][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 2][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 2][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = p_id[0]; // Outside
              tab_id[1] = v_id[tab1[2 * edges_inter - 1][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 1][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 1][2]];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = p_id[0]; // Inside
              tab_id[1] = v_id[tab1[2 * edges_inter - 1][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 1][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 1][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = p_id[0]; // Outside
              tab_id[1] = v_id[tab1[2 * edges_inter - 2][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 2][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 2][2]];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells(); // Inside
    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets[0]->InsertNextCell(npts, v_id);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();

    totalnewcells = cellarrayout->GetNumberOfCells(); // Outside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarrayout->GetNextCell(npts, v_id);
      newCellId = tets[1]->InsertNextCell(npts, v_id);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
    cellarrayout->Delete();
  }
  arraytetra->Delete();
}

//------------------------------------------------------------------------------
// ClipHexahedronInOut
//
// The difference between ClipHexahedron and ClipHexahedronInOut is the outputs.
// The ClipHexahedronInOut generate both outputs: inside and outside the clip hexahedron.
//
void vtkBoxClipDataSet::ClipHexahedronInOut(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** tets, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytetra = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[4];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType ptIdout[4];
  vtkIdType tab_id[6];
  vtkIdType ptstetra = 4;

  int i, j, k;
  int allInside;

  /* Edges Tetrahedron */
  vtkIdType edges[6][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
    { 0, 3 },
    { 1, 3 },
    { 2, 3 },
  };
  double deltaScalar;
  double p[6], t;
  double v_tetra[4][3];
  double v[3], x[3];
  double *p1, *p2;

  unsigned int idtetranew;
  unsigned int idcellnew;
  unsigned int planes;

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  this->CellGrid(
    cellType, npts, cellptId.data(), arraytetra); // Convert all volume cells to tetrahedra

  unsigned int totalnewtetra = arraytetra->GetNumberOfCells();
  for (idtetranew = 0; idtetranew < totalnewtetra; idtetranew++)
  {
    arraytetra->GetNextCell(ptstetra, v_id);

    for (allInside = 1, i = 0; i < 4; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]);
      }

      if (!((p[0] <= 0) && (p[1] <= 0) && (p[2] <= 0) && (p[3] <= 0) && (p[4] <= 0) && (p[5] <= 0)))
      {
        allInside = 0;
      }
    } // for all points of the tetrahedron.

    // Test Outside
    unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
    for (i = 0; i < 4; i++)
    {
      ptIdout[i] = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v_tetra[i]);

      // Use plane equation
      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v_tetra[i][0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v_tetra[i][1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v_tetra[i][2] - this->PlanePoint[k][2]);
      }

      for (k = 0; k < 3; k++)
      {
        if (p[2 * k] < 0)
        {
          test[2 * k] = 0;
        }
        if (p[2 * k + 1] < 0)
        {
          test[2 * k + 1] = 0;
        }
      }

    } // for all points of the cell.

    if (!allInside &&
      ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1)))
    {
      for (i = 0; i < 4; i++)
      {
        if (locator->InsertUniquePoint(v_tetra[i], iid[i]))
        {
          outPD[0]->CopyData(inPD, ptIdout[i], iid[i]);
          outPD[1]->CopyData(inPD, ptIdout[i], iid[i]);
        }
      }
      int newCellId = tets[1]->InsertNextCell(4, iid);
      outCD[1]->CopyData(inCD, cellId, newCellId);
      continue; // Tetrahedron is outside.
    }

    for (i = 0; i < 4; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      // Currently all points are injected because of the possibility
      // of intersection point merging.

      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD[0]->CopyData(inPD, ptId, iid[i]);
        outPD[1]->CopyData(inPD, ptId, iid[i]);
      }

    } // for all points of the tetrahedron.

    if (allInside)
    {
      int newCellId = tets[0]->InsertNextCell(4, iid); // Tetrahedron inside.
      outCD[0]->CopyData(inCD, cellId, newCellId);
      continue;
    }

    // float *pc1  , *pc2;
    double *pedg1, *pedg2;

    // Tetrahedron Intersection Cases
    constexpr unsigned int tab4[6][6] = {
      { 1, 1, 0, 3, 3, 2 },
      { 2, 0, 0, 3, 2, 1 },
      { 3, 3, 2, 0, 2, 1 },
      { 1, 0, 2, 0, 1, 3 },
      { 0, 0, 1, 2, 3, 3 },
      { 0, 1, 2, 1, 2, 3 },
    };
    constexpr unsigned int tab3[4][6] = {
      { 0, 2, 1, 1, 3, 2 },
      { 0, 1, 2, 0, 2, 3 },
      { 0, 1, 2, 1, 0, 3 },
      { 0, 1, 2, 0, 1, 2 },
    };
    constexpr unsigned int tab2[12][5] = {
      { 0, 0, 1, 2, 3 },
      { 2, 1, 0, 1, 3 },
      { 1, 0, 1, 0, 3 },
      { 2, 0, 1, 3, 0 },
      { 3, 1, 0, 1, 0 },
      { 1, 0, 1, 2, 0 },
      { 3, 1, 0, 2, 1 },
      { 2, 1, 0, 0, 1 },
      { 0, 0, 1, 3, 1 },
      { 1, 0, 1, 3, 2 },
      { 3, 1, 0, 0, 2 },
      { 0, 0, 1, 1, 2 },
    };
    constexpr unsigned int tab1[12][3] = {
      { 2, 3, 1 },
      { 3, 2, 0 },
      { 3, 0, 1 },
      { 0, 3, 2 },
      { 1, 3, 0 },
      { 3, 1, 2 },
      { 2, 1, 0 },
      { 1, 2, 3 },
      { 2, 0, 3 },
      { 0, 2, 1 },
      { 0, 1, 3 },
      { 1, 0, 2 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkCellArray* cellarrayout = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(4, iid);

    // Test Cell intersection with each plane of box
    // FIXME: there is no difference in the for loop (planes has no influence!)
    for (planes = 0; planes < 6; planes++)
    {
      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int i0, i1;
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        vtkIdType p_id[4];

        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_tetra[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_tetra[1]);
        newPoints->GetPoint(v_id[2], v_tetra[2]);
        newPoints->GetPoint(v_id[3], v_tetra[3]);

        p[0] = this->PlaneNormal[planes][0] * (v_tetra[0][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[0][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[0][2] - this->PlanePoint[planes][2]);
        p[1] = this->PlaneNormal[planes][0] * (v_tetra[1][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[1][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[1][2] - this->PlanePoint[planes][2]);
        p[2] = this->PlaneNormal[planes][0] * (v_tetra[2][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[2][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[2][2] - this->PlanePoint[planes][2]);
        p[3] = this->PlaneNormal[planes][0] * (v_tetra[3][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_tetra[3][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_tetra[3][2] - this->PlanePoint[planes][2]);

        for (int edgeNum = 0; edgeNum < 6; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_tetra[verts[0]];
          p2 = v_tetra[verts[1]];
          double s1 = p[verts[0]];
          double s2 = p[verts[1]];
          if ((s1 * s2) < 0)
          {
            deltaScalar = s2 - s1;

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
              t = s1;
              s1 = s2;
              s2 = t;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (-s1) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);

            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD[0], p_id[num_inter], v_id[v1], v_id[v2], t);
              this->InterpolateEdge(outPD[1], p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 4; i++)
          {
            if (p[i] > 0)
            {              // If only one vertex is outside, so the tetrahedron is outside
              outside = 1; // because there is not intersection.
              break;       // some vertex could be on plane, so you need to test all vertex
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(4, v_id);
          }
          else
          {
            newCellId = tets[1]->InsertNextCell(4, v_id);
            outCD[1]->CopyData(inCD, cellId, newCellId);
          }
          continue;
        }

        switch (num_inter)
        {
          case 4: // We have two wedges
            switch (edges_inter)
            {
              case 1246:
                i0 = 0;
                break;
              case 2345:
                i0 = 2;
                break;
              case 1356:
                i0 = 4;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (p[3] > 0)
            {
              // The v_tetra[3] is outside box, so the first wedge is outside
              // ps: v_tetra[3] is always in first wedge (see tab)

              tab_id[0] = p_id[tab4[i0 + 1][0]]; // Inside
              tab_id[1] = v_id[tab4[i0 + 1][1]];
              tab_id[2] = p_id[tab4[i0 + 1][2]];
              tab_id[3] = p_id[tab4[i0 + 1][3]];
              tab_id[4] = v_id[tab4[i0 + 1][4]];
              tab_id[5] = p_id[tab4[i0 + 1][5]];
              this->CreateTetra(6, tab_id, newcellArray);

              tab_id[0] = p_id[tab4[i0][0]]; // Outside
              tab_id[1] = v_id[tab4[i0][1]];
              tab_id[2] = p_id[tab4[i0][2]];
              tab_id[3] = p_id[tab4[i0][3]];
              tab_id[4] = v_id[tab4[i0][4]];
              tab_id[5] = p_id[tab4[i0][5]];
              this->CreateTetra(6, tab_id, cellarrayout);
            }
            else
            {
              tab_id[0] = p_id[tab4[i0][0]]; // Inside
              tab_id[1] = v_id[tab4[i0][1]];
              tab_id[2] = p_id[tab4[i0][2]];
              tab_id[3] = p_id[tab4[i0][3]];
              tab_id[4] = v_id[tab4[i0][4]];
              tab_id[5] = p_id[tab4[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);

              tab_id[0] = p_id[tab4[i0 + 1][0]]; // Outside
              tab_id[1] = v_id[tab4[i0 + 1][1]];
              tab_id[2] = p_id[tab4[i0 + 1][2]];
              tab_id[3] = p_id[tab4[i0 + 1][3]];
              tab_id[4] = v_id[tab4[i0 + 1][4]];
              tab_id[5] = p_id[tab4[i0 + 1][5]];
              this->CreateTetra(6, tab_id, cellarrayout);
            }

            break;
          case 3: // We have one tetrahedron and one wedge
            switch (edges_inter)
            {
              case 134:
                i0 = 0;
                break;
              case 125:
                i0 = 1;
                break;
              case 236:
                i0 = 2;
                break;
              case 456:
                i0 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (p[i0] > 0)
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = p_id[tab3[i0][0]]; // Inside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[tab3[i0][3]];
              tab_id[4] = v_id[tab3[i0][4]];
              tab_id[5] = v_id[tab3[i0][5]];
              this->CreateTetra(6, tab_id, newcellArray);

              tab_id[0] = p_id[tab3[i0][0]]; // Outside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[i0];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = p_id[tab3[i0][0]]; // Inside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[i0];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = p_id[tab3[i0][0]]; // Outside
              tab_id[1] = p_id[tab3[i0][1]];
              tab_id[2] = p_id[tab3[i0][2]];
              tab_id[3] = v_id[tab3[i0][3]];
              tab_id[4] = v_id[tab3[i0][4]];
              tab_id[5] = v_id[tab3[i0][5]];
              this->CreateTetra(6, tab_id, cellarrayout);
            }
            break;
          case 2:                // We have one tetrahedron and one pyramid
            switch (edges_inter) // i1 = vertex of the tetrahedron
            {
              case 12:
                i0 = 0;
                i1 = 1;
                break;
              case 13:
                i0 = 1;
                i1 = 0;
                break;
              case 23:
                i0 = 2;
                i1 = 2;
                break;
              case 25:
                i0 = 3;
                i1 = 1;
                break;
              case 26:
                i0 = 4;
                i1 = 2;
                break;
              case 56:
                i0 = 5;
                i1 = 3;
                break;
              case 34:
                i0 = 6;
                i1 = 0;
                break;
              case 46:
                i0 = 7;
                i1 = 3;
                break;
              case 36:
                i0 = 8;
                i1 = 2;
                break;
              case 14:
                i0 = 9;
                i1 = 0;
                break;
              case 15:
                i0 = 10;
                i1 = 1;
                break;
              case 45:
                i0 = 11;
                i1 = 3;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = %" << edges_inter);
                continue;
            }

            if (p[i1] > 0)
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = v_id[tab2[i0][0]]; // Inside
              tab_id[1] = p_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = v_id[tab2[i0][3]];
              tab_id[4] = v_id[tab2[i0][4]];
              this->CreateTetra(5, tab_id, newcellArray);

              tab_id[0] = v_id[i1]; // Outside
              tab_id[1] = v_id[tab2[i0][4]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = p_id[tab2[i0][1]];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = v_id[i1]; // Inside
              tab_id[1] = v_id[tab2[i0][4]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = p_id[tab2[i0][1]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = v_id[tab2[i0][0]]; // Outside
              tab_id[1] = p_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              tab_id[3] = v_id[tab2[i0][3]];
              tab_id[4] = v_id[tab2[i0][4]];
              this->CreateTetra(5, tab_id, cellarrayout);
            }
            break;
          case 1: // We have two tetrahedron.
            if ((edges_inter > 6) || (edges_inter < 1))
            {
              vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                            << " Edges_inter = " << edges_inter);
              continue;
            }
            if (p[tab1[2 * edges_inter - 1][2]] > 0)
            {
              // Isolate vertex is outside box, so the tetrahedron is outside
              tab_id[0] = p_id[0]; // Inside
              tab_id[1] = v_id[tab1[2 * edges_inter - 2][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 2][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 2][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = p_id[0]; // Outside
              tab_id[1] = v_id[tab1[2 * edges_inter - 1][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 1][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 1][2]];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            else
            {
              tab_id[0] = p_id[0]; // Inside
              tab_id[1] = v_id[tab1[2 * edges_inter - 1][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 1][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 1][2]];
              newCellId = newcellArray->InsertNextCell(4, tab_id);

              tab_id[0] = p_id[0]; // Outside
              tab_id[1] = v_id[tab1[2 * edges_inter - 2][0]];
              tab_id[2] = v_id[tab1[2 * edges_inter - 2][1]];
              tab_id[3] = v_id[tab1[2 * edges_inter - 2][2]];
              newCellId = cellarrayout->InsertNextCell(4, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells(); // Inside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets[0]->InsertNextCell(npts, v_id);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();

    totalnewcells = cellarrayout->GetNumberOfCells(); // Outside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarrayout->GetNextCell(npts, v_id);
      newCellId = tets[1]->InsertNextCell(npts, v_id);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
    cellarrayout->Delete();
  }
  arraytetra->Delete();
}

//-------------------------------------------------------

//-------------------------------------------------------
void vtkBoxClipDataSet::ClipBox2D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray* tets, vtkPointData* inPD, vtkPointData* outPD,
  vtkCellData* inCD, vtkIdType cellId, vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytriangle = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[3];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType tab_id[3];
  vtkIdType ptstriangle = 3;

  int i, j;
  unsigned int allInside;
  unsigned int planes;
  unsigned int cutInd;

  /* Edges Triangle*/
  vtkIdType edges[3][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
  };
  double value, deltaScalar;
  double t, *p1, *p2;
  double v[3], x[3];
  double v_triangle[3][3];

  // To avoid false positive warning.
  tab_id[0] = 0;
  tab_id[1] = 0;
  tab_id[2] = 0;

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 2d cells to triangle
  this->CellGrid(cellType, npts, cellptId.data(), arraytriangle);

  unsigned int totalnewtriangle = arraytriangle->GetNumberOfCells();
  unsigned int idtrianglenew;

  for (idtrianglenew = 0; idtrianglenew < totalnewtriangle; idtrianglenew++)
  {
    arraytriangle->GetNextCell(ptstriangle, v_id);

    for (allInside = 1, i = 0; i < 3; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      if (!(((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
            (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
            (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1]))))
      {
        // outside,its type might change later (nearby intersection)
        allInside = 0;
      }
    }

    // Test Outside:
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 3; i++)
      {
        cellPts->GetPoint(v_id[i], v);

        if (v[0] >= this->BoundBoxClip[0][0])
        {
          test[0] = 0;
        }
        if (v[0] <= this->BoundBoxClip[0][1])
        {
          test[1] = 0;
        }
        if (v[1] >= this->BoundBoxClip[1][0])
        {
          test[2] = 0;
        }
        if (v[1] <= this->BoundBoxClip[1][1])
        {
          test[3] = 0;
        }
        if (v[2] >= this->BoundBoxClip[2][0])
        {
          test[4] = 0;
        }
        if (v[2] <= this->BoundBoxClip[2][1])
        {
          test[5] = 0;
        }
      } // for all points of the triangle.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        continue; // Triangle is outside.
      }
    }

    for (i = 0; i < 3; i++)
    {
      // Currently all points are injected because of the possibility
      // of intersection point merging.
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD->CopyData(inPD, ptId, iid[i]);
      }

    } // for all points of the triangle.

    if (allInside)
    {
      // Triangle inside.
      int newCellId = tets->InsertNextCell(3, iid);
      outCD->CopyData(inCD, cellId, newCellId);
      continue;
    }

    // float *pc1  , *pc2;
    double *pedg1, *pedg2;

    // Triangle intersection cases

    unsigned int tab2[3][4] = {
      { 1, 2, 1, 0 },
      { 2, 0, 0, 1 },
      { 0, 1, 0, 1 },
    };
    unsigned int tab1[3][2] = {
      { 2, 1 },
      { 0, 2 },
      { 1, 0 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(3, iid);
    unsigned int idcellnew;

    // Test triangle intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      // The index of the dimension of the cut plane (x == 0, y == 1, z == 2).
      cutInd = planes / 2;

      // The plane is always parallel to unitary cube.
      value = this->BoundBoxClip[cutInd][planes % 2];

      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        unsigned int i0;
        vtkIdType p_id[3];
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_triangle[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_triangle[1]);
        newPoints->GetPoint(v_id[2], v_triangle[2]);
        for (int edgeNum = 0; edgeNum < 3; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_triangle[verts[0]];
          p2 = v_triangle[verts[1]];

          if ((p1[cutInd] < value && value < p2[cutInd]) ||
            (p2[cutInd] < value && value < p1[cutInd]))
          {
            deltaScalar = p2[cutInd] - p1[cutInd];

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (value - pedg1[cutInd]) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);
            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD, p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 3; i++)
          {
            if (((v_triangle[i][cutInd] < value) && ((planes % 2) == 0)) ||
              // If only one vertex is outside, so the triangle is outside
              ((v_triangle[i][cutInd] > value) &&
                ((planes % 2) == 1))) // because there is not intersection.
            {
              outside = 1;
              break;
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(3, v_id);
          }
          continue;
        }
        switch (num_inter)
        {
          case 2: // We have one quad and one triangle
            switch (edges_inter)
            {
              case 12:
                i0 = 1;
                break;
              case 23:
                i0 = 2;
                break;
              case 13:
                i0 = 0;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_triangle[i0][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_triangle[i0][cutInd] > value) && ((planes % 2) == 1)))
            {
              // The v_triangle[i0] is outside box, so
              // The Quad is inside: two triangles: (v0,v1,p0) and (p0,p1,v1)
              tab_id[0] = v_id[tab2[i0][0]];
              tab_id[1] = v_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
              tab_id[0] = p_id[tab2[i0][2]];
              tab_id[1] = p_id[tab2[i0][3]];
              tab_id[2] = v_id[tab2[i0][0]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            else
            {
              // The Triangle is inside: (v0,p0,p1)
              // The correct winding of the new triangle depends on where the
              // plane intersected the original triangle.
              switch (edges_inter)
              {
                case 12:
                case 23:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[1];
                  tab_id[2] = p_id[0];
                  break;
                case 13:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[0];
                  tab_id[2] = p_id[1];
                  break;
              }
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            break;

          case 1: // We have two triangles
            switch (edges_inter)
            {
              case 1:
                i0 = 0;
                break;
              case 2:
                i0 = 1;
                break;
              case 3:
                i0 = 2;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_triangle[i0][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_triangle[i0][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Test one of the vertices  vertex i0 is outside
              tab_id[0] = v_id[tab1[i0][1]];
              tab_id[1] = v_id[tab1[i0][0]];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            else
            {
              tab_id[0] = v_id[tab1[i0][0]];
              tab_id[1] = v_id[i0];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells();

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets->InsertNextCell(npts, v_id);
      outCD->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();
  }
  arraytriangle->Delete();
}
//-------------------------------------------------------

void vtkBoxClipDataSet::ClipBoxInOut2D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** tets, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytriangle = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[3];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType ptIdout[4];
  vtkIdType tab_id[3];
  vtkIdType ptstriangle = 3;

  int i, j;
  unsigned int allInside;
  unsigned int cutInd;
  unsigned int planes;
  unsigned int idcellnew;

  /* Edges Triangle */
  vtkIdType edges[3][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
  };
  double value, deltaScalar;
  double t, *p1, *p2;
  double v[3], x[3];
  double v_triangle[3][3];

  // To avoid false positive warning.
  tab_id[0] = 0;
  tab_id[1] = 0;
  tab_id[2] = 0;

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 2D cells to triangle
  this->CellGrid(cellType, npts, cellptId.data(), arraytriangle);
  unsigned int totalnewtriangle = arraytriangle->GetNumberOfCells();
  unsigned int idtrianglenew;

  for (idtrianglenew = 0; idtrianglenew < totalnewtriangle; idtrianglenew++)
  {
    arraytriangle->GetNextCell(ptstriangle, v_id);

    for (allInside = 1, i = 0; i < 3; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      if (!(((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
            (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
            (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1]))))
      {
        // outside,its type might change later (nearby intersection)
        allInside = 0;
      }
    } // for all points of the cell.

    // Test Outside: see(1)
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 3; i++)
      {
        ptIdout[i] = cellIds->GetId(v_id[i]);
        cellPts->GetPoint(v_id[i], v_triangle[i]);

        if (v_triangle[i][0] >= this->BoundBoxClip[0][0])
        {
          test[0] = 0;
        }
        if (v_triangle[i][0] <= this->BoundBoxClip[0][1])
        {
          test[1] = 0;
        }
        if (v_triangle[i][1] >= this->BoundBoxClip[1][0])
        {
          test[2] = 0;
        }
        if (v_triangle[i][1] <= this->BoundBoxClip[1][1])
        {
          test[3] = 0;
        }
        if (v_triangle[i][2] >= this->BoundBoxClip[2][0])
        {
          test[4] = 0;
        }
        if (v_triangle[i][2] <= this->BoundBoxClip[2][1])
        {
          test[5] = 0;
        }

      } // for all points of the cell.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        for (i = 0; i < 3; i++)
        {
          if (locator->InsertUniquePoint(v_triangle[i], iid[i]))
          {
            outPD[0]->CopyData(inPD, ptIdout[i], iid[i]);
            outPD[1]->CopyData(inPD, ptIdout[i], iid[i]);
          }
        }

        int newCellId = tets[1]->InsertNextCell(3, iid);
        outCD[1]->CopyData(inCD, cellId, newCellId);
        continue; // Triangle is outside.
      }
    } // if not allInside.

    for (i = 0; i < 3; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      // Currently all points are injected because of the possibility
      // of intersection point merging.
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD[0]->CopyData(inPD, ptId, iid[i]);
        outPD[1]->CopyData(inPD, ptId, iid[i]);
      }
    } // for all points of the triangle.

    if (allInside)
    {
      // Triangle inside.
      int newCellId = tets[0]->InsertNextCell(3, iid);
      outCD[0]->CopyData(inCD, cellId, newCellId);
      continue;
    }

    // float *pc1  , *pc2;
    double *pedg1, *pedg2;

    // Triangle intersection cases

    unsigned int tab2[3][4] = {
      { 1, 2, 1, 0 },
      { 2, 0, 0, 1 },
      { 0, 1, 0, 1 },
    };
    unsigned int tab1[3][2] = {
      { 2, 1 },
      { 0, 2 },
      { 1, 0 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkCellArray* cellarrayout = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(3, iid);

    // Test Cell intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      // The index of the dimension of the cut plane (x == 0, y == 1, z == 2).
      cutInd = planes / 2;

      // The plane is always parallel to unitary cube.
      value = this->BoundBoxClip[cutInd][planes % 2];

      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        unsigned int i0;
        vtkIdType p_id[3];
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_triangle[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_triangle[1]);
        newPoints->GetPoint(v_id[2], v_triangle[2]);
        for (int edgeNum = 0; edgeNum < 3; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_triangle[verts[0]];
          p2 = v_triangle[verts[1]];

          if ((p1[cutInd] < value && value < p2[cutInd]) ||
            (p2[cutInd] < value && value < p1[cutInd]))
          {
            deltaScalar = p2[cutInd] - p1[cutInd];

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (value - pedg1[cutInd]) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);
            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD[0], p_id[num_inter], v_id[v1], v_id[v2], t);
              this->InterpolateEdge(outPD[1], p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 3; i++)
          {
            if (((v_triangle[i][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_triangle[i][cutInd] > value) && ((planes % 2) == 1)))
            {
              // If only one vertex is outside, so the triangle is outside
              // because there is not intersection.
              outside = 1;
              break;
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(3, v_id);
          }
          else
          {
            newCellId = tets[1]->InsertNextCell(3, v_id);
            outCD[1]->CopyData(inCD, cellId, newCellId);
          }
          continue;
        }
        switch (num_inter)
        {
          case 2: // We have one quad and one triangle
            // i0 gets the index of the triangle point that lies alone on
            // one side of the plane.
            switch (edges_inter)
            {
              case 12:
                i0 = 1;
                break;
              case 23:
                i0 = 2;
                break;
              case 13:
                i0 = 0;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_triangle[i0][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_triangle[i0][cutInd] > value) && ((planes % 2) == 1)))
            {
              // The v_triangle[i0] is outside box, so

              tab_id[0] = v_id[tab2[i0][0]]; // Quad Inside
              tab_id[1] = v_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
              tab_id[0] = p_id[tab2[i0][2]];
              tab_id[1] = p_id[tab2[i0][3]];
              tab_id[2] = v_id[tab2[i0][0]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              switch (edges_inter) // Triangle Outside
              {
                case 12:
                case 23:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[1];
                  tab_id[2] = p_id[0];
                  break;
                case 13:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[0];
                  tab_id[2] = p_id[1];
                  break;
              }
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            else
            {
              // The Triangle is inside: (v0,p0,p1)
              switch (edges_inter)
              {
                case 12:
                case 23:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[1];
                  tab_id[2] = p_id[0];
                  break;
                case 13:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[0];
                  tab_id[2] = p_id[1];
                  break;
              }
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              tab_id[0] = v_id[tab2[i0][0]]; // Quad is Outside
              tab_id[1] = v_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
              tab_id[0] = p_id[tab2[i0][2]];
              tab_id[1] = p_id[tab2[i0][3]];
              tab_id[2] = v_id[tab2[i0][0]];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            break;

          case 1: // We have two triangles
            switch (edges_inter)
            {
              case 1:
                i0 = 0;
                break;
              case 2:
                i0 = 1;
                break;
              case 3:
                i0 = 2;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (((v_triangle[i0][cutInd] < value) && ((planes % 2) == 0)) ||
              ((v_triangle[i0][cutInd] > value) && ((planes % 2) == 1)))
            {
              // Test one of the vertices vertex i0 is outside

              tab_id[0] = v_id[tab1[i0][1]]; // Inside
              tab_id[1] = v_id[tab1[i0][0]];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              tab_id[0] = v_id[tab1[i0][0]]; // Outside
              tab_id[1] = v_id[i0];
              tab_id[2] = p_id[0];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            else
            {
              tab_id[0] = v_id[tab1[i0][0]]; // Inside
              tab_id[1] = v_id[i0];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              tab_id[0] = v_id[tab1[i0][1]]; // Outside
              tab_id[1] = v_id[tab1[i0][0]];
              tab_id[2] = p_id[0];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells(); // Inside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets[0]->InsertNextCell(npts, v_id);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();

    totalnewcells = cellarrayout->GetNumberOfCells(); // Outside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarrayout->GetNextCell(npts, v_id);
      newCellId = tets[1]->InsertNextCell(npts, v_id);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
    cellarrayout->Delete();
  }
  arraytriangle->Delete();
}

//-------------------------------------------------------

void vtkBoxClipDataSet::ClipHexahedron2D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray* tets, vtkPointData* inPD, vtkPointData* outPD,
  vtkCellData* inCD, vtkIdType cellId, vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytriangle = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[3];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType tab_id[3];
  vtkIdType ptstriangle = 3;

  int i, j, k;
  unsigned int allInside;
  unsigned int idtrianglenew;
  unsigned int idcellnew;
  unsigned int planes;

  vtkIdType edges[3][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
  };
  double deltaScalar;
  double t, *p1, *p2;
  double v[3], x[3];
  double p[6];
  double v_triangle[3][3];

  // To avoid false positive warning.
  tab_id[0] = 0;
  tab_id[1] = 0;
  tab_id[2] = 0;

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  this->CellGrid(
    cellType, npts, cellptId.data(), arraytriangle); // Convert all volume cells to triangle

  unsigned int totalnewtriangle = arraytriangle->GetNumberOfCells();
  for (idtrianglenew = 0; idtrianglenew < totalnewtriangle; idtrianglenew++)
  {
    arraytriangle->GetNextCell(ptstriangle, v_id);

    for (allInside = 1, i = 0; i < 3; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]);
      }

      if (!((p[0] <= 0) && (p[1] <= 0) && (p[2] <= 0) && (p[3] <= 0) && (p[4] <= 0) && (p[5] <= 0)))
      {
        allInside = 0;
      }
    } // for all points of the triangle.

    // Test Outside
    unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
    for (i = 0; i < 3; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      // Use plane equation
      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]);
      }

      for (k = 0; k < 3; k++)
      {
        if (p[2 * k] <= 0)
        {
          test[2 * k] = 0;
        }
        if (p[2 * k + 1] <= 0)
        {
          test[2 * k + 1] = 0;
        }
      }
    } // for all points of the cell.

    if (!allInside &&
      ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1)))
    {
      continue; // Triangle is outside.
    }

    for (i = 0; i < 3; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      // Currently all points are injected because of the possibility
      // of intersection point merging.

      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD->CopyData(inPD, ptId, iid[i]);
      }
    } // for all points of the triangle.

    if (allInside)
    {
      int newCellId = tets->InsertNextCell(3, iid); // Triangle inside.
      outCD->CopyData(inCD, cellId, newCellId);
      continue;
    }

    // float *pc1  , *pc2;
    double *pedg1, *pedg2;

    unsigned int tab2[3][4] = {
      { 1, 2, 1, 0 },
      { 2, 0, 0, 1 },
      { 0, 1, 0, 1 },
    };
    unsigned int tab1[3][2] = {
      { 2, 1 },
      { 0, 2 },
      { 1, 0 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(3, iid);

    // Test Cell intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int i0;
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        vtkIdType p_id[3];

        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_triangle[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_triangle[1]);
        newPoints->GetPoint(v_id[2], v_triangle[2]);

        p[0] = this->PlaneNormal[planes][0] * (v_triangle[0][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_triangle[0][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_triangle[0][2] - this->PlanePoint[planes][2]);
        p[1] = this->PlaneNormal[planes][0] * (v_triangle[1][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_triangle[1][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_triangle[1][2] - this->PlanePoint[planes][2]);
        p[2] = this->PlaneNormal[planes][0] * (v_triangle[2][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_triangle[2][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_triangle[2][2] - this->PlanePoint[planes][2]);

        for (int edgeNum = 0; edgeNum < 3; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_triangle[verts[0]];
          p2 = v_triangle[verts[1]];
          double s1 = p[verts[0]];
          double s2 = p[verts[1]];
          if ((s1 * s2) < 0)
          {
            deltaScalar = s2 - s1;

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
              t = s1;
              s1 = s2;
              s2 = t;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (-s1) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);

            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD, p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 3; i++)
          {
            if (p[i] > 0) // If only one vertex is outside, so the triangle is outside
            {
              outside = 1; // because there is not intersection.
              break;       // some vertex could be on plane, so you need to test all vertex
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(3, v_id);
          }
          continue;
        }
        switch (num_inter)
        {
          case 2: // We have one quad and one triangle
                  // i0 gets the index of the triangle point that lies alone on
                  // one side of the plane.
            switch (edges_inter)
            {
              case 12:
                i0 = 1;
                break;
              case 23:
                i0 = 2;
                break;
              case 13:
                i0 = 0;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (p[i0] > 0)
            {
              // The v_triangle[3] is outside box, so
              // the first wedge is outside

              // The v_triangle[3] is outside box, so the quad is outside
              // The Quad is inside: two triangles: (v0,v1,p0) and (p0,p1,v1)
              tab_id[0] = v_id[tab2[i0][0]];
              tab_id[1] = v_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
              tab_id[0] = p_id[tab2[i0][2]];
              tab_id[1] = p_id[tab2[i0][3]];
              tab_id[2] = v_id[tab2[i0][0]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            else
            {
              // The Triangle is inside: (v0,p0,p1)
              // The correct winding of the new triangle depends on where the
              // plane intersected the original triangle.
              switch (edges_inter)
              {
                case 12:
                case 23:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[1];
                  tab_id[2] = p_id[0];
                  break;
                case 13:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[0];
                  tab_id[2] = p_id[1];
                  break;
              }
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            break;

          case 1: // We have two triangles
            switch (edges_inter)
            {
              case 1:
                i0 = 0;
                break;
              case 2:
                i0 = 1;
                break;
              case 3:
                i0 = 2;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (p[i0] > 0)
            {
              // Isolate vertex is outside box, so the triangle is outside
              tab_id[0] = v_id[tab1[i0][1]];
              tab_id[1] = v_id[tab1[i0][0]];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            else
            {
              tab_id[0] = v_id[tab1[i0][0]];
              tab_id[1] = v_id[i0];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells();

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets->InsertNextCell(npts, v_id);
      outCD->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();
  }
  arraytriangle->Delete();
}

//-------------------------------------------------------

void vtkBoxClipDataSet::ClipHexahedronInOut2D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** tets, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arraytriangle = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[3];
  const vtkIdType* v_id = nullptr;
  vtkIdType *verts, v1, v2;
  vtkIdType ptId;
  vtkIdType ptIdout[3];
  vtkIdType tab_id[3];
  vtkIdType ptstriangle = 3;

  int i, j, k;
  unsigned int allInside;
  unsigned int idtrianglenew;
  unsigned int idcellnew;
  unsigned int planes;

  /* Edges Triangle */
  vtkIdType edges[3][2] = {
    { 0, 1 },
    { 1, 2 },
    { 2, 0 },
  };
  double deltaScalar;
  double t, *p1, *p2;
  double v[3], x[3];
  double p[6];
  double v_triangle[3][3];

  // To avoid false positive warning.
  tab_id[0] = 0;
  tab_id[1] = 0;
  tab_id[2] = 0;

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all polygon cells to triangles
  this->CellGrid(cellType, npts, cellptId.data(), arraytriangle);

  unsigned int totalnewtriangle = arraytriangle->GetNumberOfCells();
  for (idtrianglenew = 0; idtrianglenew < totalnewtriangle; idtrianglenew++)
  {
    arraytriangle->GetNextCell(ptstriangle, v_id);

    for (allInside = 1, i = 0; i < 3; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]);
      }

      if (!((p[0] <= 0) && (p[1] <= 0) && (p[2] <= 0) && (p[3] <= 0) && (p[4] <= 0) && (p[5] <= 0)))
      {
        allInside = 0;
      }
    } // for all points of the trianglehedron.

    // Test Outside
    unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
    for (i = 0; i < 3; i++)
    {
      ptIdout[i] = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v_triangle[i]);

      // Use plane equation
      for (k = 0; k < 6; k++)
      {
        p[k] = this->PlaneNormal[k][0] * (v_triangle[i][0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v_triangle[i][1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v_triangle[i][2] - this->PlanePoint[k][2]);
      }

      for (k = 0; k < 3; k++)
      {
        if (p[2 * k] <= 0)
        {
          test[2 * k] = 0;
        }
        if (p[2 * k + 1] <= 0)
        {
          test[2 * k + 1] = 0;
        }
      }
    } // for all points of the cell.

    if (!allInside &&
      ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1)))
    {
      for (i = 0; i < 3; i++)
      {
        if (locator->InsertUniquePoint(v_triangle[i], iid[i]))
        {
          outPD[0]->CopyData(inPD, ptIdout[i], iid[i]);
          outPD[1]->CopyData(inPD, ptIdout[i], iid[i]);
        }
      }

      int newCellId = tets[1]->InsertNextCell(3, iid);
      outCD[1]->CopyData(inCD, cellId, newCellId);
      continue; // Triangle is outside.
    }

    for (i = 0; i < 3; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      // Currently all points are injected because of the possibility
      // of intersection point merging.
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD[0]->CopyData(inPD, ptId, iid[i]);
        outPD[1]->CopyData(inPD, ptId, iid[i]);
      }

    } // for all points of the trianglehedron.

    if (allInside)
    {
      int newCellId = tets[0]->InsertNextCell(3, iid); // Tetrahedron inside.
      outCD[0]->CopyData(inCD, cellId, newCellId);
      continue;
    }

    double *pedg1, *pedg2;

    unsigned int tab2[3][4] = {
      { 1, 2, 1, 0 },
      { 2, 0, 0, 1 },
      { 0, 1, 0, 1 },
    };
    unsigned int tab1[3][2] = {
      { 2, 1 },
      { 0, 2 },
      { 1, 0 },
    };

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkCellArray* cellarrayout = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(3, iid);

    // Test Cell intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        unsigned int i0;
        unsigned int num_inter = 0;
        unsigned int edges_inter = 0;
        vtkIdType p_id[3];

        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_triangle[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_triangle[1]);
        newPoints->GetPoint(v_id[2], v_triangle[2]);

        p[0] = this->PlaneNormal[planes][0] * (v_triangle[0][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_triangle[0][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_triangle[0][2] - this->PlanePoint[planes][2]);
        p[1] = this->PlaneNormal[planes][0] * (v_triangle[1][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_triangle[1][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_triangle[1][2] - this->PlanePoint[planes][2]);
        p[2] = this->PlaneNormal[planes][0] * (v_triangle[2][0] - this->PlanePoint[planes][0]) +
          this->PlaneNormal[planes][1] * (v_triangle[2][1] - this->PlanePoint[planes][1]) +
          this->PlaneNormal[planes][2] * (v_triangle[2][2] - this->PlanePoint[planes][2]);

        for (int edgeNum = 0; edgeNum < 3; edgeNum++)
        {
          verts = edges[edgeNum];

          p1 = v_triangle[verts[0]];
          p2 = v_triangle[verts[1]];
          double s1 = p[verts[0]];
          double s2 = p[verts[1]];
          if ((s1 * s2) < 0)
          {
            deltaScalar = s2 - s1;

            if (deltaScalar > 0)
            {
              pedg1 = p1;
              pedg2 = p2;
              v1 = verts[0];
              v2 = verts[1];
            }
            else
            {
              pedg1 = p2;
              pedg2 = p1;
              v1 = verts[1];
              v2 = verts[0];
              deltaScalar = -deltaScalar;
              t = s1;
              s1 = s2;
              s2 = t;
            }

            // linear interpolation
            t = (deltaScalar == 0.0 ? 0.0 : (-s1) / deltaScalar);

            for (j = 0; j < 3; j++)
            {
              x[j] = pedg1[j] + t * (pedg2[j] - pedg1[j]);
            }

            // Incorporate point into output and interpolate edge data as necessary
            edges_inter = edges_inter * 10 + (edgeNum + 1);

            if (locator->InsertUniquePoint(x, p_id[num_inter]))
            {
              this->InterpolateEdge(outPD[0], p_id[num_inter], v_id[v1], v_id[v2], t);
              this->InterpolateEdge(outPD[1], p_id[num_inter], v_id[v1], v_id[v2], t);
            }

            num_inter++;
          } // if edge intersects value
        }   // for all edges

        if (num_inter == 0)
        {
          unsigned int outside = 0;
          for (i = 0; i < 3; i++)
          {
            if (p[i] > 0) // If only one vertex is outside, so the trianglehedron is outside
            {
              outside = 1; // because there is not intersection.
              break;       // some vertex could be on plane, so you need to test all vertex
            }
          }
          if (outside == 0)
          {
            // else it is possible intersection if other plane
            newCellId = newcellArray->InsertNextCell(3, v_id);
          }
          else
          {
            newCellId = tets[1]->InsertNextCell(3, v_id);
            outCD[1]->CopyData(inCD, cellId, newCellId);
          }
          continue;
        }
        switch (num_inter)
        {
          case 2: // We have one quad and one triangle
            switch (edges_inter)
            {
              case 12:
                i0 = 1;
                break;
              case 23:
                i0 = 2;
                break;
              case 13:
                i0 = 0;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }

            if (p[i0] > 0)
            {
              // The v_triangle[3] is outside box, so
              // the first wedge is outside

              // The Quad is inside: two triangles: (v0,v1,p0) and (p0,p1,v1)
              tab_id[0] = v_id[tab2[i0][0]];
              tab_id[1] = v_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);
              tab_id[0] = p_id[tab2[i0][2]];
              tab_id[1] = p_id[tab2[i0][3]];
              tab_id[2] = v_id[tab2[i0][0]];
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              switch (edges_inter) // Triangle Outside
              {
                case 12:
                case 23:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[1];
                  tab_id[2] = p_id[0];
                  break;
                case 13:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[0];
                  tab_id[2] = p_id[1];
                  break;
              }
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            else
            {
              // The Triangle is inside: (v0,p0,p1)
              switch (edges_inter)
              {
                case 12:
                case 23:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[1];
                  tab_id[2] = p_id[0];
                  break;
                case 13:
                  tab_id[0] = v_id[i0];
                  tab_id[1] = p_id[0];
                  tab_id[2] = p_id[1];
                  break;
              }
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              // The Quad is outside: two triangles: (v0,v1,p0) and (p0,p1,v1)
              tab_id[0] = v_id[tab2[i0][0]];
              tab_id[1] = v_id[tab2[i0][1]];
              tab_id[2] = p_id[tab2[i0][2]];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
              tab_id[0] = p_id[tab2[i0][2]];
              tab_id[1] = p_id[tab2[i0][3]];
              tab_id[2] = v_id[tab2[i0][0]];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            break;

          case 1: // We have two triangles
            switch (edges_inter)
            {
              case 1:
                i0 = 0;
                break;
              case 2:
                i0 = 1;
                break;
              case 3:
                i0 = 2;
                break;
              default:
                vtkErrorMacro(<< "Intersection not found: Num_inter = " << num_inter
                              << " Edges_inter = " << edges_inter);
                continue;
            }
            if (p[i0] > 0)
            {
              // Isolate vertex is outside box, so
              // the triangle is outside
              tab_id[0] = v_id[tab1[i0][1]]; // Inside
              tab_id[1] = v_id[tab1[i0][0]];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              tab_id[0] = v_id[tab1[i0][0]]; // Outside
              tab_id[1] = v_id[i0];
              tab_id[2] = p_id[0];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            else
            {
              tab_id[0] = v_id[tab1[i0][0]]; // Inside
              tab_id[1] = v_id[i0];
              tab_id[2] = p_id[0];
              newCellId = newcellArray->InsertNextCell(3, tab_id);

              tab_id[0] = v_id[tab1[i0][1]]; // Outside
              tab_id[1] = v_id[tab1[i0][0]];
              tab_id[2] = p_id[0];
              newCellId = cellarrayout->InsertNextCell(3, tab_id);
            }
            break;
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells(); // Inside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = tets[0]->InsertNextCell(npts, v_id);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();

    totalnewcells = cellarrayout->GetNumberOfCells(); // Outside

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarrayout->GetNextCell(npts, v_id);
      newCellId = tets[1]->InsertNextCell(npts, v_id);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
    cellarrayout->Delete();
  }
  arraytriangle->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipBox1D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray* lines, vtkPointData* inPD, vtkPointData* outPD,
  vtkCellData* inCD, vtkIdType cellId, vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayline = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[2];
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType tab_id[2];
  vtkIdType ptsline = 2;

  int i, j;
  unsigned int allInside;
  unsigned int planes;
  unsigned int cutInd;

  double value;
  double t;
  double v[3], x[3];
  double v_line[2][3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 1d cells to single line.
  this->CellGrid(cellType, npts, cellptId.data(), arrayline);

  unsigned int totalnewline = arrayline->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewline; idlinenew++)
  {
    arrayline->GetNextCell(ptsline, v_id);

    for (allInside = 1, i = 0; i < 2; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      if (!((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
            (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
            (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1])))
      {
        // outside
        allInside = 0;
      }
    }

    // Test Outside:
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 2; i++)
      {
        cellPts->GetPoint(v_id[i], v);

        if (v[0] >= this->BoundBoxClip[0][0])
        {
          test[0] = 0;
        }
        if (v[0] <= this->BoundBoxClip[0][1])
        {
          test[1] = 0;
        }
        if (v[1] >= this->BoundBoxClip[1][0])
        {
          test[2] = 0;
        }
        if (v[1] <= this->BoundBoxClip[1][1])
        {
          test[3] = 0;
        }
        if (v[2] >= this->BoundBoxClip[2][0])
        {
          test[4] = 0;
        }
        if (v[2] <= this->BoundBoxClip[2][1])
        {
          test[5] = 0;
        }
      } // for all points of the line.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        continue; // Line is outside.
      }
    } // if not allInside

    for (i = 0; i < 2; i++)
    {
      // Currently all points are injected because of the possibility
      // of intersection point merging.
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD->CopyData(inPD, ptId, iid[i]);
      }
    } // for all points of the triangle.

    if (allInside)
    {
      // Triangle inside.
      int newCellId = lines->InsertNextCell(2, iid);
      outCD->CopyData(inCD, cellId, newCellId);
      continue;
    }

    vtkCellArray* cellarray = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(2, iid);
    unsigned int idcellnew;

    // Test triangle intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      // The index of the dimension of the cut plane (x == 0, y == 1, z == 2).
      cutInd = planes / 2;

      // The plane is always parallel to unitary cube.
      value = this->BoundBoxClip[cutInd][planes % 2];

      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        vtkIdType p_id;
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_line[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_line[1]);

        // Check to see if line is inside plane.
        if (((planes % 2 == 0) && (v_line[0][cutInd] >= value) && (v_line[1][cutInd] >= value)) ||
          ((planes % 2 == 1) && (v_line[0][cutInd] <= value) && (v_line[1][cutInd] <= value)))
        {
          newCellId = newcellArray->InsertNextCell(2, v_id);
          continue;
        }

        // Check to see if line is outside plane.
        if (((planes % 2 == 0) && (v_line[0][cutInd] <= value) && (v_line[1][cutInd] <= value)) ||
          ((planes % 2 == 1) && (v_line[0][cutInd] >= value) && (v_line[1][cutInd] >= value)))
        {
          continue;
        }

        // If we are here, the plane intersects the line segment.
        t = (value - v_line[0][cutInd]) / (v_line[1][cutInd] - v_line[0][cutInd]);
        for (j = 0; j < 3; j++)
        {
          x[j] = (v_line[1][j] - v_line[0][j]) * t + v_line[0][j];
        }

        // Incorporate point into output and interpolate edge data as
        // necessary.
        if (locator->InsertUniquePoint(x, p_id))
        {
          this->InterpolateEdge(outPD, p_id, v_id[0], v_id[1], t);
        }

        // Add the clipped line to the output.
        if (((planes % 2 == 0) && (v_line[0][cutInd] >= value)) ||
          ((planes % 2 == 1) && (v_line[0][cutInd] <= value)))
        {
          // First point of line is inside.
          tab_id[0] = v_id[0];
          tab_id[1] = p_id;
          newcellArray->InsertNextCell(2, tab_id);
        }
        else
        {
          // Second point of line is inside.
          tab_id[0] = p_id;
          tab_id[1] = v_id[1];
          newcellArray->InsertNextCell(2, tab_id);
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells();

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = lines->InsertNextCell(npts, v_id);
      outCD->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();
  }
  arrayline->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipBoxInOut1D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** lines, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayline = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[2];
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType tab_id[2];
  vtkIdType ptsline = 2;

  int i, j;
  unsigned int allInside;
  unsigned int planes;
  unsigned int cutInd;

  double value;
  double t;
  double v[3], x[3];
  double v_line[2][3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 1d cells to single line.
  this->CellGrid(cellType, npts, cellptId.data(), arrayline);

  unsigned int totalnewline = arrayline->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewline; idlinenew++)
  {
    arrayline->GetNextCell(ptsline, v_id);

    for (allInside = 1, i = 0; i < 2; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      if (!((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
            (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
            (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1])))
      {
        // outside
        allInside = 0;
      }

      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD[0]->CopyData(inPD, ptId, iid[i]);
        outPD[1]->CopyData(inPD, ptId, iid[i]);
      }
    }

    // Test Outside:
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 2; i++)
      {
        cellPts->GetPoint(v_id[i], v);

        if (v[0] >= this->BoundBoxClip[0][0])
        {
          test[0] = 0;
        }
        if (v[0] <= this->BoundBoxClip[0][1])
        {
          test[1] = 0;
        }
        if (v[1] >= this->BoundBoxClip[1][0])
        {
          test[2] = 0;
        }
        if (v[1] <= this->BoundBoxClip[1][1])
        {
          test[3] = 0;
        }
        if (v[2] >= this->BoundBoxClip[2][0])
        {
          test[4] = 0;
        }
        if (v[2] <= this->BoundBoxClip[2][1])
        {
          test[5] = 0;
        }
      } // for all points of the line.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        int newCellId = lines[1]->InsertNextCell(2, iid);
        outCD[1]->CopyData(inCD, cellId, newCellId);
        continue; // Line is outside.
      }
    } // if not allInside

    if (allInside)
    {
      // Triangle inside.
      int newCellId = lines[0]->InsertNextCell(2, iid);
      outCD[0]->CopyData(inCD, cellId, newCellId);
      continue;
    }

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkCellArray* cellarrayout = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(2, iid);
    unsigned int idcellnew;

    // Test triangle intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      // The index of the dimension of the cut plane (x == 0, y == 1, z == 2).
      cutInd = planes / 2;

      // The plane is always parallel to unitary cube.
      value = this->BoundBoxClip[cutInd][planes % 2];

      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        vtkIdType p_id;
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_line[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_line[1]);

        // Check to see if line is inside plane.
        if (((planes % 2 == 0) && (v_line[0][cutInd] >= value) && (v_line[1][cutInd] >= value)) ||
          ((planes % 2 == 1) && (v_line[0][cutInd] <= value) && (v_line[1][cutInd] <= value)))
        {
          newCellId = newcellArray->InsertNextCell(2, v_id);
          continue;
        }

        // Check to see if line is outside plane.
        if (((planes % 2 == 0) && (v_line[0][cutInd] <= value) && (v_line[1][cutInd] <= value)) ||
          ((planes % 2 == 1) && (v_line[0][cutInd] >= value) && (v_line[1][cutInd] >= value)))
        {
          newCellId = lines[1]->InsertNextCell(2, v_id);
          outCD[1]->CopyData(inCD, cellId, newCellId);
          continue;
        }

        // If we are here, the plane intersects the line segment.
        t = (value - v_line[0][cutInd]) / (v_line[1][cutInd] - v_line[0][cutInd]);
        for (j = 0; j < 3; j++)
        {
          x[j] = (v_line[1][j] - v_line[0][j]) * t + v_line[0][j];
        }

        // Incorporate point into output and interpolate edge data as
        // necessary.
        if (locator->InsertUniquePoint(x, p_id))
        {
          this->InterpolateEdge(outPD[0], p_id, v_id[0], v_id[1], t);
          this->InterpolateEdge(outPD[1], p_id, v_id[0], v_id[1], t);
        }

        // Add the clipped line to the output.
        if (((planes % 2 == 0) && (v_line[0][cutInd] >= value)) ||
          ((planes % 2 == 1) && (v_line[0][cutInd] <= value)))
        {
          // First point of line is inside.
          tab_id[0] = v_id[0];
          tab_id[1] = p_id;
          newcellArray->InsertNextCell(2, tab_id);

          // Second point of line is outside.
          tab_id[0] = p_id;
          tab_id[1] = v_id[1];
          cellarrayout->InsertNextCell(2, tab_id);
        }
        else
        {
          // Second point of line is inside.
          tab_id[0] = p_id;
          tab_id[1] = v_id[1];
          newcellArray->InsertNextCell(2, tab_id);

          // First point of line is outside.
          tab_id[0] = v_id[0];
          tab_id[1] = p_id;
          cellarrayout->InsertNextCell(2, tab_id);
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells(); // Inside
    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = lines[0]->InsertNextCell(npts, v_id);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();

    totalnewcells = cellarrayout->GetNumberOfCells(); // Outside
    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarrayout->GetNextCell(npts, v_id);
      newCellId = lines[1]->InsertNextCell(npts, v_id);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
    cellarrayout->Delete();
  }
  arrayline->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipHexahedron1D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray* lines, vtkPointData* inPD, vtkPointData* outPD,
  vtkCellData* inCD, vtkIdType cellId, vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayline = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[2];
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType tab_id[2];
  vtkIdType ptsline = 2;

  int i, j;
  unsigned int allInside;
  unsigned int planes;

  double values[2];
  double t;
  double v[3], x[3];
  double v_line[2][3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 1d cells to single line.
  this->CellGrid(cellType, npts, cellptId.data(), arrayline);

  unsigned int totalnewline = arrayline->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewline; idlinenew++)
  {
    arrayline->GetNextCell(ptsline, v_id);

    for (allInside = 1, i = 0; i < 2; i++)
    {
      cellPts->GetPoint(v_id[i], v);

      for (int k = 0; k < 6; k++)
      {
        values[0] = (this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]));
        if (values[0] > 0)
        {
          // outside
          allInside = 0;
        }
      }
    }

    // Test Outside:
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 2; i++)
      {
        cellPts->GetPoint(v_id[i], v);

        // Use plane equation.
        for (int k = 0; k < 6; k++)
        {
          values[0] = (this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
            this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
            this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]));
          if (values[0] <= 0)
          {
            test[k] = 0;
          }
        } // for all planes of the hexahedron.
      }   // for all points of the line.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        continue; // Line is outside.
      }
    } // if not allInside

    for (i = 0; i < 2; i++)
    {
      // Currently all points are injected because of the possibility
      // of intersection point merging.
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);
      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD->CopyData(inPD, ptId, iid[i]);
      }
    } // for all points of the triangle.

    if (allInside)
    {
      // Triangle inside.
      int newCellId = lines->InsertNextCell(2, iid);
      outCD->CopyData(inCD, cellId, newCellId);
      continue;
    }

    vtkCellArray* cellarray = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(2, iid);
    unsigned int idcellnew;

    // Test triangle intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        vtkIdType p_id;
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_line[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_line[1]);

        const double* planeNormal = this->PlaneNormal[planes];
        const double* planePoint = this->PlanePoint[planes];
        values[0] = (planeNormal[0] * (v_line[0][0] - planePoint[0]) +
          planeNormal[1] * (v_line[0][1] - planePoint[1]) +
          planeNormal[2] * (v_line[0][2] - planePoint[2]));
        values[1] = (planeNormal[0] * (v_line[1][0] - planePoint[0]) +
          planeNormal[1] * (v_line[1][1] - planePoint[1]) +
          planeNormal[2] * (v_line[1][2] - planePoint[2]));

        // Check to see if line is inside plane.
        if ((values[0] <= 0) && (values[1] <= 0))
        {
          newCellId = newcellArray->InsertNextCell(2, v_id);
          continue;
        }

        // Check to see if line is outside plane.
        if ((values[0] >= 0) && (values[1] >= 0))
        {
          continue;
        }

        // If we are here, the plane intersects the line segment.
        t = values[0] / (values[0] - values[1]);
        for (j = 0; j < 3; j++)
        {
          x[j] = (v_line[1][j] - v_line[0][j]) * t + v_line[0][j];
        }

        // Incorporate point into output and interpolate edge data as
        // necessary.
        if (locator->InsertUniquePoint(x, p_id))
        {
          this->InterpolateEdge(outPD, p_id, v_id[0], v_id[1], t);
        }

        // Add the clipped line to the output.
        if (values[0] <= 0)
        {
          // First point of line is inside.
          tab_id[0] = v_id[0];
          tab_id[1] = p_id;
          newcellArray->InsertNextCell(2, tab_id);
        }
        else
        {
          // Second point of line is inside.
          tab_id[0] = p_id;
          tab_id[1] = v_id[1];
          newcellArray->InsertNextCell(2, tab_id);
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells();

    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = lines->InsertNextCell(npts, v_id);
      outCD->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();
  }
  arrayline->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipHexahedronInOut1D(vtkPoints* newPoints, vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** lines, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayline = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid[2];
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType tab_id[2];
  vtkIdType ptsline = 2;

  int i, j;
  unsigned int allInside;
  unsigned int planes;

  double values[2];
  double t;
  double v[3], x[3];
  double v_line[2][3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 1d cells to single line.
  this->CellGrid(cellType, npts, cellptId.data(), arrayline);

  unsigned int totalnewline = arrayline->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewline; idlinenew++)
  {
    arrayline->GetNextCell(ptsline, v_id);

    for (allInside = 1, i = 0; i < 2; i++)
    {
      ptId = cellIds->GetId(v_id[i]);
      cellPts->GetPoint(v_id[i], v);

      for (int k = 0; k < 6; k++)
      {
        values[0] = (this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
          this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
          this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]));
        if (values[0] > 0)
        {
          // outside
          allInside = 0;
        }
      }

      if (locator->InsertUniquePoint(v, iid[i]))
      {
        outPD[0]->CopyData(inPD, ptId, iid[i]);
        outPD[1]->CopyData(inPD, ptId, iid[i]);
      }
    }

    // Test Outside:
    if (!allInside)
    {
      unsigned int test[6] = { 1, 1, 1, 1, 1, 1 };
      for (i = 0; i < 2; i++)
      {
        cellPts->GetPoint(v_id[i], v);

        // Use plane equation.
        for (int k = 0; k < 6; k++)
        {
          values[0] = (this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
            this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
            this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]));
          if (values[0] <= 0)
          {
            test[k] = 0;
          }
        } // for all planes of the hexahedron.
      }   // for all points of the line.

      if ((test[0] == 1) || (test[1] == 1) || (test[2] == 1) || (test[3] == 1) || (test[4] == 1) ||
        (test[5] == 1))
      {
        int newCellId = lines[1]->InsertNextCell(2, iid);
        outCD[1]->CopyData(inCD, cellId, newCellId);
        continue; // Line is outside.
      }
    } // if not allInside

    if (allInside)
    {
      // Triangle inside.
      int newCellId = lines[0]->InsertNextCell(2, iid);
      outCD[0]->CopyData(inCD, cellId, newCellId);
      continue;
    }

    vtkCellArray* cellarray = vtkCellArray::New();
    vtkCellArray* cellarrayout = vtkCellArray::New();
    int newCellId = cellarray->InsertNextCell(2, iid);
    unsigned int idcellnew;

    // Test triangle intersection with each plane of box
    for (planes = 0; planes < 6; planes++)
    {
      unsigned int totalnewcells = cellarray->GetNumberOfCells();
      vtkCellArray* newcellArray = vtkCellArray::New();

      for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
      {
        vtkIdType p_id;
        cellarray->GetNextCell(npts, v_id);

        newPoints->GetPoint(v_id[0], v_line[0]); // coord (x,y,z)
        newPoints->GetPoint(v_id[1], v_line[1]);

        const double* planeNormal = this->PlaneNormal[planes];
        const double* planePoint = this->PlanePoint[planes];
        values[0] = (planeNormal[0] * (v_line[0][0] - planePoint[0]) +
          planeNormal[1] * (v_line[0][1] - planePoint[1]) +
          planeNormal[2] * (v_line[0][2] - planePoint[2]));
        values[1] = (planeNormal[0] * (v_line[1][0] - planePoint[0]) +
          planeNormal[1] * (v_line[1][1] - planePoint[1]) +
          planeNormal[2] * (v_line[1][2] - planePoint[2]));

        // Check to see if line is inside plane.
        if ((values[0] <= 0) && (values[1] <= 0))
        {
          newCellId = newcellArray->InsertNextCell(2, v_id);
          continue;
        }

        // Check to see if line is outside plane.
        if ((values[0] >= 0) && (values[1] >= 0))
        {
          newCellId = lines[1]->InsertNextCell(2, v_id);
          outCD[1]->CopyData(inCD, cellId, newCellId);
          continue;
        }

        // If we are here, the plane intersects the line segment.
        t = values[0] / (values[0] - values[1]);
        for (j = 0; j < 3; j++)
        {
          x[j] = (v_line[1][j] - v_line[0][j]) * t + v_line[0][j];
        }

        // Incorporate point into output and interpolate edge data as
        // necessary.
        if (locator->InsertUniquePoint(x, p_id))
        {
          this->InterpolateEdge(outPD[0], p_id, v_id[0], v_id[1], t);
          this->InterpolateEdge(outPD[1], p_id, v_id[0], v_id[1], t);
        }

        // Add the clipped line to the output.
        if (values[0] <= 0)
        {
          // First point of line is inside.
          tab_id[0] = v_id[0];
          tab_id[1] = p_id;
          newcellArray->InsertNextCell(2, tab_id);

          // Second point of line is outside.
          tab_id[0] = p_id;
          tab_id[1] = v_id[1];
          cellarrayout->InsertNextCell(2, tab_id);
        }
        else
        {
          // Second point of line is inside.
          tab_id[0] = p_id;
          tab_id[1] = v_id[1];
          newcellArray->InsertNextCell(2, tab_id);

          // First point of line is outside.
          tab_id[0] = v_id[0];
          tab_id[1] = p_id;
          cellarrayout->InsertNextCell(2, tab_id);
        }
      } // for all new cells
      cellarray->Delete();
      cellarray = newcellArray;
    } // for all planes

    unsigned int totalnewcells = cellarray->GetNumberOfCells(); // Inside
    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarray->GetNextCell(npts, v_id);
      newCellId = lines[0]->InsertNextCell(npts, v_id);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    cellarray->Delete();

    totalnewcells = cellarrayout->GetNumberOfCells(); // Outside
    for (idcellnew = 0; idcellnew < totalnewcells; idcellnew++)
    {
      cellarrayout->GetNextCell(npts, v_id);
      newCellId = lines[1]->InsertNextCell(npts, v_id);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
    cellarrayout->Delete();
  }
  arrayline->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipBox0D(vtkGenericCell* cell, vtkIncrementalPointLocator* locator,
  vtkCellArray* verts, vtkPointData* inPD, vtkPointData* outPD, vtkCellData* inCD, vtkIdType cellId,
  vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayvert = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid;
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType ptsvert = 1;

  int i;

  double v[3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 0d cells to single vert.
  this->CellGrid(cellType, npts, cellptId.data(), arrayvert);

  unsigned int totalnewvert = arrayvert->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewvert; idlinenew++)
  {
    arrayvert->GetNextCell(ptsvert, v_id);

    // Clipping verts is easy.  Either it is inside the box or it isn't.
    cellPts->GetPoint(v_id[0], v);
    if ((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
      (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
      (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1]))
    {
      // Vert is inside.
      ptId = cellIds->GetId(v_id[0]);
      if (locator->InsertUniquePoint(v, iid))
      {
        outPD->CopyData(inPD, ptId, iid);
      }

      int newCellId = verts->InsertNextCell(1, &iid);
      outCD->CopyData(inCD, cellId, newCellId);
    }
  }
  arrayvert->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipBoxInOut0D(vtkGenericCell* cell, vtkIncrementalPointLocator* locator,
  vtkCellArray** verts, vtkPointData* inPD, vtkPointData** outPD, vtkCellData* inCD,
  vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayvert = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid;
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType ptsvert = 1;

  int i;

  double v[3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 0d cells to single vert.
  this->CellGrid(cellType, npts, cellptId.data(), arrayvert);

  unsigned int totalnewvert = arrayvert->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewvert; idlinenew++)
  {
    arrayvert->GetNextCell(ptsvert, v_id);

    // One way or another, we are adding the point.
    ptId = cellIds->GetId(v_id[0]);
    cellPts->GetPoint(v_id[0], v);

    if (locator->InsertUniquePoint(v, iid))
    {
      outPD[0]->CopyData(inPD, ptId, iid);
      outPD[1]->CopyData(inPD, ptId, iid);
    }

    // Clipping verts is easy.  Either it is inside the box or it isn't.
    if ((v[0] >= this->BoundBoxClip[0][0]) && (v[0] <= this->BoundBoxClip[0][1]) &&
      (v[1] >= this->BoundBoxClip[1][0]) && (v[1] <= this->BoundBoxClip[1][1]) &&
      (v[2] >= this->BoundBoxClip[2][0]) && (v[2] <= this->BoundBoxClip[2][1]))
    {
      // Vert is inside.
      int newCellId = verts[0]->InsertNextCell(1, &iid);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    else
    {
      // Vert is outside.
      int newCellId = verts[1]->InsertNextCell(1, &iid);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
  }
  arrayvert->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipHexahedron0D(vtkGenericCell* cell, vtkIncrementalPointLocator* locator,
  vtkCellArray* verts, vtkPointData* inPD, vtkPointData* outPD, vtkCellData* inCD, vtkIdType cellId,
  vtkCellData* outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayvert = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid;
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType ptsvert = 1;

  int i;

  double v[3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 0d cells to single vert.
  this->CellGrid(cellType, npts, cellptId.data(), arrayvert);

  unsigned int totalnewvert = arrayvert->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewvert; idlinenew++)
  {
    arrayvert->GetNextCell(ptsvert, v_id);

    // Clipping verts is easy.  Either it is inside the hexahedron or it isn't.
    cellPts->GetPoint(v_id[0], v);
    int inside = 1;

    for (int k = 0; k < 6; k++)
    {
      double value = (this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
        this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
        this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]));
      if (value > 0)
      {
        inside = 0;
      }
    }

    if (inside)
    {
      // Vert is inside.
      ptId = cellIds->GetId(v_id[0]);
      if (locator->InsertUniquePoint(v, iid))
      {
        outPD->CopyData(inPD, ptId, iid);
      }

      int newCellId = verts->InsertNextCell(1, &iid);
      outCD->CopyData(inCD, cellId, newCellId);
    }
  }
  arrayvert->Delete();
}

//------------------------------------------------------------------------------

void vtkBoxClipDataSet::ClipHexahedronInOut0D(vtkGenericCell* cell,
  vtkIncrementalPointLocator* locator, vtkCellArray** verts, vtkPointData* inPD,
  vtkPointData** outPD, vtkCellData* inCD, vtkIdType cellId, vtkCellData** outCD)
{
  vtkIdType cellType = cell->GetCellType();
  vtkIdList* cellIds = cell->GetPointIds();
  vtkCellArray* arrayvert = vtkCellArray::New();
  vtkPoints* cellPts = cell->GetPoints();
  vtkIdType npts = cellPts->GetNumberOfPoints();
  std::vector<vtkIdType> cellptId(npts);
  vtkIdType iid;
  const vtkIdType* v_id = nullptr;
  vtkIdType ptId;
  vtkIdType ptsvert = 1;

  int i;

  double v[3];

  for (i = 0; i < npts; i++)
  {
    cellptId[i] = cellIds->GetId(i);
  }

  // Convert all 0d cells to single vert.
  this->CellGrid(cellType, npts, cellptId.data(), arrayvert);

  unsigned int totalnewvert = arrayvert->GetNumberOfCells();
  for (unsigned int idlinenew = 0; idlinenew < totalnewvert; idlinenew++)
  {
    arrayvert->GetNextCell(ptsvert, v_id);

    // One way or another, we are adding the point.
    ptId = cellIds->GetId(v_id[0]);
    cellPts->GetPoint(v_id[0], v);

    if (locator->InsertUniquePoint(v, iid))
    {
      outPD[0]->CopyData(inPD, ptId, iid);
      outPD[1]->CopyData(inPD, ptId, iid);
    }

    int inside = 1;
    for (int k = 0; k < 6; k++)
    {
      double value = (this->PlaneNormal[k][0] * (v[0] - this->PlanePoint[k][0]) +
        this->PlaneNormal[k][1] * (v[1] - this->PlanePoint[k][1]) +
        this->PlaneNormal[k][2] * (v[2] - this->PlanePoint[k][2]));
      if (value > 0)
      {
        inside = 0;
      }
    }

    // Clipping verts is easy.  Either it is inside the box or it isn't.
    if (inside)
    {
      // Vert is inside.
      int newCellId = verts[0]->InsertNextCell(1, &iid);
      outCD[0]->CopyData(inCD, cellId, newCellId);
    }
    else
    {
      // Vert is outside.
      int newCellId = verts[1]->InsertNextCell(1, &iid);
      outCD[1]->CopyData(inCD, cellId, newCellId);
    }
  }
  arrayvert->Delete();
}
VTK_ABI_NAMESPACE_END
