Salome HOME
Merge remote-tracking branch 'origin/BR_1064' into BR_HYDRO_IMPS_2016
[modules/hydro.git] / src / HYDROData / HYDROData_DTM.cxx
index 544dd2e53184269221fe352cacc1f099c5b7fb0f..df831b619a110a4ba5dd9b61549e7c3be98774fd 100644 (file)
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <limits>
 
+#include <BRepLib_MakeEdge.hxx>
+#include <BRepLib_MakeWire.hxx>
+#include <BRep_Builder.hxx>
+#include <GeomProjLib.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <Geom_Plane.hxx>
+#include <BRepTools_WireExplorer.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <TopExp.hxx>
+#include <TopTools_IndexedMapOfOrientedShape.hxx>
+
+#include <BRepLib_MakeEdge.hxx>
+#include <BRepLib_MakeWire.hxx>
+#include <BRep_Builder.hxx>
+#include <ShapeAnalysis_Wire.hxx>
+#include <BRepAlgo_NormalProjection.hxx>
+#include <ShapeUpgrade_UnifySameDomain.hxx>
+#include <BRepBuilderAPI_MakePolygon.hxx>
+#include <BOPAlgo_Builder.hxx>
+
+#include <TopTools_IndexedDataMapOfShapeShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_SequenceOfShape.hxx>
+
 IMPLEMENT_STANDARD_HANDLE( HYDROData_DTM, HYDROData_Bathymetry )
 IMPLEMENT_STANDARD_RTTIEXT( HYDROData_DTM, HYDROData_Bathymetry )
 
-
-HYDROData_DTM::CurveUZ::CurveUZ( double theXCurv, const gp_Vec2d& theProfileDir )
-  : myXcurv( theXCurv ), myProfileDir( theProfileDir )
+HYDROData_DTM::CurveUZ::CurveUZ( double theXCurv, const gp_Vec2d& theProfileDir, double theDeltaZ )
+  : myXcurv( theXCurv ), myProfileDir( theProfileDir ), myDeltaZ( theDeltaZ )
 {
 }
 
@@ -54,10 +78,19 @@ gp_Vec2d HYDROData_DTM::CurveUZ::ProfileDir() const
   return myProfileDir;
 }
 
+double HYDROData_DTM::CurveUZ::DeltaZ() const
+{
+  return myDeltaZ;
+}
+
 HYDROData_DTM::CurveUZ HYDROData_DTM::CurveUZ::operator + ( const CurveUZ& c ) const
 {
-  HYDROData_DTM::CurveUZ res( Xcurv() + c.Xcurv(), ProfileDir() + c.ProfileDir() );
-  size_t n = size();
+  HYDROData_DTM::CurveUZ res( Xcurv() + c.Xcurv(), ProfileDir() + c.ProfileDir(), DeltaZ() + c.DeltaZ() );
+  size_t n = size(), n1 = c.size();
+  if( n!=n1 )
+  {
+    std::cout << "Warning: different number of points in curves: " << n << ", " << n1 << std::endl;
+  }
   res.reserve( n );
   for( int i=0; i<n; i++ )
   {
@@ -71,7 +104,7 @@ HYDROData_DTM::CurveUZ HYDROData_DTM::CurveUZ::operator + ( const CurveUZ& c ) c
 
 HYDROData_DTM::CurveUZ HYDROData_DTM::CurveUZ::operator * ( double d ) const
 {
-  HYDROData_DTM::CurveUZ res( Xcurv()*d, ProfileDir()*d );
+  HYDROData_DTM::CurveUZ res( Xcurv()*d, ProfileDir()*d, DeltaZ()*d );
   size_t n = size();
   res.reserve( n );
   for( int i=0; i<n; i++ )
@@ -84,56 +117,6 @@ HYDROData_DTM::CurveUZ HYDROData_DTM::CurveUZ::operator * ( double d ) const
   return res;
 }
 
-void HYDROData_DTM::Bank::reserve( int theNbPoints )
-{
-  myPoints.reserve( theNbPoints );
-  myDirs.reserve( theNbPoints );
-}
-
-void HYDROData_DTM::Bank::push_back( const gp_Pnt& thePnt, const gp_Dir& theTangent )
-{
-  myPoints.push_back( thePnt );
-  myDirs.push_back( theTangent );
-}
-
-void HYDROData_DTM::Bank::clear()
-{
-  myPoints.clear();
-  myDirs.clear();
-}
-
-TopoDS_Edge HYDROData_DTM::Bank::createEdge3d() const
-{
-  size_t n = myPoints.size();
-  if( n<2 )
-    return TopoDS_Edge();
-
-  Handle_Geom_BSplineCurve aCurve;
-
-  Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt( 1, (int)n );
-  TColgp_Array1OfVec tangents( 1, (int)n );
-  Handle(TColStd_HArray1OfBoolean) flags = new TColStd_HArray1OfBoolean( 1, (int)n );
-
-  for( size_t i = 1; i <= n; i++ )
-  {
-    gp_Pnt aPnt = myPoints[i-1];
-    gp_Vec aVec = myDirs[i-1];
-    points->SetValue( (int)i, aPnt );
-    tangents.SetValue( (int)i, aVec );
-    flags->SetValue( (int)i, Standard_True );
-  }
-
-  GeomAPI_Interpolate anInterpolator( points, Standard_False, Standard_False );
-  anInterpolator.Load( tangents, flags );
-  anInterpolator.Perform();
-  if( anInterpolator.IsDone() )
-  {
-    aCurve = anInterpolator.Curve();
-    return BRepBuilderAPI_MakeEdge( aCurve ).Edge();
-  }
-  else
-    return TopoDS_Edge();
-}
 
 
 
@@ -153,6 +136,7 @@ HYDROData_SequenceOfObjects HYDROData_DTM::GetProfiles() const
 void HYDROData_DTM::SetProfiles( const HYDROData_SequenceOfObjects& theProfiles )
 {
   SetReferenceObjects( theProfiles, DataTag_Profiles );
+  Changed( Geom_3d );
 }
 
 double HYDROData_DTM::GetDDZ() const
@@ -163,6 +147,7 @@ double HYDROData_DTM::GetDDZ() const
 void HYDROData_DTM::SetDDZ( double theDDZ )
 {
   SetDouble( DataTag_DDZ, theDDZ );
+  Changed( Geom_3d );
 }
 
 double HYDROData_DTM::GetSpatialStep() const
@@ -173,40 +158,371 @@ double HYDROData_DTM::GetSpatialStep() const
 void HYDROData_DTM::SetSpatialStep( double theSpatialStep )
 {
   SetDouble( DataTag_SpatialStep, theSpatialStep );
+  Changed( Geom_3d );
 }
 
+void HYDROData_DTM::PointToWire(const AltitudePoints& pnts, TopoDS_Wire& W )
+{
+  /*BRepLib_MakeWire WM;
+  if (pnts.empty())
+    return;
+  for (int i = 0; i < pnts.size() - 1; i++)
+  {
+    gp_Pnt p1(pnts[i].X, pnts[i].Y, pnts[i].Z);
+    gp_Pnt p2(pnts[i+1].X, pnts[i+1].Y, pnts[i+1].Z);    
+    WM.Add(BRepLib_MakeEdge(p1, p2).Edge()); 
+  }
+  if (WM.IsDone())*/
+  
+  BRepBuilderAPI_MakePolygon PM;
+  for (int i = 0; i < pnts.size(); i++)
+    PM.Add(gp_Pnt(pnts[i].X, pnts[i].Y, pnts[i].Z));
+  
+  W = PM.Wire();
+}
+
+TopTools_IndexedMapOfOrientedShape HYDROData_DTM::Create3DShape(const AltitudePoints& left,
+                                                                const AltitudePoints& right,
+                                                                const std::vector<AltitudePoints>& main_profiles)
+{  
+  TopTools_IndexedMapOfOrientedShape ll;
+  TopoDS_Wire LWire, RWire;
+  PointToWire(left, LWire);
+  PointToWire(right, RWire);
+  if (!LWire.IsNull())
+    ll.Add(LWire.Oriented(TopAbs_FORWARD));
+
+  for (int k = 0; k < main_profiles.size(); k++)
+  {
+    TopoDS_Wire W;
+    PointToWire(main_profiles[k], W);
+    TopAbs_Orientation Ori = TopAbs_INTERNAL;
+    if (k == 0 || k == main_profiles.size() - 1)
+      Ori = TopAbs_FORWARD;
+    ll.Add(W.Oriented(Ori));
+  }
+
+  if (!RWire.IsNull())
+    ll.Add(RWire.Oriented(TopAbs_FORWARD)); 
+  //yes, add subshapes in this order (left + profiles + right)
+  //otherwise the projected wire will be non-manifold
+
+  return ll;
+}
+
+
 void HYDROData_DTM::Update()
 {
-  HYDROData_SequenceOfObjects objs = GetProfiles();
-  int aLower = objs.Lower(), anUpper = objs.Upper();
-  size_t n = anUpper-aLower+1;
+  AltitudePoints points;
+  TopoDS_Shape Out3dPres;
+  TopoDS_Shape Out2dPres;
+  TopoDS_Shape OutLeftB;
+  TopoDS_Shape OutRightB;
+  TopoDS_Shape OutInlet;
+  TopoDS_Shape OutOutlet;
+
+  HYDROData_SequenceOfObjects objs = GetProfiles();  
+  double ddz = GetDDZ();
+  double step = GetSpatialStep();
+  std::set<int> InvInd;
+  bool WireIntersections; //__TODO
+  CreateProfilesFromDTM( objs, ddz, step, points, Out3dPres, Out2dPres, OutLeftB, OutRightB, OutInlet, OutOutlet, true, true, InvInd, -1, WireIntersections );
+  SetAltitudePoints( points );  
+
+  SetShape( DataTag_LeftBankShape, OutLeftB);
+  SetShape( DataTag_RightBankShape, OutRightB);
+  SetShape( DataTag_InletShape, OutInlet);
+  SetShape( DataTag_OutletShape, OutOutlet );
+  SetShape( DataTag_3DShape, Out3dPres );
+  SetShape( DataTag_2DShape, Out2dPres );
+
+  HYDROData_Bathymetry::Update();
+}
+
+void HYDROData_DTM::GetPresentationShapes( TopoDS_Shape& Out3dPres,
+                                           TopoDS_Shape& Out2dPres,
+                                           TopoDS_Shape& OutLeftB,
+                                           TopoDS_Shape& OutRightB,
+                                           TopoDS_Shape& OutInlet,
+                                           TopoDS_Shape& OutOutlet )
+{
+  //without update!
+  OutLeftB = GetShape( DataTag_LeftBankShape);
+  OutRightB = GetShape( DataTag_RightBankShape);
+  OutInlet = GetShape( DataTag_InletShape);
+  OutOutlet = GetShape( DataTag_OutletShape );
+  Out3dPres = GetShape( DataTag_3DShape );
+  Out2dPres = GetShape( DataTag_2DShape );
+}
+void HYDROData_DTM::CreateProfilesFromDTM (const HYDROData_SequenceOfObjects& InpProfiles,
+                                           double ddz,
+                                           double step, 
+                                           AltitudePoints& points,
+                                           TopoDS_Shape& Out3dPres,
+                                           TopoDS_Shape& Out2dPres,
+                                           TopoDS_Shape& OutLeftB,
+                                           TopoDS_Shape& OutRightB,
+                                           TopoDS_Shape& OutInlet,
+                                           TopoDS_Shape& OutOutlet,
+                                           bool Create3dPres,
+                                           bool Create2dPres,
+                                           std::set<int>& InvInd,
+                                           int thePntsLimit,
+                                           bool& WireIntersections)
+{
+  int aLower = InpProfiles.Lower(), anUpper = InpProfiles.Upper();
+  size_t n = anUpper - aLower + 1;
 
   std::vector<Handle_HYDROData_Profile> profiles;
-  profiles.reserve( n );
+  profiles.reserve( n ); 
   for( int i=aLower; i<=anUpper; i++ )
   {
-    Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( objs.Value( i ) );
+    Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( InpProfiles.Value( i ) );
     if( !aProfile.IsNull() )
       profiles.push_back( aProfile );
   }
-
-  double ddz = GetDDZ();
-  double step = GetSpatialStep();
   const double EPS = 1E-3;
-  AltitudePoints points;
-  
-  myLeft.clear();
-  myRight.clear();
+  AltitudePoints left;
+  AltitudePoints right;
+  std::vector<AltitudePoints> main_profiles;
+
+  if( thePntsLimit > 0 )
+  {
+    int aNbPoints = EstimateNbPoints( profiles, ddz, step );
+    if( aNbPoints < 0 || aNbPoints > thePntsLimit )
+      return;
+  }
+
   if( ddz>EPS && step>EPS )
-    points = Interpolate( profiles, ddz, step, &myLeft, &myRight );
-  SetAltitudePoints( points );
+    CreateProfiles(profiles, ddz, step, left, right, points, main_profiles, 
+    Out3dPres, Out2dPres, OutLeftB, OutRightB, OutInlet, OutOutlet, Create3dPres, Create2dPres, InvInd, WireIntersections );
 }
 
+void HYDROData_DTM::ProjWireOnPlane(const TopoDS_Shape& inpWire, const Handle_Geom_Plane& RefPlane, 
+  TopTools_DataMapOfShapeListOfShape* E2PE)
+{
+  BRep_Builder BB;
+
+  //project shape (edges) on planar face
+  TopoDS_Face F;
+  BB.MakeFace(F, RefPlane, Precision::Confusion());
+  BRepAlgo_NormalProjection nproj(F);
+  nproj.Add(inpWire);
+  nproj.SetDefaultParams();
+  nproj.Build();
+  if(!nproj.IsDone())
+    return;
 
+  TopoDS_Shape projRes = nproj.Projection();
 
+  // unite all vertexes/edges from projected result
+  BOPAlgo_Builder anAlgo;
+  TopExp_Explorer exp(projRes, TopAbs_EDGE);
+  for (;exp.More(); exp.Next())
+  {
+    const TopoDS_Edge& E = TopoDS::Edge(exp.Current());
+    if (E.Orientation() != TopAbs_INTERNAL)
+      anAlgo.AddArgument(E);
+  }
+  anAlgo.Perform(); 
+  int stat = anAlgo.ErrorStatus();
+  TopoDS_Shape projResConn = anAlgo.Shape();
+
+  // make wire => vertexes and edges should be untouched after this operation!
+  exp.Init(projResConn, TopAbs_EDGE);
+  //TopTools_ListOfShape llE;
+  //TopoDS_Wire RW;
+  //BRepLib_MakeWire WM;
+
+  //for (;exp.More();exp.Next()) 
+  //  llE.Append(exp.Current());
+  //
+  //WM.Add(llE);
+  //outWire = WM.Wire();
+
+  //outWire.Orientation(inpWire.Orientation()); //take from the original wire
+
+  //history mode: edge to projected edges
+  if (E2PE)
+  {
+    TopExp_Explorer ex(inpWire, TopAbs_EDGE);
+    for (;ex.More();ex.Next())
+    {
+      const TopoDS_Edge& CE = TopoDS::Edge(ex.Current());
+      TopTools_ListOfShape NEL;
+      const TopTools_ListOfShape& LS = nproj.Generated(CE);
+      TopTools_ListIteratorOfListOfShape it(LS);
+      for (;it.More();it.Next())
+      {
+        const TopoDS_Shape& PCE = it.Value();
+        TopTools_ListOfShape PLS = anAlgo.Modified(PCE);
+        if (PLS.IsEmpty())
+          PLS.Append(PCE);
+        TopTools_ListIteratorOfListOfShape itp(PLS);
+        for (;itp.More();itp.Next())
+          NEL.Append(itp.Value());
+      }
+
+      E2PE->Bind(CE, NEL);
+    }
+  }
+}
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+bool HYDROData_DTM::Get2dFaceFrom3dPres(const TopoDS_Compound& cmp, TopoDS_Face& outF,
+  TopTools_SequenceOfShape* Boundr, std::set<int> ind )
+{
+  //ind : set of indices (starts with 0). index == number of boundary (inlet, outlet, etc..)
+  //in compound cmp. 
+  //if Boundr is not null => this method will return sequence of boundary wires (inlet, outlet...)
+
+  Handle_Geom_Plane refpl = new Geom_Plane(gp_Pnt(0,0,0), gp_Dir(0,0,1));
+  TopTools_DataMapOfShapeListOfShape E2PE;
+  ProjWireOnPlane(cmp, refpl, &E2PE);
+  TopTools_ListOfShape ELL;
+
+  TopoDS_Iterator it(cmp);
+  int i = 0;
+  for (;it.More(); it.Next())
+  {
+    const TopoDS_Wire& W = TopoDS::Wire(it.Value());
+    if (W.Orientation() != TopAbs_INTERNAL)
+    {
+      TopoDS_Wire PW;
+      TopExp_Explorer ex(W, TopAbs_EDGE);   
+      TopTools_ListOfShape LEpW;
+      TopTools_ListOfShape LEpWDummy;
+      for (;ex.More();ex.Next())
+      {
+        const TopoDS_Edge& CE = TopoDS::Edge(ex.Current());
+        TopTools_ListOfShape LS = E2PE.Find(CE);
+        LEpW.Append(LS);
+      }
+      
+      if (ind.count(i) != 0)
+      {
+        BRepLib_MakeWire WM;
+        WM.Add(LEpW);
+        const TopoDS_Wire& WMW = WM.Wire();
+        //assume that wire is a straight line,
+        //take first and last vertex and make simple edge (RE)
+        TopoDS_Vertex VF, VL;
+        TopExp::Vertices(WMW, VF, VL);
+        TopoDS_Edge RE = BRepLib_MakeEdge(VF, VL).Edge();
+        if (RE.IsNull())
+        {
+          LEpWDummy = LEpW; //LEpW will be nullified after appending to ELL
+          ELL.Append(LEpW);
+        }
+        else
+        {
+          LEpWDummy.Append(RE); 
+          ELL.Append(RE);
+        }
+        //TODO: in the new version of OCCT, USD can process separate wires
+        //ShapeUpgrade_UnifySameDomain USD(WMW, 1U, 0U, 1U); //concat bsplines
+        //USD.Build();
+        //const TopoDS_Shape& RSU = USD.Shape();
+        //TopExp_Explorer exp(RSU, TopAbs_EDGE);
+        //TopTools_ListOfShape DummyL;
+        //for (;it.More();it.Next())
+        //  DummyL.Append(it.Value());
+        //if (DummyL.Extent() == 1)
+        //  ELL.Append(DummyL.First()); //if one edge => accept this result 
+        //else
+        //  ELL.Append(LEpW);  //else put 'as is'
+      }
+      else
+      {
+        LEpWDummy = LEpW;
+        ELL.Append(LEpW);
+      }
+
+      if (Boundr)
+      {
+        //make inlet, outlet, left/tight banks [wires]
+        //shouldn't change topology of the edges
+        BRepLib_MakeWire IWM;
+        IWM.Add(LEpWDummy);
+        Boundr->Append(IWM.Wire());
+      }
+    }
+    i++;
+  }
+
+  //make primary wire
+  BRepLib_MakeWire WME;
+  WME.Add(ELL);
 
+  const TopoDS_Wire& resW = WME.Wire();
+  BRepBuilderAPI_MakeFace mf(refpl, resW, true); //check inside is true by def
+  outF = mf.Face();
 
+  ShapeAnalysis_Wire WA(resW, outF, Precision::Confusion());
+  bool res = WA.CheckSelfIntersection(); //TODO check that this return false if OK
+  return res;
 
+  ///!!! the internal wires cant be added with 'internal' ori.
+  // it's possible to do with brep builder yet the result will not be correct!
+  // more proper way is to use BOP operation here.
+  /*for (int i = 1; i <= IntW.Extent(); i++)
+  {
+  TopoDS_Wire outIW;
+  const TopoDS_Wire& W = TopoDS::Wire(IntW(i));
+  ProjWireOnPlane(W, refpl, outIW);
+  BB.Add(outF, outIW);
+  }*/
+}
+
+void HYDROData_DTM::CreateProfiles(const std::vector<Handle_HYDROData_Profile>& theProfiles,
+                                   double theDDZ,
+                                   double theSpatialStep,
+                                   AltitudePoints& theOutLeft,
+                                   AltitudePoints& theOutRight,
+                                   AltitudePoints& theOutPoints,
+                                   std::vector<AltitudePoints>& theOutMainProfiles,
+                                   TopoDS_Shape& Out3dPres,
+                                   TopoDS_Shape& Out2dPres,
+                                   TopoDS_Shape& OutLeftB,
+                                   TopoDS_Shape& OutRightB,
+                                   TopoDS_Shape& OutInlet,
+                                   TopoDS_Shape& OutOutlet,
+                                   bool Create3dPres,
+                                   bool Create2dPres,
+                                   std::set<int>& InvInd,
+                                   bool& WireIntersections)
+{
+  if (theProfiles.empty())
+    return;
+  theOutPoints = Interpolate( theProfiles, theDDZ, theSpatialStep, theOutLeft, theOutRight, theOutMainProfiles, InvInd );
+  //note that if Create3dPres is false => Create2dPres flag is meaningless!
+  if (Create3dPres)
+  {
+    TopTools_IndexedMapOfOrientedShape ll = Create3DShape( theOutLeft, theOutRight, theOutMainProfiles);
+    
+    if (ll.IsEmpty())
+      return;
+    BRep_Builder BB;
+    TopoDS_Compound cmp;
+    BB.MakeCompound(cmp);
+    for (int i = 1; i <= ll.Extent(); i++)
+      BB.Add(cmp, ll(i));
+
+    Out3dPres = cmp;
+
+    //same order as in HYDROData_DTM::Update()
+    OutLeftB = ll(1);
+    OutRightB = ll(ll.Extent());
+    OutInlet = ll(2);
+    OutOutlet = ll(ll.Extent() - 1);
+
+    if (Create2dPres)
+    {
+      TopoDS_Face outF;
+      WireIntersections = Get2dFaceFrom3dPres(cmp, outF); //__TODO
+      Out2dPres = outF;
+    };
+  }
+}
 
 
 
@@ -366,7 +682,7 @@ std::vector<Handle_Geom2d_Curve> HYDROData_DTM::ProfileToParametric(
   GetProperties( theProfile, aLowest, theDir, false, zmin, zmax );
 
   gp_Ax3 aStd3d( gp_Pnt( 0, 0, 0 ), gp_Dir( 0, 0, 1 ), gp_Dir( 1, 0, 0 ) );
-  gp_Ax3 aLocal( aLowest, gp_Dir( 0, 0, 1 ), gp_Dir( theDir.X(), theDir.Y(), 0 ) );
+  gp_Ax3 aLocal( gp_Pnt( aLowest.X(), aLowest.Y(), 0 ), gp_Dir( 0, 0, 1 ), gp_Dir( theDir.X(), theDir.Y(), 0 ) );
 
   gp_Trsf aTransf;
   aTransf.SetTransformation( aStd3d, aLocal );
@@ -393,18 +709,19 @@ std::vector<Handle_Geom2d_Curve> HYDROData_DTM::ProfileToParametric(
 }
 
 
-bool CalcMidWidth( const std::vector<gp_Pnt2d>& intersections, double& theMid, double& theWid )
+bool CalcMidWidth( const std::set<double>& intersections, double& theMid, double& theWid )
 {
   double umin = std::numeric_limits<double>::max(),
          umax = -umin;
 
   size_t n = intersections.size();
-  if( n <= 1 )
+  if( n <= 0 )
     return false;
 
-  for( size_t i = 0; i < n; i++ )
+  std::set<double>::const_iterator it = intersections.begin(), last = intersections.end();
+  for( ; it!=last; it++ )
   {
-    double u = intersections[i].X();
+    double u = *it;
     if( u<umin )
       umin = u;
     if( u>umax )
@@ -418,8 +735,9 @@ bool CalcMidWidth( const std::vector<gp_Pnt2d>& intersections, double& theMid, d
 void HYDROData_DTM::ProfileDiscretization( const Handle_HYDROData_Profile& theProfile, 
                                            double theXCurv, double theMinZ, double theMaxZ, double theDDZ,
                                            CurveUZ& theMidPointCurve,
-                                           CurveUZ& theWidthCurve,
-                                           double theTolerance )
+                                           CurveUZ& theWidthCurve,                                           
+                                           int& intersection_nb,
+                                           double theTolerance)
 {
   double aDblMax = std::numeric_limits<double>::max(),
          aUMin = aDblMax,
@@ -447,31 +765,33 @@ void HYDROData_DTM::ProfileDiscretization( const Handle_HYDROData_Profile& thePr
   curves.push_back( aT2 );
   
   int psize = ( int )( ( theMaxZ-theMinZ ) / theDDZ + 1 );
-  theMidPointCurve = CurveUZ( theXCurv, aProfileDir );
+  theMidPointCurve = CurveUZ( theXCurv, aProfileDir, theMinZ );
   theMidPointCurve.reserve( psize );
-  theWidthCurve = CurveUZ( theXCurv, aProfileDir );
+  theWidthCurve = CurveUZ( theXCurv, aProfileDir, theMinZ );
   theWidthCurve.reserve( psize );
 
   n = curves.size();
   // for each discrete value of z we search intersection with profile
-  for( double z = theMinZ; z <= theMaxZ; z += theDDZ )
+  for( double z1 = theMinZ; z1 <= theMaxZ; z1 += theDDZ )
   {
-    Handle(Geom2d_Line) aLine = new Geom2d_Line( gp_Pnt2d( 0, z ), gp_Dir2d( 1, 0 ) );
-    std::vector<gp_Pnt2d> intersections;
+    Handle(Geom2d_Line) aLine = new Geom2d_Line( gp_Pnt2d( 0, z1 ), gp_Dir2d( 1, 0 ) );
+    std::set<double> intersections;
     for( size_t i = 0; i < n; i++ )
     {
       Handle_Geom2d_Curve aCurve = curves[i];
       Geom2dAPI_InterCurveCurve anIntersect( aCurve, aLine, theTolerance );
       for( int k=1, m=anIntersect.NbPoints(); k<=m; k++ )
-        intersections.push_back( anIntersect.Point( k ) );
+        intersections.insert( anIntersect.Point( k ).X() );
     }
 
-    if( intersections.size() >= 2 )
+    intersection_nb = intersections.size();
+    if( intersection_nb >= 1 )
     {
       double u_mid, u_wid;
       if( !CalcMidWidth( intersections, u_mid, u_wid ) )
         continue;
 
+      double z = z1 - theMinZ;
       PointUZ p_mid;
       p_mid.U = u_mid;
       p_mid.Z = z;
@@ -506,8 +826,7 @@ void HYDROData_DTM::Interpolate( const CurveUZ& theCurveA, const CurveUZ& theCur
 #include <BRepLib_MakeEdge2d.hxx>
 void HYDROData_DTM::CurveTo3D( const Handle_Geom2d_BSplineCurve& theHydraulicAxis,
                                const CurveUZ& theMidCurve, const CurveUZ& theWidthCurve,
-                               AltitudePoints& thePoints,
-                               Bank* theLeft, Bank* theRight, double dz )
+                               AltitudePoints& thePoints )
 {
   Geom2dAdaptor_Curve anAdaptor( theHydraulicAxis );
   TopoDS_Edge E2d = BRepLib_MakeEdge2d(theHydraulicAxis).Edge();
@@ -517,13 +836,11 @@ void HYDROData_DTM::CurveTo3D( const Handle_Geom2d_BSplineCurve& theHydraulicAxi
   gp_Pnt2d point;
   anAdaptor.D0( aParam, point );
   gp_Vec2d profile_dir = theMidCurve.ProfileDir();
-  gp_Dir tangent_n( -profile_dir.Y(), profile_dir.X(), dz );
+  //gp_Dir tangent_n( -profile_dir.Y(), profile_dir.X(), dz );
   profile_dir.Normalize();
   
   size_t n = theMidCurve.size();
-  double min_param = 1E+15;
-  double max_param = -1E+15;
-  double z1, z2;
+  std::map<double, AltitudePoint> sorted_points;
   for( size_t i=0; i<n; i++ )
   {
     double param1 = theMidCurve[i].U - theWidthCurve[i].U / 2;
@@ -532,46 +849,20 @@ void HYDROData_DTM::CurveTo3D( const Handle_Geom2d_BSplineCurve& theHydraulicAxi
     gp_Pnt2d p1 = point.Translated( param1 * profile_dir);
     gp_Pnt2d p2 = point.Translated( param2 * profile_dir);
 
-    double z = theMidCurve[i].Z;
-
-    if( param1 < min_param )
-    {
-      min_param = param1;
-      z1 = z;
-    }
-    if( param2 < min_param )
-    {
-      min_param = param2;
-      z1 = z;
-    }
-    if( param1 > max_param )
-    {
-      max_param = param1;
-      z2 = z;
-    }
-    if( param2 > max_param )
-    {
-      max_param = param2;
-      z2 = z;
-    }
+    double z = theMidCurve[i].Z + theMidCurve.DeltaZ();
 
     AltitudePoint p3d_1( p1.X(), p1.Y(), z ), p3d_2( p2.X(), p2.Y(), z );
-    thePoints.push_back( p3d_1 );
-    thePoints.push_back( p3d_2 );
-  }
 
-  if( theLeft )
-  {
-    gp_Pnt2d left2d = point.Translated( min_param * profile_dir );
-    gp_Pnt left( left2d.X(), left2d.Y(), z1 );
-    theLeft->push_back( left, tangent_n );
-  }
-  if( theRight )
-  {
-    gp_Pnt2d right2d = point.Translated( max_param * profile_dir );
-    gp_Pnt right( right2d.X(), right2d.Y(), z2 );
-    theRight->push_back( right, tangent_n );
+    sorted_points[param1] = p3d_1;
+    sorted_points[param2] = p3d_2;
   }
+
+  thePoints.reserve( sorted_points.size() );
+  const double EPS = 1E-12;
+  std::map<double, AltitudePoint>::const_iterator it = sorted_points.begin(), last = sorted_points.end();
+  for( ; it!=last; it++ )
+    if( thePoints.empty() || thePoints.back().SquareDistance( it->second ) > EPS )
+      thePoints.push_back( it->second );
 }
 
 inline double max( double a, double b )
@@ -582,16 +873,24 @@ inline double max( double a, double b )
     return b;
 }
 
+inline double min( double a, double b )
+{
+  if( a<b )
+    return a;
+  else
+    return b;
+}
+
 #include <BRepLib_MakeWire.hxx>
 
-HYDROData_Bathymetry::AltitudePoints HYDROData_DTM::Interpolate
+std::vector<HYDROData_Bathymetry::AltitudePoints> HYDROData_DTM::Interpolate
   ( const Handle_Geom2d_BSplineCurve& theHydraulicAxis,
     const Handle_HYDROData_Profile& theProfileA,
     double theXCurvA,
     const Handle_HYDROData_Profile& theProfileB,
     double theXCurvB,
     double theDDZ, int theNbSteps, bool isAddSecond,
-    Bank* theLeft, Bank* theRight )
+    int& inter_nb_1, int& inter_nb_2)
 {
   double zminA, zmaxA, zminB, zmaxB;
   gp_Pnt lowestA, lowestB;
@@ -600,16 +899,18 @@ HYDROData_Bathymetry::AltitudePoints HYDROData_DTM::Interpolate
   GetProperties( theProfileA, lowestA, dirA, false, zminA, zmaxA ); 
   GetProperties( theProfileB, lowestB, dirB, false, zminB, zmaxB ); 
 
-  double dz = zminB - zminA;
+  
+  double hmax = max( zmaxA-zminA, zmaxB-zminB );
 
-  double zmin = max( zminA, zminB );
-  double zmax = max( zmaxA, zmaxB );
+  //double dz = zminB - zminA;
+  //double zmin = min( zminA, zminB );
+  //double zmax = max( zmaxA, zmaxB );
 
-  CurveUZ midA(0, gp_Vec2d()), midB(0, gp_Vec2d());
-  CurveUZ widA(0, gp_Vec2d()), widB(0, gp_Vec2d());
+  CurveUZ midA(0, gp_Vec2d(), 0), midB(0, gp_Vec2d(), 0);
+  CurveUZ widA(0, gp_Vec2d(), 0), widB(0, gp_Vec2d(), 0);
 
-  ProfileDiscretization( theProfileA, theXCurvA, zmin, zmax, theDDZ, midA, widA ); 
-  ProfileDiscretization( theProfileB, theXCurvB, zmin, zmax, theDDZ, midB, widB );
+  ProfileDiscretization( theProfileA, theXCurvA, zminA, zminA+hmax, theDDZ, midA, widA, inter_nb_1 ); 
+  ProfileDiscretization( theProfileB, theXCurvB, zminB, zminB+hmax, theDDZ, midB, widB, inter_nb_2 );
 
   std::vector<CurveUZ> mid, wid;
   Interpolate( midA, midB, theNbSteps, mid, isAddSecond );
@@ -617,23 +918,25 @@ HYDROData_Bathymetry::AltitudePoints HYDROData_DTM::Interpolate
 
   size_t p = mid.size();
   size_t q = p>0 ? 2*mid[0].size() : 1;
-  AltitudePoints points;
-  points.reserve( p*q );
+  std::vector<AltitudePoints> points;
+  points.resize( p );
+
   for( size_t i=0; i<p; i++ )
-    CurveTo3D( theHydraulicAxis, mid[i], wid[i], points, theLeft, theRight, dz );
+  {
+    points[i].reserve( q );
+    CurveTo3D( theHydraulicAxis, mid[i], wid[i], points[i] );
+  }
 
-  BRepLib_MakeWire WM;
-  for (int i =0; i < theLeft->myPoints.size() - 1; i++)
-    WM.Add(BRepLib_MakeEdge(theLeft->myPoints[i], theLeft->myPoints[i+1]).Edge()); 
-  TopoDS_Wire W = WM.Wire();
   return points;
 }
 
 HYDROData_Bathymetry::AltitudePoints HYDROData_DTM::Interpolate
   ( const std::vector<Handle_HYDROData_Profile>& theProfiles,
     double theDDZ, double theSpatialStep,
-    Bank* theLeft,
-    Bank* theRight )
+    AltitudePoints& theLeft,
+    AltitudePoints& theRight,
+    std::vector<AltitudePoints>& theMainProfiles,
+    std::set<int>& invalInd)
 {
   AltitudePoints points;
   size_t n = theProfiles.size();
@@ -645,37 +948,81 @@ HYDROData_Bathymetry::AltitudePoints HYDROData_DTM::Interpolate
   if( aHydraulicAxis.IsNull() )
     return points;
 
-  int aNbStepsComplete = 0;
-  for( size_t i=0, n1=n-1; i<n1; i++ )
-  {
-    double aDistance = distances[i+1]-distances[i];
-    aNbStepsComplete += ( int(aDistance/theSpatialStep) /*+ 1*/ );
-  }
-  if( theLeft )
-    theLeft->reserve( aNbStepsComplete );
-  if( theRight )
-    theRight->reserve( aNbStepsComplete );
-  
+  theMainProfiles.reserve( n );
+
   for( size_t i=0, n1=n-1; i<n1; i++ )
   {
     double aDistance = distances[i+1]-distances[i];
-    int aNbSteps = int(aDistance/theSpatialStep) /*+ 1*/;
+    int aNbSteps = int(aDistance/theSpatialStep);
     bool isAddSecond = i==n1-1;
 
-    AltitudePoints local_points = Interpolate( aHydraulicAxis, theProfiles[i], distances[i], 
-      theProfiles[i+1], distances[i+1], theDDZ, aNbSteps, isAddSecond, theLeft, theRight );
+    // 1. Calculate interpolated profiles
+    int inter_nb_1, inter_nb_2;
+    std::vector<AltitudePoints> local_points = Interpolate( aHydraulicAxis, theProfiles[i], distances[i], 
+      theProfiles[i+1], distances[i+1], theDDZ, aNbSteps, isAddSecond, inter_nb_1, inter_nb_2 );
+    int lps = local_points.size();
+
+    if (inter_nb_1 > 2)
+      invalInd.insert(i);
 
+    if (inter_nb_2 > 2)
+      invalInd.insert(i+1);
+
+    // 2. Put all points into the global container
+    for( size_t j=0; j<lps; j++ )
+    {
+      const AltitudePoints& lp = local_points[j];
+      if( i==0 && j==0 )
+        points.reserve( lp.size() * n );
+      for( size_t k=0, ks=lp.size(); k<ks; k++ )
+        points.push_back( lp[k] );
+    }
+
+    // 3. Get left/right banks' points
     if( i==0 )
-      points.reserve( local_points.size() * ( n-1 ) );
+    {
+      theLeft.reserve( lps * n );
+      theRight.reserve( lps * n );
+    }
+    for( size_t j=0; j<lps; j++ )
+    {
+      const AltitudePoints& lp = local_points[j];
+      theLeft.push_back( lp[0] );
+      theRight.push_back( lp[lp.size()-1] );
+    }
 
-    for( size_t j=0, m=local_points.size(); j<m; j++ )
-      points.push_back( local_points[j] );
+    // 4. Get main profiles points
+    theMainProfiles.push_back( local_points[0] );
+    if( isAddSecond )
+      theMainProfiles.push_back( local_points[lps-1] );
   }
   return points;
 }
 
-void HYDROData_DTM::CreateBankShapes( TopoDS_Edge& theLeft, TopoDS_Edge& theRight ) const
+int HYDROData_DTM::EstimateNbPoints( const std::vector<Handle_HYDROData_Profile>& theProfiles,
+                                     double theDDZ, double theSpatialStep )
 {
-  theLeft = myLeft.createEdge3d();
-  theRight = myRight.createEdge3d();
+  size_t n = theProfiles.size();
+  if( n<=1 )
+    return 0;
+  if( theDDZ<1E-6 || theSpatialStep<1E-6 )
+    return 1 << 20;
+
+  std::vector<double> distances;
+  Handle_Geom2d_BSplineCurve aHydraulicAxis = CreateHydraulicAxis( theProfiles, distances );
+  if( aHydraulicAxis.IsNull() )
+    return 0;
+
+  double aCompleteDistance = distances[n-1];
+  int aNbSteps = int( aCompleteDistance / theSpatialStep ) + 1;
+  gp_Pnt aLowest;
+  gp_Vec2d aDir;
+  double aZMin, aZMax;
+  GetProperties( theProfiles[0], aLowest, aDir, true, aZMin, aZMax );
+  int aNbZSteps = (aZMax-aZMin)/theDDZ;
+
+  if( aNbSteps > ( 1<<16 ) || aNbZSteps > ( 1<<16 ) )
+    return 1 << 20;
+
+  return aNbSteps * aNbZSteps;
 }