// Created on: 1998-04-08
// Created by: Philippe MANGIN
// 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.

#ifndef _BRepOffsetAPI_MakePipeShell_HeaderFile
#define _BRepOffsetAPI_MakePipeShell_HeaderFile

#include <Standard.hxx>
#include <Standard_DefineAlloc.hxx>
#include <Standard_Handle.hxx>

#include <BRepPrimAPI_MakeSweep.hxx>
#include <BRepFill_PipeShell.hxx>
#include <BRepFill_TypeOfContact.hxx>
#include <BRepBuilderAPI_PipeError.hxx>
#include <Standard_Integer.hxx>
#include <BRepBuilderAPI_TransitionMode.hxx>
#include <TopoDS_Shape.hxx>
#include <NCollection_List.hxx>
class TopoDS_Wire;
class gp_Ax2;
class gp_Dir;
class TopoDS_Shape;
class TopoDS_Vertex;
class Law_Function;

//! This class provides for a framework to construct a shell
//! or a solid along a spine consisting in a wire.
//! To produce a solid, the initial wire must be closed.
//! Two approaches are used:
//! - definition by section
//! - by a section and a scaling law
//! - by addition of successive intermediary sections
//! - definition by sweep mode.
//! - pseudo-Frenet
//! - constant
//! - binormal constant
//! - normal defined by a surface support
//! - normal defined by a guiding contour.
//! The two global approaches can also be combined.
//! You can also close the surface later in order to form a solid.
//! Warning: some limitations exist
//! -- Mode with auxiliary spine is incompatible with hometetic laws
//! -- Mode with auxiliary spine and keep contact produce only CO surface.
class BRepOffsetAPI_MakePipeShell : public BRepPrimAPI_MakeSweep
{
public:
  DEFINE_STANDARD_ALLOC

  //! Constructs the shell-generating framework defined by the wire Spine.
  //! Sets an sweep's mode
  //! If no mode are set, the mode use in MakePipe is used
  Standard_EXPORT BRepOffsetAPI_MakePipeShell(const TopoDS_Wire& Spine);

  //! Sets a Frenet or a CorrectedFrenet trihedron
  //! to perform the sweeping
  //! If IsFrenet is false, a corrected Frenet trihedron is used.
  Standard_EXPORT void SetMode(const bool IsFrenet = false);

  //! Sets a Discrete trihedron
  //! to perform the sweeping
  Standard_EXPORT void SetDiscreteMode();

  //! Sets a fixed trihedron to perform the sweeping
  //! all sections will be parallel.
  Standard_EXPORT void SetMode(const gp_Ax2& Axe);

  //! Sets a fixed BiNormal direction to perform the
  //! sweeping. Angular relations between the
  //! section(s) and <BiNormal> will be constant
  Standard_EXPORT void SetMode(const gp_Dir& BiNormal);

  //! Sets support to the spine to define the BiNormal of
  //! the trihedron, like the normal to the surfaces.
  //! Warning: To be effective, Each edge of the <spine> must
  //! have a representation on one face of<SpineSupport>
  Standard_EXPORT bool SetMode(const TopoDS_Shape& SpineSupport);

  //! Sets an auxiliary spine to define the Normal
  //! For each Point of the Spine P, an Point Q is evaluated
  //! on <AuxiliarySpine>
  //! If <CurvilinearEquivalence>
  //! Q split <AuxiliarySpine> with the same length ratio
  //! than P split <Spline>.
  //! Else the plan define by P and the tangent to the <Spine>
  //! intersect <AuxiliarySpine> in Q.
  //! If <KeepContact> equals BRepFill_NoContact: The Normal is defined
  //! by the vector PQ.
  //! If <KeepContact> equals BRepFill_Contact: The Normal is defined to
  //! achieve that the sweeped section is in contact to the
  //! auxiliarySpine. The width of section is constant all along the path.
  //! In other words, the auxiliary spine lies on the swept surface,
  //! but not necessarily is a boundary of this surface. However,
  //! the auxiliary spine has to be close enough to the main spine
  //! to provide intersection with any section all along the path.
  //! If <KeepContact> equals BRepFill_ContactOnBorder: The auxiliary spine
  //! becomes a boundary of the swept surface and the width of section varies
  //! along the path.
  //! Give section to sweep.
  //! Possibilities are:
  //! - Give one or several section
  //! - Give one profile and an homotetic law.
  //! - Automatic compute of correspondence between spine, and section
  //! on the sweeped shape
  //! - correspondence between spine, and section on the sweeped shape
  //! defined by a vertex of the spine
  Standard_EXPORT void SetMode(const TopoDS_Wire&           AuxiliarySpine,
                               const bool                   CurvilinearEquivalence,
                               const BRepFill_TypeOfContact KeepContact = BRepFill_NoContact);

  //! Adds the section Profile to this framework. First and last
  //! sections may be punctual, so the shape Profile may be
  //! both wire and vertex. Correspondent point on spine is
  //! computed automatically.
  //! If WithContact is true, the section is translated to be in
  //! contact with the spine.
  //! If WithCorrection is true, the section is rotated to be
  //! orthogonal to the spine?s tangent in the correspondent
  //! point. This option has no sense if the section is punctual
  //! (Profile is of type TopoDS_Vertex).
  Standard_EXPORT void Add(const TopoDS_Shape& Profile,
                           const bool          WithContact    = false,
                           const bool          WithCorrection = false);

  //! Adds the section Profile to this framework.
  //! Correspondent point on the spine is given by Location.
  //! Warning:
  //! To be effective, it is not recommended to combine methods Add and SetLaw.
  Standard_EXPORT void Add(const TopoDS_Shape&  Profile,
                           const TopoDS_Vertex& Location,
                           const bool           WithContact    = false,
                           const bool           WithCorrection = false);

  //! Sets the evolution law defined by the wire Profile with
  //! its position (Location, WithContact, WithCorrection
  //! are the same options as in methods Add) and a
  //! homotetic law defined by the function L.
  //! Warning:
  //! To be effective, it is not recommended to combine methods Add and SetLaw.
  Standard_EXPORT void SetLaw(const TopoDS_Shape&              Profile,
                              const occ::handle<Law_Function>& L,
                              const bool                       WithContact    = false,
                              const bool                       WithCorrection = false);

  //! Sets the evolution law defined by the wire Profile with
  //! its position (Location, WithContact, WithCorrection
  //! are the same options as in methods Add) and a
  //! homotetic law defined by the function L.
  //! Warning:
  //! To be effective, it is not recommended to combine methods Add and SetLaw.
  Standard_EXPORT void SetLaw(const TopoDS_Shape&              Profile,
                              const occ::handle<Law_Function>& L,
                              const TopoDS_Vertex&             Location,
                              const bool                       WithContact    = false,
                              const bool                       WithCorrection = false);

  //! Removes the section Profile from this framework.
  Standard_EXPORT void Delete(const TopoDS_Shape& Profile);

  //! Returns true if this tool object is ready to build the
  //! shape, i.e. has a definition for the wire section Profile.
  Standard_EXPORT bool IsReady() const;

  //! Get a status, when Simulate or Build failed. It can be
  //! BRepBuilderAPI_PipeDone,
  //! BRepBuilderAPI_PipeNotDone,
  //! BRepBuilderAPI_PlaneNotIntersectGuide,
  //! BRepBuilderAPI_ImpossibleContact.
  Standard_EXPORT BRepBuilderAPI_PipeError GetStatus() const;

  //! Sets the following tolerance values
  //! - 3D tolerance Tol3d
  //! - boundary tolerance BoundTol
  //! - angular tolerance TolAngular.
  Standard_EXPORT void SetTolerance(const double Tol3d      = 1.0e-4,
                                    const double BoundTol   = 1.0e-4,
                                    const double TolAngular = 1.0e-2);

  //! Define the maximum V degree of resulting surface
  Standard_EXPORT void SetMaxDegree(const int NewMaxDegree);

  //! Define the maximum number of spans in V-direction
  //! on resulting surface
  Standard_EXPORT void SetMaxSegments(const int NewMaxSegments);

  //! Set the flag that indicates attempt to approximate
  //! a C1-continuous surface if a swept surface proved
  //! to be C0.
  Standard_EXPORT void SetForceApproxC1(const bool ForceApproxC1);

  //! Sets the transition mode to manage discontinuities on
  //! the swept shape caused by fractures on the spine. The
  //! transition mode can be BRepBuilderAPI_Transformed
  //! (default value), BRepBuilderAPI_RightCorner,
  //! BRepBuilderAPI_RoundCorner:
  //! -              RepBuilderAPI_Transformed:
  //! discontinuities are treated by
  //! modification of the sweeping mode. The
  //! pipe is "transformed" at the fractures of
  //! the spine. This mode assumes building a
  //! self-intersected shell.
  //! -              BRepBuilderAPI_RightCorner:
  //! discontinuities are treated like right
  //! corner. Two pieces of the pipe
  //! corresponding to two adjacent
  //! segments of the spine are extended
  //! and intersected at a fracture of the spine.
  //! -              BRepBuilderAPI_RoundCorner:
  //! discontinuities are treated like round
  //! corner. The corner is treated as rotation
  //! of the profile around an axis which
  //! passes through the point of the spine's
  //! fracture. This axis is based on cross
  //! product of directions tangent to the
  //! adjacent segments of the spine at their common point.
  //! Warnings
  //! The mode BRepBuilderAPI_RightCorner provides a
  //! valid result if intersection of two pieces of the pipe
  //! (corresponding to two adjacent segments of the spine)
  //! in the neighborhood of the spine?s fracture is
  //! connected and planar. This condition can be violated if
  //! the spine is non-linear in some neighborhood of the
  //! fracture or if the profile was set with a scaling law.
  //! The last mode, BRepBuilderAPI_RoundCorner, will
  //! assuredly provide a good result only if a profile was set
  //! with option WithCorrection = True, i.e. it is strictly
  //! orthogonal to the spine.
  Standard_EXPORT void SetTransitionMode(
    const BRepBuilderAPI_TransitionMode Mode = BRepBuilderAPI_Transformed);

  //! Simulates the resulting shape by calculating its
  //! cross-sections. The spine is divided by this
  //! cross-sections into (NumberOfSection - 1) equal
  //! parts, the number of cross-sections is
  //! NumberOfSection. The cross-sections are wires and
  //! they are returned in the list Result.
  //! This gives a rapid preview of the resulting shape,
  //! which will be obtained using the settings you have provided.
  //! Raises NotDone if <me> it is not Ready
  Standard_EXPORT void Simulate(const int NumberOfSection, NCollection_List<TopoDS_Shape>& Result);

  //! Builds the resulting shape (redefined from MakeShape).
  Standard_EXPORT void Build(
    const Message_ProgressRange& theRange = Message_ProgressRange()) override;

  //! Transforms the sweeping Shell in Solid.
  //! If a propfile is not closed returns False
  Standard_EXPORT bool MakeSolid();

  //! Returns the TopoDS Shape of the bottom of the sweep.
  Standard_EXPORT TopoDS_Shape FirstShape() override;

  //! Returns the TopoDS Shape of the top of the sweep.
  Standard_EXPORT TopoDS_Shape LastShape() override;

  //! Returns a list of new shapes generated from the shape
  //! S by the shell-generating algorithm.
  //! This function is redefined from BRepOffsetAPI_MakeShape::Generated.
  //! S can be an edge or a vertex of a given Profile (see methods Add).
  Standard_EXPORT const NCollection_List<TopoDS_Shape>& Generated(const TopoDS_Shape& S) override;

  Standard_EXPORT double ErrorOnSurface() const;

  //! Sets the build history flag.
  //! If set to True, the pipe shell will store the history of the sections
  //! and the spine, which can be used for further modifications or analysis.
  inline void SetIsBuildHistory(const bool theIsBuildHistory)
  {
    myPipe->SetIsBuildHistory(theIsBuildHistory);
  }

  //! Returns the build history flag.
  //! If True, the pipe shell stores the history of the sections and the spine.
  inline bool IsBuildHistory() const { return myPipe->IsBuildHistory(); }

  //! Returns the list of original profiles
  void Profiles(NCollection_List<TopoDS_Shape>& theProfiles) { myPipe->Profiles(theProfiles); }

  //! Returns the spine
  const TopoDS_Wire& Spine() { return myPipe->Spine(); }

private:
  occ::handle<BRepFill_PipeShell> myPipe;
};

#endif // _BRepOffsetAPI_MakePipeShell_HeaderFile
