// Created on: 1996-09-04
// Created by: Olga PILLOT
// Copyright (c) 1996-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 <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <BRepLib.hxx>
#include <BRepLib_MakeEdge.hxx>
#include <BRepLib_MakeVertex.hxx>
#include <BRepLib_MakeWire.hxx>
#include <BRepTools.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Line.hxx>
#include <Geom_Plane.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_Surface.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <gp.hxx>
#include <gp_Ax3.hxx>
#include <gp_Lin.hxx>
#include <gp_Pln.hxx>
#include <gp_Vec.hxx>
#include <LocOpe.hxx>
#include <LocOpe_BuildShape.hxx>
#include <LocOpe_DPrism.hxx>
#include <Standard_ConstructionError.hxx>
#include <StdFail_NotDone.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_MapOfShape.hxx>

#ifdef OCCT_DEBUG
extern Standard_Boolean BRepFeat_GettraceFEAT();
#endif

#define NECHANT 7 // voir BRepFeat.cxx

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

LocOpe_DPrism::LocOpe_DPrism(const TopoDS_Face&  Spine,
                             const Standard_Real Height1,
                             const Standard_Real Height2,
                             const Standard_Real Angle)
    : mySpine(Spine)
{
  Standard_Integer i;

  myHeight        = Height1 + Height2;
  Standard_Real y = Height1 * sin(Angle);
  Standard_Real z = Height1 * cos(Angle);

  TopoDS_Vertex Vert2 = BRepLib_MakeVertex(gp_Pnt(0, y, z));

  Standard_Real y1 = -Height2 * sin(Angle);
  Standard_Real z1 = -Height2 * cos(Angle);

  TopoDS_Vertex Vert1 = BRepLib_MakeVertex(gp_Pnt(0, y1, z1));

  myProfile2 = BRepLib_MakeEdge(Vert1, Vert2);

  Standard_Real Umin, Umax, Vmin, Vmax;
  Umax = 0.;
  Umin = 0.;
  Vmin = 0.;
  Vmax = 0.;

  BRepTools::UVBounds(Spine, Umin, Umax, Vmin, Vmax);
  Standard_Real Deltay = Max(Umax - Umin, Vmax - Vmin) + Abs(y);
  Deltay *= 2;

  TopoDS_Vertex Vert3 = BRepLib_MakeVertex(gp_Pnt(0, y + Deltay, z));
  myProfile3          = BRepLib_MakeEdge(Vert2, Vert3);

  Umax = 0.;
  Umin = 0.;
  Vmin = 0.;
  Vmax = 0.;

  BRepTools::UVBounds(Spine, Umin, Umax, Vmin, Vmax);
  Standard_Real Deltay1 = Max(Umax - Umin, Vmax - Vmin) + Abs(y1);
  Deltay1 *= 2;

  TopoDS_Vertex Vert4 = BRepLib_MakeVertex(gp_Pnt(0, y1 + Deltay1, z1));
  myProfile1          = BRepLib_MakeEdge(Vert4, Vert1);

  myProfile = BRepLib_MakeWire(myProfile1, myProfile2, myProfile3);

  myDPrism.Perform(mySpine, myProfile, gp::XOY());

  if (myDPrism.IsDone())
  {
    LocOpe_BuildShape    BS;
    BRep_Builder         B;
    TopoDS_Compound      C;
    TopoDS_Compound      D;
    TopTools_ListOfShape lfaces, lcomplete;

    B.MakeCompound(C);
    TopTools_ListIteratorOfListOfShape it;
    TopExp_Explorer                    ExpS(mySpine, TopAbs_EDGE);
    TopTools_MapOfShape                View;
    for (; ExpS.More(); ExpS.Next())
    {
      const TopoDS_Shape&         ES   = ExpS.Current();
      const TopTools_ListOfShape& lffs = myDPrism.GeneratedShapes(ES, myProfile1);
      for (it.Initialize(lffs); it.More(); it.Next())
      {
        if (View.Add(it.Value()))
          B.Add(C, it.Value());
      }
    }

    TopTools_IndexedDataMapOfShapeListOfShape theMapEF;
    TopExp::MapShapesAndAncestors(C, TopAbs_EDGE, TopAbs_FACE, theMapEF);
    View.Clear();

    for (i = 1; i <= theMapEF.Extent(); i++)
    {
      if (theMapEF(i).Extent() == 1)
      {
        const TopoDS_Edge& edg = TopoDS::Edge(theMapEF.FindKey(i));
        const TopoDS_Face& fac = TopoDS::Face(theMapEF(i).First());
        if (View.Add(fac))
        {
          TopoDS_Shape aLocalShape = fac.EmptyCopied();
          TopoDS_Face  newFace(TopoDS::Face(aLocalShape));
          //	  TopoDS_Face newFace(TopoDS::Face(fac.EmptyCopied()));
          TopExp_Explorer exp;
          for (exp.Init(fac.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp.More(); exp.Next())
          {
            //	    for (TopExp_Explorer exp2(exp.Current(),TopAbs_EDGE);
            TopExp_Explorer exp2(exp.Current(), TopAbs_EDGE);
            for (; exp2.More(); exp2.Next())
            {
              if (exp2.Current().IsSame(edg))
              {
                B.Add(newFace, exp.Current());
                lfaces.Append(newFace);
                lcomplete.Append(newFace);
                break;
              }
            }
            if (exp2.More())
            {
              break;
            }
          }
        }
      }
    }

    BS.Perform(lfaces);
    myFirstShape = BS.Shape();

    B.MakeCompound(D);

    ExpS.ReInit();
    View.Clear();

    for (; ExpS.More(); ExpS.Next())
    {
      const TopoDS_Shape&         ES   = ExpS.Current();
      const TopTools_ListOfShape& lfls = myDPrism.GeneratedShapes(ES, myProfile3);
      for (it.Initialize(lfls); it.More(); it.Next())
      {
        if (View.Add(it.Value()))
          B.Add(D, it.Value());
      }
    }

    lfaces.Clear();
    theMapEF.Clear();
    TopExp::MapShapesAndAncestors(D, TopAbs_EDGE, TopAbs_FACE, theMapEF);
    View.Clear();

    for (i = 1; i <= theMapEF.Extent(); i++)
    {
      if (theMapEF(i).Extent() == 1)
      {
        const TopoDS_Edge& edg = TopoDS::Edge(theMapEF.FindKey(i));
        const TopoDS_Face& fac = TopoDS::Face(theMapEF(i).First());
        if (View.Add(fac))
        {
          TopoDS_Shape aLocalShape = fac.EmptyCopied();
          TopoDS_Face  newFace(TopoDS::Face(aLocalShape));
          //	  TopoDS_Face newFace(TopoDS::Face(fac.EmptyCopied()));
          TopExp_Explorer exp;
          for (exp.Init(fac.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp.More(); exp.Next())
          {
            //	    for (TopExp_Explorer exp2(exp.Current(),TopAbs_EDGE);
            TopExp_Explorer exp2(exp.Current(), TopAbs_EDGE);
            for (; exp2.More(); exp2.Next())
            {
              if (exp2.Current().IsSame(edg))
              {
                B.Add(newFace, exp.Current());
                lfaces.Append(newFace);
                lcomplete.Append(newFace);
                break;
              }
            }
            if (exp2.More())
            {
              break;
            }
          }
        }
      }
    }
    BS.Perform(lfaces);
    myLastShape = BS.Shape();

    View.Clear();

    for (ExpS.ReInit(); ExpS.More(); ExpS.Next())
    {
      const TopoDS_Shape&         ES   = ExpS.Current();
      const TopTools_ListOfShape& lffs = myDPrism.GeneratedShapes(ES, myProfile2);

      for (it.Initialize(lffs); it.More(); it.Next())
      {
        if (it.Value().ShapeType() == TopAbs_EDGE)
        {
          break;
        }
      }
      if (it.More())
      {
        TopoDS_Shape RemovedEdge = it.Value();
        TopoDS_Face  NewFace;
        TopoDS_Wire  NewWire;
        B.MakeWire(NewWire);
        TopAbs_Orientation Orref = TopAbs_FORWARD;
        TopExp_Explorer    exp;
        for (it.Initialize(lffs); it.More(); it.Next())
        {
          if (it.Value().ShapeType() == TopAbs_FACE)
          {
            exp.Init(it.Value().Oriented(TopAbs_FORWARD), TopAbs_WIRE);
            const TopoDS_Shape theWire = exp.Current();
            if (NewFace.IsNull())
            {
              Handle(Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(it.Value()));
              if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
              {
                S = Handle(Geom_RectangularTrimmedSurface)::DownCast(S)->BasisSurface();
              }
              if (S->DynamicType() != STANDARD_TYPE(Geom_Plane))
              {
                break;
              }

              B.MakeFace(NewFace, S, BRep_Tool::Tolerance(TopoDS::Face(it.Value())));
              NewFace.Orientation(TopAbs_FORWARD);
              Orref = theWire.Orientation();
              for (exp.Init(theWire.Oriented(TopAbs_FORWARD), TopAbs_EDGE); exp.More(); exp.Next())
              {
                if (!exp.Current().IsSame(RemovedEdge))
                {
                  B.Add(NewWire, exp.Current());
                }
              }
            }
            else
            {
              for (exp.Init(theWire.Oriented(TopAbs_FORWARD), TopAbs_EDGE); exp.More(); exp.Next())
              {
                if (!exp.Current().IsSame(RemovedEdge))
                {
                  if (theWire.Orientation() != Orref)
                  { // Les 2 faces planes ont des normales opposees
                    B.Add(NewWire, exp.Current());
                  }
                  else
                  {
                    B.Add(NewWire, exp.Current().Reversed());
                  }
                }
              }
            }
          }
        }
        if (!NewFace.IsNull())
        {
          B.Add(NewFace, NewWire.Oriented(Orref));
          lcomplete.Append(NewFace);
          TopTools_ListOfShape thelist;
          myMap.Bind(ES, thelist);
          myMap(ES).Append(NewFace);
        }
        else
        {
          for (it.Initialize(lffs); it.More(); it.Next())
          {
            if (View.Add(it.Value()) && it.Value().ShapeType() == TopAbs_FACE)
            {
              lcomplete.Append(it.Value());
            }
          }
        }
      }
      else
      {
        for (it.Initialize(lffs); it.More(); it.Next())
        {
          if (View.Add(it.Value()) && it.Value().ShapeType() == TopAbs_FACE)
          {
            lcomplete.Append(it.Value());
          }
        }
      }

      TopExp_Explorer ExpS2;
      for (ExpS2.Init(ES, TopAbs_VERTEX); ExpS2.More(); ExpS2.Next())
      {
        const TopTools_ListOfShape& ls2 = myDPrism.GeneratedShapes(ExpS2.Current(), myProfile2);
        for (it.Initialize(ls2); it.More(); it.Next())
        {
          if (View.Add(it.Value()) && it.Value().ShapeType() == TopAbs_FACE)
          {
            lcomplete.Append(it.Value());
          }
        }
      }
    }

    BS.Perform(lcomplete);
    myRes = BS.Shape();
    BRepLib::UpdateTolerances(myRes);
  }
}

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

LocOpe_DPrism::LocOpe_DPrism(const TopoDS_Face&  Spine,
                             const Standard_Real Height,
                             const Standard_Real Angle)
    : mySpine(Spine)
{
  Standard_Integer i;
  myHeight        = Height;
  Standard_Real y = Height * sin(Angle);
  Standard_Real z = Height * cos(Angle);

  TopoDS_Vertex Vert1 = BRepLib_MakeVertex(gp_Pnt(0, 0, 0));
  TopoDS_Vertex Vert2 = BRepLib_MakeVertex(gp_Pnt(0, y, z));
  myProfile2          = BRepLib_MakeEdge(Vert1, Vert2);

  Standard_Real Umin, Umax, Vmin, Vmax;
  BRepTools::UVBounds(Spine, Umin, Umax, Vmin, Vmax);
  Standard_Real Deltay = Max(Umax - Umin, Vmax - Vmin) + Abs(y);
  Deltay *= 2;

  TopoDS_Vertex Vert3 = BRepLib_MakeVertex(gp_Pnt(0, y + Deltay, z));
  myProfile3          = BRepLib_MakeEdge(Vert2, Vert3);

  TopoDS_Vertex Vert4 = BRepLib_MakeVertex(gp_Pnt(0, Deltay, 0));
  myProfile1          = BRepLib_MakeEdge(Vert4, Vert1);

  myProfile = BRepLib_MakeWire(myProfile1, myProfile2, myProfile3);
  myDPrism.Perform(mySpine, myProfile, gp::XOY());

  if (myDPrism.IsDone())
  {
    LocOpe_BuildShape    BS;
    BRep_Builder         B;
    TopoDS_Compound      C;
    TopoDS_Compound      D;
    TopTools_ListOfShape lfaces, lcomplete;

    B.MakeCompound(C);
    TopTools_ListIteratorOfListOfShape it;
    TopExp_Explorer                    ExpS(mySpine, TopAbs_EDGE);
    TopTools_MapOfShape                View;
    for (; ExpS.More(); ExpS.Next())
    {
      const TopoDS_Shape&         ES   = ExpS.Current();
      const TopTools_ListOfShape& lffs = myDPrism.GeneratedShapes(ES, myProfile1);
      for (it.Initialize(lffs); it.More(); it.Next())
      {
        if (View.Add(it.Value()))
          B.Add(C, it.Value());
      }
    }

    TopTools_IndexedDataMapOfShapeListOfShape theMapEF;
    TopExp::MapShapesAndAncestors(C, TopAbs_EDGE, TopAbs_FACE, theMapEF);
    View.Clear();

    for (i = 1; i <= theMapEF.Extent(); i++)
    {
      if (theMapEF(i).Extent() == 1)
      {
        const TopoDS_Edge& edg = TopoDS::Edge(theMapEF.FindKey(i));
        const TopoDS_Face& fac = TopoDS::Face(theMapEF(i).First());
        if (View.Add(fac))
        {
          TopoDS_Shape aLocalShape = fac.EmptyCopied();
          TopoDS_Face  newFace(TopoDS::Face(aLocalShape));
          //	  TopoDS_Face newFace(TopoDS::Face(fac.EmptyCopied()));
          TopExp_Explorer exp;
          for (exp.Init(fac.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp.More(); exp.Next())
          {
            //	    for (TopExp_Explorer exp2(exp.Current(),TopAbs_EDGE);
            TopExp_Explorer exp2(exp.Current(), TopAbs_EDGE);
            for (; exp2.More(); exp2.Next())
            {
              if (exp2.Current().IsSame(edg))
              {
                B.Add(newFace, exp.Current());
                lfaces.Append(newFace);
                lcomplete.Append(newFace);
                break;
              }
            }
            if (exp2.More())
            {
              break;
            }
          }
        }
      }
    }

    BS.Perform(lfaces);
    myFirstShape = BS.Shape();

    B.MakeCompound(D);

    ExpS.ReInit();
    View.Clear();

    for (; ExpS.More(); ExpS.Next())
    {
      const TopoDS_Shape&         ES   = ExpS.Current();
      const TopTools_ListOfShape& lfls = myDPrism.GeneratedShapes(ES, myProfile3);
      for (it.Initialize(lfls); it.More(); it.Next())
      {
        if (View.Add(it.Value()))
          B.Add(D, it.Value());
      }
    }

    lfaces.Clear();
    theMapEF.Clear();
    TopExp::MapShapesAndAncestors(D, TopAbs_EDGE, TopAbs_FACE, theMapEF);
    View.Clear();

    for (i = 1; i <= theMapEF.Extent(); i++)
    {
      if (theMapEF(i).Extent() == 1)
      {
        const TopoDS_Edge& edg = TopoDS::Edge(theMapEF.FindKey(i));
        const TopoDS_Face& fac = TopoDS::Face(theMapEF(i).First());
        if (View.Add(fac))
        {
          TopoDS_Shape aLocalShape = fac.EmptyCopied();
          TopoDS_Face  newFace(TopoDS::Face(aLocalShape));
          //	  TopoDS_Face newFace(TopoDS::Face(fac.EmptyCopied()));
          TopExp_Explorer exp;
          for (exp.Init(fac.Oriented(TopAbs_FORWARD), TopAbs_WIRE); exp.More(); exp.Next())
          {
            //	    for (TopExp_Explorer exp2(exp.Current(),TopAbs_EDGE);
            TopExp_Explorer exp2(exp.Current(), TopAbs_EDGE);
            for (; exp2.More(); exp2.Next())
            {
              if (exp2.Current().IsSame(edg))
              {
                B.Add(newFace, exp.Current());
                lfaces.Append(newFace);
                lcomplete.Append(newFace);
                break;
              }
            }
            if (exp2.More())
            {
              break;
            }
          }
        }
      }
    }
    BS.Perform(lfaces);
    myLastShape = BS.Shape();

    View.Clear();
    for (ExpS.ReInit(); ExpS.More(); ExpS.Next())
    {
      const TopoDS_Shape&         ES = ExpS.Current();
      const TopTools_ListOfShape& ls = myDPrism.GeneratedShapes(ES, myProfile2);
      for (it.Initialize(ls); it.More(); it.Next())
      {
        if (View.Add(it.Value()))
        {
          lcomplete.Append(it.Value());
        }
      }
      TopExp_Explorer ExpS2;
      for (ExpS2.Init(ES, TopAbs_VERTEX); ExpS2.More(); ExpS2.Next())
      {
        const TopTools_ListOfShape& ls2 = myDPrism.GeneratedShapes(ExpS2.Current(), myProfile2);
        for (it.Initialize(ls2); it.More(); it.Next())
        {
          if (View.Add(it.Value()) && it.Value().ShapeType() == TopAbs_FACE)
          {
            lcomplete.Append(it.Value());
          }
        }
      }
    }

    BS.Perform(lcomplete);
    myRes = BS.Shape();
    BRepLib::UpdateTolerances(myRes);
  }
}

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

Standard_Boolean LocOpe_DPrism::IsDone() const
{
  return myDPrism.IsDone();
}

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

const TopoDS_Shape& LocOpe_DPrism::Shape() const
{
  if (!myDPrism.IsDone())
  {
    throw StdFail_NotDone();
  }
  return myRes;
}

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

const TopoDS_Shape& LocOpe_DPrism::Spine() const
{
  return mySpine;
}

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

const TopoDS_Shape& LocOpe_DPrism::Profile() const
{
  return myProfile;
}

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

const TopoDS_Shape& LocOpe_DPrism::FirstShape() const
{
  return myFirstShape;
}

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

const TopoDS_Shape& LocOpe_DPrism::LastShape() const
{
  return myLastShape;
}

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

const TopTools_ListOfShape& LocOpe_DPrism::Shapes(const TopoDS_Shape& S) const
{
  if (!myDPrism.IsDone())
  {
    throw StdFail_NotDone();
  }
  if (myMap.IsBound(S))
  {
    return myMap(S);
  }
  else
  {
    return myDPrism.GeneratedShapes(S, myProfile2);
  }
}

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

void LocOpe_DPrism::Curves(TColGeom_SequenceOfCurve& Scurves) const
{
  // Retrieves dy and dz with myProfile2
  TopoDS_Vertex V1, V2;
  TopExp::Vertices(myProfile2, V1, V2);
  gp_Pnt        P1 = BRep_Tool::Pnt(V1);
  gp_Pnt        P2 = BRep_Tool::Pnt(V2);
  Standard_Real dy = P2.Y() - P1.Y();
  Standard_Real dz = P2.Z() - P1.Z();
  Scurves.Clear();
  Handle(Geom_Surface) S = BRep_Tool::Surface(mySpine);
  if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
  {
    S = Handle(Geom_RectangularTrimmedSurface)::DownCast(S)->BasisSurface();
  }

  Handle(Geom_Plane) PP = Handle(Geom_Plane)::DownCast(S);
  if (PP.IsNull())
  {
    throw Standard_ConstructionError();
  }

  gp_Pln P = PP->Pln();
  gp_Dir Normale(P.Axis().Direction());
  if (!P.Direct())
  {
    Normale.Reverse();
  }

  TopTools_MapOfShape theMap;
  TopExp_Explorer     exp(mySpine.Oriented(TopAbs_FORWARD), TopAbs_EDGE);
  TopLoc_Location     Loc;
  Handle(Geom_Curve)  C;
  Standard_Real       f, l, prm;
  Standard_Integer    i;

  for (; exp.More(); exp.Next())
  {
    const TopoDS_Edge& edg = TopoDS::Edge(exp.Current());
    if (!theMap.Add(edg))
    {
      continue;
    }
    if (!BRep_Tool::Degenerated(edg))
    {
      C                = BRep_Tool::Curve(edg, Loc, f, l);
      C                = Handle(Geom_Curve)::DownCast(C->Transformed(Loc.Transformation()));
      Standard_Real u1 = -2 * Abs(myHeight);
      Standard_Real u2 = 2 * Abs(myHeight);

      for (i = 0; i <= NECHANT; i++)
      {
        prm = ((NECHANT - i) * f + i * l) / NECHANT;
        gp_Pnt pt;
        gp_Vec d1;
        C->D1(prm, pt, d1);
        if (exp.Current().Orientation() == TopAbs_REVERSED)
        {
          d1.Reverse();
        }
        d1.Normalize();
        gp_Dir                    locy = Normale.Crossed(d1);
        gp_Vec                    ldir = dy * locy.XYZ() + dz * Normale.XYZ();
        gp_Lin                    lin(pt, ldir);
        Handle(Geom_Line)         Lin   = new Geom_Line(lin);
        Handle(Geom_TrimmedCurve) trlin = new Geom_TrimmedCurve(Lin, u1, u2, Standard_True);
        Scurves.Append(trlin);
      }
    }
  }
}

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

Handle(Geom_Curve) LocOpe_DPrism::BarycCurve() const
{
  TopoDS_Vertex V1, V2;
  TopExp::Vertices(myProfile2, V1, V2);
  gp_Pnt        P1 = BRep_Tool::Pnt(V1);
  gp_Pnt        P2 = BRep_Tool::Pnt(V2);
  Standard_Real dz = P2.Z() - P1.Z();

  Handle(Geom_Surface) S = BRep_Tool::Surface(mySpine);
  if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
  {
    S = Handle(Geom_RectangularTrimmedSurface)::DownCast(S)->BasisSurface();
  }

  Handle(Geom_Plane) PP = Handle(Geom_Plane)::DownCast(S);
  if (PP.IsNull())
  {
    throw Standard_ConstructionError();
  }

  gp_Pln P = PP->Pln();
  gp_Dir Normale(P.Axis().Direction());
  if (!P.Direct())
  {
    Normale.Reverse();
  }
  if (mySpine.Orientation() == TopAbs_REVERSED)
  {
#ifdef OCCT_DEBUG
    Standard_Boolean trc = BRepFeat_GettraceFEAT();
    if (trc)
    {
      std::cout << "LocOpe_DPrism::BarycCurve()" << std::endl;
      std::cout << " Reversed Spine orientation" << std::endl;
    }
#endif
    //    Normale.Reverse();  //cts20871
  }
  gp_Vec Vec = dz * Normale.XYZ();

  gp_Pnt               bar(0., 0., 0.);
  TColgp_SequenceOfPnt spt;
  if (!myFirstShape.IsNull())
  {
    LocOpe::SampleEdges(myFirstShape, spt);
  }
  else
  {
    LocOpe::SampleEdges(mySpine, spt);
  }
  for (Standard_Integer jj = 1; jj <= spt.Length(); jj++)
  {
    const gp_Pnt& pvt = spt(jj);
    bar.ChangeCoord() += pvt.XYZ();
  }
  bar.ChangeCoord().Divide(spt.Length());
  gp_Ax1            newAx(bar, Vec);
  Handle(Geom_Line) theLin = new Geom_Line(newAx);
  return theLin;
}
