Salome HOME
refs #493: provide Python API
[modules/hydro.git] / src / HYDROData / HYDROData_Stream.cxx
1 // Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "HYDROData_Stream.h"
24
25 #include "HYDROData_Document.h"
26 #include "HYDROData_PolylineXY.h"
27 #include "HYDROData_Polyline3D.h"
28 #include "HYDROData_Profile.h"
29 #include "HYDROData_ShapesGroup.h"
30 #include "HYDROData_ShapesTool.h"
31 #include "HYDROData_IAltitudeObject.h"
32 #include "HYDROData_IProfilesInterpolator.h"
33 #include "HYDROData_Tool.h"
34
35 #include <TDataStd_RealArray.hxx>
36
37 #include <Precision.hxx>
38
39 #include <NCollection_DataMap.hxx>
40
41 #include <TColStd_Array1OfReal.hxx>
42 #include <TColStd_ListOfReal.hxx>
43 #include <TColStd_ListIteratorOfListOfReal.hxx>
44 #include <TCollection_CompareOfReal.hxx>
45 #include <TColgp_Array1OfPnt.hxx>
46 #include <TColgp_HArray1OfPnt.hxx>
47
48 #include <TopoDS.hxx>
49 #include <TopoDS_Wire.hxx>
50 #include <TopoDS_Shell.hxx>
51 #include <TopoDS_Face.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Vertex.hxx>
54 #include <TopExp.hxx>
55 #include <TopExp_Explorer.hxx>
56
57 #include <Bnd_Box.hxx>
58
59 #include <BRep_Builder.hxx>
60 #include <BRepBuilderAPI_MakeEdge.hxx>
61 #include <BRepBuilderAPI_MakeWire.hxx>
62 #include <BRepBuilderAPI_MakeFace.hxx>
63
64 #include <BRepBndLib.hxx>
65 #include <BRepProj_Projection.hxx>
66 #include <BRepExtrema_ExtCC.hxx>
67 #include <BRepCheck_Analyzer.hxx>
68
69 #include <gp.hxx>
70 #include <gp_Ax1.hxx>
71 #include <gp_Ax2.hxx>
72 #include <gp_Ax3.hxx>
73 #include <gp_Vec.hxx>
74 #include <gp_Pnt.hxx>
75 #include <gp_Pln.hxx>
76
77 #include <GeomAPI_Interpolate.hxx>
78 #include <Geom_BSplineCurve.hxx>
79
80 #include <TopTools_Array1OfShape.hxx>
81
82 #include <SortTools_QuickSortOfReal.hxx>
83
84 #include <QColor>
85 #include <QStringList>
86
87 //#define DEB_STREAM 1
88 #ifdef DEB_STREAM
89 //#define DEB_HASINT 1
90 //#define DEB_UPDATE 1
91 #include <BRepTools.hxx>
92 #include <TCollection_AsciiString.hxx>
93 #endif
94
95 typedef NCollection_DataMap<Standard_Real, Handle(HYDROData_Profile)> HYDROData_DataMapOfRealOfHDProfile;
96
97 IMPLEMENT_STANDARD_HANDLE(HYDROData_Stream,HYDROData_NaturalObject)
98 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Stream,HYDROData_NaturalObject)
99
100
101 HYDROData_Stream::HYDROData_Stream()
102 : HYDROData_NaturalObject()
103 {
104 }
105
106 HYDROData_Stream::~HYDROData_Stream()
107 {
108 }
109
110 QStringList HYDROData_Stream::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
111 {
112   QStringList aResList = dumpObjectCreation( theTreatedObjects );
113   QString aName = GetObjPyName();
114
115   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
116   setPythonReferenceObject( theTreatedObjects, aResList, aHydAxis, "SetHydraulicAxis" );
117
118   HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles();
119   for ( int i = 1, aNb = aSeqOfProfiles.Size(); i <= aNb; ++i )
120   {
121     const Handle(HYDROData_Entity) aProfile = aSeqOfProfiles.Value( i );
122     setPythonReferenceObject( theTreatedObjects, aResList, aProfile, "AddProfile" );
123   }
124
125   // Set bottom polyline if exists
126   const Handle(HYDROData_Polyline3D) aBottomPolyline = GetBottomPolyline();
127   if ( !aBottomPolyline.IsNull() ) {
128     setPythonReferenceObject( theTreatedObjects, aResList, aBottomPolyline, "SetBottomPolyline" );
129   }
130
131   aResList << QString( "" );
132   aResList << QString( "%1.Update();" ).arg( aName );
133   aResList << QString( "" );
134
135   return aResList;
136 }
137
138 HYDROData_SequenceOfObjects HYDROData_Stream::GetAllReferenceObjects() const
139 {
140   HYDROData_SequenceOfObjects aResSeq = HYDROData_Object::GetAllReferenceObjects();
141
142   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
143   if ( !aHydAxis.IsNull() )
144     aResSeq.Append( aHydAxis );
145
146   HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles();
147   aResSeq.Append( aSeqOfProfiles );
148
149   return aResSeq;
150 }
151
152 TopoDS_Shape HYDROData_Stream::GetTopShape() const
153 {
154   return getTopShape();
155 }
156
157 TopoDS_Shape HYDROData_Stream::GetShape3D() const
158 {
159   return getShape3D();
160 }
161
162 Handle(Geom_BSplineCurve) HYDROData_Stream::buildInterpolationCurve( 
163   const Handle(TColgp_HArray1OfPnt)& theArrayOfPnt )
164 {
165   Handle(Geom_BSplineCurve) aBSpline;
166   GeomAPI_Interpolate anInterpolator (theArrayOfPnt, Standard_False, 1.0e-5); 
167   anInterpolator.Perform() ;
168   if (anInterpolator.IsDone()) 
169     aBSpline = anInterpolator.Curve();
170   return aBSpline; 
171 }
172
173 void HYDROData_Stream::Update()
174 {
175   updateProfilesOrder();
176
177   // Update bottom polyline if exists
178   const Handle(HYDROData_Polyline3D) aBottomPolyline = GetBottomPolyline();
179   if ( !aBottomPolyline.IsNull() ) {
180     if ( GenerateBottomPolyline() ) {
181       Handle(HYDROData_PolylineXY) aPolylineXY = aBottomPolyline->GetPolylineXY();
182       if ( !aPolylineXY.IsNull() ) {
183         aPolylineXY->Update();
184       }
185       aBottomPolyline->Update();
186     }
187   }
188
189   UpdatePrs();
190 }
191
192 bool HYDROData_Stream::IsHas2dPrs() const
193 {
194   return true;
195 }
196
197 bool HYDROData_Stream::CreatePresentations( const Handle(HYDROData_PolylineXY)& theHydAxis,
198                                             const HYDROData_SequenceOfObjects&  theProfiles,
199                                             PrsDefinition&                      thePrs )
200 {
201   if ( theHydAxis.IsNull() || theProfiles.Length() < 2 )
202     return false;
203
204   gp_Pnt aPrevFirstPoint, aPrevLastPoint;
205   Handle(TColgp_HArray1OfPnt) anArrayOfFPnt    = new TColgp_HArray1OfPnt(1, theProfiles.Length());
206   Handle(TColgp_HArray1OfPnt) anArrayOfLPnt    = new TColgp_HArray1OfPnt(1, theProfiles.Length());  
207   TopTools_Array1OfShape anArrOfProfiles(1, theProfiles.Length());
208   TopTools_Array1OfShape anArrOf2DProfiles(1, theProfiles.Length());
209
210   // Pre-processing
211   HYDROData_SequenceOfObjects::Iterator anIter( theProfiles );
212   for (int i=1 ; anIter.More(); anIter.Next(),i++ )
213   {
214     Handle(HYDROData_Profile) aProfile =
215       Handle(HYDROData_Profile)::DownCast( anIter.Value() );
216     if ( aProfile.IsNull() )
217       continue;
218
219     const TopoDS_Shape& aProf3d = aProfile->GetShape3D();
220     gp_XY aPnt1, aPnt2;
221     if ( !aProfile->GetLeftPoint( aPnt1, false ) || !aProfile->GetRightPoint( aPnt2, false ) )
222       continue;
223
224     anArrOfProfiles.SetValue(i,aProfile->GetShape3D());//aProfile->GetTopShape();
225     anArrOf2DProfiles.SetValue(i,aProfile->GetTopShape());
226
227     gp_Pnt aCurFirstPoint( aPnt1.X(), aPnt1.Y(), 0 ), aCurFP;
228     gp_Pnt aCurLastPoint(  aPnt2.X(), aPnt2.Y(), 0 ), aCurLP;
229     TopoDS_Vertex aV1, aV2;
230     TopExp::Vertices(TopoDS::Wire(aProf3d), aV1, aV2);
231        gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
232     if(aP1.X() == aPnt1.X() && aP1.Y() == aPnt1.Y())
233       aCurFP = aP1;
234     else
235       aCurLP = aP1;
236     aP1 = BRep_Tool::Pnt(aV2);
237     if(aP1.X() == aPnt2.X() && aP1.Y() == aPnt2.Y())
238       aCurLP = aP1;
239     else
240       aCurFP = aP1;
241     anArrayOfFPnt->SetValue(i,aCurFP);
242     anArrayOfLPnt->SetValue(i,aCurLP);
243   }
244
245   // Construct of the 3D presentation
246   Handle(Geom_BSplineCurve) aBSpline = buildInterpolationCurve (anArrayOfFPnt);
247   if(aBSpline.IsNull())
248     return false;
249
250   TopoDS_Edge anEdgLeft, anEdgRight;
251   
252   BRepBuilderAPI_MakeEdge aMakeEdge(aBSpline);
253   if(aMakeEdge.IsDone()) 
254     anEdgLeft = aMakeEdge.Edge();
255
256   if(anEdgLeft.IsNull())
257     return false;
258
259   aBSpline.Nullify();
260   aBSpline = buildInterpolationCurve (anArrayOfLPnt);  
261   if(aBSpline.IsNull())
262     return false;
263
264   aMakeEdge.Init(aBSpline);
265   if(aMakeEdge.IsDone()) 
266     anEdgRight = aMakeEdge.Edge();
267
268   if(anEdgRight.IsNull())
269     return false;
270
271   BRep_Builder aBB;
272   TopoDS_Compound aCmp;
273   aBB.MakeCompound(aCmp);
274   anIter.Init( theProfiles );
275   for (int i=1 ; i < anArrOfProfiles.Length() +1; i++ )  
276     aBB.Add(aCmp, anArrOfProfiles.Value(i));
277
278   aBB.Add(aCmp,anEdgLeft);
279   aBB.Add(aCmp,anEdgRight);
280   BRepCheck_Analyzer aCh(aCmp);
281   if(aCh.IsValid())
282     thePrs.myPrs3D = aCmp;
283 #ifdef DEB_UPDATE
284   else {
285     BRepTools::Write(aCmp, "str3d.brep");
286     thePrs.myPrs3D = aCmp;
287   }
288 #endif
289
290   // Construct the top presentation
291   for(int i=1;i<= anArrayOfLPnt->Length();i++) {
292       gp_Pnt aPnt = anArrayOfFPnt->Value(i);
293       aPnt.SetZ(.0); // make 2d
294       anArrayOfFPnt->SetValue(i, aPnt);
295       aPnt = anArrayOfLPnt->Value(i);
296       aPnt.SetZ(.0);
297       anArrayOfLPnt->SetValue(i, aPnt);
298   }
299
300   aBSpline.Nullify();
301   aBSpline = buildInterpolationCurve (anArrayOfFPnt);  
302   if(aBSpline.IsNull())
303     return false; 
304
305   aMakeEdge.Init(aBSpline);
306   if(aMakeEdge.IsDone()) 
307       anEdgLeft = aMakeEdge.Edge();
308
309   aBSpline.Nullify();
310   aBSpline = buildInterpolationCurve (anArrayOfLPnt);  
311   if(aBSpline.IsNull())
312     return false; 
313
314   aMakeEdge.Init(aBSpline);
315   if(aMakeEdge.IsDone()) 
316     anEdgRight = aMakeEdge.Edge();
317   if(anEdgRight.IsNull())
318     return false;
319
320   BRepBuilderAPI_MakeEdge aMakeEdge2(anArrayOfFPnt->Value(1),anArrayOfLPnt->Value(1));
321   TopoDS_Edge aBotEdge, aTopEdge;
322   if(aMakeEdge2.IsDone()) 
323     aBotEdge = aMakeEdge2.Edge();
324
325   BRepBuilderAPI_MakeEdge aMakeEdge3(anArrayOfFPnt->Value(anArrayOfFPnt->Length()),anArrayOfLPnt->Value(anArrayOfLPnt->Length()));
326   if(aMakeEdge3.IsDone()) 
327     aTopEdge = aMakeEdge3.Edge();
328
329   // Make wire for 2D presentation with updating of corresponding edges
330   BRepBuilderAPI_MakeWire aMakeWire;
331   
332   aMakeWire.Add( aBotEdge );
333   thePrs.myInlet = aMakeWire.Edge();
334
335   aMakeWire.Add( anEdgLeft );
336   thePrs.myLeftBank = aMakeWire.Edge();
337
338   aMakeWire.Add( aTopEdge );
339   thePrs.myOutlet = aMakeWire.Edge();
340
341   aMakeWire.Add( anEdgRight );
342   thePrs.myRightBank = aMakeWire.Edge();
343
344   TopoDS_Wire aSectProfileWire;
345   if(aMakeWire.IsDone())
346     aSectProfileWire = aMakeWire.Wire();
347
348   BRepBuilderAPI_MakeFace aMakeFace( aSectProfileWire, Standard_True );
349   TopoDS_Face aFace;
350   aMakeFace.Build();
351   if( aMakeFace.IsDone() )
352     aFace = aMakeFace.Face();
353
354   aCmp.Nullify();
355   aBB.MakeCompound(aCmp);
356   aBB.Add(aCmp,aFace);
357   for(int i=1;i <= anArrOf2DProfiles.Length(); i++)
358     aBB.Add(aCmp,anArrOf2DProfiles.Value(i));
359
360   aCh.Init(aCmp);
361   if(aCh.IsValid())
362    thePrs.myPrs2D = aCmp;
363 #ifdef DEB_UPDATE
364   else {
365     BRepTools::Write(aCmp, "str2d.brep");
366     thePrs.myPrs2D = aCmp;
367   }
368 #endif
369
370   return true;
371 }
372
373 void HYDROData_Stream::UpdatePrs()
374 {
375   HYDROData_NaturalObject::Update();
376
377   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
378   HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
379
380   PrsDefinition aResultPrs;
381   if ( !CreatePresentations( aHydAxis, aRefProfiles, aResultPrs ) )
382     return;
383
384   SetShape3D( aResultPrs.myPrs3D );
385   SetTopShape( aResultPrs.myPrs2D );
386
387   // Create the stream groups
388   QString aLeftGroupName = GetName() + "_Left_Bank";
389
390   Handle(HYDROData_ShapesGroup) aLeftGroup = createGroupObject();
391   aLeftGroup->SetName( aLeftGroupName );
392   aLeftGroup->AddShape( aResultPrs.myLeftBank );
393
394   QString aRightGroupName = GetName() + "_Right_Bank";
395
396   Handle(HYDROData_ShapesGroup) aRightGroup = createGroupObject();
397   aRightGroup->SetName( aRightGroupName );
398   aRightGroup->AddShape( aResultPrs.myRightBank );
399
400   QString anInGroupName = GetName() + "_Inlet";
401
402   Handle(HYDROData_ShapesGroup) anInGroup = createGroupObject();
403   anInGroup->SetName( anInGroupName );
404   anInGroup->AddShape( aResultPrs.myInlet );
405
406   QString anOutGroupName = GetName() + "_Outlet";
407   
408   Handle(HYDROData_ShapesGroup) anOutGroup = createGroupObject();
409   anOutGroup->SetName( anOutGroupName );
410   anOutGroup->AddShape( aResultPrs.myOutlet );
411 }
412
413 QColor HYDROData_Stream::DefaultFillingColor()
414 {
415   return QColor( Qt::green );
416 }
417
418 QColor HYDROData_Stream::DefaultBorderColor()
419 {
420   return QColor( Qt::transparent );
421 }
422
423 bool HYDROData_Stream::IsValidAsAxis( const Handle(HYDROData_PolylineXY)& theHydAxis )
424 {
425   if ( theHydAxis.IsNull() )
426     return false;
427
428   TopoDS_Shape aHydraulicShape = theHydAxis->GetShape();
429   if ( aHydraulicShape.IsNull() || 
430        aHydraulicShape.ShapeType() != TopAbs_WIRE ||
431        BRep_Tool::IsClosed( aHydraulicShape ) )
432     return false; // The polyline must be a single not closed wire
433
434   return true;
435 }
436
437 TopoDS_Shape getShapeFromGroup( const HYDROData_SequenceOfObjects& theGroups,
438                                 const int                          theGroupId )
439 {
440   TopoDS_Shape aResShape;
441   if ( theGroups.Length() != 4 )
442     return aResShape;
443
444   Handle(HYDROData_ShapesGroup) aGroup =
445     Handle(HYDROData_ShapesGroup)::DownCast( theGroups.Value( theGroupId ) );
446   if ( aGroup.IsNull() )
447     return aResShape;
448
449   TopTools_SequenceOfShape aGroupShapes;
450   aGroup->GetShapes( aGroupShapes );
451
452   if ( !aGroupShapes.IsEmpty() )
453     aResShape = aGroupShapes.First();
454
455   return aResShape;
456 }
457
458 TopoDS_Shape HYDROData_Stream::GetLeftShape() const
459 {
460   HYDROData_SequenceOfObjects aGroups = GetGroups();
461   return getShapeFromGroup( aGroups, 1 );
462 }
463
464 TopoDS_Shape HYDROData_Stream::GetRightShape() const
465 {
466   HYDROData_SequenceOfObjects aGroups = GetGroups();
467   return getShapeFromGroup( aGroups, 2 );
468 }
469
470 TopoDS_Shape HYDROData_Stream::GetInletShape() const
471 {
472   HYDROData_SequenceOfObjects aGroups = GetGroups();
473   return getShapeFromGroup( aGroups, 3 );
474 }
475
476 TopoDS_Shape HYDROData_Stream::GetOutletShape() const
477 {
478   HYDROData_SequenceOfObjects aGroups = GetGroups();
479   return getShapeFromGroup( aGroups, 4 );
480 }
481
482 QColor HYDROData_Stream::getDefaultFillingColor() const
483 {
484   return DefaultFillingColor();
485 }
486
487 QColor HYDROData_Stream::getDefaultBorderColor() const
488 {
489   return DefaultBorderColor();
490 }
491
492 bool HYDROData_Stream::SetHydraulicAxis( const Handle(HYDROData_PolylineXY)& theAxis )
493 {
494   if ( !IsValidAsAxis( theAxis ) )
495     return false;
496
497   Handle(HYDROData_PolylineXY) aPrevAxis = GetHydraulicAxis();
498   if ( IsEqual( aPrevAxis, theAxis ) )
499     return true;
500
501   SetReferenceObject( theAxis, DataTag_HydraulicAxis );
502
503   // Update the order of profiles
504   updateProfilesOrder();
505
506   // Indicate model of the need to update the stream presentation
507   SetToUpdate( true );
508
509   return true;
510 }
511
512 Handle(HYDROData_PolylineXY) HYDROData_Stream::GetHydraulicAxis() const
513 {
514   return Handle(HYDROData_PolylineXY)::DownCast( 
515            GetReferenceObject( DataTag_HydraulicAxis ) );
516 }
517
518 void HYDROData_Stream::RemoveHydraulicAxis()
519 {
520   Handle(HYDROData_PolylineXY) aPrevAxis = GetHydraulicAxis();
521   if ( aPrevAxis.IsNull() )
522     return;
523
524   ClearReferenceObjects( DataTag_HydraulicAxis );
525
526   // We remove the reference profiles
527   RemoveProfiles();
528
529   // Indicate model of the need to update the stream presentation
530   SetToUpdate( true );
531 }
532
533 bool HYDROData_Stream::HasIntersection( const Handle(HYDROData_Profile)& theProfile,
534                                         const TopoDS_Face&               thePlane,
535                                         Standard_Real&                   theOutPar ) const
536 {
537   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
538   return HasIntersection( aHydAxis, theProfile, thePlane, theOutPar );
539 }
540
541 bool HYDROData_Stream::HasIntersection( const Handle(HYDROData_PolylineXY)& theHydAxis, 
542                                         const Handle(HYDROData_Profile)&    theProfile, 
543                                         const TopoDS_Face&                  thePlane,
544                                         Standard_Real&                      theOutPar )
545 {
546   if ( theProfile.IsNull() || !IsValidAsAxis( theHydAxis ) )
547     return false; 
548
549   TopoDS_Wire aHydraulicWire = TopoDS::Wire( theHydAxis->GetShape() ); //guide line
550   TopoDS_Wire aProfileWire = TopoDS::Wire( theProfile->GetTopShape() );
551   if ( aHydraulicWire.IsNull() || aProfileWire.IsNull() )
552     return false;
553
554   BRepProj_Projection aProjector (aProfileWire, thePlane, gp::OZ().Direction());
555   if(!aProjector.IsDone())
556     return false;
557   TopoDS_Shape aPrjProfile = aProjector.Shape();
558   if(aPrjProfile.IsNull())
559     return false;
560   TopoDS_Vertex aV1, aV2;
561   if(aPrjProfile.ShapeType() == TopAbs_EDGE)
562     TopExp::Vertices(TopoDS::Edge(aPrjProfile), aV1, aV2);
563   else if(aPrjProfile.ShapeType() == TopAbs_WIRE)  
564     TopExp::Vertices(TopoDS::Wire(aPrjProfile), aV1, aV2);
565   else if(aPrjProfile.ShapeType() == TopAbs_COMPOUND){
566     TopExp_Explorer anExp(aPrjProfile, TopAbs_WIRE);
567     if(anExp.More()) {
568       TopExp::Vertices(TopoDS::Wire(anExp.Current()), aV1, aV2);
569     } else {
570       anExp.Init(aPrjProfile, TopAbs_EDGE);
571       if(anExp.More()) {
572         TopExp::Vertices(TopoDS::Edge(anExp.Current()), aV1, aV2);
573       }
574     }
575   }
576   if(aV1.IsNull() || aV2.IsNull())
577     return false;
578   gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
579   gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
580   aPnt1.SetZ(0.0);
581   aPnt2.SetZ(0.0);
582   BRepBuilderAPI_MakeEdge aMk(aPnt1, aPnt2); 
583   if(!aMk.IsDone())
584     return false;
585   const TopoDS_Edge& anEdg2 = aMk.Edge();//Section edge
586   Standard_Integer aNum(0);
587   
588   TopExp_Explorer anExplo(aHydraulicWire, TopAbs_EDGE);
589   for(;anExplo.More();anExplo.Next()) aNum++;
590   // check for self-intersection
591   const Standard_Real SquareTolerance = Precision::Confusion()*Precision::Confusion();
592   Standard_Boolean hasInt(false);
593   Standard_Real aSqDist(DBL_MAX);
594   Standard_Integer anIndx(0);
595   BRepExtrema_ExtCC aCC;
596   aCC.Initialize(anEdg2);
597   theOutPar = 0.0;
598   anExplo.Init(aHydraulicWire, TopAbs_EDGE);
599   for(Standard_Integer j=1;anExplo.More();anExplo.Next(),j++) {
600     const TopoDS_Edge& anEdg1 = TopoDS::Edge(anExplo.Current());
601     if(anEdg1.IsNull())
602       continue;
603     Standard_Boolean hasSol(false);
604     aCC.Perform(anEdg1);
605     if(aCC.IsDone()) {
606     // find minimal dist
607     for(Standard_Integer i=1; i<= aCC.NbExt();i++)
608       if(aCC.SquareDistance(i) < aSqDist) {
609         aSqDist = aCC.SquareDistance(i);
610         anIndx = i;
611         hasSol = true;
612       }  
613     }
614     if(hasSol) {
615       if(aSqDist <= SquareTolerance) { // hasInt
616         const gp_Pnt& aPnt = aCC.PointOnE1(anIndx);
617         if(aNum > 1) {
618           TopExp::Vertices(anEdg1, aV1, aV2, Standard_True);
619           theOutPar += BRep_Tool::Pnt(aV1).Distance(aPnt);
620         } else {
621           Standard_Real aPar = aCC.ParameterOnE1(anIndx);
622           theOutPar = aPar;
623         }
624         hasInt = true;
625         break;
626       } else {
627           // no ints-n
628         if(aNum > 1) {
629           TopExp::Vertices(anEdg1, aV1, aV2);
630           theOutPar += BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
631         }
632       }
633     } else if(aNum > 1) {
634       TopExp::Vertices(anEdg1, aV1, aV2);
635       theOutPar += BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
636     }
637   }
638   if(hasInt)
639     return true;
640   return false;
641 }
642
643 bool HYDROData_Stream::AddProfile( const Handle(HYDROData_Profile)& theProfile )
644 {
645   if ( theProfile.IsNull() )
646     return false;
647
648   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
649   if ( aHydAxis.IsNull() )
650     return false;
651
652   TopoDS_Face aPlane;
653   if(!BuildFace(aHydAxis, aPlane))
654     return false;
655
656   Standard_Real aPar(.0);
657   if ( HasReference( theProfile, DataTag_Profile ) || !HasIntersection( theProfile, aPlane, aPar ) )
658     return false; // Object is already in reference list or it has no intersection
659   
660   int aProfileIndex = insertParameter( aPar );
661   insertProfileInToOrder( theProfile, aProfileIndex );
662   
663   // Indicate model of the need to update the stream presentation
664   SetToUpdate( true );
665
666   return true;
667 }
668
669 bool HYDROData_Stream::SetProfiles( const HYDROData_SequenceOfObjects& theProfiles,
670                                     const bool&                        theIsToOrder )
671 {
672   if ( theIsToOrder )
673   {
674     for ( int i = 1; i <= theProfiles.Length(); ++i )
675     {
676       Handle(HYDROData_Profile) aProfile = 
677         Handle(HYDROData_Profile)::DownCast( theProfiles.Value( i ) );
678       if ( aProfile.IsNull() )
679         continue;
680
681       if ( !AddProfile( aProfile ) )
682         return false;
683     }
684   }
685   else // Just store the sequence of objects as is
686   {
687     bool anIsToUpdate = true;
688
689     HYDROData_SequenceOfObjects anOldProfiles = GetProfiles();
690     if ( anOldProfiles.Length() == theProfiles.Length() )
691     {
692       anIsToUpdate = false;
693
694       for ( int i = 1; i <= theProfiles.Length(); ++i )
695       {
696         Handle(HYDROData_Entity) anOldProfile = anOldProfiles.Value( i );
697         Handle(HYDROData_Entity) aNewProfile = theProfiles.Value( i );
698         if ( !IsEqual( anOldProfile, aNewProfile ) )
699         {
700           anIsToUpdate = true;
701           break;
702         }
703       }
704     }
705     
706     SetReferenceObjects( theProfiles, DataTag_Profile );
707
708     if ( anIsToUpdate )
709       SetToUpdate( true );
710   }
711
712   return true;
713 }
714
715 HYDROData_SequenceOfObjects HYDROData_Stream::GetProfiles() const
716 {
717   return GetReferenceObjects( DataTag_Profile );
718 }
719
720 bool HYDROData_Stream::RemoveProfile( const Handle(HYDROData_Profile)& theProfile )
721 {
722   if ( theProfile.IsNull() )
723     return false;
724
725   int aProfileIndex = -1;
726
727   HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
728   HYDROData_SequenceOfObjects::Iterator anIter( aRefProfiles );
729   for ( int i = 0 ; anIter.More(); anIter.Next(), ++i )
730   {
731     Handle(HYDROData_Profile) aProfile =
732       Handle(HYDROData_Profile)::DownCast( anIter.Value() );
733     if ( aProfile.IsNull() )
734       continue;
735
736     if ( IsEqual( theProfile, aProfile ) )
737     {
738       aProfileIndex = i;
739       break;
740     }
741   }
742
743   if ( aProfileIndex == -1 )
744     return false;
745
746   RemoveReferenceObject( theProfile->Label(), DataTag_Profile );
747
748   // Remove parameter for removed profile
749   removeParameter( aProfileIndex );
750
751   // Indicate model of the need to update the stream presentation
752   SetToUpdate( true );
753
754   return true;
755 }
756
757 void HYDROData_Stream::RemoveProfiles()
758 {
759   bool anIsToUpdate = IsMustBeUpdated() || NbReferenceObjects( DataTag_Profile ) > 0;
760
761   ClearReferenceObjects( DataTag_Profile );
762
763   // Remove the parameters array
764   removeParametersArray();
765
766   // Indicate model of the need to update the stream presentation
767   SetToUpdate( anIsToUpdate );
768 }
769
770 void HYDROData_Stream::insertProfileInToOrder( const Handle(HYDROData_Profile)& theProfile,
771                                                const int                        theBeforeIndex )
772 {
773   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
774   if ( theProfile.IsNull() || aHydAxis.IsNull() )
775     return; 
776
777   TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() );
778   TopoDS_Wire aProfileWire = TopoDS::Wire( theProfile->GetTopShape() );
779   if ( aHydraulicWire.IsNull() || aProfileWire.IsNull() )
780     return;
781
782   if ( theBeforeIndex == -1 )
783     AddReferenceObject( theProfile, DataTag_Profile );
784   else
785     InsertReferenceObject( theProfile, DataTag_Profile, theBeforeIndex );
786 }
787
788 bool HYDROData_Stream::BuildFace( const Handle(HYDROData_PolylineXY)& theHydAxis,
789                                   TopoDS_Face&                        thePlane )
790 {
791   if ( !IsValidAsAxis( theHydAxis ) )
792     return false;
793
794   TopoDS_Wire aHydraulicWire = TopoDS::Wire( theHydAxis->GetShape() );
795
796   gp_Ax2 aX2(gp::XOY());
797   gp_Ax3 aX3(aX2);
798   gp_Pln aPln(aX3);   
799   Bnd_Box B;
800   BRepBndLib::Add(aHydraulicWire,B);
801   Standard_Real axmin,aymin,azmin,axmax,aymax,azmax;
802   B.Get(axmin,aymin,azmin,axmax,aymax,azmax);
803   BRepBuilderAPI_MakeFace aMkr(aPln, axmin-500., axmax+500., aymin-500., aymax+500.); // to be tuned later according max/ Profile deviation
804   if(!aMkr.IsDone() || aMkr.Shape().IsNull()) return false;
805   thePlane = TopoDS::Face(aMkr.Shape());
806   return true;
807 }
808
809 void HYDROData_Stream::updateProfilesOrder()
810 {
811   HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
812   if ( aRefProfiles.IsEmpty() )
813     return;
814
815   // At first we remove all profiles from order
816   RemoveProfiles();
817
818   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
819   if ( aHydAxis.IsNull() )
820     return; 
821
822   TopoDS_Face aPlane;
823   if ( !BuildFace( aHydAxis, aPlane ) )
824     return;
825
826   Standard_Real aPar( .0 );
827
828 #ifdef DEB_HASINT
829   BRep_Builder aBB;
830   TopoDS_Compound aCmp;
831   aBB.MakeCompound(aCmp);
832 #endif
833
834   HYDROData_DataMapOfRealOfHDProfile aDM;  
835   TColStd_ListOfReal aList;
836   HYDROData_SequenceOfObjects::Iterator anIter( aRefProfiles );
837   for (int i = 1 ; anIter.More(); anIter.Next(), i++ )
838   {
839     Handle(HYDROData_Profile) aProfile =
840       Handle(HYDROData_Profile)::DownCast( anIter.Value() );
841 #ifdef DEB_HASINT
842   TopoDS_Wire aProfileWire = TopoDS::Wire( aProfile->GetTopShape() );
843   aBB.Add( aCmp, aProfileWire ); 
844 #endif
845     if ( aProfile.IsNull() || !HasIntersection( aProfile, aPlane, aPar ) )
846       continue;
847     
848     aDM.Bind( aPar, aProfile );
849     aList.Append( aPar );
850   }
851   
852   if ( aList.IsEmpty() )
853     return;
854
855   TColStd_Array1OfReal anArr( 1, aList.Extent() );
856
857   TColStd_ListIteratorOfListOfReal it( aList );
858   for ( int j = 1; it.More(); it.Next(), j++ )
859     anArr( j ) = it.Value();
860
861   // sorting
862   if ( aList.Extent() > 1 )
863   {
864     TCollection_CompareOfReal Compar;
865     SortTools_QuickSortOfReal::Sort( anArr, Compar );
866
867     for (int j = 1; j <= anArr.Length(); j++) {
868       const Standard_Real aKey =  anArr(j);
869       const Handle(HYDROData_Profile)& aProfile = aDM.Find(aKey);
870       insertProfileInToOrder( aProfile );
871     }
872   } else if ( aList.Extent() == 1 ) {
873      const Standard_Real aKey = aList.Last();
874      const Handle(HYDROData_Profile)& aProfile = aDM.Find(aKey);
875      insertProfileInToOrder( aProfile );
876   } 
877
878   setParametersArray( anArr );
879
880 #ifdef DEB_HASINT
881   TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() );
882   BRepTools::Write(aHydraulicWire, "Path.brep");
883   BRepTools::Write(aCmp, "Prof.brep");
884 #endif
885 }
886
887 ObjectKind HYDROData_Stream::getAltitudeObjectType() const
888 {
889   return KIND_STREAM_ALTITUDE;
890 }
891
892 void HYDROData_Stream::setParametersArray( const TColStd_Array1OfReal& theArray )
893 {
894   if ( theArray.Length() == 0 )
895   {
896     removeParametersArray();
897     return;
898   }
899
900   TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray );
901   
902   Handle(TDataStd_RealArray) aParamsArray = 
903     TDataStd_RealArray::Set( aLabel, theArray.Lower(), theArray.Upper() );
904
905   for ( int i = theArray.Lower(), n = theArray.Upper(); i <= n; ++i )
906   {
907     const Standard_Real& aParam = theArray( i );
908     aParamsArray->SetValue( i, aParam );
909   }
910 }
911
912 TColStd_Array1OfReal* HYDROData_Stream::getParametersArray() const
913 {
914   TColStd_Array1OfReal* anArray = NULL;
915
916   TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray, false );
917   if ( !aLabel.IsNull() )
918   {
919     Handle(TDataStd_RealArray) aParamsArray;
920     if ( aLabel.FindAttribute( TDataStd_RealArray::GetID(), aParamsArray ) )
921     {
922       anArray = new TColStd_Array1OfReal( aParamsArray->Lower(), aParamsArray->Upper() );
923       for ( int i = aParamsArray->Lower(), n = aParamsArray->Upper(); i <= n; ++i )
924       {
925         const Standard_Real& aParam = aParamsArray->Value( i );
926         anArray->SetValue( i, aParam );
927       }
928     }
929   }
930
931   return anArray;
932 }
933
934 void HYDROData_Stream::removeParametersArray()
935 {
936   TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray, false );
937   if ( !aLabel.IsNull() )
938     aLabel.ForgetAllAttributes();
939 }
940
941 int HYDROData_Stream::insertParameter( const Standard_Real& theParam )
942 {
943   int aResIndex = -1;
944
945   TColStd_Array1OfReal* anArr = getParametersArray();
946   if ( anArr )
947   {
948     aResIndex = 0;
949
950     TColStd_Array1OfReal aNewArr( anArr->Lower(), anArr->Upper() + 1 );
951
952     bool isInserted = false;
953     for ( int i = anArr->Lower(), j = i, n = anArr->Upper(); i <= n; ++i, ++j )
954     {
955       const Standard_Real& aStoredParam = anArr->Value( i );
956       if ( !isInserted )
957       {
958         if ( theParam > aStoredParam )
959         {
960           aResIndex++;
961         }
962         else
963         {
964           aNewArr( j ) = theParam;
965           isInserted = true;
966           ++j;
967         }
968       }
969
970       aNewArr( j ) = aStoredParam;
971     }
972
973     if ( !isInserted )
974     {
975       aResIndex = -1;
976       aNewArr( aNewArr.Upper() ) = theParam;
977     }
978     
979     setParametersArray( aNewArr );
980     delete anArr;
981   }
982   else
983   {
984     TColStd_Array1OfReal aNewArr( 1, 1 );
985     aNewArr.SetValue( 1, theParam );
986     setParametersArray( aNewArr );
987   }
988
989   return aResIndex;
990 }
991
992 void HYDROData_Stream::removeParameter( const int& theIndex )
993 {
994   TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray, false );
995   if ( aLabel.IsNull() )
996     return;
997
998   Handle(TDataStd_RealArray) aParamsArray;
999   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), aParamsArray ) )
1000     return;
1001
1002   if ( aParamsArray->Length() == 1 )
1003   {
1004     removeParametersArray();
1005     return;
1006   }
1007
1008   TColStd_Array1OfReal aNewArr( aParamsArray->Lower(), aParamsArray->Upper() - 1 );
1009
1010   for ( int i = aParamsArray->Lower(), j = i, k = 0, n = aParamsArray->Upper(); i <= n; ++i, ++k )
1011   {
1012     const Standard_Real& aStoredParam = aParamsArray->Value( i );
1013     if ( k == theIndex )
1014       continue;
1015
1016     aNewArr.SetValue( j, aStoredParam );
1017     ++j;
1018   }
1019
1020   setParametersArray( aNewArr );
1021 }
1022
1023 bool HYDROData_Stream::GenerateBottomPolyline()
1024 {
1025   // Get the document
1026   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
1027   if ( aDocument.IsNull() ) {
1028     return false;
1029   }
1030
1031   // Collect bottom points ( one bottom point from each profile of the stream )
1032   HYDROData_Profile::ProfilePoints aBottomPoints;
1033   
1034   HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles();
1035   for ( int i = 1, aNb = aSeqOfProfiles.Size(); i <= aNb; i++ ) {
1036     const Handle(HYDROData_Profile) aProfile = 
1037       Handle(HYDROData_Profile)::DownCast( aSeqOfProfiles.Value( i ) );
1038     if ( aProfile.IsNull() ) {
1039       continue;
1040     }
1041     
1042     aBottomPoints.Append( aProfile->GetBottomPoint() );
1043   }
1044
1045   int aNbBottomPoints = aBottomPoints.Size();
1046
1047   if ( aNbBottomPoints < 2 ) {
1048     return false;
1049   }
1050
1051   // Create bottom polyline object if the stream doesn't contain it yet
1052   Handle(HYDROData_Polyline3D) aBottom = GetBottomPolyline();
1053   if ( aBottom.IsNull() ) {
1054     aBottom = Handle(HYDROData_Polyline3D)::DownCast( aDocument->CreateObject( KIND_POLYLINE ) );  
1055     QString aBaseName = GetName() + "_bottom";
1056     QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName, QStringList(), true );
1057     aBottom->SetName( aName );
1058
1059     SetReferenceObject( aBottom, DataTag_BottomPolyline );
1060   }
1061   
1062   // Create 2D polyline if the bottom polyline doesn't contain it yet
1063   Handle(HYDROData_PolylineXY) aPolylineXY = aBottom->GetPolylineXY();
1064   if ( aPolylineXY.IsNull() ) {
1065     aPolylineXY = Handle(HYDROData_PolylineXY)::DownCast( aDocument->CreateObject( KIND_POLYLINEXY ) );
1066     QString aBaseName = GetName() + "_bottom_2d";
1067     QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName, QStringList(), true );
1068     aPolylineXY->SetName( aName );
1069     aBottom->SetPolylineXY( aPolylineXY, false );
1070   }
1071
1072   aPolylineXY->RemoveSections();
1073   aPolylineXY->AddSection( "", HYDROData_PolylineXY::SECTION_SPLINE, false );
1074   
1075   // Create profile if the bottom polyline doesn't contain it yet
1076   Handle(HYDROData_ProfileUZ) aProfileUZ = aBottom->GetProfileUZ();
1077   if ( aProfileUZ.IsNull() ) {
1078     Handle(HYDROData_Profile) aProfile = 
1079       Handle(HYDROData_Profile)::DownCast( aDocument->CreateObject( KIND_PROFILE ) );
1080     QString aBaseName = GetName() + "_bottom_profile";
1081     QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName, QStringList(), true );
1082     aProfile->SetName( aName );
1083     aProfileUZ = aProfile->GetProfileUZ( true );
1084     aBottom->SetProfileUZ( aProfileUZ );
1085   }
1086   
1087   aProfileUZ->RemoveSection( 0 );
1088
1089   // Fill 2D polyline
1090   for ( int i = 1; i <= aNbBottomPoints; i++ ) {
1091     const HYDROData_Profile::ProfilePoint& aBottomPoint = aBottomPoints.Value( i );
1092     aPolylineXY->AddPoint( 0, HYDROData_PolylineXY::Point( aBottomPoint.X(), aBottomPoint.Y() ) );
1093   }
1094   
1095   // Calculate profile UZ points
1096
1097   // First point
1098   const HYDROData_Profile::ProfilePoint& aFirstBottomPoint = aBottomPoints.First();
1099   aProfileUZ->AddPoint( 0, HYDROData_ProfileUZ::Point( 0, aFirstBottomPoint.Z() ) );
1100
1101   // Intermediate points
1102   double aPolylineCommonDist = aPolylineXY->GetDistance( 0, aPolylineXY->NbPoints( 0 ) - 1 );
1103
1104   for ( int i = 2, aNbPoints = aBottomPoints.Size(); i < aNbPoints; i++ ) {
1105     const HYDROData_Profile::ProfilePoint& aBottomPoint = aBottomPoints.Value( i );
1106     
1107     double aDistance = aPolylineXY->GetDistance( 0, i - 1 );
1108     
1109     Standard_Real anU = aDistance; // = ( aDistance / aPolylineCommonDist ) * aPolylineCommonDist;
1110     aProfileUZ->AddPoint( 0, HYDROData_ProfileUZ::Point( anU, aBottomPoint.Z() ) );
1111   }
1112   
1113   // Last point
1114   const HYDROData_Profile::ProfilePoint& aLastBottomPoint = aBottomPoints.Last();
1115   aProfileUZ->AddPoint( 0, HYDROData_ProfileUZ::Point( aPolylineCommonDist, aLastBottomPoint.Z() ) );
1116   
1117   return true;
1118 }
1119
1120 Handle(HYDROData_Polyline3D) HYDROData_Stream::GetBottomPolyline() const
1121 {
1122   return Handle(HYDROData_Polyline3D)::DownCast( 
1123            GetReferenceObject( DataTag_BottomPolyline ) );
1124 }
1125
1126 bool HYDROData_Stream::SetBottomPolyline( const Handle(HYDROData_Polyline3D)& theBottom )
1127 {
1128   if ( theBottom.IsNull() ) {
1129     return false;
1130   }
1131
1132   SetReferenceObject( theBottom, DataTag_BottomPolyline );
1133
1134   return true;
1135 }
1136
1137 bool HYDROData_Stream::Interpolate( HYDROData_IProfilesInterpolator* theInterpolator )
1138 {
1139   // Get the document
1140   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
1141   if ( aDocument.IsNull() ) {
1142     return false;
1143   }
1144   
1145   if ( theInterpolator->GetCalculatedProfilesNumber() < 1 ) {
1146     theInterpolator->Calculate();
1147   }
1148
1149   if ( theInterpolator->GetErrorCode() != OK ) {
1150     return false;
1151   }
1152
1153   bool isOK = true;
1154
1155   for ( int aProfileInd = 0; aProfileInd < theInterpolator->GetCalculatedProfilesNumber(); aProfileInd++ ) {
1156     // Get calculated point coordinates
1157     HYDROData_Profile::ProfilePoints aResultPoints = theInterpolator->GetResultProfilePoints( aProfileInd );
1158     if ( aResultPoints.IsEmpty() ) {
1159       isOK = false;
1160       continue;
1161     }
1162         
1163     // Create profile object
1164     Handle(HYDROData_Profile) aProfile = 
1165       Handle(HYDROData_Profile)::DownCast( aDocument->CreateObject( KIND_PROFILE ) );
1166     QString aBaseName = GetName() + "_interp_profile";
1167     QString aName = HYDROData_Tool::GenerateObjectName( aDocument, aBaseName );
1168     aProfile->SetName( aName );
1169
1170     // Fill the profile with points
1171     aProfile->SetProfilePoints( aResultPoints );
1172
1173     // Add profile to the stream
1174     bool isAdded = AddProfile( aProfile );
1175     if ( !isAdded ) {
1176       aProfile->Remove();
1177     }
1178     else
1179       aProfile->Update();
1180   }
1181
1182   if ( isOK )
1183     Update();
1184
1185   return isOK;
1186 }