// Created on: 1999-03-05
// Created by: Fabrice SERVANT
// Copyright (c) 1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.

#ifndef _IntPolyh_Triangle_HeaderFile
#define _IntPolyh_Triangle_HeaderFile

#include <Adaptor3d_Surface.hxx>
#include <Bnd_Box.hxx>
#include <IntPolyh_ArrayOfPoints.hxx>
#include <IntPolyh_ArrayOfTriangles.hxx>
#include <IntPolyh_ArrayOfEdges.hxx>

//! The class represents the triangle built from three IntPolyh points
//! and three IntPolyh edges.
class IntPolyh_Triangle
{
public:
  DEFINE_STANDARD_ALLOC

  //! Constructor
  IntPolyh_Triangle()
      : myHasIntersection(Standard_False),
        myIsIntersectionPossible(Standard_True),
        myIsDegenerated(Standard_False),
        myDeflection(0.0)
  {
    myPoints[0]            = -1;
    myPoints[1]            = -1;
    myPoints[2]            = -1;
    myEdges[0]             = -1;
    myEdges[1]             = -1;
    myEdges[2]             = -1;
    myEdgesOrientations[0] = 0;
    myEdgesOrientations[1] = 0;
    myEdgesOrientations[2] = 0;
  }

  //! Constructor
  IntPolyh_Triangle(const Standard_Integer thePoint1,
                    const Standard_Integer thePoint2,
                    const Standard_Integer thePoint3)
      : myHasIntersection(Standard_False),
        myIsIntersectionPossible(Standard_True),
        myIsDegenerated(Standard_False),
        myDeflection(0.0)
  {
    myPoints[0]            = thePoint1;
    myPoints[1]            = thePoint2;
    myPoints[2]            = thePoint3;
    myEdges[0]             = -1;
    myEdges[1]             = -1;
    myEdges[2]             = -1;
    myEdgesOrientations[0] = 0;
    myEdgesOrientations[1] = 0;
    myEdgesOrientations[2] = 0;
  }

  //! Returns the first point
  Standard_Integer FirstPoint() const { return myPoints[0]; }

  //! Returns the second point
  Standard_Integer SecondPoint() const { return myPoints[1]; }

  //! Returns the third point
  Standard_Integer ThirdPoint() const { return myPoints[2]; }

  //! Returns the first edge
  Standard_Integer FirstEdge() const { return myEdges[0]; }

  //! Returns the orientation of the first edge
  Standard_Integer FirstEdgeOrientation() const { return myEdgesOrientations[0]; }

  //! Returns the second edge
  Standard_Integer SecondEdge() const { return myEdges[1]; }

  //! Returns the orientation of the second edge
  Standard_Integer SecondEdgeOrientation() const { return myEdgesOrientations[1]; }

  //! Returns the third edge
  Standard_Integer ThirdEdge() const { return myEdges[2]; }

  //! Returns the orientation of the third edge
  Standard_Integer ThirdEdgeOrientation() const { return myEdgesOrientations[2]; }

  //! Returns the deflection of the triangle
  Standard_Real Deflection() const { return myDeflection; }

  //! Returns possibility of the intersection
  Standard_Boolean IsIntersectionPossible() const { return myIsIntersectionPossible; }

  //! Returns true if the triangle has interfered the other triangle
  Standard_Boolean HasIntersection() const { return myHasIntersection; }

  //! Returns the Degenerated flag
  Standard_Boolean IsDegenerated() const { return myIsDegenerated; }

  //! Sets the first point
  void SetFirstPoint(const Standard_Integer thePoint) { myPoints[0] = thePoint; }

  //! Sets the second point
  void SetSecondPoint(const Standard_Integer thePoint) { myPoints[1] = thePoint; }

  //! Sets the third point
  void SetThirdPoint(const Standard_Integer thePoint) { myPoints[2] = thePoint; }

  //! Sets the first edge
  void SetFirstEdge(const Standard_Integer theEdge, const Standard_Integer theEdgeOrientation)
  {
    myEdges[0]             = theEdge;
    myEdgesOrientations[0] = theEdgeOrientation;
  }

  //! Sets the second edge
  void SetSecondEdge(const Standard_Integer theEdge, const Standard_Integer theEdgeOrientation)
  {
    myEdges[1]             = theEdge;
    myEdgesOrientations[1] = theEdgeOrientation;
  }

  //! Sets the third edge
  void SetThirdEdge(const Standard_Integer theEdge, const Standard_Integer theEdgeOrientation)
  {
    myEdges[2]             = theEdge;
    myEdgesOrientations[2] = theEdgeOrientation;
  }

  //! Sets the deflection
  void SetDeflection(const Standard_Real theDeflection) { myDeflection = theDeflection; }

  //! Sets the flag of possibility of intersection
  void SetIntersectionPossible(const Standard_Boolean theIP) { myIsIntersectionPossible = theIP; }

  //! Sets the flag of intersection
  void SetIntersection(const Standard_Boolean theInt) { myHasIntersection = theInt; }

  //! Sets the degenerated flag
  void SetDegenerated(const Standard_Boolean theDegFlag) { myIsDegenerated = theDegFlag; }

  //! Gets the edge number by the index
  Standard_Integer GetEdgeNumber(const Standard_Integer theEdgeIndex) const
  {
    return ((theEdgeIndex >= 1 && theEdgeIndex <= 3) ? myEdges[theEdgeIndex - 1] : 0);
  }

  //! Sets the edge by the index
  void SetEdge(const Standard_Integer theEdgeIndex, const Standard_Integer theEdgeNumber)
  {
    if (theEdgeIndex >= 1 && theEdgeIndex <= 3)
    {
      myEdges[theEdgeIndex - 1] = theEdgeNumber;
    }
  }

  //! Gets the edges orientation by the index
  Standard_Integer GetEdgeOrientation(const Standard_Integer theEdgeIndex) const
  {
    return ((theEdgeIndex >= 1 && theEdgeIndex <= 3) ? myEdgesOrientations[theEdgeIndex - 1] : 0);
  }

  //! Sets the edges orientation by the index
  void SetEdgeOrientation(const Standard_Integer theEdgeIndex,
                          const Standard_Integer theEdgeOrientation)
  {
    if (theEdgeIndex >= 1 && theEdgeIndex <= 3)
    {
      myEdgesOrientations[theEdgeIndex - 1] = theEdgeOrientation;
    }
  }

  //! Computes the deflection for the triangle
  Standard_EXPORT Standard_Real ComputeDeflection(const Handle(Adaptor3d_Surface)& theSurface,
                                                  const IntPolyh_ArrayOfPoints&    thePoints);

  //! Gets the adjacent triangle
  Standard_EXPORT Standard_Integer GetNextTriangle(const Standard_Integer       theTriangle,
                                                   const Standard_Integer       theEdgeNum,
                                                   const IntPolyh_ArrayOfEdges& TEdges) const;

  //! Splits the triangle on two to decrease its deflection
  Standard_EXPORT void MiddleRefinement(const Standard_Integer           theTriangleNumber,
                                        const Handle(Adaptor3d_Surface)& theSurface,
                                        IntPolyh_ArrayOfPoints&          TPoints,
                                        IntPolyh_ArrayOfTriangles&       TTriangles,
                                        IntPolyh_ArrayOfEdges&           TEdges);

  //! Splits the current triangle and new triangles until the refinement
  //! criterion is not achieved
  Standard_EXPORT void MultipleMiddleRefinement(const Standard_Real              theRefineCriterion,
                                                const Bnd_Box&                   theBox,
                                                const Standard_Integer           theTriangleNumber,
                                                const Handle(Adaptor3d_Surface)& theSurface,
                                                IntPolyh_ArrayOfPoints&          TPoints,
                                                IntPolyh_ArrayOfTriangles&       TTriangles,
                                                IntPolyh_ArrayOfEdges&           TEdges);

  //! Links edges to triangle
  Standard_EXPORT void LinkEdges2Triangle(const IntPolyh_ArrayOfEdges& TEdges,
                                          const Standard_Integer       theEdge1,
                                          const Standard_Integer       theEdge2,
                                          const Standard_Integer       theEdge3);

  //! Sets the appropriate edge and orientation for the triangle.
  Standard_EXPORT void SetEdgeAndOrientation(const IntPolyh_Edge&   theEdge,
                                             const Standard_Integer theEdgeIndex);

  //! Returns the bounding box of the triangle.
  Standard_EXPORT const Bnd_Box& BoundingBox(const IntPolyh_ArrayOfPoints& thePoints);

  //! Dumps the contents of the triangle.
  Standard_EXPORT void Dump(const Standard_Integer v) const;

protected:
private:
  Standard_Integer myPoints[3];
  Standard_Integer myEdges[3];
  Standard_Integer myEdgesOrientations[3];
  Standard_Boolean myHasIntersection : 1;
  Standard_Boolean myIsIntersectionPossible : 1;
  Standard_Boolean myIsDegenerated : 1;
  Standard_Real    myDeflection;
  Bnd_Box          myBox;
};

#endif // _IntPolyh_Triangle_HeaderFile
