// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause

#include "vtkAppendFilter.h"
#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataSetSurfaceFilter.h"
#include "vtkDoubleArray.h"
#include "vtkGenericCell.h"
#include "vtkHexahedron.h"
#include "vtkPlaneSource.h"
#include "vtkPointData.h"
#include "vtkPointLocator.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkPolyLine.h"
#include "vtkQuadraticWedge.h"
#include "vtkRectilinearGrid.h"
#include "vtkRegularPolygonSource.h"
#include "vtkSmartPointer.h"
#include "vtkStripper.h"
#include "vtkStructuredGrid.h"
#include "vtkTestErrorObserver.h"
#include "vtkTetra.h"
#include "vtkTriangleFilter.h"
#include "vtkUniformGrid.h"
#include "vtkUnstructuredGrid.h"

#include <map>
#include <sstream>

static vtkSmartPointer<vtkDataSet> CreatePolyData(int xres, int yres);
static vtkSmartPointer<vtkDataSet> CreateTriangleStripData(int xres, int yres);
static vtkSmartPointer<vtkDataSet> CreateTetraData();
static vtkSmartPointer<vtkDataSet> CreatePolygonData(int sides = 6);
static vtkSmartPointer<vtkDataSet> CreateQuadraticWedgeData();
static vtkSmartPointer<vtkDataSet> CreateUniformGrid(unsigned int, unsigned int, unsigned int);
static vtkSmartPointer<vtkDataSet> CreateRectilinearGrid();
static vtkSmartPointer<vtkDataSet> CreateStructuredGrid(bool blank = false);
static vtkSmartPointer<vtkDataSet> CreateBadAttributes();
static vtkSmartPointer<vtkDataSet> CreateGenericCellData(int cellType);

namespace test
{
// What to expect for a cell
class CellDescription
{
public:
  CellDescription(int cellType, int numCells)
  {
    this->Type = cellType;
    this->Cells = numCells;
  }
  CellDescription()
    : Type(0)
    , Cells(0)
  {
  }
  int Type;
  int Cells;
};
}
int UnitTestDataSetSurfaceFilter(int, char*[])
{
  int status = EXIT_SUCCESS;
  {
    std::cout << "Testing empty print...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    std::ostringstream emptyPrint;
    filter->Print(emptyPrint);
    std::cout << "PASSED." << std::endl;
  }
  {
    std::map<std::string, test::CellDescription> typesToProcess;
    typesToProcess["Vertex"] = test::CellDescription(VTK_VERTEX, 1);
    typesToProcess["Line"] = test::CellDescription(VTK_LINE, 1);
    typesToProcess["Triangle"] = test::CellDescription(VTK_TRIANGLE, 1);
    typesToProcess["Pixel"] = test::CellDescription(VTK_PIXEL, 1);
    typesToProcess["Quad"] = test::CellDescription(VTK_QUAD, 1);
    typesToProcess["Tetra"] = test::CellDescription(VTK_TETRA, 4);
    typesToProcess["Voxel"] = test::CellDescription(VTK_VOXEL, 6);
    typesToProcess["Hexahedron"] = test::CellDescription(VTK_HEXAHEDRON, 6);
    typesToProcess["Wedge"] = test::CellDescription(VTK_WEDGE, 5);
    typesToProcess["Pyramid"] = test::CellDescription(VTK_PYRAMID, 5);
    typesToProcess["PentagonalPrism"] = test::CellDescription(VTK_PENTAGONAL_PRISM, 7);
    typesToProcess["HexagonalPrism"] = test::CellDescription(VTK_HEXAGONAL_PRISM, 8);
    typesToProcess["QuadraticEdge"] = test::CellDescription(VTK_QUADRATIC_EDGE, 1);
    typesToProcess["QuadraticTriangle"] = test::CellDescription(VTK_QUADRATIC_TRIANGLE, 1);
    typesToProcess["QuadraticQuad"] = test::CellDescription(VTK_QUADRATIC_QUAD, 1);
    typesToProcess["QuadraticTetra"] = test::CellDescription(VTK_QUADRATIC_TETRA, 16);
    typesToProcess["QuadraticHexahedron"] = test::CellDescription(VTK_QUADRATIC_HEXAHEDRON, 36);
    typesToProcess["QuadraticWedge"] = test::CellDescription(VTK_QUADRATIC_WEDGE, 26);
    typesToProcess["QuadraticPyramid"] = test::CellDescription(VTK_QUADRATIC_PYRAMID, 22);
    typesToProcess["BiQuadraticQuad"] = test::CellDescription(VTK_BIQUADRATIC_QUAD, 8);
    typesToProcess["QuadraticLinearQuad"] = test::CellDescription(VTK_QUADRATIC_LINEAR_QUAD, 4);
    typesToProcess["QuadraticLinearWedge"] = test::CellDescription(VTK_QUADRATIC_LINEAR_WEDGE, 20);
    typesToProcess["BiQuadraticQuadraticWedge"] =
      test::CellDescription(VTK_BIQUADRATIC_QUADRATIC_WEDGE, 32);
    typesToProcess["TriQuadraticHexahedron"] =
      test::CellDescription(VTK_TRIQUADRATIC_HEXAHEDRON, 768);
    typesToProcess["TriQuadraticPyramid"] = test::CellDescription(VTK_TRIQUADRATIC_PYRAMID, 32);
    typesToProcess["EmptyCell"] = test::CellDescription(VTK_EMPTY_CELL, 0);

    std::map<std::string, test::CellDescription>::iterator it;
    for (it = typesToProcess.begin(); it != typesToProcess.end(); ++it)
    {
      std::cout << "Testing (" << it->first << ")...";
      vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
        vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
      filter->SetInputData(CreateGenericCellData(it->second.Type));
      filter->PassThroughCellIdsOn();
      filter->PassThroughPointIdsOn();
      if (it->first == "QuadraticTriangle" || it->first == "QuadraticQuad")
      {
        filter->SetNonlinearSubdivisionLevel(0);
      }
      if (it->first == "TriQuadraticHexahedron")
      {
        filter->SetNonlinearSubdivisionLevel(3);
      }
      filter->Update();
      int got = filter->GetOutput()->GetNumberOfCells();
      int expected = it->second.Cells;
      if (got != expected)
      {
        std::cout << " got " << got << " cells but expected " << expected;
        std::cout << " FAILED." << std::endl;
        status++;
      }
      else
      {
        std::cout << " # of cells: " << got;
        std::cout << " PASSED." << std::endl;
      }
      std::cout.flush();
    }
  }
  {
    std::cout << "Testing default settings (PolyData)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreatePolyData(10, 20));
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (TriangleStrips)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateTriangleStripData(10, 20));
    filter->PassThroughCellIdsOff();
    filter->PassThroughPointIdsOff();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (PolyData Polygons)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreatePolygonData(9));
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (UnstructuredGrid, QuadraticWedge, Tetra, PassThroughCellIds, "
                 "PassThroughPointIds)...";
    vtkSmartPointer<vtkAppendFilter> append = vtkSmartPointer<vtkAppendFilter>::New();
    append->AddInputData(CreateTetraData());
    append->AddInputData(CreateQuadraticWedgeData());

    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputConnection(append->GetOutputPort());
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (UniformGrid(5,10,1), PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateUniformGrid(5, 10, 1));
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::ostringstream fullPrint;
    filter->Print(fullPrint);

    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (UniformGrid(1,5,10), PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateUniformGrid(1, 5, 10));
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::ostringstream fullPrint;
    filter->Print(fullPrint);

    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (UniformGrid(5,1,10), PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateUniformGrid(5, 1, 10));
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::ostringstream fullPrint;
    filter->Print(fullPrint);

    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (UniformGrid, PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateUniformGrid(10, 5, 1));
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing DataSetExecute...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();

    vtkSmartPointer<vtkDataSet> ugrid = CreateUniformGrid(10, 5, 1);

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    filter->DataSetExecute(ugrid, polyData);

    int got = polyData->GetNumberOfCells();
    std::cout << " # of cells: " << got;

    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing UniformGridExecute all faces...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();

    vtkSmartPointer<vtkDataSet> ugrid = CreateUniformGrid(10, 5, 1);

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    vtkUniformGrid* grid = vtkUniformGrid::SafeDownCast(ugrid);
    int* tmpext = grid->GetExtent();
    vtkIdType ext[6];
    ext[0] = tmpext[0];
    ext[1] = tmpext[1];
    ext[2] = tmpext[2];
    ext[3] = tmpext[3];
    ext[4] = tmpext[4];
    ext[5] = tmpext[5];
    bool faces[6] = { true, true, true, true, true, true };
    filter->UniformGridExecute(ugrid, polyData, ext, ext, faces);

    int got = polyData->GetNumberOfCells();
    std::cout << " # of cells: " << got;

    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing UniformGridExecute three faces...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();

    vtkSmartPointer<vtkDataSet> ugrid = CreateUniformGrid(10, 5, 2);

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    vtkUniformGrid* grid = vtkUniformGrid::SafeDownCast(ugrid);
    int* tmpext = grid->GetExtent();
    vtkIdType ext[6];
    ext[0] = tmpext[0];
    ext[1] = tmpext[1];
    ext[2] = tmpext[2];
    ext[3] = tmpext[3];
    ext[4] = tmpext[4];
    ext[5] = tmpext[5];
    bool faces[6] = { true, false, true, false, true, false };
    filter->UniformGridExecute(ugrid, polyData, ext, ext, faces);

    int got = polyData->GetNumberOfCells();
    std::cout << " # of cells: " << got;

    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (RectilinearGrid, PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateRectilinearGrid());
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();

    int got = filter->GetOutput()->GetNumberOfCells();
    std::cout << " # of cells: " << got;
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (StructuredGrid, PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateStructuredGrid());
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    vtkPolyData* output = filter->GetOutput();
    if (output->GetNumberOfCells() != 10)
    {
      std::cerr << "Incorrect number of cells generated by vtkDataSetSurfaceFilter!\n"
                << "Expected: 10, Found: " << output->GetNumberOfCells();
      return 1;
    }
    else if (output->GetNumberOfPoints() != 32)
    {
      std::cerr << "Incorrect number of points generated by vtkDataSetSurfaceFilter\n"
                << "Expected 32, Found : " << output->GetNumberOfPoints();
      return 1;
    }
    std::cout << " PASSED." << std::endl;
  }
  {
    std::cout << "Testing (StructuredGrid, Blanking, PassThroughCellIds, PassThroughPointIds)...";
    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    vtkSmartPointer<vtkDataSet> input = CreateStructuredGrid(true);
    filter->SetInputData(input);
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->Update();
    vtkPolyData* output = filter->GetOutput();
    if (output->GetNumberOfCells() != 6)
    {
      std::cerr << "Incorrect number of cells generated by vtkDataSetSurfaceFilter!\n"
                << "Expected: 6, Found: " << output->GetNumberOfCells();
      return 1;
    }
    else if (output->GetNumberOfPoints() != 8)
    {
      std::cerr << "Incorrect number of points generated by vtkDataSetSurfaceFilter\n"
                << "Expected 8, Found : " << output->GetNumberOfPoints();
      return 1;
    }
    // verify that the blanked point is not present in output.
    double blankPt[3];
    input->GetPoint(6, blankPt);
    for (vtkIdType ptId = 0; ptId < output->GetNumberOfPoints(); ++ptId)
    {
      double x[3];
      output->GetPoint(ptId, x);
      if (vtkMath::Distance2BetweenPoints(blankPt, x) < 1.0e-5)
      {
        std::cerr << "Blanked point included in vtkDataSetSurfaceFilter output!\n"
                  << "ptId: " << ptId << '\n';
        return 1;
      }
    }
    std::cout << " PASSED." << std::endl;
  }
  // Error and warnings
  {
    std::cout << "Testing cells == 0 ...";
    vtkSmartPointer<vtkTest::ErrorObserver> warningObserver =
      vtkSmartPointer<vtkTest::ErrorObserver>::New();

    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(vtkSmartPointer<vtkPolyData>::New());
    filter->AddObserver(vtkCommand::WarningEvent, warningObserver);
    filter->Update();

    if (warningObserver->GetError() || warningObserver->GetWarning())
    {
      std::cout << " FAILED." << std::endl;
      status++;
    }
    else
    {
      std::cout << " PASSED." << std::endl;
    }
  }
  {
    std::cout << "Testing DataSetExecute cells == 0 ...";
    vtkSmartPointer<vtkTest::ErrorObserver> warningObserver =
      vtkSmartPointer<vtkTest::ErrorObserver>::New();

    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->AddObserver(vtkCommand::WarningEvent, warningObserver);

    vtkSmartPointer<vtkUnstructuredGrid> ugrid = vtkSmartPointer<vtkUnstructuredGrid>::New();

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    filter->DataSetExecute(ugrid, polyData);
    if (warningObserver->GetError() || warningObserver->GetWarning())
    {
      std::cout << " FAILED." << std::endl;
      status++;
    }
    else
    {
      std::cout << " PASSED." << std::endl;
    }
  }
  {
    std::cout << "Testing StructuredExecute invalid dataset error...";
    vtkSmartPointer<vtkTest::ErrorObserver> errorObserver =
      vtkSmartPointer<vtkTest::ErrorObserver>::New();

    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->AddObserver(vtkCommand::ErrorEvent, errorObserver);

    vtkSmartPointer<vtkUnstructuredGrid> ugrid = vtkSmartPointer<vtkUnstructuredGrid>::New();

    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    vtkIdType ext[6];
    ext[0] = 0;
    ext[1] = 1;
    ext[2] = 0;
    ext[3] = 1;
    ext[4] = 0;
    ext[5] = 1;

    filter->StructuredExecute(ugrid, polyData, ext, ext);

    int status1 = errorObserver->CheckErrorMessage("Invalid data set type: 4");
    if (status1)
    {
      std::cout << " FAILED." << std::endl;
      status++;
    }
    else
    {
      std::cout << " PASSED." << std::endl;
    }
  }
  {
    std::cout << "Testing BadAttributes error...";
    vtkSmartPointer<vtkTest::ErrorObserver> errorObserver =
      vtkSmartPointer<vtkTest::ErrorObserver>::New();

    vtkSmartPointer<vtkDataSetSurfaceFilter> filter =
      vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
    filter->SetInputData(CreateBadAttributes());
    filter->PassThroughCellIdsOn();
    filter->PassThroughPointIdsOn();
    filter->GetInput()->AddObserver(vtkCommand::ErrorEvent, errorObserver);
    filter->Update();

    int status1 = errorObserver->CheckErrorMessage(
      "Point array PointDataTestArray with 1 components, only has 2 tuples but there are 3 points");
    if (status1)
    {
      std::cout << " FAILED." << std::endl;
      status++;
    }
    else
    {
      std::cout << " PASSED." << std::endl;
    }
  }
  return status;
}

vtkSmartPointer<vtkDataSet> CreateTriangleStripData(int xres, int yres)
{
  vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
  plane->SetXResolution(xres);
  plane->SetYResolution(yres);
  plane->Update();

  vtkSmartPointer<vtkTriangleFilter> tris = vtkSmartPointer<vtkTriangleFilter>::New();
  tris->SetInputConnection(plane->GetOutputPort());
  vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
  stripper->SetInputConnection(tris->GetOutputPort());
  stripper->Update();

  vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid =
    vtkSmartPointer<vtkUnstructuredGrid>::New();
  unstructuredGrid->SetPoints(stripper->GetOutput()->GetPoints());
  unstructuredGrid->SetCells(VTK_TRIANGLE_STRIP, stripper->GetOutput()->GetStrips());
  return unstructuredGrid;
}

vtkSmartPointer<vtkDataSet> CreatePolyData(int xres, int yres)
{
  vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
  plane->SetXResolution(xres);
  plane->SetYResolution(yres);
  plane->Update();

  vtkSmartPointer<vtkTriangleFilter> tris = vtkSmartPointer<vtkTriangleFilter>::New();
  tris->SetInputConnection(plane->GetOutputPort());
  vtkSmartPointer<vtkStripper> stripper = vtkSmartPointer<vtkStripper>::New();
  stripper->SetInputConnection(tris->GetOutputPort());
  stripper->Update();

  vtkSmartPointer<vtkPolyData> pd = vtkSmartPointer<vtkPolyData>::New();
  pd = plane->GetOutput();
  return pd;
}

vtkSmartPointer<vtkDataSet> CreatePolygonData(int sides)
{
  vtkSmartPointer<vtkRegularPolygonSource> polygon =
    vtkSmartPointer<vtkRegularPolygonSource>::New();
  polygon->SetNumberOfSides(sides);
  polygon->Update();
  vtkSmartPointer<vtkIntArray> cellData = vtkSmartPointer<vtkIntArray>::New();
  cellData->SetNumberOfTuples(polygon->GetOutput()->GetNumberOfCells());
  cellData->SetName("CellDataTestArray");
  vtkIdType c = 0;
  for (vtkIdType i = 0; i < polygon->GetOutput()->GetNumberOfCells(); ++i)
  {
    cellData->SetTuple1(c++, i);
  }
  vtkSmartPointer<vtkIntArray> pointData = vtkSmartPointer<vtkIntArray>::New();
  pointData->SetNumberOfTuples(polygon->GetOutput()->GetNumberOfPoints());
  pointData->SetName("PointDataTestArray");
  c = 0;
  for (int i = 0; i < polygon->GetOutput()->GetNumberOfPoints(); ++i)
  {
    pointData->SetTuple1(c++, i);
  }

  vtkSmartPointer<vtkPolyData> pd = vtkSmartPointer<vtkPolyData>::New();
  pd = polygon->GetOutput();
  pd->GetPointData()->SetScalars(pointData);
  pd->GetCellData()->SetScalars(cellData);

  return pd;
}

vtkSmartPointer<vtkDataSet> CreateTetraData()
{
  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  points->InsertNextPoint(0, 0, 0);
  points->InsertNextPoint(1, 0, 0);
  points->InsertNextPoint(1, 1, 0);
  points->InsertNextPoint(0, 1, 1);
  points->InsertNextPoint(5, 5, 5);
  points->InsertNextPoint(6, 5, 5);
  points->InsertNextPoint(6, 6, 5);
  points->InsertNextPoint(5, 6, 6);

  vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid =
    vtkSmartPointer<vtkUnstructuredGrid>::New();
  unstructuredGrid->SetPoints(points);

  vtkSmartPointer<vtkTetra> tetra = vtkSmartPointer<vtkTetra>::New();
  tetra->GetPointIds()->SetId(0, 4);
  tetra->GetPointIds()->SetId(1, 5);
  tetra->GetPointIds()->SetId(2, 6);
  tetra->GetPointIds()->SetId(3, 7);

  vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
  cellArray->InsertNextCell(tetra);
  unstructuredGrid->SetCells(VTK_TETRA, cellArray);

  vtkSmartPointer<vtkIntArray> pointData = vtkSmartPointer<vtkIntArray>::New();
  pointData->SetNumberOfTuples(unstructuredGrid->GetNumberOfPoints());
  pointData->SetName("PointDataTestArray");
  int c = 0;
  for (vtkIdType id = 0; id < tetra->GetNumberOfPoints(); ++id)
  {
    pointData->SetTuple1(c++, id);
  }
  unstructuredGrid->GetPointData()->SetScalars(pointData);

  return unstructuredGrid;
}
vtkSmartPointer<vtkDataSet> CreateQuadraticWedgeData()
{
  vtkSmartPointer<vtkQuadraticWedge> aWedge = vtkSmartPointer<vtkQuadraticWedge>::New();
  double* pcoords = aWedge->GetParametricCoords();
  for (int i = 0; i < aWedge->GetNumberOfPoints(); ++i)
  {
    aWedge->GetPointIds()->SetId(i, i);
    aWedge->GetPoints()->SetPoint(
      i, *(pcoords + 3 * i), *(pcoords + 3 * i + 1), *(pcoords + 3 * i + 2));
  }

  vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid =
    vtkSmartPointer<vtkUnstructuredGrid>::New();
  unstructuredGrid->SetPoints(aWedge->GetPoints());

  vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
  cellArray->InsertNextCell(aWedge);
  unstructuredGrid->SetCells(VTK_QUADRATIC_WEDGE, cellArray);
  return unstructuredGrid;
}
vtkSmartPointer<vtkDataSet> CreateUniformGrid(
  unsigned int dimx, unsigned int dimy, unsigned int dimz)
{
  vtkSmartPointer<vtkUniformGrid> image = vtkSmartPointer<vtkUniformGrid>::New();

  image->SetDimensions(dimx, dimy, dimz);

  image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);

  for (unsigned int x = 0; x < dimx; x++)
  {
    for (unsigned int y = 0; y < dimy; y++)
    {
      for (unsigned int z = 0; z < dimz; z++)
      {
        unsigned char* pixel = static_cast<unsigned char*>(image->GetScalarPointer(x, y, 0));
        if (x < dimx / 2)
        {
          pixel[0] = 50;
        }
        else
        {
          pixel[0] = 150;
        }
      }
    }
  }
  return image;
}

vtkSmartPointer<vtkDataSet> CreateGenericCellData(int cellType)
{
  vtkSmartPointer<vtkGenericCell> aCell = vtkSmartPointer<vtkGenericCell>::New();
  aCell->SetCellType(cellType);
  if (aCell->RequiresInitialization())
  {
    aCell->Initialize();
  }

  int numPts = aCell->GetNumberOfPoints();
  double* pcoords = aCell->GetParametricCoords();
  for (int j = 0; j < numPts; ++j)
  {
    aCell->GetPointIds()->SetId(j, j);
    aCell->GetPoints()->SetPoint(j, pcoords + 3 * j);
  }

  vtkSmartPointer<vtkIntArray> pointData = vtkSmartPointer<vtkIntArray>::New();
  pointData->SetNumberOfTuples(numPts);
  pointData->SetName("PointDataTestArray");
  for (int j = 0; j < numPts; ++j)
  {
    pointData->SetTuple1(j, j);
  }

  vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid =
    vtkSmartPointer<vtkUnstructuredGrid>::New();
  unstructuredGrid->SetPoints(aCell->GetPoints());
  unstructuredGrid->GetPointData()->SetScalars(pointData);

  vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
  cellArray->InsertNextCell(aCell);
  unstructuredGrid->SetCells(cellType, cellArray);
  return unstructuredGrid;
}

vtkSmartPointer<vtkDataSet> CreateRectilinearGrid()
{
  vtkSmartPointer<vtkRectilinearGrid> grid = vtkSmartPointer<vtkRectilinearGrid>::New();
  grid->SetDimensions(2, 3, 1);

  vtkSmartPointer<vtkDoubleArray> xArray = vtkSmartPointer<vtkDoubleArray>::New();
  xArray->InsertNextValue(0.0);
  xArray->InsertNextValue(2.0);

  vtkSmartPointer<vtkDoubleArray> yArray = vtkSmartPointer<vtkDoubleArray>::New();
  yArray->InsertNextValue(0.0);
  yArray->InsertNextValue(1.0);
  yArray->InsertNextValue(2.0);

  vtkSmartPointer<vtkDoubleArray> zArray = vtkSmartPointer<vtkDoubleArray>::New();
  zArray->InsertNextValue(0.0);

  grid->SetXCoordinates(xArray);
  grid->SetYCoordinates(yArray);
  grid->SetZCoordinates(zArray);

  return grid;
}

// Generate a 1x2x1 vtkStructuredGrid with 12 points.
vtkSmartPointer<vtkDataSet> CreateStructuredGrid(bool blank)
{
  vtkSmartPointer<vtkStructuredGrid> grid = vtkSmartPointer<vtkStructuredGrid>::New();

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  double x, y, z;

  x = 0.0;
  y = 0.0;
  z = 0.0;

  for (unsigned int k = 0; k < 2; k++)
  {
    z += 2.0;
    for (unsigned int j = 0; j < 3; j++)
    {
      y += 1.0;
      for (unsigned int i = 0; i < 2; i++)
      {
        x += .5;
        points->InsertNextPoint(x, y, z);
      }
    }
  }

  // Specify the dimensions of the grid
  grid->SetDimensions(2, 3, 2);
  grid->SetPoints(points);

  // When blanking==true, the 6th point (0th cell) is blanked.
  if (blank)
  {
    grid->BlankPoint(points->GetNumberOfPoints() / 2);
  }
  return grid;
}

vtkSmartPointer<vtkDataSet> CreateBadAttributes()
{
  vtkSmartPointer<vtkPolyLine> aPolyLine = vtkSmartPointer<vtkPolyLine>::New();
  aPolyLine->GetPointIds()->SetNumberOfIds(3);
  aPolyLine->GetPointIds()->SetId(0, 0);
  aPolyLine->GetPointIds()->SetId(1, 1);
  aPolyLine->GetPointIds()->SetId(2, 2);

  aPolyLine->GetPoints()->SetNumberOfPoints(3);
  aPolyLine->GetPoints()->SetPoint(0, 10.0, 20.0, 30.0);
  aPolyLine->GetPoints()->SetPoint(1, 10.0, 30.0, 30.0);
  aPolyLine->GetPoints()->SetPoint(2, 10.0, 30.0, 40.0);

  vtkSmartPointer<vtkUnstructuredGrid> unstructuredGrid =
    vtkSmartPointer<vtkUnstructuredGrid>::New();
  unstructuredGrid->SetPoints(aPolyLine->GetPoints());

  vtkSmartPointer<vtkIntArray> pointData = vtkSmartPointer<vtkIntArray>::New();
  pointData->SetNumberOfTuples(2);
  pointData->SetName("PointDataTestArray");
  for (int j = 0; j < 2; ++j)
  {
    pointData->SetTuple1(j, j);
  }

  vtkSmartPointer<vtkCellArray> cellArray = vtkSmartPointer<vtkCellArray>::New();
  cellArray->InsertNextCell(aPolyLine);
  unstructuredGrid->SetCells(VTK_POLY_LINE, cellArray);
  unstructuredGrid->GetPointData()->SetScalars(pointData);

  return unstructuredGrid;
}
