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

// .NAME Test of vtkOrderedTriangulator
// .SECTION Description
// this program tests the class vtkOrderedTriangulator
// It shows the effect of the delaunay criteria compare to an iso parametric
// case where this criteria does not apply.

#include "vtkDataSetMapper.h"
#include "vtkOrderedTriangulator.h"
#include "vtkPoints.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkShrinkFilter.h"
#include "vtkUnstructuredGrid.h"

//------------------------------------------------------------------------------
static double para_coord1[24] = {
  0.0, 0.0, 0.0, // 0
  1.0, 0.0, 0.0, // 1
  0.0, 1.0, 0.0, // 2
  0.5, 0.0, 0.0, // 3
  0.0, 0.5, 0.0, // 4
  0.0, 0.0, 1.0, // 5
};

static double para_coord2[24] = {
  0.0, 1.0, 0.0, // 0
  0.0, 0.0, 0.0, // 1
  1.0, 0.0, 0.0, // 2
  0.0, 0.5, 0.0, // 3
  0.5, 0.5, 0.0, // 4
  0.0, 0.0, 1.0, // 5
};

static double points[33] = {
  0.0, 0.0, 0.0,  // 0
  0.0, -1.0, 0.0, // 1
  1.0, 0.0, 0.0,  // 2
  0.0, -0.5, 0.0, // 3
  0.5, 0.0, 0.0,  // 4
  0.0, 0.0, 1.0,  // 5
};

//------------------------------------------------------------------------------
static void isomorphism(double in[3], double out[3])
{
  out[0] = in[0] + in[2];
  out[1] = in[0] + in[1];
  out[2] = in[1] + in[2];
}

//------------------------------------------------------------------------------
int TestOrderedTriangulator(int argc, char* argv[])
{
  int i;
  vtkOrderedTriangulator* triangulator1 = vtkOrderedTriangulator::New();
  triangulator1->InitTriangulation(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 200);
  triangulator1->PreSortedOff();

  vtkOrderedTriangulator* triangulator2 = vtkOrderedTriangulator::New();
  triangulator2->InitTriangulation(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 200);
  triangulator2->PreSortedOff();

  vtkOrderedTriangulator* isotriangulator1 = vtkOrderedTriangulator::New();
  isotriangulator1->InitTriangulation(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 200);
  isotriangulator1->PreSortedOff();

  vtkOrderedTriangulator* isotriangulator2 = vtkOrderedTriangulator::New();
  isotriangulator2->InitTriangulation(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 200);
  isotriangulator2->PreSortedOff();

  double* p = points;

  vtkPoints* Points = vtkPoints::New();
  Points->SetNumberOfPoints(6);
  for (i = 0; i < 6; i++, p += 3)
  {
    Points->SetPoint(i, p);
  }

  // first case
  for (i = 0; i < 6; i++)
  {
    double* temp = points + 3 * i;
    double* temp2 = para_coord1 + 3 * i;
    triangulator1->InsertPoint(i, temp, temp2, 0);
  }
  triangulator1->Triangulate();

  // second case:
  for (i = 0; i < 6; i++)
  {
    double* temp = points + 3 * i;
    double* temp2 = para_coord2 + 3 * i;
    triangulator2->InsertPoint(i, temp, temp2, 0);
  }
  triangulator2->Triangulate();

  // We now use isocoordinate and repeat case one and two
  // first case
  for (i = 0; i < 6; i++)
  {
    double* temp = points + 3 * i;
    double* temp2 = para_coord1 + 3 * i;
    double iso[3];
    isomorphism(temp2, iso);
    isotriangulator1->InsertPoint(i, temp, iso, 0);
  }
  isotriangulator1->Triangulate();

  // second case:
  for (i = 0; i < 6; i++)
  {
    double* temp = points + 3 * i;
    double* temp2 = para_coord2 + 3 * i;
    double iso[3];
    isomorphism(temp2, iso);
    isotriangulator2->InsertPoint(i, temp, iso, 0);
  }
  isotriangulator2->Triangulate();

  vtkUnstructuredGrid* aTetraGrid1 = vtkUnstructuredGrid::New();
  aTetraGrid1->Allocate(1, 1);
  triangulator1->AddTetras(0, aTetraGrid1);
  aTetraGrid1->SetPoints(Points);

  vtkUnstructuredGrid* aTetraGrid2 = vtkUnstructuredGrid::New();
  aTetraGrid2->Allocate(1, 1);
  triangulator2->AddTetras(0, aTetraGrid2);
  aTetraGrid2->SetPoints(Points);

  // iso cases:
  vtkUnstructuredGrid* isoTetraGrid1 = vtkUnstructuredGrid::New();
  isoTetraGrid1->Allocate(1, 1);
  isotriangulator1->AddTetras(0, isoTetraGrid1);
  isoTetraGrid1->SetPoints(Points);

  vtkUnstructuredGrid* isoTetraGrid2 = vtkUnstructuredGrid::New();
  isoTetraGrid2->Allocate(1, 1);
  isotriangulator2->AddTetras(0, isoTetraGrid2);
  isoTetraGrid2->SetPoints(Points);

  // First tets:
  vtkShrinkFilter* shrink1 = vtkShrinkFilter::New();
  shrink1->SetInputData(aTetraGrid1);
  shrink1->SetShrinkFactor(0.7);

  vtkDataSetMapper* aTetraMapper1 = vtkDataSetMapper::New();
  aTetraMapper1->SetInputConnection(shrink1->GetOutputPort());

  vtkActor* aTetraActor1 = vtkActor::New();
  aTetraActor1->SetMapper(aTetraMapper1);

  // Second tets:
  vtkShrinkFilter* shrink2 = vtkShrinkFilter::New();
  shrink2->SetInputData(aTetraGrid2);
  shrink2->SetShrinkFactor(0.7);

  vtkDataSetMapper* aTetraMapper2 = vtkDataSetMapper::New();
  aTetraMapper2->SetInputConnection(shrink2->GetOutputPort());

  vtkActor* aTetraActor2 = vtkActor::New();
  aTetraActor2->SetMapper(aTetraMapper2);

  // iso cases:
  // First tets:
  vtkShrinkFilter* isoshrink1 = vtkShrinkFilter::New();
  isoshrink1->SetInputData(isoTetraGrid1);
  isoshrink1->SetShrinkFactor(0.7);

  vtkDataSetMapper* isoTetraMapper1 = vtkDataSetMapper::New();
  isoTetraMapper1->SetInputConnection(isoshrink1->GetOutputPort());

  vtkActor* isoTetraActor1 = vtkActor::New();
  isoTetraActor1->SetMapper(isoTetraMapper1);

  // Second tets:
  vtkShrinkFilter* isoshrink2 = vtkShrinkFilter::New();
  isoshrink2->SetInputData(isoTetraGrid2);
  isoshrink2->SetShrinkFactor(0.7);

  vtkDataSetMapper* isoTetraMapper2 = vtkDataSetMapper::New();
  isoTetraMapper2->SetInputConnection(isoshrink2->GetOutputPort());

  vtkActor* isoTetraActor2 = vtkActor::New();
  isoTetraActor2->SetMapper(isoTetraMapper2);

  // Place everybody
  aTetraActor2->AddPosition(1.2, 0.0, 0);
  isoTetraActor1->AddPosition(0.0, 1.2, 0);
  isoTetraActor2->AddPosition(1.2, 1.2, 0);

  vtkRenderer* renderer = vtkRenderer::New();
  vtkRenderWindow* renWin = vtkRenderWindow::New();
  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();

  renderer->SetBackground(1, 1, 1);
  renderer->AddActor(aTetraActor1);
  renderer->AddActor(aTetraActor2);
  renderer->AddActor(isoTetraActor1);
  renderer->AddActor(isoTetraActor2);

  renWin->AddRenderer(renderer);
  renWin->SetSize(300, 300);

  iren->SetRenderWindow(renWin);
  renWin->Render();

  int retVal = vtkRegressionTestImage(renWin);
  if (retVal == vtkRegressionTester::DO_INTERACTOR)
  {
    iren->Start();
  }

  // Clean up
  Points->Delete();
  triangulator1->Delete();
  aTetraGrid1->Delete();
  shrink1->Delete();
  aTetraActor1->Delete();
  aTetraMapper1->Delete();

  triangulator2->Delete();
  aTetraGrid2->Delete();
  shrink2->Delete();
  aTetraActor2->Delete();
  aTetraMapper2->Delete();

  isotriangulator1->Delete();
  isoTetraGrid1->Delete();
  isoshrink1->Delete();
  isoTetraActor1->Delete();
  isoTetraMapper1->Delete();

  isotriangulator2->Delete();
  isoTetraGrid2->Delete();
  isoshrink2->Delete();
  isoTetraActor2->Delete();
  isoTetraMapper2->Delete();

  renderer->Delete();
  renWin->Delete();
  iren->Delete();

  return 0;
}
