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

  Program:   Visualization Toolkit
  Module:    quadCellConsistency.cxx

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

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

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

// Hide VTK_DEPRECATED_IN_9_0_0() warnings for this class.
#define VTK_DEPRECATION_LEVEL 0

// .NAME
// .SECTION Description
// this program tests the consistency of face/edge ids between linear and quadratic cells

#include "vtkBiQuadraticQuad.h"
#include "vtkBiQuadraticQuadraticHexahedron.h"
#include "vtkBiQuadraticQuadraticWedge.h"
#include "vtkBiQuadraticTriangle.h"
#include "vtkCubicLine.h"
#include "vtkHexahedron.h"
#include "vtkLine.h"
#include "vtkPyramid.h"
#include "vtkQuad.h"
#include "vtkQuadraticEdge.h"
#include "vtkQuadraticHexahedron.h"
#include "vtkQuadraticLinearQuad.h"
#include "vtkQuadraticLinearWedge.h"
#include "vtkQuadraticPyramid.h"
#include "vtkQuadraticQuad.h"
#include "vtkQuadraticTetra.h"
#include "vtkQuadraticTriangle.h"
#include "vtkQuadraticWedge.h"
#include "vtkTetra.h"
#include "vtkTriQuadraticHexahedron.h"
#include "vtkTriangle.h"
#include "vtkWedge.h"

void InitializeCell(vtkCell* cell)
{
  // Default initialize the cell ids to 0,1,2 ... n
  int n = cell->GetNumberOfPoints();
  for (int i = 0; i < n; i++)
  {
    cell->GetPointIds()->SetId(i, i);
  }
}

// Check that corner points id match quad ones for each edges
int CompareCellEdges(vtkCell* linear, vtkCell* quadratic)
{
  int dif;
  int sum = 0;
  int nEdges = linear->GetNumberOfEdges();
  for (int edge = 0; edge < nEdges; edge++)
  {
    vtkCell* lEdge = linear->GetEdge(edge);
    vtkCell* qEdge = quadratic->GetEdge(edge);

    int n = lEdge->GetNumberOfPoints();
    // Check that the points of the linear cell match the one from the quadratic one
    for (int i = 0; i < n; i++)
    {
      dif = lEdge->GetPointIds()->GetId(i) - qEdge->GetPointIds()->GetId(i);
      sum += dif;
    }
  }
  return sum;
}

// Check that corner points id match quad ones for each faces
int CompareCellFaces(vtkCell* linear, vtkCell* quadratic)
{
  int dif;
  int sum = 0;
  int nFaces = linear->GetNumberOfFaces();
  for (int face = 0; face < nFaces; face++)
  {
    vtkCell* lFace = linear->GetFace(face);
    vtkCell* qFace = quadratic->GetFace(face);

    int n = lFace->GetNumberOfPoints();
    // Check that linear Triangle match quad Tri
    if (lFace->GetCellType() == VTK_TRIANGLE)
      sum += (qFace->GetCellType() != VTK_QUADRATIC_TRIANGLE &&
        qFace->GetCellType() != VTK_BIQUADRATIC_TRIANGLE);
    // Check that linear Quad match quad Quad
    if (lFace->GetCellType() == VTK_QUAD &&
      (qFace->GetCellType() != VTK_QUADRATIC_QUAD && qFace->GetCellType() != VTK_BIQUADRATIC_QUAD &&
        qFace->GetCellType() != VTK_QUADRATIC_LINEAR_QUAD))
      sum++;
    // Check that the points of the linear cell match the one from the quadratic one
    for (int i = 0; i < n; i++)
    {
      dif = lFace->GetPointIds()->GetId(i) - qFace->GetPointIds()->GetId(i);
      sum += dif;
    }
  }
  return sum;
}

int quadCellConsistency(int, char*[])
{
  int ret = 0;
  // Line / vtkQuadraticEdge / CubicLine:
  vtkLine* edge = vtkLine::New();
  vtkQuadraticEdge* qedge = vtkQuadraticEdge::New();
  vtkCubicLine* culine = vtkCubicLine::New();

  InitializeCell(edge);
  InitializeCell(qedge);
  ret += CompareCellEdges(edge, qedge);
  ret += CompareCellFaces(edge, qedge);

  qedge->Delete();

  InitializeCell(culine);
  ret += CompareCellEdges(edge, culine);
  ret += CompareCellFaces(edge, culine);

  edge->Delete();
  culine->Delete();

  // Triangles:
  vtkTriangle* tri = vtkTriangle::New();
  vtkQuadraticTriangle* qtri = vtkQuadraticTriangle::New();
  vtkBiQuadraticTriangle* bitri = vtkBiQuadraticTriangle::New();

  InitializeCell(tri);
  InitializeCell(qtri);
  ret += CompareCellEdges(tri, qtri);
  ret += CompareCellFaces(tri, qtri);

  qtri->Delete();

  InitializeCell(bitri);
  ret += CompareCellEdges(tri, bitri);
  ret += CompareCellFaces(tri, bitri);

  tri->Delete();
  bitri->Delete();

  // Quad
  vtkQuad* quad = vtkQuad::New();
  vtkQuadraticQuad* qquad = vtkQuadraticQuad::New();
  vtkBiQuadraticQuad* biqquad = vtkBiQuadraticQuad::New();
  vtkQuadraticLinearQuad* qlquad = vtkQuadraticLinearQuad::New();

  InitializeCell(quad);
  InitializeCell(qquad);
  InitializeCell(biqquad);
  InitializeCell(qlquad);
  ret += CompareCellEdges(quad, qquad);
  ret += CompareCellFaces(quad, qquad);
  ret += CompareCellEdges(quad, biqquad);
  ret += CompareCellFaces(quad, biqquad);
  ret += CompareCellEdges(quad, qlquad);
  ret += CompareCellFaces(quad, qlquad);

  quad->Delete();
  qquad->Delete();
  biqquad->Delete();
  qlquad->Delete();

  // Tetra
  vtkTetra* tetra = vtkTetra::New();
  vtkQuadraticTetra* qtetra = vtkQuadraticTetra::New();

  InitializeCell(tetra);
  InitializeCell(qtetra);
  ret += CompareCellEdges(tetra, qtetra);
  ret += CompareCellFaces(tetra, qtetra);

  tetra->Delete();
  qtetra->Delete();

  // Hexhedron
  vtkHexahedron* hex = vtkHexahedron::New();
  vtkQuadraticHexahedron* qhex = vtkQuadraticHexahedron::New();
  vtkTriQuadraticHexahedron* triqhex = vtkTriQuadraticHexahedron::New();
  vtkBiQuadraticQuadraticHexahedron* biqqhex = vtkBiQuadraticQuadraticHexahedron::New();

  InitializeCell(hex);
  InitializeCell(qhex);
  InitializeCell(triqhex);
  InitializeCell(biqqhex);
  ret += CompareCellEdges(hex, qhex);
  ret += CompareCellFaces(hex, qhex);
  ret += CompareCellEdges(hex, triqhex);
  ret += CompareCellFaces(hex, triqhex);
  ret += CompareCellEdges(hex, biqqhex);
  ret += CompareCellFaces(hex, biqqhex);

  hex->Delete();
  qhex->Delete();
  triqhex->Delete();
  biqqhex->Delete();

  // Pyramid
  vtkPyramid* pyr = vtkPyramid::New();
  vtkQuadraticPyramid* qpyr = vtkQuadraticPyramid::New();

  InitializeCell(pyr);
  InitializeCell(qpyr);
  ret += CompareCellEdges(pyr, qpyr);
  ret += CompareCellFaces(pyr, qpyr);

  pyr->Delete();
  qpyr->Delete();

  // Wedge cells
  vtkWedge* wedge = vtkWedge::New();
  vtkQuadraticWedge* qwedge = vtkQuadraticWedge::New();
  vtkBiQuadraticQuadraticWedge* biqwedge = vtkBiQuadraticQuadraticWedge::New();

  InitializeCell(wedge);
  InitializeCell(qwedge);
  InitializeCell(biqwedge);
  ret += CompareCellEdges(wedge, qwedge);
  ret += CompareCellFaces(wedge, qwedge);
  ret += CompareCellEdges(wedge, biqwedge);
  ret += CompareCellFaces(wedge, biqwedge);

  wedge->Delete();
  qwedge->Delete();
  biqwedge->Delete();

  return ret;
}
