text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    TestQuadraticPolygon.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.
  
  =========================================================================*/
  
  #include "vtkMath.h"
  #include "vtkNew.h"
  #include "vtkObjectFactory.h"
  #include "vtkPoints.h"
  #include "vtkPolygon.h"
  #include "vtkQuadraticPolygon.h"
  
  class vtkQuadraticPolygonTest : public vtkQuadraticPolygon
  {
  public:
    static vtkQuadraticPolygonTest* New();
    vtkTypeMacro(vtkQuadraticPolygonTest, vtkQuadraticPolygon);
  
    bool IsClose(double v1, double v2);
    bool IsClose(double* point1, double* point2);
  
    void InitializeCircle();
    void InitializeSquare();
    void InitializeSquareWithQuadraticEdge();
  
    int TestGetSet();
    int TestGetPermutations();
    int TestInitializePolygon();
    int TestIntersectWithLine();
    int TestInterpolateFunctions();
    int TestInterpolateFunctionsUsingMVC();
  
    int TestAll();
  
  protected:
    vtkQuadraticPolygonTest()
      : Tolerance(0.000001)
    {
    }
  
  private:
    double Tolerance;
  };
  
  vtkStandardNewMacro(vtkQuadraticPolygonTest);
  
  int TestQuadraticPolygon(int, char*[])
  {
    vtkNew<vtkQuadraticPolygonTest> test;
    int result = test->TestAll();
    cout << ((result == EXIT_SUCCESS) ? "SUCCESS" : "FAILURE") << endl;
    return result;
  }
  
  int vtkQuadraticPolygonTest::TestAll()
  {
    int result = EXIT_SUCCESS;
  
    this->InitializeSquareWithQuadraticEdge();
    result |= this->TestGetSet();
    result |= this->TestGetPermutations();
    result |= this->TestInitializePolygon();
    result |= this->TestIntersectWithLine();
    this->InitializeSquare();
    result |= this->TestInterpolateFunctions();
    result |= this->TestInterpolateFunctionsUsingMVC();
  
    return result;
  }
  
  bool vtkQuadraticPolygonTest::IsClose(double v1, double v2)
  {
    return (v1 < v2 ? (v2 - v1 < this->Tolerance) : (v1 - v2 < this->Tolerance));
  }
  
  bool vtkQuadraticPolygonTest::IsClose(double* point1, double* point2)
  {
    return (vtkMath::Distance2BetweenPoints(point1, point2) < this->Tolerance * this->Tolerance);
  }
  
  void vtkQuadraticPolygonTest::InitializeSquare()
  {
    this->GetPointIds()->SetNumberOfIds(8);
    this->GetPointIds()->SetId(0, 0);
    this->GetPointIds()->SetId(1, 1);
    this->GetPointIds()->SetId(2, 2);
    this->GetPointIds()->SetId(3, 3);
    this->GetPointIds()->SetId(4, 4);
    this->GetPointIds()->SetId(5, 5);
    this->GetPointIds()->SetId(6, 6);
    this->GetPointIds()->SetId(7, 7);
  
    this->GetPoints()->SetNumberOfPoints(8);
    this->GetPoints()->SetPoint(0, 0.0, 0.0, 0.0);
    this->GetPoints()->SetPoint(1, 2.0, 0.0, 0.0);
    this->GetPoints()->SetPoint(2, 2.0, 2.0, 0.0);
    this->GetPoints()->SetPoint(3, 0.0, 2.0, 0.0);
    this->GetPoints()->SetPoint(4, 1.0, 0.0, 0.0);
    this->GetPoints()->SetPoint(5, 2.0, 1.0, 0.0);
    this->GetPoints()->SetPoint(6, 1.0, 2.0, 0.0);
    this->GetPoints()->SetPoint(7, 0.0, 1.0, 0.0);
  }
  
  void vtkQuadraticPolygonTest::InitializeSquareWithQuadraticEdge()
  {
    this->InitializeSquare();
    this->GetPoints()->SetPoint(5, 3.0, 1.0, 0.0);
  }
  
  int vtkQuadraticPolygonTest::TestGetSet()
  {
    if (this->GetCellType() != VTK_QUADRATIC_POLYGON)
    {
      cerr << "ERROR:  quadratic polygon type is " << this->GetCellType() << ", should be "
           << VTK_QUADRATIC_POLYGON << endl;
      return EXIT_FAILURE;
    }
  
    if (this->GetCellDimension() != 2)
    {
      cerr << "ERROR:  quadratic polygon dim is " << this->GetCellDimension() << ", should be 2"
           << endl;
      return EXIT_FAILURE;
    }
  
    if (this->GetNumberOfEdges() != 4)
    {
      cerr << "ERROR:  quadratic polygon edges number is " << this->GetNumberOfEdges()
           << ", should be 4" << endl;
      return EXIT_FAILURE;
    }
  
    if (this->GetNumberOfFaces() != 0)
    {
      cerr << "ERROR:  quadratic polygon faces number is " << this->GetNumberOfFaces()
           << ", should be 0" << endl;
      return EXIT_FAILURE;
    }
  
    if (this->GetFace(0) != nullptr)
    {
      cerr << "ERROR:  quadratic polygon face is " << this->GetFace(0) << ", should be 0" << endl;
      return EXIT_FAILURE;
    }
  
    if (this->GetEdge(0)->PointIds->GetId(0) != 0)
    {
      cerr << "ERROR:  quadratic polygon edge[0] point[0] id is "
           << this->GetEdge(0)->PointIds->GetId(0) << ", should be 0" << endl;
      return EXIT_FAILURE;
    }
    if (this->GetEdge(0)->PointIds->GetId(1) != 1)
    {
      cerr << "ERROR:  quadratic polygon edge[0] point[1] id is "
           << this->GetEdge(0)->PointIds->GetId(1) << ", should be 1" << endl;
      return EXIT_FAILURE;
    }
    if (this->GetEdge(0)->PointIds->GetId(2) != 4)
    {
      cerr << "ERROR:  quadratic polygon edge[0] point[2] id is "
           << this->GetEdge(0)->PointIds->GetId(2) << ", should be 4" << endl;
      return EXIT_FAILURE;
    }
  
    if (this->IsPrimaryCell() != 0)
    {
      cerr << "ERROR:  quadratic polygon primary boolean is " << this->IsPrimaryCell()
           << ", should be 0" << endl;
      return EXIT_FAILURE;
    }
  
    if (!this->GetUseMVCInterpolation())
    {
      cerr << "ERROR:  quadratic polygon MVC boolean is " << this->GetUseMVCInterpolation()
           << ", should be 1" << endl;
      return EXIT_FAILURE;
    }
  
    this->SetUseMVCInterpolation(false);
    if (this->GetUseMVCInterpolation())
    {
      cerr << "ERROR:  quadratic polygon MVC boolean is " << this->GetUseMVCInterpolation()
           << ", should be 0" << endl;
      return EXIT_FAILURE;
    }
  
    return EXIT_SUCCESS;
  }
  
  int vtkQuadraticPolygonTest::TestGetPermutations()
  {
    // reference permutation
    vtkIdType temp[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
    vtkNew<vtkIdList> permutationToPolygonRef;
    permutationToPolygonRef->SetNumberOfIds(8);
    for (vtkIdType i = 0; i < 8; i++)
    {
      permutationToPolygonRef->SetId(i, temp[i]);
    }
  
    // computed permutation
    vtkNew<vtkIdList> permutationToPolygon;
    vtkQuadraticPolygon::GetPermutationToPolygon(8, permutationToPolygon);
  
    // reference permutation
    vtkIdType temp2[] = { 0, 4, 1, 5, 2, 6, 3, 7 };
    vtkNew<vtkIdList> permutationFromPolygonRef;
    permutationFromPolygonRef->SetNumberOfIds(8);
    for (vtkIdType i = 0; i < 8; i++)
    {
      permutationFromPolygonRef->SetId(i, temp2[i]);
    }
  
    // computed permutation
    vtkNew<vtkIdList> permutationFromPolygon;
    vtkQuadraticPolygon::GetPermutationFromPolygon(8, permutationFromPolygon);
  
    for (vtkIdType i = 0; i < 8; i++)
    {
      if (permutationToPolygonRef->GetId(i) != permutationToPolygon->GetId(i))
      {
        cerr << "ERROR:  permutation to polygon is wrong" << endl;
        return EXIT_FAILURE;
      }
      if (permutationFromPolygonRef->GetId(i) != permutationFromPolygon->GetId(i))
      {
        cerr << "ERROR:  permutation from polygon is wrong" << endl;
        return EXIT_FAILURE;
      }
    }
  
    return EXIT_SUCCESS;
  }
  
  int vtkQuadraticPolygonTest::TestInitializePolygon()
  {
    // reference permutation
    vtkIdType temp[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
    vtkNew<vtkIdList> permutationToPolygonRef;
    permutationToPolygonRef->SetNumberOfIds(8);
    for (vtkIdType i = 0; i < 8; i++)
    {
      permutationToPolygonRef->SetId(i, temp[i]);
    }
  
    this->InitializePolygon();
    vtkPolygon* polygon = this->Polygon;
  
    for (vtkIdType i = 0; i < 8; i++)
    {
      if (this->GetPointIds()->GetId(i) !=
        polygon->GetPointIds()->GetId(permutationToPolygonRef->GetId(i)))
      {
        cerr << "ERROR:  quadratic polygon point id at index " << i << " is "
             << this->GetPointIds()->GetId(i) << ", should be "
             << polygon->GetPointIds()->GetId(permutationToPolygonRef->GetId(i)) << endl;
        return EXIT_FAILURE;
      }
      for (int j = 0; j < 3; j++)
      {
        if (!this->IsClose(this->GetPoints()->GetPoint(i)[j],
              polygon->GetPoints()->GetPoint(permutationToPolygonRef->GetId(i))[j]))
        {
          cerr << "ERROR:  quadratic polygon point at index " << i << " (coord " << j << ") is "
               << this->GetPoints()->GetPoint(i)[j] << ", should be "
               << polygon->GetPoints()->GetPoint(permutationToPolygonRef->GetId(i))[j] << endl;
          return EXIT_FAILURE;
        }
      }
    }
  
    return EXIT_SUCCESS;
  }
  
  int vtkQuadraticPolygonTest::TestIntersectWithLine()
  {
    double t, x[3], pcoords[3];
    int subId;
  
    double p1[3] = { 2.5, 1.0, -1.0 };
    double p2[3] = { 2.5, 1.0, 1.0 };
    int intersect = this->IntersectWithLine(p1, p2, 0.0, t, x, pcoords, subId);
  
    if (x[0] != 2.5 || x[1] != 1.0 || x[2] != 0.0)
    {
      cerr << "ERROR:  vtkQuadraticPolygon::IntersectWithLine returns point (" << x[0] << "," << x[1]
           << "," << x[2] << ")"
           << ", should return point (2.5,1.0,0.0)" << endl;
      return EXIT_FAILURE;
    }
  
    if (!intersect)
    {
      cerr << "ERROR:  vtkQuadraticPolygon::IntersectWithLine returns " << intersect
           << ", should return 1" << endl;
      return EXIT_FAILURE;
    }
  
    p1[0] = 3.5;
    p2[0] = 3.5;
    intersect = this->IntersectWithLine(p1, p2, 0.0, t, x, pcoords, subId);
  
    if (intersect)
    {
      cerr << "ERROR:  vtkQuadraticPolygon::IntersectWithLine returns " << intersect
           << ", should return 0" << endl;
      return EXIT_FAILURE;
    }
  
    return EXIT_SUCCESS;
  }
  
  int vtkQuadraticPolygonTest::TestInterpolateFunctions()
  {
    int nbPoints = this->GetNumberOfPoints();
  
    double x[3] = { 1.0, 1.0, 0.0 };
    double* weights = new double[nbPoints];
    double w1 = 1. / 12.;
    double w2 = 1. / 6.;
    this->SetUseMVCInterpolation(false);
    this->InterpolateFunctions(x, weights);
  
    int i;
    for (i = 0; i < nbPoints / 2; i++)
    {
      if (!this->IsClose(weights[i], w1))
      {
        cerr << "ERROR:  quadratic polygon weights is " << weights[i] << ", should be " << w1 << endl;
        delete[] weights;
        return EXIT_FAILURE;
      }
    }
    for (; i < nbPoints; i++)
    {
      if (!this->IsClose(weights[i], w2))
      {
        cerr << "ERROR:  quadratic polygon weights is " << weights[i] << ", should be " << w2 << endl;
        delete[] weights;
        return EXIT_FAILURE;
      }
    }
  
    delete[] weights;
    return EXIT_SUCCESS;
  }
  
  int vtkQuadraticPolygonTest::TestInterpolateFunctionsUsingMVC()
  {
    int nbPoints = this->GetNumberOfPoints();
  
    double x[3] = { 1.0, 1.0, 0.0 };
    double* weights = new double[nbPoints];
    double w1 = (sqrt(2.) - 1.) / 4.;
    double w2 = (sqrt(2.) - 1.) / (2. * sqrt(2.));
    this->SetUseMVCInterpolation(true);
    this->InterpolateFunctions(x, weights);
  
    int i;
    for (i = 0; i < nbPoints / 2; i++)
    {
      if (!this->IsClose(weights[i], w1))
      {
        cerr << "ERROR:  quadratic polygon weights is " << weights[i] << ", should be " << w1 << endl;
        delete[] weights;
        return EXIT_FAILURE;
      }
    }
    for (; i < nbPoints; i++)
    {
      if (!this->IsClose(weights[i], w2))
      {
        cerr << "ERROR:  quadratic polygon weights is " << weights[i] << ", should be " << w2 << endl;
        delete[] weights;
        return EXIT_FAILURE;
      }
    }
  
    delete[] weights;
    return EXIT_SUCCESS;
  }
  