// File:	StdPrs_ToolShadedShape.cxx
// Created:	Wed Oct 27 09:29:14 1993
// Author:	Jean-LOuis FRENKEL
//		<jlf@stylox>

#define OCC8563     //AEL   Code correction in method StdPrs_ToolShadedShape::Normal().

#include <StdPrs_ToolShadedShape.ixx>
#include <Poly_Triangulation.hxx>
#include <TColgp_HArray1OfPnt.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <Poly_Connect.hxx>
#include <TopAbs_Orientation.hxx>
#include <GeomAbs_SurfaceType.hxx>
#include <CSLib.hxx>
#include <gp_Vec.hxx>
#include <Precision.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRep_Tool.hxx>
#include <TopLoc_Location.hxx>


//=======================================================================
//function : IsClosed
//purpose  : 
//=======================================================================

Standard_Boolean StdPrs_ToolShadedShape::IsClosed(const TopoDS_Shape& aShape) 
{
  return aShape.Closed();
}


//=======================================================================
//function : Triangulation
//purpose  : 
//=======================================================================

Handle(Poly_Triangulation) StdPrs_ToolShadedShape::Triangulation
   (const TopoDS_Face& aFace,
    TopLoc_Location&   loc)
{
  return BRep_Tool::Triangulation(aFace, loc);
}


//=======================================================================
//function : Normal
//purpose  : 
//=======================================================================

void StdPrs_ToolShadedShape::Normal(const TopoDS_Face&  aFace,
				    Poly_Connect&       pc,
				    TColgp_Array1OfDir& Nor)
{
  const Handle(Poly_Triangulation)& T = pc.Triangulation();
  BRepAdaptor_Surface S;
  Standard_Boolean hasUV = T->HasUVNodes();
  Standard_Integer i;
  TopLoc_Location l;
  Handle(Geom_Surface) GS = BRep_Tool::Surface(aFace, l);

  if (hasUV && !GS.IsNull()) {
    Standard_Boolean OK = Standard_True;
    gp_Vec D1U,D1V;
    gp_Vec D2U,D2V,D2UV;
    gp_Pnt P;
    Standard_Real U, V;
    CSLib_DerivativeStatus Status;
    CSLib_NormalStatus NStat;
    S.Initialize(aFace, Standard_False);
    const TColgp_Array1OfPnt2d& UVNodes = T->UVNodes();
#ifdef OCC8563
    if (S.GetType() != GeomAbs_Plane) {
#else
    if (!S.GetType() == GeomAbs_Plane) {
#endif
      for (i = UVNodes.Lower(); i <= UVNodes.Upper(); i++) {
	U = UVNodes(i).X();
	V = UVNodes(i).Y();
	S.D1(U,V,P,D1U,D1V);
	CSLib::Normal(D1U,D1V,Precision::Angular(),Status,Nor(i));
	if (Status != CSLib_Done) {
	  S.D2(U,V,P,D1U,D1V,D2U,D2V,D2UV);
	  CSLib::Normal(D1U,D1V,D2U,D2V,D2UV,Precision::Angular(),OK,NStat,Nor(i));
	}
	if (aFace.Orientation() == TopAbs_REVERSED) (Nor(i)).Reverse();
      }
    }
    else {
      // une seule normale suffit.
      gp_Dir NPlane;
      U = UVNodes(UVNodes.Lower()).X();
      V = UVNodes(UVNodes.Lower()).Y();
      S.D1(U,V,P,D1U,D1V);
      CSLib::Normal(D1U,D1V,Precision::Angular(),Status,NPlane);
      if (Status != CSLib_Done) {
	S.D2(U,V,P,D1U,D1V,D2U,D2V,D2UV);
	CSLib::Normal(D1U,D1V,D2U,D2V,D2UV,Precision::Angular(),OK,NStat,NPlane);
      }
      if (aFace.Orientation() == TopAbs_REVERSED) NPlane.Reverse();
      Nor.Init(NPlane);

    }
  }
  else {
    const TColgp_Array1OfPnt& Nodes = T->Nodes();
    Standard_Integer n[3];
    const Poly_Array1OfTriangle& triangles = T->Triangles();

    for (i = Nodes.Lower(); i <= Nodes.Upper(); i++) {
      gp_XYZ eqPlan(0, 0, 0);
      for (pc.Initialize(i);  pc.More(); pc.Next()) {
	triangles(pc.Value()).Get(n[0], n[1], n[2]);
	gp_XYZ v1(Nodes(n[1]).Coord()-Nodes(n[0]).Coord());
	gp_XYZ v2(Nodes(n[2]).Coord()-Nodes(n[1]).Coord());
	eqPlan += (v1^v2).Normalized();
      }
      Nor(i) = gp_Dir(eqPlan);
      if (aFace.Orientation() == TopAbs_REVERSED) (Nor(i)).Reverse();
    }
  }

}

