// Created on: 1998-07-14
// Created by: data exchange team
// 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 _ShapeConstruct_ProjectCurveOnSurface_HeaderFile
#define _ShapeConstruct_ProjectCurveOnSurface_HeaderFile

#include <Standard.hxx>
#include <Standard_Type.hxx>

#include <Standard_Integer.hxx>
#include <gp_Pnt.hxx>
#include <gp_Pnt2d.hxx>
#include <Standard_Transient.hxx>
#include <ShapeExtend_Status.hxx>
#include <GeomAbs_Shape.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColgp_HArray1OfPnt2d.hxx>
#include <TColgp_HArray1OfPnt.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TColgp_SequenceOfPnt2d.hxx>
#include <TColStd_SequenceOfReal.hxx>
class ShapeAnalysis_Surface;
class Geom_Surface;
class Geom_Curve;
class Geom2d_Curve;

// resolve name collisions with X11 headers
#ifdef Status
  #undef Status
#endif

class ShapeConstruct_ProjectCurveOnSurface;
DEFINE_STANDARD_HANDLE(ShapeConstruct_ProjectCurveOnSurface, Standard_Transient)

//! This tool provides a method for computing pcurve by projecting
//! 3d curve onto a surface.
//! Projection is done by 23 or more points (this number is changed
//! for B-Splines according to the following rule:
//! the total number of the points is not less than number of spans *
//! (degree + 1);
//! it is increased recursively starting with 23 and is added with 22
//! until the condition is fulfilled).
//! Isoparametric cases (if curve corresponds to U=const or V=const on
//! the surface) are recognized with the given precision.
class ShapeConstruct_ProjectCurveOnSurface : public Standard_Transient
{

public:
  //! Empty constructor.
  Standard_EXPORT ShapeConstruct_ProjectCurveOnSurface();

  //! Initializes the object with all necessary parameters,
  //! i.e. surface and precision
  Standard_EXPORT virtual void Init(const Handle(Geom_Surface)& surf, const Standard_Real preci);

  //! Initializes the object with all necessary parameters,
  //! i.e. surface and precision
  Standard_EXPORT virtual void Init(const Handle(ShapeAnalysis_Surface)& surf,
                                    const Standard_Real                  preci);

  //! Loads a surface (in the form of Geom_Surface) to project on
  Standard_EXPORT void SetSurface(const Handle(Geom_Surface)& surf);

  //! Loads a surface (in the form of ShapeAnalysis_Surface) to project on
  Standard_EXPORT void SetSurface(const Handle(ShapeAnalysis_Surface)& surf);

  //! Sets value for current precision
  Standard_EXPORT void SetPrecision(const Standard_Real preci);

  //! Returns (modifiable) the build-curve-3d mode, by default False
  //! If True, if the projected curve has been recomputed by
  //! interpolation, the 3d curve is also rebuild by interpolation
  Standard_EXPORT Standard_Boolean& BuildCurveMode();

  //! Returns (modifiable) the flag specifying to which side of
  //! parametrical space adjust part of pcurve which lies on seam.
  //! This is required in very rare case when 3d curve which is
  //! to be projected goes partly along the seam on the closed
  //! surface with singularity (e.g. sphere), goes through the
  //! degenerated point and paerly lies on internal area of surface.
  //!
  //! If this flag is True, the seam part of such curve will be
  //! adjusted to the left side of parametric space (on sphere U=0),
  //! else to the right side (on sphere U=2*PI)
  //! Default value is True
  Standard_EXPORT Standard_Integer& AdjustOverDegenMode();

  //! Returns the status of last Perform
  Standard_EXPORT Standard_Boolean Status(const ShapeExtend_Status theStatus) const;

  //! Computes the projection of 3d curve onto a surface using the
  //! specialized algorithm. Returns False if projector fails,
  //! otherwise, if pcurve computed successfully, returns True.
  //! The output curve 2D is guaranteed to be same-parameter
  //! with input curve 3D on the interval [First, Last]. If the output curve
  //! lies on a direct line the infinite line is returned, in the case
  //! same-parameter condition is satisfied.
  //! TolFirst and TolLast are the tolerances at the ends of input curve 3D.
  Standard_EXPORT virtual Standard_Boolean Perform(Handle(Geom_Curve)&   c3d,
                                                   const Standard_Real   First,
                                                   const Standard_Real   Last,
                                                   Handle(Geom2d_Curve)& c2d,
                                                   const Standard_Real   TolFirst = -1,
                                                   const Standard_Real   TolLast  = -1);

  //! Computes the projection of 3d curve onto a surface using the
  //! standard algorithm from ProjLib. Returns False if standard
  //! projector fails or raises an exception or cuts the curve by
  //! parametrical bounds of the surface. Else, if pcurve computed
  //! successfully, returns True.
  //! The continuity, maxdeg and nbinterval are parameters of call
  //! to Approx_CurveOnSurface. If nbinterval is equal to -1
  //! (default), this value is computed depending on source 3d curve
  //! and surface.
  Standard_EXPORT Standard_Boolean PerformByProjLib(Handle(Geom_Curve)&    c3d,
                                                    const Standard_Real    First,
                                                    const Standard_Real    Last,
                                                    Handle(Geom2d_Curve)&  c2d,
                                                    const GeomAbs_Shape    continuity = GeomAbs_C1,
                                                    const Standard_Integer maxdeg     = 12,
                                                    const Standard_Integer nbinterval = -1);

  DEFINE_STANDARD_RTTIEXT(ShapeConstruct_ProjectCurveOnSurface, Standard_Transient)

protected:
  //! Try to approximate 3D curve by Geom2d_Line
  //! or Geom2d_BsplineCurve with degree 1 with specified tolerance.
  //! points - points obtained from 3d curve.
  //! params - parameters corresponding points on 3d curves
  //! points2d - 2d points lies on line in parametric space
  //! theTol - tolerance used for compare initial points 3d and
  //! 3d points obtained from line lying in parameric space of surface
  Standard_EXPORT Handle(Geom2d_Curve) getLine(const TColgp_SequenceOfPnt&   points,
                                               const TColStd_SequenceOfReal& params,
                                               TColgp_SequenceOfPnt2d&       points2d,
                                               const Standard_Real           theTol,
                                               Standard_Boolean&             IsRecompute,
                                               Standard_Boolean&             isFromCashe) const;

  Handle(ShapeAnalysis_Surface) mySurf;
  Standard_Real                 myPreci;
  Standard_Boolean              myBuild;
  Standard_Integer              myStatus;
  Standard_Integer              myAdjustOverDegen;
  Standard_Integer              myNbCashe;
  gp_Pnt                        myCashe3d[2];
  gp_Pnt2d                      myCashe2d[2];

private:
  Standard_EXPORT Handle(Geom2d_Curve) ProjectAnalytic(const Handle(Geom_Curve)& c3d) const;

  Standard_EXPORT Standard_Boolean ApproxPCurve(const Standard_Integer    nbrPnt,
                                                const Handle(Geom_Curve)& c3d,
                                                const Standard_Real       TolFirst,
                                                const Standard_Real       TolLast,
                                                TColgp_SequenceOfPnt&     points,
                                                TColStd_SequenceOfReal&   params,
                                                TColgp_SequenceOfPnt2d&   points2d,
                                                Handle(Geom2d_Curve)&     c2d);

  Standard_EXPORT void CorrectExtremity(const Handle(Geom_Curve)&     theC3d,
                                        const TColStd_SequenceOfReal& theParams,
                                        TColgp_SequenceOfPnt2d&       thePnt2d,
                                        const Standard_Boolean        theIsFirstPoint,
                                        const gp_Pnt2d&               thePointOnIsoLine,
                                        const Standard_Boolean        theIsUiso);

  Standard_EXPORT void InsertAdditionalPointOrAdjust(Standard_Boolean&         ToAdjust,
                                                     const Standard_Integer    theIndCoord,
                                                     const Standard_Real       Period,
                                                     const Standard_Real       TolOnPeriod,
                                                     Standard_Real&            CurCoord,
                                                     const Standard_Real       prevCoord,
                                                     const Handle(Geom_Curve)& c3d,
                                                     Standard_Integer&         theIndex,
                                                     TColgp_SequenceOfPnt&     points,
                                                     TColStd_SequenceOfReal&   params,
                                                     TColgp_SequenceOfPnt2d&   pnt2d);

  Standard_EXPORT Handle(Geom2d_Curve) InterpolatePCurve(const Standard_Integer         nbrPnt,
                                                         Handle(TColgp_HArray1OfPnt2d)& points2d,
                                                         Handle(TColStd_HArray1OfReal)& params,
                                                         const Handle(Geom_Curve)&      orig) const;

  Standard_EXPORT Handle(Geom2d_Curve) ApproximatePCurve(const Standard_Integer         nbrPnt,
                                                         Handle(TColgp_HArray1OfPnt2d)& points2d,
                                                         Handle(TColStd_HArray1OfReal)& params,
                                                         const Handle(Geom_Curve)&      orig) const;

  Standard_EXPORT Handle(Geom_Curve) InterpolateCurve3d(const Standard_Integer         nbrPnt,
                                                        Handle(TColgp_HArray1OfPnt)&   points,
                                                        Handle(TColStd_HArray1OfReal)& params,
                                                        const Handle(Geom_Curve)&      orig) const;

  Standard_EXPORT void CheckPoints(Handle(TColgp_HArray1OfPnt)&   points,
                                   Handle(TColStd_HArray1OfReal)& params,
                                   Standard_Real&                 preci) const;

  Standard_EXPORT void CheckPoints2d(Handle(TColgp_HArray1OfPnt2d)& points,
                                     Handle(TColStd_HArray1OfReal)& params,
                                     Standard_Real&                 preci) const;

  Standard_EXPORT Standard_Boolean IsAnIsoparametric(const Standard_Integer        nbrPnt,
                                                     const TColgp_SequenceOfPnt&   points,
                                                     const TColStd_SequenceOfReal& params,
                                                     Standard_Boolean&             isoTypeU,
                                                     Standard_Boolean&             p1OnIso,
                                                     gp_Pnt2d&                     valueP1,
                                                     Standard_Boolean&             p2OnIso,
                                                     gp_Pnt2d&                     valueP2,
                                                     Standard_Boolean&             isoPar2d3d,
                                                     Handle(Geom_Curve)&           cIso,
                                                     Standard_Real&                t1,
                                                     Standard_Real&                t2,
                                                     TColStd_Array1OfReal&         pout) const;
};

#endif // _ShapeConstruct_ProjectCurveOnSurface_HeaderFile
