// Created on: 1998-04-21
// Created by: Stephanie HUMEAU
// Copyright (c) 1998-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.

#include <GeomFill_LocationDraft.hxx>

#include <Adaptor3d_Curve.hxx>
#include <Adaptor3d_Surface.hxx>
#include <Geom_Line.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomFill_DraftTrihedron.hxx>
#include <GeomFill_FunctionDraft.hxx>
#include <GeomFill_LocationLaw.hxx>
#include <GeomFill_Tensor.hxx>
#include <GeomFill_TrihedronLaw.hxx>
#include <gp_Dir.hxx>
#include <gp_Mat.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <IntCurveSurface_HInter.hxx>
#include <IntCurveSurface_Intersection.hxx>
#include <IntCurveSurface_IntersectionPoint.hxx>
#include <math_FunctionSetWithDerivatives.hxx>
#include <math_Gauss.hxx>
#include <math_Matrix.hxx>
#include <math_NewtonFunctionSetRoot.hxx>
#include <math_Vector.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_Type.hxx>

IMPLEMENT_STANDARD_RTTIEXT(GeomFill_LocationDraft, GeomFill_LocationLaw)

//=================================================================================================

GeomFill_LocationDraft::GeomFill_LocationDraft(const gp_Dir& Direction, const Standard_Real Angle)
{
  myDir = Direction; // direction de depouille

  myAngle = Angle; // angle de depouille (teta prime)

  mySurf.Nullify();
  myLaw     = new (GeomFill_DraftTrihedron)(myDir, Angle); // triedre
  myNbPts   = 41;                                          // nb de points utilises pour les calculs
  myPoles2d = new (TColgp_HArray1OfPnt2d)(1, 2 * myNbPts);
  Intersec  = Standard_False; // intersection avec surface d'arret ?
  WithTrans = Standard_False;
}

//=================================================================================================

Handle(GeomFill_LocationLaw) GeomFill_LocationDraft::Copy() const
{
  Handle(GeomFill_TrihedronLaw) law;
  law                                 = myLaw->Copy();
  Handle(GeomFill_LocationDraft) copy = new (GeomFill_LocationDraft)(myDir, myAngle);
  copy->SetCurve(myCurve);
  copy->SetStopSurf(mySurf);
  if (WithTrans)
    copy->SetTrsf(Trans);

  return copy;
}

//=================================================================================================

void GeomFill_LocationDraft::SetTrsf(const gp_Mat& Transfo)
{
  Trans = Transfo;
  gp_Mat Aux;
  Aux.SetIdentity();
  Aux -= Trans;
  WithTrans = Standard_False; // Au cas ou Trans = I
  for (Standard_Integer ii = 1; ii <= 3 && !WithTrans; ii++)
    for (Standard_Integer jj = 1; jj <= 3 && !WithTrans; jj++)
      if (Abs(Aux.Value(ii, jj)) > 1.e-14)
        WithTrans = Standard_True;
}

//==================================================================
// Function: SetCurve
// Purpose : Calcul des poles sur la surfaces d'arret (intersection
// entre la generatrice et la surface en myNbPts points de la section)
//==================================================================
Standard_Boolean GeomFill_LocationDraft::SetCurve(const Handle(Adaptor3d_Curve)& C)
{
  myCurve               = C;
  myTrimmed             = C;
  Standard_Boolean isOK = myLaw->SetCurve(C);

  Prepare();
  return isOK;
}

//=================================================================================================

void GeomFill_LocationDraft::SetStopSurf(const Handle(Adaptor3d_Surface)& Surf)
{
  mySurf = Surf;
  Prepare();
}

//=================================================================================================

void GeomFill_LocationDraft::SetAngle(const Standard_Real Angle)
{
  myAngle = Angle;
  myLaw->SetAngle(myAngle);
  Prepare();
}

//==================================================================
// Function: Prepare
// Purpose : Poses les jalon de l'intersection : depouille / Surface
//==================================================================
void GeomFill_LocationDraft::Prepare()
{
  if (mySurf.IsNull())
  {
    Intersec = Standard_False;
    return;
  }

  Intersec = Standard_True;

  Standard_Integer                  ii, jj;
  Standard_Real                     f, l, t;
  gp_Pnt                            P;
  gp_Vec                            D, T, N, B;
  Handle(Geom_Line)                 L;
  IntCurveSurface_IntersectionPoint P1, P2;
  f = myCurve->FirstParameter();
  l = myCurve->LastParameter();

  for (ii = 1; ii <= myNbPts; ii++)
  {
    t = Standard_Real(myNbPts - ii) * f + Standard_Real(ii - 1) * l;
    t /= (myNbPts - 1);

    myCurve->D0(t, P);
    myLaw->D0(t, T, N, B);

    // Generatrice
    D = Cos(myAngle) * B + Sin(myAngle) * N;

    L = new (Geom_Line)(P, D);

    IntCurveSurface_HInter    Int; // intersection surface / generatrice
    Handle(GeomAdaptor_Curve) AC = new (GeomAdaptor_Curve)(L);
    Int.Perform(AC, mySurf); // calcul de l'intersection

    if (Int.NbPoints() > 0) // il y a au moins 1 intersection
    {
      P1 = Int.Point(1); // 1er  point d'intersection

      for (jj = 2; jj <= Int.NbPoints(); jj++)
      {
        P2 = Int.Point(jj);
        if (P1.W() > P2.W())
          P1 = P2; // point le plus proche
      } // for_jj

      gp_Pnt2d p(P1.W(), t);              // point de la courbe
      gp_Pnt2d q(P1.U(), P1.V());         // point sur la surface
      myPoles2d->SetValue(2 * ii - 1, p); // point de la courbe (indice impair)
      myPoles2d->SetValue(2 * ii, q);     // point sur la surface (indice pair)
    }
    else
    { // au moins un point ou il n'y a pas intersection
      Intersec = Standard_False;
    }

  } // for_ii
}

//==================================================================
// Function: GetCurve
// Purpose : return the path
//==================================================================
const Handle(Adaptor3d_Curve)& GeomFill_LocationDraft::GetCurve() const
{
  return myCurve;
}

//=================================================================================================

Standard_Boolean GeomFill_LocationDraft::D0(const Standard_Real Param, gp_Mat& M, gp_Vec& V)
{
  Standard_Boolean Ok;
  gp_Vec           T, N, B;
  gp_Pnt           P;

  myTrimmed->D0(Param, P);
  V.SetXYZ(P.XYZ());

  Ok = myLaw->D0(Param, T, N, B);
  if (!Ok)
    return Ok;
  M.SetCols(N.XYZ(), B.XYZ(), T.XYZ());

  if (WithTrans)
  {
    M *= Trans;
  }

  return Standard_True;
}

//==================================================================
// Function: D0
// Purpose : calcul de l'intersection (C0) sur la surface
//==================================================================
Standard_Boolean GeomFill_LocationDraft::D0(const Standard_Real   Param,
                                            gp_Mat&               M,
                                            gp_Vec&               V,
                                            TColgp_Array1OfPnt2d& Poles2d)
{
  Standard_Boolean Ok;
  //  gp_Vec D,T,N,B,DT,DN,DB;
  gp_Vec D, T, N, B;
  gp_Pnt P;

  myCurve->D0(Param, P);
  V.SetXYZ(P.XYZ());
  Ok = myLaw->D0(Param, T, N, B);
  if (!Ok)
    return Ok;
  M.SetCols(N.XYZ(), B.XYZ(), T.XYZ());

  if (WithTrans)
  {
    M *= Trans;
  }

  if (Intersec == Standard_True)
  {
    // la generatrice intersecte la surface d'arret
    // la generatrice
    D = Cos(myAngle) * B + Sin(myAngle) * N;

    Handle(Geom_Line)         L = new (Geom_Line)(P, D);
    Handle(GeomAdaptor_Curve) G = new (GeomAdaptor_Curve)(L);

    Standard_Real t1, t2, Paramt1, t2Param;
    Standard_Real U0 = 0, V0 = 0, W0 = 0;

    Standard_Integer ii = 1;

    // on recherche l'intervalle auquel appartient Param
    while (ii < 2 * myNbPts && myPoles2d->Value(ii).Coord(2) < Param)
      ii = ii + 2;

    if (ii < 2 * myNbPts && !IsEqual(myPoles2d->Value(ii).Coord(2), Param))
    {

      // interpolation lineaire pour initialiser le germe de la recherche
      t1 = myPoles2d->Value(ii).Coord(2);
      t2 = myPoles2d->Value(ii - 2).Coord(2);

      Paramt1 = (Param - t1) / (t2 - t1);
      t2Param = (t2 - Param) / (t2 - t1);

      W0 = myPoles2d->Value(ii - 2).Coord(1) * Paramt1 + myPoles2d->Value(ii).Coord(1) * t2Param;
      U0 =
        myPoles2d->Value(ii - 1).Coord(1) * Paramt1 + myPoles2d->Value(ii + 1).Coord(1) * t2Param;
      V0 =
        myPoles2d->Value(ii - 1).Coord(2) * Paramt1 + myPoles2d->Value(ii + 1).Coord(2) * t2Param;
    } // if
    // on est sur un param ou les points ont deja ete calcules
    else if (ii < 2 * myNbPts && IsEqual(myPoles2d->Value(ii).Coord(2), Param))
    {
      W0 = myPoles2d->Value(ii).Coord(1);
      U0 = myPoles2d->Value(ii + 1).Coord(1);
      V0 = myPoles2d->Value(ii + 1).Coord(2);
    } // else if

    // recherche de la solution (pt d'intersection generatrice / surface)
    // point initial
    math_Vector X(1, 3);
    X(1) = W0;
    X(2) = U0;
    X(3) = V0;

    // tolerance sur X
    math_Vector XTol(1, 3);
    XTol.Init(0.00001);

    // tolerance sur F
    Standard_Real    FTol = 0.0000001;
    Standard_Integer Iter = 100;

    // fonction dont il faut trouver la racine : G(W)-S(U,V)=0
    GeomFill_FunctionDraft E(mySurf, G);

    // resolution
    math_NewtonFunctionSetRoot Result(E, XTol, FTol, Iter);
    Result.Perform(E, X);

    if (Result.IsDone())
    {
      math_Vector R(1, 3);
      Result.Root(R); // solution

      gp_Pnt2d p(R(2), R(3));  // point sur la surface
      gp_Pnt2d q(R(1), Param); // point de la courbe
      Poles2d.SetValue(1, p);
      Poles2d.SetValue(2, q);
    }
    else
    {
      return Standard_False;
    }
  } // if_Intersec

  // la generatrice n'intersecte pas la surface d'arret
  return Standard_True;
}

//==================================================================
// Function: D1
// Purpose : calcul de l'intersection (C1) sur la surface
//==================================================================
Standard_Boolean GeomFill_LocationDraft::D1(const Standard_Real   Param,
                                            gp_Mat&               M,
                                            gp_Vec&               V,
                                            gp_Mat&               DM,
                                            gp_Vec&               DV,
                                            TColgp_Array1OfPnt2d& Poles2d,
                                            TColgp_Array1OfVec2d& DPoles2d)
{
  Standard_Boolean Ok;
  gp_Vec           D, T, N, B, DT, DN, DB;
  gp_Pnt           P;

  myCurve->D1(Param, P, DV);
  V.SetXYZ(P.XYZ());

  Ok = myLaw->D1(Param, T, DT, N, DN, B, DB);
  if (!Ok)
    return Standard_False;

  M.SetCols(N.XYZ(), B.XYZ(), T.XYZ());
  DM.SetCols(DN.XYZ(), DB.XYZ(), DT.XYZ());

  if (WithTrans)
  {
    M *= Trans;
    DM *= Trans;
  }

  if (Intersec == Standard_True)
  { // la generatrice intersecte la surface d'arret
    // la generatrice
    D = Cos(myAngle) * B + Sin(myAngle) * N;

    Handle(Geom_Line)         L = new (Geom_Line)(P, D);
    Handle(GeomAdaptor_Curve) G = new (GeomAdaptor_Curve)(L);

    Standard_Real t1, t2, Paramt1, t2Param;
    Standard_Real U0 = 0, V0 = 0, W0 = 0;

    Standard_Integer ii = 1;

    // recherche de la solution (pt d'intersection  generatrice / surface)

    // on recherche l'intervalle auquel appartient Param
    while (ii < 2 * myNbPts && myPoles2d->Value(ii).Coord(2) < Param)
      ii = ii + 2;

    if (ii < 2 * myNbPts && !IsEqual(myPoles2d->Value(ii).Coord(2), Param))
    {
      // interpolation lineaire pour initialiser le germe de la recherche
      t1 = myPoles2d->Value(ii).Coord(2);
      t2 = myPoles2d->Value(ii - 2).Coord(2);

      Paramt1 = (Param - t1) / (t2 - t1);
      t2Param = (t2 - Param) / (t2 - t1);

      W0 = myPoles2d->Value(ii - 2).Coord(1) * Paramt1 + myPoles2d->Value(ii).Coord(1) * t2Param;
      U0 =
        myPoles2d->Value(ii - 1).Coord(1) * Paramt1 + myPoles2d->Value(ii + 1).Coord(1) * t2Param;
      V0 =
        myPoles2d->Value(ii - 1).Coord(2) * Paramt1 + myPoles2d->Value(ii + 1).Coord(2) * t2Param;
    } // if
    else if (ii < 2 * myNbPts && IsEqual(myPoles2d->Value(ii).Coord(2), Param))
    {
      W0 = myPoles2d->Value(ii).Coord(1);
      U0 = myPoles2d->Value(ii + 1).Coord(1);
      V0 = myPoles2d->Value(ii + 1).Coord(2);
    } // else if

    // germe
    math_Vector X(1, 3);
    X(1) = W0;
    X(2) = U0;
    X(3) = V0;

    // tolerance sur X
    math_Vector XTol(1, 3);
    XTol.Init(0.0001);

    // tolerance sur F
    Standard_Real    FTol = 0.000001;
    Standard_Integer Iter = 100;

    // fonction dont il faut trouver la racine : G(W)-S(U,V)=0
    GeomFill_FunctionDraft E(mySurf, G);

    // resolution
    math_NewtonFunctionSetRoot Result(E, XTol, FTol, Iter);
    Result.Perform(E, X);

    if (Result.IsDone())
    {
      math_Vector R(1, 3);
      Result.Root(R); // solution

      gp_Pnt2d p(R(2), R(3));  // point sur la surface
      gp_Pnt2d q(R(1), Param); // point de la courbe
      Poles2d.SetValue(1, p);
      Poles2d.SetValue(2, q);

      // derivee de la fonction par rapport a Param
      math_Vector DEDT(1, 3, 0);
      E.DerivT(myTrimmed, Param, R(1), DN, myAngle, DEDT); // dE/dt => DEDT

      math_Vector DSDT(1, 3, 0);
      math_Matrix DEDX(1, 3, 1, 3, 0);
      E.Derivatives(R, DEDX); // dE/dx au point R => DEDX

      // resolution du syst. lin. : DEDX*DSDT = -DEDT
      math_Gauss Ga(DEDX);
      if (Ga.IsDone())
      {
        Ga.Solve(DEDT.Opposite(), DSDT); // resolution du syst. lin.
        gp_Vec2d dp(DSDT(2), DSDT(3));   // surface
        gp_Vec2d dq(DSDT(1), 1);         //  courbe
        DPoles2d.SetValue(1, dp);
        DPoles2d.SetValue(2, dq);
      } // if

    } // if_Result
    else
    { // la generatrice n'intersecte pas la surface d'arret
      return Standard_False;
    }
  } // if_Intersec
  return Standard_True;
}

//==================================================================
// Function: D2
// Purpose : calcul de l'intersection (C2) sur la surface
//==================================================================
Standard_Boolean GeomFill_LocationDraft::D2(const Standard_Real   Param,
                                            gp_Mat&               M,
                                            gp_Vec&               V,
                                            gp_Mat&               DM,
                                            gp_Vec&               DV,
                                            gp_Mat&               D2M,
                                            gp_Vec&               D2V,
                                            TColgp_Array1OfPnt2d& Poles2d,
                                            TColgp_Array1OfVec2d& DPoles2d,
                                            TColgp_Array1OfVec2d& D2Poles2d)
{
  Standard_Boolean Ok;
  gp_Vec           D, T, N, B, DT, DN, DB, D2T, D2N, D2B;
  gp_Pnt           P;

  myCurve->D2(Param, P, DV, D2V);
  V.SetXYZ(P.XYZ());

  Ok = myLaw->D2(Param, T, DT, D2T, N, DN, D2N, B, DB, D2B);
  if (!Ok)
    return Ok;

  M.SetCols(N.XYZ(), B.XYZ(), T.XYZ());
  DM.SetCols(DN.XYZ(), DB.XYZ(), DT.XYZ());
  D2M.SetCols(D2N.XYZ(), D2B.XYZ(), D2T.XYZ());

  if (WithTrans)
  {
    M *= Trans;
    DM *= Trans;
    D2M *= Trans;
  }
  if (Intersec == Standard_True)
  { // la generatrice intersecte la surface d'arret

    // la generatrice
    D = Cos(myAngle) * B + Sin(myAngle) * N;

    Handle(Geom_Line)         L = new (Geom_Line)(P, D);
    Handle(GeomAdaptor_Curve) G = new (GeomAdaptor_Curve)(L);

    Standard_Real t1, t2, Paramt1, t2Param;
    Standard_Real U0 = 0, V0 = 0, W0 = 0;

    Standard_Integer ii = 1;

    // on recherche l'intervalle auquel appartient Param
    while (ii < 2 * myNbPts && myPoles2d->Value(ii).Coord(2) < Param)
      ii = ii + 2;

    if (ii < 2 * myNbPts && !IsEqual(myPoles2d->Value(ii).Coord(2), Param))
    {

      // interpolation lineaire pour initialiser le germe de la recherche
      t1 = myPoles2d->Value(ii).Coord(2);
      t2 = myPoles2d->Value(ii - 2).Coord(2);

      Paramt1 = (Param - t1) / (t2 - t1);
      t2Param = (t2 - Param) / (t2 - t1);

      W0 = myPoles2d->Value(ii - 2).Coord(1) * Paramt1 + myPoles2d->Value(ii).Coord(1) * t2Param;
      U0 =
        myPoles2d->Value(ii - 1).Coord(1) * Paramt1 + myPoles2d->Value(ii + 1).Coord(1) * t2Param;
      V0 =
        myPoles2d->Value(ii - 1).Coord(2) * Paramt1 + myPoles2d->Value(ii + 1).Coord(2) * t2Param;
    } // if
    else if (ii < 2 * myNbPts && IsEqual(myPoles2d->Value(ii).Coord(2), Param))
    {
      W0 = myPoles2d->Value(ii).Coord(1);
      U0 = myPoles2d->Value(ii + 1).Coord(1);
      V0 = myPoles2d->Value(ii + 1).Coord(2);
    } // else if

    // recherche de la solution (pt d'intersection generatrice / surface)
    // germe
    math_Vector X(1, 3);
    X(1) = W0;
    X(2) = U0;
    X(3) = V0;

    // tolerance sur X
    math_Vector XTol(1, 3);
    XTol.Init(0.0001);

    // tolerance sur F
    Standard_Real    FTol = 0.000001;
    Standard_Integer Iter = 150;

    // fonction dont il faut trouver la racine : G(W)-S(U,V)=0
    GeomFill_FunctionDraft E(mySurf, G);

    // resolution
    math_NewtonFunctionSetRoot Result(E, XTol, FTol, Iter);
    Result.Perform(E, X);

    if (Result.IsDone())
    {
      math_Vector R(1, 3);
      Result.Root(R); // solution

      // solution
      gp_Pnt2d p(R(2), R(3));  // point sur la surface
      gp_Pnt2d q(R(1), Param); // point de la courbe
      Poles2d.SetValue(1, p);
      Poles2d.SetValue(2, q);

      // premiere derivee de la fonction
      math_Vector DEDT(1, 3, 0);
      E.DerivT(myTrimmed, Param, R(1), DN, myAngle, DEDT); // dE/dt => DEDT

      math_Vector DSDT(1, 3, 0);
      math_Matrix DEDX(1, 3, 1, 3, 0);
      E.Derivatives(R, DEDX); // dE/dx => DEDX

      // resolution du syst. lin.
      math_Gauss Ga(DEDX);
      if (Ga.IsDone())
      {
        Ga.Solve(DEDT.Opposite(), DSDT);
        gp_Vec2d dp(DSDT(2), DSDT(3)); // surface
        gp_Vec2d dq(DSDT(1), 1);       //  courbe
        DPoles2d.SetValue(1, dp);
        DPoles2d.SetValue(2, dq);
      } // if

      // deuxieme derivee
      GeomFill_Tensor D2EDX2(3, 3, 3);
      E.Deriv2X(R, D2EDX2); // d2E/dx2

      math_Vector D2EDT2(1, 3, 0);
      E.Deriv2T(myTrimmed, Param, R(1), D2N, myAngle, D2EDT2); // d2E/dt2

      math_Matrix D2EDTDX(1, 3, 1, 3, 0);
      E.DerivTX(DN, myAngle, D2EDTDX); // d2E/dtdx

      math_Vector D2SDT2(1, 3, 0); // d2s/dt2
      math_Matrix aT(1, 3, 1, 3, 0);
      D2EDX2.Multiply(DSDT, aT);

      // resolution du syst. lin.
      math_Gauss Ga1(DEDX);
      if (Ga1.IsDone())
      {
        Ga1.Solve(-aT * DSDT - 2 * D2EDTDX * DSDT - D2EDT2, D2SDT2);
        gp_Vec2d d2p(D2SDT2(2), D2SDT2(3)); // surface
        gp_Vec2d d2q(D2SDT2(1), 0);         // courbe
        D2Poles2d.SetValue(1, d2p);
        D2Poles2d.SetValue(2, d2q);
      } // if
      else
      { // la generatrice n'intersecte pas la surface d'arret
        return Standard_False;
      }
    } // if_Result
  } // if_Intersec

  return Standard_True;
}

//=================================================================================================

Standard_Boolean GeomFill_LocationDraft::HasFirstRestriction() const
{
  return Standard_False;
}

//=================================================================================================

Standard_Boolean GeomFill_LocationDraft::HasLastRestriction() const
{

  if (Intersec == Standard_True)
    return Standard_True;
  else
    return Standard_False;
}

//=================================================================================================

Standard_Integer GeomFill_LocationDraft::TraceNumber() const
{
  if (Intersec == Standard_True)
    return 1;
  else
    return 0;
}

//=================================================================================================

Standard_Integer GeomFill_LocationDraft::NbIntervals(const GeomAbs_Shape S) const
{
  return myLaw->NbIntervals(S);
}

//=================================================================================================

void GeomFill_LocationDraft::Intervals(TColStd_Array1OfReal& T, const GeomAbs_Shape S) const
{
  myLaw->Intervals(T, S);
}

//=================================================================================================

void GeomFill_LocationDraft::SetInterval(const Standard_Real First, const Standard_Real Last)
{
  myLaw->SetInterval(First, Last);
  myTrimmed = myCurve->Trim(First, Last, 0);
}

//=================================================================================================

void GeomFill_LocationDraft::GetInterval(Standard_Real& First, Standard_Real& Last) const
{
  First = myTrimmed->FirstParameter();
  Last  = myTrimmed->LastParameter();
}

//=================================================================================================

void GeomFill_LocationDraft::GetDomain(Standard_Real& First, Standard_Real& Last) const
{
  First = myCurve->FirstParameter();
  Last  = myCurve->LastParameter();
}

//=================================================================================================

void GeomFill_LocationDraft::Resolution(const Standard_Integer Index,
                                        const Standard_Real    Tol,
                                        Standard_Real&         TolU,
                                        Standard_Real&         TolV) const

{
  if (Index == 1)
  {
    TolU = mySurf->UResolution(Tol);
    TolV = mySurf->VResolution(Tol);
  }
  else
  {
    TolU = Tol;
    TolV = Tol;
  }
}

//==================================================================
// Function:GetMaximalNorm
// Purpose :  On suppose les triedres normes => return 1
//==================================================================
Standard_Real GeomFill_LocationDraft::GetMaximalNorm()
{
  return 1.;
}

//=================================================================================================

void GeomFill_LocationDraft::GetAverageLaw(gp_Mat& AM, gp_Vec& AV)
{
  Standard_Integer ii;
  Standard_Real    U, delta;
  gp_Vec           V1, V2, V3, V;

  myLaw->GetAverageLaw(V1, V2, V3);
  AM.SetCols(V1.XYZ(), V2.XYZ(), V3.XYZ());

  AV.SetCoord(0., 0., 0.);
  delta = (myTrimmed->LastParameter() - myTrimmed->FirstParameter()) / 10;
  U     = myTrimmed->FirstParameter();
  for (ii = 0; ii <= 10; ii++, U += delta)
  {
    V.SetXYZ(myTrimmed->Value(U).XYZ());
    AV += V;
  }
  AV /= 11;
}

//=================================================================================================

// Standard_Boolean GeomFill_LocationDraft::IsTranslation(Standard_Real& Error) const
Standard_Boolean GeomFill_LocationDraft::IsTranslation(Standard_Real&) const
{
  return myLaw->IsConstant();
}

//=================================================================================================

Standard_Boolean GeomFill_LocationDraft::IsRotation(Standard_Real& Error) const
{
  GeomAbs_CurveType Type;
  Error = 0;
  Type  = myCurve->GetType();
  if (Type == GeomAbs_Circle)
  {
    return myLaw->IsOnlyBy3dCurve();
  }
  return Standard_False;
}

//=================================================================================================

void GeomFill_LocationDraft::Rotation(gp_Pnt& Centre) const
{
  Centre = myCurve->Circle().Location();
}

//=================================================================================================

Standard_Boolean GeomFill_LocationDraft::IsIntersec() const
{
  return Intersec;
}

//=================================================================================================

gp_Dir GeomFill_LocationDraft::Direction() const
{
  return myDir;
}
