Salome HOME
fix test on stream linear interpolation
[modules/hydro.git] / src / HYDROData / HYDROData_DTM.cxx
1
2 #include <HYDROData_DTM.h>
3 #include <HYDROData_Profile.h>
4
5 #include <Geom2d_BSplineCurve.hxx>
6 #include <Geom2dAPI_Interpolate.hxx>
7 #include <TColgp_HArray1OfPnt2d.hxx>
8 #include <TColgp_Array1OfVec2d.hxx>
9 #include <TColStd_HArray1OfBoolean.hxx>
10 #include <TopoDS.hxx>
11 #include <TopoDS_Edge.hxx>
12 #include <TopoDS_Wire.hxx>
13 #include <TopExp_Explorer.hxx>
14 #include <BRep_Tool.hxx>
15 #include <gp_Ax3.hxx>
16 #include <Geom_Line.hxx>
17 #include <Geom2d_Line.hxx>
18 #include <Geom2d_TrimmedCurve.hxx>
19 #include <Geom_BSplineCurve.hxx>
20 #include <Geom2d_BSplineCurve.hxx>
21 #include <GeomAPI_Interpolate.hxx>
22 #include <TColStd_Array1OfReal.hxx>
23 #include <TColStd_Array1OfInteger.hxx>
24 #include <TColgp_Array1OfPnt.hxx>
25 #include <TColgp_Array1OfVec.hxx>
26 #include <TColgp_HArray1OfPnt.hxx>
27 #include <Geom2dAPI_InterCurveCurve.hxx>
28 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
29 #include <Geom2dAdaptor_Curve.hxx>
30 #include <GCPnts_AbscissaPoint.hxx>
31 #include <BRepBuilderAPI_MakeEdge.hxx>
32 #include <limits>
33 #include <Bnd_Box2d.hxx>
34
35 #include <BRepLib_MakeEdge.hxx>
36 #include <BRepLib_MakeWire.hxx>
37 #include <BRep_Builder.hxx>
38 #include <GeomProjLib.hxx>
39 #include <Geom_TrimmedCurve.hxx>
40 #include <BRepTools_WireExplorer.hxx>
41 #include <TopTools_IndexedMapOfShape.hxx>
42 #include <BRepBuilderAPI_MakeFace.hxx>
43 #include <TopExp.hxx>
44 #include <TopTools_IndexedMapOfOrientedShape.hxx>
45 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
46
47 #include <BRepLib_MakeEdge.hxx>
48 #include <BRepLib_MakeWire.hxx>
49 #include <BRep_Builder.hxx>
50 #include <ShapeAnalysis_Wire.hxx>
51 #include <BRepAlgo_NormalProjection.hxx>
52 #include <ShapeUpgrade_UnifySameDomain.hxx>
53 #include <BRepBuilderAPI_MakePolygon.hxx>
54 #include <BOPAlgo_Builder.hxx>
55 #include <BRepAdaptor_Curve.hxx>
56 #include <GeomProjLib.hxx>
57 #include <gp_Pln.hxx>
58 #include <TopTools_IndexedDataMapOfShapeShape.hxx>
59 #include <TopTools_ListIteratorOfListOfShape.hxx>
60 #include <TopTools_SequenceOfShape.hxx>
61 #include <assert.h>
62 #include <NCollection_DataMap.hxx>
63 #include <QSet>
64 #include <QString>
65 #include <float.h>
66
67 double PREC = 0.001;
68 IMPLEMENT_STANDARD_RTTIEXT( HYDROData_DTM, HYDROData_Bathymetry )
69
70 HYDROData_DTM::CurveUZ::CurveUZ( double theXCurv, const gp_Vec2d& theProfileDir, double theDeltaZ, double theMaxZ )
71   : myXcurv( theXCurv ), myProfileDir( theProfileDir ), myDeltaZ( theDeltaZ ), myMaxZ (theMaxZ)
72 {
73 }
74
75 HYDROData_DTM::CurveUZ::~CurveUZ()
76 {
77 }
78
79 double HYDROData_DTM::CurveUZ::Xcurv() const
80 {
81   return myXcurv;
82 }
83
84 gp_Vec2d HYDROData_DTM::CurveUZ::ProfileDir() const
85 {
86   return myProfileDir;
87 }
88
89 double HYDROData_DTM::CurveUZ::DeltaZ() const
90 {
91   return myDeltaZ;
92 }
93
94 double HYDROData_DTM::CurveUZ::MaxZ() const
95 {
96   return myMaxZ;
97 }
98
99 HYDROData_DTM::CurveUZ HYDROData_DTM::CurveUZ::operator + ( const CurveUZ& c ) const
100 {
101   HYDROData_DTM::CurveUZ res( Xcurv() + c.Xcurv(), ProfileDir() + c.ProfileDir(), DeltaZ() + c.DeltaZ(), MaxZ() + c.MaxZ() );
102   size_t n = size(), n1 = c.size();
103   if( n!=n1 )
104   {
105     std::cout << "Warning: different number of points in curves: " << n << ", " << n1 << std::endl;
106   }
107   int q = n < n1 ? n : n1;
108   res.reserve( q );
109   for( int i=0; i<q; i++ )
110   {
111     PointUZ p;
112     p.U = operator[]( i ).U + c[i].U;
113     p.Z = operator[]( i ).Z;
114     res.push_back( p );
115   }
116   return res;
117 }
118
119 HYDROData_DTM::CurveUZ HYDROData_DTM::CurveUZ::operator * ( double d ) const
120 {
121   HYDROData_DTM::CurveUZ res( Xcurv()*d, ProfileDir()*d, DeltaZ()*d, MaxZ()*d );
122   size_t n = size();
123   res.reserve( n );
124   for( int i=0; i<n; i++ )
125   {
126     PointUZ p;
127     p.U = operator[]( i ).U * d;
128     p.Z = operator[]( i ).Z;
129     res.push_back( p );
130   }
131   return res;
132 }
133
134
135
136
137 HYDROData_DTM::HYDROData_DTM()
138 {
139 }
140
141 HYDROData_DTM::~HYDROData_DTM()
142 {
143 }
144
145 HYDROData_SequenceOfObjects HYDROData_DTM::GetProfiles() const
146 {
147   return GetReferenceObjects( DataTag_Profiles );
148 }
149
150 void HYDROData_DTM::SetProfiles( const HYDROData_SequenceOfObjects& theProfiles )
151 {
152   SetReferenceObjects( theProfiles, DataTag_Profiles );
153   Changed( Geom_3d );
154 }
155
156 double HYDROData_DTM::GetDDZ() const
157 {
158   return GetDouble( DataTag_DDZ );
159 }
160
161 void HYDROData_DTM::SetDDZ( double theDDZ )
162 {
163   SetDouble( DataTag_DDZ, theDDZ );
164   Changed( Geom_3d );
165 }
166
167 double HYDROData_DTM::GetSpatialStep() const
168 {
169   return GetDouble( DataTag_SpatialStep );
170 }
171
172 void HYDROData_DTM::SetSpatialStep( double theSpatialStep )
173 {
174   SetDouble( DataTag_SpatialStep, theSpatialStep );
175   Changed( Geom_3d );
176 }
177
178 void HYDROData_DTM::PointsToWire(const AltitudePoints& pnts, TopoDS_Wire& W )
179 {
180  
181   BRepBuilderAPI_MakePolygon PM;
182   for (int i = 0; i < pnts.size(); i++)
183     PM.Add(gp_Pnt(pnts[i].X, pnts[i].Y, pnts[i].Z));
184   
185   W = PM.Wire();
186 }
187
188 void HYDROData_DTM::PointsToEdge(const AltitudePoints& pnts, TopoDS_Edge& E )
189
190   Handle(TColgp_HArray1OfPnt) gpPoints = new TColgp_HArray1OfPnt(1, (int)pnts.size());
191
192   for (int i = 0; i < pnts.size(); i++)
193     gpPoints->SetValue(i+1, gp_Pnt(pnts[i].X, pnts[i].Y, pnts[i].Z));
194
195   GeomAPI_Interpolate anInterpolator(gpPoints, Standard_False,1.0e-6);
196   anInterpolator.Perform() ;
197   if (anInterpolator.IsDone()) 
198   {
199     Handle(Geom_BSplineCurve) C = anInterpolator.Curve();
200     E = BRepBuilderAPI_MakeEdge(C).Edge();
201   }
202 }
203
204 TopTools_IndexedMapOfOrientedShape HYDROData_DTM::Create3DShape(const AltitudePoints& left,
205                                                                 const AltitudePoints& right,
206                                                                 const std::vector<AltitudePoints>& main_profiles)
207 {  
208   TopTools_IndexedMapOfOrientedShape ll;
209   //TopoDS_Wire LWire, RWire;
210   //PointsToWire(left, LWire);
211   //PointsToWire(right, RWire);
212   TopoDS_Edge LEdge, REdge;
213   PointsToEdge(left, LEdge);
214   PointsToEdge(right, REdge);
215   if (!LEdge.IsNull())
216     ll.Add(LEdge.Oriented(TopAbs_FORWARD));
217
218   for (int k = 0; k < main_profiles.size(); k++)
219   {
220     TopoDS_Wire W;
221     PointsToWire(main_profiles[k], W);
222     TopAbs_Orientation Ori = TopAbs_INTERNAL;
223     if (k == 0 || k == main_profiles.size() - 1)
224       Ori = TopAbs_FORWARD;
225     ll.Add(W.Oriented(Ori));
226   }
227
228   if (!REdge.IsNull())
229     ll.Add(REdge.Oriented(TopAbs_FORWARD)); 
230   //yes, add subshapes in this order (left + profiles + right)
231   //otherwise the projected wire will be non-manifold
232
233   return ll;
234 }
235
236
237 void HYDROData_DTM::Update()
238 {
239   AltitudePoints points;
240   TopoDS_Shape Out3dPres;
241   TopoDS_Shape Out2dPres;
242   TopoDS_Shape OutLeftB;
243   TopoDS_Shape OutRightB;
244   TopoDS_Shape OutInlet;
245   TopoDS_Shape OutOutlet;
246
247   HYDROData_SequenceOfObjects objs = GetProfiles();  
248   double ddz = GetDDZ();
249   double step = GetSpatialStep();
250   std::set<int> InvInd;
251   bool WireIntersections; //__TODO
252   myWarnings.Clear();
253   bool ToEstimateWarnings; //NOT NEEDED here
254   CreateProfilesFromDTM( objs, ddz, step, points, Out3dPres, Out2dPres, OutLeftB, OutRightB, OutInlet, OutOutlet,
255     true, true, InvInd, -1, WireIntersections, myWarnings, ToEstimateWarnings );
256   SetAltitudePoints( points );  
257   
258   SetShape( DataTag_LeftBankShape, OutLeftB);
259   SetShape( DataTag_RightBankShape, OutRightB);
260   SetShape( DataTag_InletShape, OutInlet);
261   SetShape( DataTag_OutletShape, OutOutlet );
262   SetShape( DataTag_3DShape, Out3dPres );
263   SetShape( DataTag_2DShape, Out2dPres );
264
265   HYDROData_Bathymetry::Update();
266 }
267
268 void HYDROData_DTM::GetPresentationShapes( TopoDS_Shape& Out3dPres,
269                                            TopoDS_Shape& Out2dPres,
270                                            TopoDS_Shape& OutLeftB,
271                                            TopoDS_Shape& OutRightB,
272                                            TopoDS_Shape& OutInlet,
273                                            TopoDS_Shape& OutOutlet )
274 {
275   //without update!
276   OutLeftB = GetShape( DataTag_LeftBankShape);
277   OutRightB = GetShape( DataTag_RightBankShape);
278   OutInlet = GetShape( DataTag_InletShape);
279   OutOutlet = GetShape( DataTag_OutletShape );
280   Out3dPres = GetShape( DataTag_3DShape );
281   Out2dPres = GetShape( DataTag_2DShape );
282 }
283 void HYDROData_DTM::CreateProfilesFromDTM (const HYDROData_SequenceOfObjects& InpProfiles,
284                                            double ddz,
285                                            double step, 
286                                            AltitudePoints& points,
287                                            TopoDS_Shape& Out3dPres,
288                                            TopoDS_Shape& Out2dPres,
289                                            TopoDS_Shape& OutLeftB,
290                                            TopoDS_Shape& OutRightB,
291                                            TopoDS_Shape& OutInlet,
292                                            TopoDS_Shape& OutOutlet,
293                                            bool Create3dPres,
294                                            bool Create2dPres,
295                                            std::set<int>& InvInd,
296                                            int thePntsLimit,
297                                            bool& WireIntersections, 
298                                            NCollection_DataMap<Handle(HYDROData_Profile), QSet<QString>>& warnings,
299                                            bool& ToEstimateWarnings)
300 {
301   int aLower = InpProfiles.Lower(), anUpper = InpProfiles.Upper();
302   size_t n = anUpper - aLower + 1;
303
304   std::vector<Handle(HYDROData_Profile)> profiles;
305   profiles.reserve( n ); 
306   for( int i=aLower; i<=anUpper; i++ )
307   {
308     Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( InpProfiles.Value( i ) );
309     if( !aProfile.IsNull() )
310       profiles.push_back( aProfile );
311   }
312   const double EPS = 1E-3;
313   AltitudePoints left;
314   AltitudePoints right;
315   std::vector<AltitudePoints> main_profiles;
316
317   bool ToEstimateWarningsOnly = false;
318   if( thePntsLimit > 0 )
319   {
320     int aNbPoints = EstimateNbPoints( profiles, ddz, step );
321     if( aNbPoints < 0 || aNbPoints > thePntsLimit )
322     {
323       ToEstimateWarningsOnly = true;
324       //return;
325     }
326   }
327
328   if( profiles.size() < 2 )
329     return;
330
331   if( ddz>EPS && step>EPS )
332     CreateProfiles(profiles, ddz, step, left, right, points, main_profiles, 
333     Out3dPres, Out2dPres, OutLeftB, OutRightB, OutInlet, OutOutlet, Create3dPres, 
334     Create2dPres, InvInd, WireIntersections, warnings, ToEstimateWarningsOnly );
335
336   ToEstimateWarnings = ToEstimateWarningsOnly;
337 }
338
339 bool HYDROData_DTM::GetPlanarFaceFromBanks( const TopoDS_Edge& LB, const TopoDS_Edge& RB, TopoDS_Face& outF,
340   TopTools_SequenceOfShape* Boundr)
341 {
342   BRep_Builder BB;
343   TopoDS_Face F;
344   Handle_Geom_Plane refpl = new Geom_Plane(gp_Pnt(0,0,0), gp_Dir(0,0,1));
345
346   TopoDS_Vertex VFI, VLI, VFO, VLO;
347   TopoDS_Edge prLB;
348   TopoDS_Edge prRB;
349
350
351   BRepAdaptor_Curve LBAD(LB);
352   Handle_Geom_Curve LBPC = GeomProjLib::ProjectOnPlane(LBAD.Curve().Curve(), refpl, gp_Dir(0, 0, -1), 1 );
353   prLB = BRepLib_MakeEdge(LBPC).Edge();
354
355   BRepAdaptor_Curve RBAD(RB);
356   Handle_Geom_Curve RBPC = GeomProjLib::ProjectOnPlane(RBAD.Curve().Curve(), refpl, gp_Dir(0, 0, -1), 1 );
357   prRB = BRepLib_MakeEdge(RBPC).Edge();
358
359   TopExp::Vertices(prLB, VFI, VFO, 1);
360   TopExp::Vertices(prRB, VLI, VLO, 1);
361   TopoDS_Edge prIL = BRepLib_MakeEdge(VFI, VLI).Edge();
362   TopoDS_Edge prOL = BRepLib_MakeEdge(VFO, VLO).Edge();
363   TopoDS_Wire prW = BRepLib_MakeWire(prLB, prIL, prOL, prRB).Wire();
364   outF = BRepBuilderAPI_MakeFace(refpl->Pln(), prW, 1).Face();
365
366   if (Boundr)
367   {
368     Boundr->Append(prLB);
369     Boundr->Append(prIL);
370     Boundr->Append(prOL);
371     Boundr->Append(prRB);
372   }
373
374   ShapeAnalysis_Wire WA(prW, outF, Precision::Confusion());
375   bool res = WA.CheckSelfIntersection();
376   return !res;
377 }
378
379 void HYDROData_DTM::CreateProfiles(const std::vector<Handle(HYDROData_Profile)>& theProfiles,
380                                    double theDDZ,
381                                    double theSpatialStep,
382                                    AltitudePoints& theOutLeft,
383                                    AltitudePoints& theOutRight,
384                                    AltitudePoints& theOutPoints,
385                                    std::vector<AltitudePoints>& theOutMainProfiles,
386                                    TopoDS_Shape& Out3dPres,
387                                    TopoDS_Shape& Out2dPres,
388                                    TopoDS_Shape& OutLeftB,
389                                    TopoDS_Shape& OutRightB,
390                                    TopoDS_Shape& OutInlet,
391                                    TopoDS_Shape& OutOutlet,
392                                    bool Create3dPres,
393                                    bool Create2dPres,
394                                    std::set<int>& InvInd,
395                                    bool& ProjStat,
396                                    NCollection_DataMap<Handle(HYDROData_Profile), QSet<QString>>& warnings,
397                                    bool ToEstimateWarningsOnly)
398 {
399   if (theProfiles.empty())
400     return;
401   theOutPoints = Interpolate( theProfiles, theDDZ, theSpatialStep, theOutLeft, theOutRight,
402     theOutMainProfiles, InvInd, warnings, ToEstimateWarningsOnly );
403   //note that if Create3dPres is false => Create2dPres flag is meaningless!
404   if( theOutPoints.empty() )
405     return;
406
407   if (Create3dPres)
408   {
409     TopTools_IndexedMapOfOrientedShape ll = Create3DShape( theOutLeft, theOutRight, theOutMainProfiles);
410     
411     if (ll.IsEmpty())
412       return;
413     BRep_Builder BB;
414     TopoDS_Compound cmp;
415     BB.MakeCompound(cmp);
416     for (int i = 1; i <= ll.Extent(); i++)
417       BB.Add(cmp, ll(i));
418
419     Out3dPres = cmp;
420
421     //same order as in HYDROData_DTM::Update()
422     OutLeftB = ll(1);
423     OutRightB = ll(ll.Extent());
424     OutInlet = ll(2);
425     OutOutlet = ll(ll.Extent() - 1);
426
427     if (Create2dPres)
428     {
429       TopoDS_Face outF;
430       ProjStat = GetPlanarFaceFromBanks(TopoDS::Edge(OutLeftB), TopoDS::Edge(OutRightB), outF, NULL);
431       Out2dPres = outF;
432     };
433   }
434 }
435
436
437
438
439 void HYDROData_DTM::GetProperties( const Handle(HYDROData_Profile)& theProfile,
440                     gp_Pnt& theLowestPoint, gp_Vec2d& theDir,
441                     double& theZMin, double& theZMax )
442 {
443   theLowestPoint = theProfile->GetBottomPoint();
444   
445   gp_XY aLeft, aRight;
446   theProfile->GetLeftPoint( aLeft, true, true );
447   theProfile->GetRightPoint( aRight, true, true );
448   double x = aRight.X()-aLeft.X();
449   double y = aRight.Y()-aLeft.Y();
450   theDir = gp_Vec2d( x, y );
451
452   HYDROData_Profile::ProfilePoints points = theProfile->GetProfilePoints();
453   int lo = points.Lower();
454   int up = points.Upper();
455   theZMin = DBL_MAX;
456   theZMax = -theZMin;
457   for( int i=lo; i<=up; i++ )
458   {
459     double z = points.Value( i ).Z();
460     if( z>theZMax )
461       theZMax = z;
462     if( z<theZMin )
463       theZMin = z;
464   }
465 }
466
467 inline gp_Pnt2d To2D( const gp_Pnt& thePnt, const gp_Trsf& theTr,
468                       double& theUMin, double& theUMax )
469 {
470   gp_Pnt p = thePnt.Transformed( theTr );
471   double u = p.X();
472   double z = p.Z();
473   if( u<theUMin )
474     theUMin = u;
475   if( u>theUMax )
476     theUMax = u;
477   return gp_Pnt2d( u, z );
478 }
479
480 Handle(TColgp_HArray1OfPnt2d) To2D( const TColgp_Array1OfPnt& thePoints,
481                                     const gp_Trsf& theTr,
482                                     double& theUMin, double& theUMax )
483 {
484   int low = thePoints.Lower(), up = thePoints.Upper();
485   Handle(TColgp_HArray1OfPnt2d) points = new TColgp_HArray1OfPnt2d( low, up );
486   for( int i=low; i<=up; i++ )
487     points->SetValue( i, To2D( thePoints.Value( i ), theTr, theUMin, theUMax ) );
488   return points;
489 }
490
491 Handle(Geom2d_Curve) CurveTo2D( const Handle(Geom_Curve)& theCurve, 
492                                 Standard_Real theFirst, Standard_Real theLast,
493                                 const gp_Trsf& theTr,
494                                 double& theUMin, double& theUMax )
495 {
496   if( theCurve->IsKind( STANDARD_TYPE( Geom_Line ) ) )
497   {
498     gp_Pnt aFirstPnt, aLastPnt;
499     theCurve->D0( theFirst, aFirstPnt );
500     theCurve->D0( theLast, aLastPnt );
501
502     gp_Pnt2d
503       aFirst2d = To2D( aFirstPnt, theTr, theUMin, theUMax ),
504       aLast2d = To2D( aLastPnt, theTr, theUMin, theUMax );
505
506     gp_Vec2d dir( aFirst2d, aLast2d );
507     Handle(Geom2d_Line) aLine2d = new Geom2d_Line( aFirst2d, gp_Dir2d( dir.X(), dir.Y() ) );
508     return new Geom2d_TrimmedCurve( aLine2d, 0, aLast2d.Distance( aFirst2d ) );
509   }
510
511   if( theCurve->IsKind( STANDARD_TYPE( Geom_BSplineCurve ) ) )
512   {
513     Handle(Geom_BSplineCurve) aSpline = Handle(Geom_BSplineCurve)::DownCast( theCurve );
514
515     Handle(TColgp_HArray1OfPnt2d) poles = To2D( aSpline->Poles(), theTr, theUMin, theUMax );
516     const TColStd_Array1OfReal& knots = aSpline->Knots();
517     const TColStd_Array1OfInteger& multiplicities = aSpline->Multiplicities();
518     int aDegree = aSpline->Degree();
519
520     return new Geom2d_BSplineCurve( poles->Array1(), knots, multiplicities, aDegree );
521   }
522
523   return Handle(Geom2d_Curve)();
524 }
525
526 #include <GCE2d_MakeSegment.hxx>
527 #include <Geom2dAPI_InterCurveCurve.hxx>
528 bool IsCooriented( const Handle(HYDROData_Profile)& theProfile1,
529                    const Handle(HYDROData_Profile)& theProfile2 ) 
530 {
531   if( theProfile1==theProfile2 )
532     return true;
533   
534   gp_XY lp1, rp1, lp2, rp2;
535   theProfile1->GetLeftPoint(lp1);
536   theProfile1->GetRightPoint(rp1);
537   theProfile2->GetLeftPoint(lp2);
538   theProfile2->GetRightPoint(rp2);
539
540   GCE2d_MakeSegment s1(lp1, lp2);
541   GCE2d_MakeSegment s2(rp1, rp2);
542
543   Geom2dAPI_InterCurveCurve inter;
544   inter.Init(s1.Value(), s2.Value());
545   if (inter.NbPoints() == 0)
546     return true;
547   else
548     return false;
549 }
550
551 Handle(Geom2d_BSplineCurve) HYDROData_DTM::CreateHydraulicAxis( 
552   const std::vector<Handle(HYDROData_Profile)>& theProfiles,
553   std::vector<double>& theDistances )
554 {
555   size_t n = theProfiles.size();
556   if( n==1 )
557     return Handle_Geom2d_BSplineCurve();
558
559   Handle_Geom2d_BSplineCurve aResult;
560
561   Handle(TColgp_HArray1OfPnt2d) points = new TColgp_HArray1OfPnt2d( 1, (int)n );
562   TColgp_Array1OfVec2d tangents( 1, (int)n );
563   Handle(TColStd_HArray1OfBoolean) flags = new TColStd_HArray1OfBoolean( 1, (int)n );
564
565   // Stage 1. Orient all profiles to be co-oriented with the first profile
566   theProfiles[0]->Update();
567   for( size_t i = 1; i < n; i++ )
568   {
569     Handle(HYDROData_Profile) aProfile = theProfiles[i];
570     Handle(HYDROData_Profile) aPrevProfile = theProfiles[i-1];
571
572     if( !IsCooriented( aProfile, aPrevProfile ) )
573     {
574       gp_XY lp, rp;
575       aProfile->GetLeftPoint( lp, true );
576       aProfile->GetRightPoint( rp, true );
577       aProfile->SetLeftPoint( rp, true );
578       aProfile->SetRightPoint( lp, true );
579     }
580     aProfile->Update();
581   }
582
583   // Stage 2. Calculate normals so that each normal "points" to the next profile
584   for( size_t i = 0; i < n; i++ )
585   {
586     Handle(HYDROData_Profile) aProfile = theProfiles[i];
587     Handle(HYDROData_Profile) aNextProfile = i==n-1 ? theProfiles[i-1] : theProfiles[i+1];
588
589     gp_Pnt aLowest;
590     gp_Vec2d aNormal;
591     double zmin, zmax;
592
593     gp_XYZ curP = aProfile->GetBottomPoint(true);
594     gp_XY curP2d = gp_XY(curP.X(), curP.Y());
595
596     gp_XYZ nextP = aNextProfile->GetBottomPoint(true);
597     gp_XY nextP2d = gp_XY(nextP.X(), nextP.Y());
598
599     gp_Vec2d aPrTangent;
600     GetProperties( aProfile, aLowest, aPrTangent, zmin, zmax );
601     aNormal.SetCoord( -aPrTangent.Y(), aPrTangent.X() );
602
603     gp_Vec2d aDirToNextProfile(nextP2d.X() - curP2d.X(), nextP2d.Y() - curP2d.Y() );
604     if( i==n-1 )
605       aDirToNextProfile.Reverse();
606
607     if (aNormal.Dot(aDirToNextProfile) < 0)
608       aNormal.Reverse();
609
610     aNormal.Normalize();
611
612     points->SetValue( (int)(i+1), gp_Pnt2d( aLowest.X(), aLowest.Y() ) );
613     tangents.SetValue( (int)(i+1), aNormal );
614     flags->SetValue( (int)(i+1), Standard_True );
615   }
616
617   Geom2dAPI_Interpolate anInterpolator( points, Standard_False, Standard_False );
618   anInterpolator.Load( tangents, flags );
619   anInterpolator.Perform();
620   if( anInterpolator.IsDone() )
621   {
622     aResult = anInterpolator.Curve();
623
624     //fill the distances vector
625     Geom2dAdaptor_Curve anAdaptor( aResult );
626
627     theDistances.clear();
628     theDistances.reserve( n );
629     Standard_Real aParamFirst = anAdaptor.FirstParameter(), aParamLast = anAdaptor.LastParameter();
630     for( size_t i = 1; i <= n; i++ )
631     {
632       gp_Pnt2d aPnt = points->Value( (Standard_Integer)i );
633       Geom2dAPI_ProjectPointOnCurve aProject( aPnt, aResult );
634       Standard_Real aParam = aProject.LowerDistanceParameter();
635       double aDistance = GCPnts_AbscissaPoint::Length( anAdaptor, aParamFirst, aParam );  
636       theDistances.push_back( aDistance );
637     }
638   }
639   return aResult;
640 }
641
642 std::vector<Handle(Geom2d_Curve)> HYDROData_DTM::ProfileToParametric( 
643   const Handle(HYDROData_Profile)& theProfile,
644   double& theUMin, double& theUMax, gp_Vec2d& theDir )
645 {
646   std::vector<Handle(Geom2d_Curve)> curves;
647   
648   // Transformation of the coordinate systems
649   gp_Pnt aLowest;
650   double zmin, zmax;
651   GetProperties( theProfile, aLowest, theDir, zmin, zmax );
652
653   gp_Ax3 aStd3d( gp_Pnt( 0, 0, 0 ), gp_Dir( 0, 0, 1 ), gp_Dir( 1, 0, 0 ) );
654   gp_Ax3 aLocal( gp_Pnt( aLowest.X(), aLowest.Y(), 0 ), gp_Dir( 0, 0, 1 ), gp_Dir( theDir.X(), theDir.Y(), 0 ) );
655
656   gp_Trsf aTransf;
657   aTransf.SetTransformation( aStd3d, aLocal );
658
659   // Iteration via edges
660   TopoDS_Wire aWire = TopoDS::Wire( theProfile->GetShape3D() );
661   TopExp_Explorer anExp( aWire, TopAbs_EDGE );
662   for( ; anExp.More(); anExp.Next() )
663   {
664     // Extract an edge from wire
665     TopoDS_Edge anEdge = TopoDS::Edge( anExp.Current() );
666
667     // Extract a curve corresponding to the edge
668     TopLoc_Location aLoc;
669     Standard_Real aFirst, aLast;
670     Handle(Geom_Curve) aCurve = BRep_Tool::Curve( anEdge, aLoc, aFirst, aLast );
671
672     // Convert the curve to 2d CS
673     Handle(Geom2d_Curve) aCurve2d = CurveTo2D( aCurve, aFirst, aLast, aTransf, theUMin, theUMax );
674     if( !aCurve2d.IsNull() )
675       curves.push_back( aCurve2d );
676   }
677   return curves;
678 }
679
680
681 //bool CalcMidWidth( const std::set<double>& intersections, double& theMid, double& theWid )
682 //{
683 //  double umin = std::numeric_limits<double>::max(),
684 //         umax = -umin;
685 //
686 //  size_t n = intersections.size();
687 //  if( n <= 0 )
688 //    return false;
689 //
690 //  std::set<double>::const_iterator it = intersections.begin(), last = intersections.end();
691 //  for( ; it!=last; it++ )
692 //  {
693 //    double u = *it;
694 //    if( u<umin )
695 //      umin = u;
696 //    if( u>umax )
697 //      umax = u;
698 //  }
699 //  theMid = ( umin+umax )/2;
700 //  theWid = umax-umin;
701 //  return true;
702 //}
703
704
705
706 bool CalcMidWidth( const Bnd_Box2d& inters_bnd, double& theMid, double& theWid )
707 {
708   double umin = DBL_MAX,
709          umax = -umin;
710
711   if (inters_bnd.IsVoid())
712     return false;
713   //size_t n = intersections.size();
714   //if( n <= 0 )
715   //  return false;
716
717   double xmin, ymin, xmax, ymax;
718   inters_bnd.Get(xmin, ymin, xmax, ymax);
719   if (Abs(ymax-ymin)>PREC)
720     return false;
721   
722   theMid = ( xmax+xmin )/2;
723   theWid = xmax-xmin;
724   return true;
725 }
726
727
728
729 void HYDROData_DTM::ProfileDiscretization( const Handle(HYDROData_Profile)& theProfile, 
730                                            double theXCurv, double theMinZ, double theMaxZ, double theTopZ, double theDDZ,
731                                            CurveUZ& theMidPointCurve,
732                                            CurveUZ& theWidthCurve,                                           
733                                            int& intersection_nb,
734                                            double theTolerance,
735                                            QSet<QString>& warnings)
736 {
737   warnings.clear();
738   double aDblMax = std::numeric_limits<double>::max(),
739          aUMin = aDblMax,
740          aUMax = -aUMin,
741          aVMax = 1000000;
742   
743   gp_Vec2d aProfileDir;
744   std::vector<Handle(Geom2d_Curve)> curves = ProfileToParametric( theProfile, aUMin, aUMax, aProfileDir );
745   size_t n = curves.size();
746
747   if( n==0 )
748   {
749     warnings.insert("no curves for discretization; skipped");
750     return;
751   }
752
753   // we add the "virtual" vertical lines to simulate the intersection with profile 
754   gp_Pnt2d aFirst, aLast;
755   curves[0]->D0( curves[0]->FirstParameter(), aFirst );
756   curves[n-1]->D0( curves[n-1]->LastParameter(), aLast );
757   Handle(Geom2d_Line) aV1 = new Geom2d_Line( aFirst, gp_Dir2d( 0, 1 ) );
758   Handle(Geom2d_TrimmedCurve) aT1 = new Geom2d_TrimmedCurve( aV1, 0.0, aVMax );
759   
760   Handle(Geom2d_Line) aV2 = new Geom2d_Line( aLast, gp_Dir2d( 0, 1 ) );
761   Handle(Geom2d_TrimmedCurve) aT2 = new Geom2d_TrimmedCurve( aV2, 0.0, aVMax );
762
763   curves.push_back( aT1 );
764   curves.push_back( aT2 );
765   
766   int psize = ( int )( ( theMaxZ-theMinZ ) / theDDZ + 1 );
767   theMidPointCurve = CurveUZ( theXCurv, aProfileDir, theMinZ, theTopZ);
768   theMidPointCurve.reserve( psize );
769   theWidthCurve = CurveUZ( theXCurv, aProfileDir, theMinZ, theTopZ );
770   theWidthCurve.reserve( psize );
771
772   {
773     bool PlatoCase = false;
774     if (Abs(aFirst.Y() - aLast.Y()) > PREC)
775     {
776       warnings.insert("One of the extreme points is higher than another");
777     }
778     double ZminExtr = Min(aFirst.Y(), aLast.Y()); 
779     double ZmaxExtr = Max(aFirst.Y(), aLast.Y()); 
780     Handle(Geom2d_Line) aLine = new Geom2d_Line( gp_Pnt2d( 0, ZminExtr ), gp_Dir2d( 1, 0 ) );
781     std::vector<gp_Pnt2d> intersections;
782     for( int i = 0; i < n; i++ )
783     {
784       Handle(Geom2d_Curve) aCurve = curves[i];
785       Geom2dAPI_InterCurveCurve anIntersect( aCurve, aLine, theTolerance );
786       for( int k=1, m=anIntersect.NbPoints(); k<=m; k++ )
787         intersections.push_back(anIntersect.Point(k));
788       if (anIntersect.NbSegments() > 0 )
789         PlatoCase = true;
790     }
791     std::vector<gp_Pnt2d> interm_intersections;
792     for (int i=0;i<intersections.size();i++)
793     {
794       gp_Pnt2d int_p2d = intersections[i];
795       //check for intermid. points: shoudl be higher than ZminExtr and not in intersection with first,last points
796       if (aFirst.Distance(int_p2d) > PREC && aLast.Distance(int_p2d) > PREC && int_p2d.Y() > ZminExtr)
797         interm_intersections.push_back(int_p2d);
798     }
799     if (!interm_intersections.empty())
800       warnings.insert("One of the internal points is higher than extreme points");
801     if (ZminExtr != ZmaxExtr && !PlatoCase)
802     {
803       //additional check of plato for zmax
804       Handle(Geom2d_Line) aLine = new Geom2d_Line( gp_Pnt2d( 0, ZmaxExtr ), gp_Dir2d( 1, 0 ) );
805       std::vector<gp_Pnt2d> intersections;
806       for( int i = 0; i < n; i++ )
807       {
808         Handle(Geom2d_Curve) aCurve = curves[i];
809         Geom2dAPI_InterCurveCurve anIntersect( aCurve, aLine, theTolerance );
810         if (anIntersect.NbSegments() > 0 )
811         {
812           PlatoCase = true;
813           break;
814         }
815       }
816     }
817     if (PlatoCase)
818       warnings.insert("Plato case on extremes");
819   }
820
821   n = curves.size();  
822
823   // for each discrete value of z we search intersection with profile
824   for( double z1 = theMinZ; z1 <= theMaxZ; z1 += theDDZ )
825   {
826     Handle(Geom2d_Line) aLine = new Geom2d_Line( gp_Pnt2d( 0, z1 ), gp_Dir2d( 1, 0 ) );
827     std::set<double> intersections;    //TODO the solutions should be treated with some epsilon~1e-8 (computation error of intersector)
828     Bnd_Box2d intersect_bndbox;
829     for( size_t i = 0; i < n; i++ )
830     {
831       Handle(Geom2d_Curve) aCurve = curves[i];
832       Geom2dAPI_InterCurveCurve anIntersect( aCurve, aLine, theTolerance );
833       for( int k=1, m=anIntersect.NbPoints(); k<=m; k++ )
834       {
835         intersections.insert( anIntersect.Point( k ).X() );
836         intersect_bndbox.Add( anIntersect.Point(k));
837       }
838       //
839       for( int k=1, m=anIntersect.NbSegments(); k<=m; k++ )
840       {
841         Handle(Geom2d_Curve) Curve1,Curve2;
842         anIntersect.Segment(k, Curve1, Curve2 );
843         double f = Curve2->FirstParameter();
844         double l = Curve2->LastParameter();
845         gp_Pnt2d Pf, Pl;
846         Curve2->D0(f, Pf);
847         Curve2->D0(l, Pl);
848         intersect_bndbox.Add( Pf );
849         intersect_bndbox.Add( Pl );
850         intersections.insert( Pf.X() );
851         intersections.insert( Pl.X() );
852       }
853     }
854
855     intersection_nb = intersections.size();
856     if (intersection_nb == 0)
857     {
858       warnings.insert("No intersections between profile & altitude Z-lines found; skipped");
859       return;
860     }
861     else if (intersection_nb > 2)
862     {
863       warnings.insert("More than 2 intersections between profile & altitude Z-lines found");
864     }
865     double xmin, ymin, xmax, ymax;
866     intersect_bndbox.Get(xmin, ymin, xmax, ymax);
867     //if (Abs(xmax-xmin)>PREC)
868     if (intersection_nb >= 1)
869     {
870       double u_mid, u_wid;
871       if( !CalcMidWidth( intersect_bndbox, u_mid, u_wid ) )
872         continue;
873
874       double z = z1 - theMinZ;
875       PointUZ p_mid;
876       p_mid.U = u_mid;
877       p_mid.Z = z;
878       theMidPointCurve.push_back( p_mid );
879
880       PointUZ p_wid;
881       p_wid.U = u_wid;
882       p_wid.Z = z;
883       theWidthCurve.push_back( p_wid );
884     }
885   
886
887     //intersection_nb = intersections.size();
888     //if( intersection_nb >= 1 )
889     //{
890     //  double u_mid, u_wid;
891     //  if( !CalcMidWidth( intersections, u_mid, u_wid ) )
892     //    continue;
893     //
894     //  double z = z1 - theMinZ;
895     //  PointUZ p_mid;
896     //  p_mid.U = u_mid;
897     //  p_mid.Z = z;
898     //  theMidPointCurve.push_back( p_mid );
899     //
900     //  PointUZ p_wid;
901     //  p_wid.U = u_wid;
902     //  p_wid.Z = z;
903     //  theWidthCurve.push_back( p_wid );
904     //}
905   }
906 }
907
908 void HYDROData_DTM::Interpolate( const CurveUZ& theCurveA, const CurveUZ& theCurveB, 
909                                  int theNbSteps, std::vector<CurveUZ>& theInterpolation,
910                                  bool isAddSecond )
911 {
912   theInterpolation.clear();
913   int d = isAddSecond ? 2 : 1;
914   theInterpolation.reserve( theNbSteps+d );
915   double dt = 1.0 / double( theNbSteps + 1 );
916   double t = dt;
917   theInterpolation.push_back( theCurveA );
918   for( int i=0; i<theNbSteps; i++, t+=dt )
919   {
920     CurveUZ anInterp = theCurveA*(1-t) + theCurveB*t;
921     theInterpolation.push_back( anInterp );
922   }
923   if( isAddSecond )
924     theInterpolation.push_back( theCurveB );
925 }
926 #include <BRepLib_MakeEdge2d.hxx>
927 void HYDROData_DTM::CurveTo3D( const Handle(Geom2d_BSplineCurve)& theHydraulicAxis,
928                                const CurveUZ& theMidCurve, const CurveUZ& theWidthCurve,
929                                AltitudePoints& thePoints )
930 {
931   Geom2dAdaptor_Curve anAdaptor( theHydraulicAxis );
932   TopoDS_Edge E2d = BRepLib_MakeEdge2d(theHydraulicAxis).Edge();
933   GCPnts_AbscissaPoint ap( anAdaptor, theMidCurve.Xcurv(), anAdaptor.FirstParameter() );  
934   double aParam = ap.Parameter();
935
936   gp_Pnt2d point;
937   anAdaptor.D0( aParam, point );
938   gp_Vec2d profile_dir = theMidCurve.ProfileDir();
939   //gp_Dir tangent_n( -profile_dir.Y(), profile_dir.X(), dz );
940   profile_dir.Normalize();
941   
942   size_t n = theMidCurve.size();
943   std::map<double, AltitudePoint> sorted_points;
944   bool isOnTop = false;
945   for( size_t i=0; i<n; i++ ) // build the two banks of the interpolated profile, from bottom to top
946   {
947     double param1 = theMidCurve[i].U - theWidthCurve[i].U / 2;
948     double param2 = theMidCurve[i].U + theWidthCurve[i].U / 2;
949
950     gp_Pnt2d p1 = point.Translated( param1 * profile_dir);
951     gp_Pnt2d p2 = point.Translated( param2 * profile_dir);
952
953     bool arrivedOnTop = false;
954     double z = 0;
955     if (theMidCurve[i].Z <= theMidCurve.MaxZ())
956       z = theMidCurve[i].Z + theMidCurve.DeltaZ();
957     else
958       {
959         z = theMidCurve.MaxZ() + theMidCurve.DeltaZ(); // limit z to linear interpolation between maxima on extremity profiles
960         arrivedOnTop = true; // do not keep points after this one
961       }
962     if (!isOnTop)
963       {
964         AltitudePoint p3d_1( p1.X(), p1.Y(), z ), p3d_2( p2.X(), p2.Y(), z );
965
966         sorted_points[param1] = p3d_1;
967         sorted_points[param2] = p3d_2;
968       }
969     //if (arrivedOnTop)
970     //  isOnTop =true; // do not keep points after this one (commented: leads to strange limits of 2D shape)
971   }
972
973   thePoints.reserve( sorted_points.size() );
974   const double EPS = 1E-12;
975   std::map<double, AltitudePoint>::const_iterator it = sorted_points.begin(), last = sorted_points.end();
976   for( ; it!=last; it++ )
977     if( thePoints.empty() || thePoints.back().SquareDistance( it->second ) > EPS )
978       thePoints.push_back( it->second );
979 }
980
981 //inline double max( double a, double b )
982 //{
983 //  if( a>b )
984 //    return a;
985 //  else
986 //    return b;
987 //}
988 //
989 //inline double min( double a, double b )
990 //{
991 //  if( a<b )
992 //    return a;
993 //  else
994 //    return b;
995 //}
996
997 #include <BRepLib_MakeWire.hxx>
998
999 std::vector<HYDROData_Bathymetry::AltitudePoints> HYDROData_DTM::Interpolate
1000   ( const Handle(Geom2d_BSplineCurve)& theHydraulicAxis,
1001     const Handle(HYDROData_Profile)& theProfileA,
1002     double theXCurvA,
1003     const Handle(HYDROData_Profile)& theProfileB,
1004     double theXCurvB,
1005     double theDDZ, int theNbSteps, bool isAddSecond,
1006     int& inter_nb_1, int& inter_nb_2,
1007     NCollection_DataMap<Handle(HYDROData_Profile), QSet<QString>>& warnings,
1008     bool ToEstimateWarningsOnly)
1009 {
1010   double zminA, zmaxA, zminB, zmaxB;
1011   gp_Pnt lowestA, lowestB;
1012   gp_Vec2d dirA, dirB;
1013
1014   GetProperties( theProfileA, lowestA, dirA, zminA, zmaxA ); 
1015   GetProperties( theProfileB, lowestB, dirB, zminB, zmaxB ); 
1016
1017   
1018   double hmax = zmaxA-zminA > zmaxB-zminB ? zmaxA-zminA : zmaxB-zminB;
1019
1020   //double dz = zminB - zminA;
1021   //double zmin = min( zminA, zminB );
1022   //double zmax = max( zmaxA, zmaxB );
1023
1024   CurveUZ midA(0, gp_Vec2d(), 0, 0), midB(0, gp_Vec2d(), 0, 0);
1025   CurveUZ widA(0, gp_Vec2d(), 0, 0), widB(0, gp_Vec2d(), 0, 0);
1026
1027   QSet<QString> warnings_per_profileA, warnings_per_profileB;
1028   
1029   ProfileDiscretization( theProfileA, theXCurvA, zminA, zminA+hmax, zmaxA-zminA, 
1030     theDDZ, midA, widA, inter_nb_1, 1E-6, warnings_per_profileA );
1031   ProfileDiscretization( theProfileB, theXCurvB, zminB, zminB+hmax, zmaxB-zminB, 
1032     theDDZ, midB, widB, inter_nb_2, 1E-6, warnings_per_profileB );
1033
1034   //process warnings
1035   if (warnings.IsBound(theProfileA))
1036   {
1037     QSet<QString>& warnings_per_profileA_old = warnings.ChangeFind(theProfileA);
1038     warnings_per_profileA_old+=warnings_per_profileA;
1039   }
1040   else
1041     warnings.Bind(theProfileA, warnings_per_profileA);
1042   
1043   if (warnings.IsBound(theProfileB))
1044   {
1045     QSet<QString>& warnings_per_profileB_old = warnings.ChangeFind(theProfileB);
1046     warnings_per_profileB_old+=warnings_per_profileB;
1047   }
1048   else
1049     warnings.Bind(theProfileB, warnings_per_profileB);
1050   //
1051
1052   if (ToEstimateWarningsOnly)
1053     return std::vector<AltitudePoints>();
1054
1055   std::vector<CurveUZ> mid, wid;
1056   Interpolate( midA, midB, theNbSteps, mid, isAddSecond );
1057   Interpolate( widA, widB, theNbSteps, wid, isAddSecond );
1058
1059   size_t p = mid.size();
1060   size_t q = p>0 ? 2*mid[0].size() : 1;
1061   std::vector<AltitudePoints> points;
1062   points.resize( p );
1063
1064   for( size_t i=0; i<p; i++ )
1065   {
1066     points[i].reserve( q );
1067     CurveTo3D( theHydraulicAxis, mid[i], wid[i], points[i] );
1068   }
1069
1070   return points;
1071 }
1072
1073 HYDROData_Bathymetry::AltitudePoints HYDROData_DTM::Interpolate
1074   ( const std::vector<Handle(HYDROData_Profile)>& theProfiles,
1075     double theDDZ, double theSpatialStep,
1076     AltitudePoints& theLeft,
1077     AltitudePoints& theRight,
1078     std::vector<AltitudePoints>& theMainProfiles,
1079     std::set<int>& invalInd,
1080     NCollection_DataMap<Handle(HYDROData_Profile), QSet<QString>>& warnings,
1081     bool ToEstimateWarningsOnly)
1082 {
1083   AltitudePoints points;
1084   size_t n = theProfiles.size();
1085   if( n<=1 )
1086     return points;
1087
1088   std::vector<double> distances;
1089   Handle(Geom2d_BSplineCurve) aHydraulicAxis;
1090   
1091   if (!ToEstimateWarningsOnly)
1092   {
1093     aHydraulicAxis = CreateHydraulicAxis( theProfiles, distances );
1094     if( aHydraulicAxis.IsNull() )
1095       return points;
1096   }
1097
1098   theMainProfiles.reserve( n );
1099
1100   for( size_t i=0, n1=n-1; i<n1; i++ )
1101   {
1102     double aDistance = 0;
1103     int aNbSteps = -1;
1104     bool isAddSecond = false;
1105   
1106     if (!ToEstimateWarningsOnly)
1107     {
1108       aDistance = distances[i+1]-distances[i];
1109       aNbSteps = int(aDistance/theSpatialStep);
1110       isAddSecond = i==n1-1;
1111     }
1112
1113     // 1. Calculate interpolated profiles
1114     int inter_nb_1, inter_nb_2;
1115     std::vector<AltitudePoints> local_points = Interpolate( aHydraulicAxis, theProfiles[i], 
1116       ToEstimateWarningsOnly ? 0 : distances[i], 
1117       theProfiles[i+1], 
1118       ToEstimateWarningsOnly ? 0 : distances[i+1], 
1119       theDDZ, aNbSteps, isAddSecond, inter_nb_1, inter_nb_2, warnings,
1120       ToEstimateWarningsOnly);
1121     int lps = local_points.size();
1122
1123     if (lps == 0)
1124       continue;
1125
1126     if (inter_nb_1 > 2)
1127       invalInd.insert(i);
1128
1129     if (inter_nb_2 > 2)
1130       invalInd.insert(i+1);
1131
1132     // 2. Put all points into the global container
1133     for( size_t j=0; j<lps; j++ )
1134     {
1135       const AltitudePoints& lp = local_points[j];
1136       if( i==0 && j==0 )
1137         points.reserve( lp.size() * n );
1138       for( size_t k=0, ks=lp.size(); k<ks; k++ )
1139         points.push_back( lp[k] );
1140     }
1141
1142     // 3. Get left/right banks' points
1143     if( i==0 )
1144     {
1145       theLeft.reserve( lps * n );
1146       theRight.reserve( lps * n );
1147     }
1148     for( size_t j=0; j<lps; j++ )
1149     {
1150       const AltitudePoints& lp = local_points[j];
1151       theLeft.push_back( lp[0] );
1152       theRight.push_back( lp[lp.size()-1] );
1153     }
1154
1155     // 4. Get main profiles points
1156     theMainProfiles.push_back( local_points[0] );
1157     if( isAddSecond )
1158       theMainProfiles.push_back( local_points[lps-1] );
1159   }
1160   return points;
1161 }
1162
1163 int HYDROData_DTM::EstimateNbPoints( const std::vector<Handle(HYDROData_Profile)>& theProfiles,
1164                                      double theDDZ, double theSpatialStep )
1165 {
1166   size_t n = theProfiles.size();
1167   if( n<=1 )
1168     return 0;
1169   if( theDDZ<1E-6 || theSpatialStep<1E-6 )
1170     return 1 << 20;
1171
1172   std::vector<double> distances;
1173   Handle(Geom2d_BSplineCurve) aHydraulicAxis = CreateHydraulicAxis( theProfiles, distances );
1174   if( aHydraulicAxis.IsNull() )
1175     return 0;
1176
1177   double aCompleteDistance = distances[n-1];
1178   int aNbSteps = int( aCompleteDistance / theSpatialStep ) + 1;
1179   gp_Pnt aLowest;
1180   gp_Vec2d aDir;
1181   double aZMin, aZMax;
1182   GetProperties( theProfiles[0], aLowest, aDir, aZMin, aZMax );
1183   int aNbZSteps = (aZMax-aZMin)/theDDZ;
1184
1185   if( aNbSteps > ( 1<<16 ) || aNbZSteps > ( 1<<16 ) )
1186     return 1 << 20;
1187
1188   return aNbSteps * aNbZSteps;
1189 }
1190
1191 void HYDROData_DTM::GetWarnings(NCollection_DataMap<Handle(HYDROData_Profile), QSet<QString>>& warnings)
1192 {
1193   warnings = myWarnings;
1194 }