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

#include "vtkMathUtilities.h"
#include "vtkMatrix3x3.h"
#include "vtkNew.h"
#include "vtkPoints2D.h"
#include "vtkTransform2D.h"

int TestMatrix3x3(int, char*[])
{
  // Instantiate a vtkMatrix3x3 and test out the functions.
  vtkNew<vtkMatrix3x3> matrix;
  cout << "Testing vtkMatrix3x3..." << endl;
  if (!matrix->IsIdentity())
  {
    vtkGenericWarningMacro("Matrix should be initialized to identity.");
    return 1;
  }
  matrix->Invert();
  if (!matrix->IsIdentity())
  {
    vtkGenericWarningMacro("Inverse of identity should be identity.");
    return 1;
  }
  // Check copying and comparison
  vtkNew<vtkMatrix3x3> matrix2;
  matrix2->DeepCopy(matrix);
  for (int i = 0; i < 3; ++i)
  {
    for (int j = 0; j < 3; ++j)
      if (matrix->GetElement(i, j) != matrix2->GetElement(i, j))
      {
        vtkGenericWarningMacro("DeepCopy of vtkMatrix3x3 failed.");
        return 1;
      }
  }
  matrix2->SetElement(0, 0, 5.0);
  if (!vtkMathUtilities::FuzzyCompare(matrix2->GetElement(0, 0), 5.0))
  {
    vtkGenericWarningMacro("Value not stored in matrix properly.");
    return 1;
  }
  matrix2->SetElement(1, 2, 42.0);
  if (!vtkMathUtilities::FuzzyCompare(matrix2->GetElement(1, 2), 42.0))
  {
    vtkGenericWarningMacro("Value not stored in matrix properly.");
    return 1;
  }

  // Test matrix transpose
  matrix2->Transpose();
  if (!vtkMathUtilities::FuzzyCompare(matrix2->GetElement(0, 0), 5.0) ||
    !vtkMathUtilities::FuzzyCompare(matrix2->GetElement(2, 1), 42.0))
  {
    vtkGenericWarningMacro("vtkMatrix::Transpose failed.");
    return 1;
  }

  matrix2->Invert();
  if (!vtkMathUtilities::FuzzyCompare(matrix2->GetElement(0, 0), 0.2) ||
    !vtkMathUtilities::FuzzyCompare(matrix2->GetElement(2, 1), -42.0))
  {
    vtkGenericWarningMacro("vtkMatrix::Invert failed.");
    return 1;
  }

  // Multiply a coordinate by this matrix.
  double inout[3] = { 12.3, 45.6, 78.9 };
  matrix2->MultiplyPoint(inout, inout);

  if (!vtkMathUtilities::FuzzyCompare(inout[0], 2.46, 1e-5) ||
    !vtkMathUtilities::FuzzyCompare(inout[1], 45.6, 1e-5) ||
    !vtkMathUtilities::FuzzyCompare(inout[2], -1836.3, 1e-5))
  {
    vtkGenericWarningMacro("vtkMatrix::MultiplyPoint failed.");
    return 1;
  }

  // Not test the 2D transform with some 2D points
  vtkNew<vtkTransform2D> transform;
  vtkNew<vtkPoints2D> points;
  vtkNew<vtkPoints2D> points2;
  points->SetNumberOfPoints(3);
  points->SetPoint(0, 0.0, 0.0);
  points->SetPoint(1, 3.0, 4.9);
  points->SetPoint(2, 42.0, 69.0);

  transform->TransformPoints(points, points2);
  for (int i = 0; i < 3; ++i)
  {
    double p1[2], p2[2];
    points->GetPoint(i, p1);
    points2->GetPoint(i, p2);
    if (!vtkMathUtilities::FuzzyCompare(p1[0], p2[0], 1e-5) ||
      !vtkMathUtilities::FuzzyCompare(p1[1], p2[1], 1e-5))
    {
      vtkGenericWarningMacro("Identity transform moved points."
        << " Delta: " << p1[0] - (p2[0] - 2.0) << ", " << p1[1] - (p2[1] - 6.9));
      return 1;
    }
  }
  transform->Translate(2.0, 6.9);
  transform->TransformPoints(points, points2);
  for (int i = 0; i < 3; ++i)
  {
    double p1[2], p2[2];
    points->GetPoint(i, p1);
    points2->GetPoint(i, p2);
    if (!vtkMathUtilities::FuzzyCompare(p1[0], p2[0] - 2.0, 1e-5) ||
      !vtkMathUtilities::FuzzyCompare(p1[1], p2[1] - 6.9, 1e-5))
    {
      vtkGenericWarningMacro("Translation transform failed. Delta: " << p1[0] -
          (p2[0] - 2.0) << ", " << p1[1] - (p2[1] - 6.9));

      return 1;
    }
  }
  transform->InverseTransformPoints(points2, points2);
  for (int i = 0; i < 3; ++i)
  {
    double p1[2], p2[2];
    points->GetPoint(i, p1);
    points2->GetPoint(i, p2);
    if (!vtkMathUtilities::FuzzyCompare(p1[0], p2[0], 1e-5) ||
      !vtkMathUtilities::FuzzyCompare(p1[1], p2[1], 1e-5))
    {
      vtkGenericWarningMacro("Inverse transform did not return original points."
        << " Delta: " << p1[0] - (p2[0] - 2.0) << ", " << p1[1] - (p2[1] - 6.9));
      return 1;
    }
  }

  // Zero out the matrix.
  matrix->Zero();
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; j < 3; j++)
    {
      if (matrix->GetElement(i, j) != 0.0)
      {
        vtkGenericWarningMacro("vtkMatrix::Zero failed.");
        return 1;
      }
    }
  }

  return 0;
}
