Salome HOME
6.12.2013.Fix of HasIntersection method.
[modules/hydro.git] / src / HYDROData / HYDROData_Stream.cxx
1
2 #include "HYDROData_Stream.h"
3
4 #include "HYDROData_Document.h"
5 #include "HYDROData_PolylineXY.h"
6 #include "HYDROData_Profile.h"
7
8 #include <BRep_Builder.hxx>
9 #include <BRepBuilderAPI_MakeEdge.hxx>
10 #include <BRepBuilderAPI_MakeWire.hxx>
11 #include <BRepBuilderAPI_MakeFace.hxx>
12
13 #include <TopoDS.hxx>
14 #include <TopoDS_Wire.hxx>
15 #include <TopoDS_Shell.hxx>
16 #include <TopoDS_Face.hxx>
17 #include <TopoDS_Edge.hxx>
18 #include <TopoDS_Vertex.hxx>
19 #include <TopExp.hxx>
20 #include <TopExp_Explorer.hxx>
21 #include <BRepProj_Projection.hxx>
22 #include <BRepExtrema_ExtCC.hxx>
23 #include <gp_Ax1.hxx>
24 #include <gp_Ax2.hxx>
25 #include <gp_Ax3.hxx>
26 #include <gp_Vec.hxx>
27 #include <gp_Pnt.hxx>
28 #include <gp_Pln.hxx>
29 #include <gp.hxx>
30 #include <Bnd_Box.hxx>
31 #include <BRepBndLib.hxx>
32 #include <TColStd_Array1OfReal.hxx>
33 #include <Precision.hxx>
34 #include <QStringList>
35
36 #include <NCollection_DataMap.hxx>
37 typedef NCollection_DataMap<Standard_Real, Handle(HYDROData_Profile)> HYDROData_DataMapOfRealOfHDProfile;
38 //typedef HYDROData_DataMapOfRealOfHDProfile::Iterator HYDROData_DataMapIteratorOfDataMapOfRealOfHDProfile;
39 #include <TColStd_ListOfReal.hxx>
40 #include <TColStd_ListIteratorOfListOfReal.hxx>
41 #include <TCollection_CompareOfReal.hxx>
42 #include <SortTools_QuickSortOfReal.hxx>
43 //#define DEB_HASINT 1
44 #ifdef DEB_HASINT
45 #include <BRepTools.hxx>
46 #include <TCollection_AsciiString.hxx>
47 #include <BRep_Builder.hxx>
48 #endif
49
50 #define PYTHON_STREAM_ID "KIND_STREAM"
51
52 IMPLEMENT_STANDARD_HANDLE(HYDROData_Stream,HYDROData_NaturalObject)
53 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Stream,HYDROData_NaturalObject)
54
55
56 HYDROData_Stream::HYDROData_Stream()
57 : HYDROData_NaturalObject()
58 {
59 }
60
61 HYDROData_Stream::~HYDROData_Stream()
62 {
63 }
64
65 QStringList HYDROData_Stream::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
66 {
67   QStringList aResList;
68
69   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
70   if ( aDocument.IsNull() )
71     return aResList;
72
73   QString aDocName = aDocument->GetDocPyName();
74   QString aStreamName = GetName();
75
76   aResList << QString( "%1 = %2.CreateObject( %3 );" )
77               .arg( aStreamName ).arg( aDocName ).arg( PYTHON_STREAM_ID );
78   aResList << QString( "%1.SetName( \"%2\" );" )
79               .arg( aStreamName ).arg( aStreamName );
80   aResList << QString( "" );
81
82   // TODO
83
84   return aResList;
85 }
86
87 HYDROData_SequenceOfObjects HYDROData_Stream::GetAllReferenceObjects() const
88 {
89   HYDROData_SequenceOfObjects aResSeq = HYDROData_Object::GetAllReferenceObjects();
90
91   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
92   if ( !aHydAxis.IsNull() )
93     aResSeq.Append( aHydAxis );
94
95   HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles();
96   aResSeq.Append( aSeqOfProfiles );
97
98   return aResSeq;
99 }
100
101 TopoDS_Shape HYDROData_Stream::GetTopShape() const
102 {
103   return getTopShape();
104 }
105
106 TopoDS_Shape HYDROData_Stream::GetShape3D() const
107 {
108   return getShape3D();
109 }
110
111 void HYDROData_Stream::Update()
112 {
113   HYDROData_NaturalObject::Update();
114
115   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
116   HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
117   if ( aHydAxis.IsNull() || aRefProfiles.IsEmpty() )
118     return; 
119
120   TopoDS_Shell a2dShell;
121   BRep_Builder a2dShellBuilder;
122   a2dShellBuilder.MakeShell( a2dShell );
123
124   bool anIsFirst = true;
125   gp_Pnt aPrevFirstPoint, aPrevLastPoint;
126   
127   // Construct the top presentation
128   HYDROData_SequenceOfObjects::Iterator anIter( aRefProfiles );
129   for ( ; anIter.More(); anIter.Next() )
130   {
131     Handle(HYDROData_Profile) aProfile =
132       Handle(HYDROData_Profile)::DownCast( anIter.Value() );
133     if ( aProfile.IsNull() )
134       continue;
135
136     gp_XY aPnt1, aPnt2;
137     if ( !aProfile->GetFirstPoint( aPnt1 ) || !aProfile->GetLastPoint( aPnt2 ) )
138       continue;
139     
140     gp_Pnt aCurFirstPoint( aPnt1.X(), aPnt1.Y(), 0 );
141     gp_Pnt aCurLastPoint(  aPnt2.X(), aPnt2.Y(), 0 );
142
143     if ( anIsFirst )
144     {
145       aPrevFirstPoint = aCurFirstPoint;
146       aPrevLastPoint = aCurLastPoint;
147       anIsFirst = false;
148       continue;
149     }
150
151     BRepBuilderAPI_MakeEdge aFirstEdge( aPrevFirstPoint, aPrevLastPoint );
152     BRepBuilderAPI_MakeEdge aSecondEdge( aPrevLastPoint, aCurLastPoint );
153     BRepBuilderAPI_MakeEdge aThirdEdge( aCurLastPoint, aCurFirstPoint );
154     BRepBuilderAPI_MakeEdge aFourthEdge( aCurFirstPoint, aPrevFirstPoint );
155
156     BRepBuilderAPI_MakeWire aMakeWire( aFirstEdge.Edge(), aSecondEdge.Edge(), 
157                                        aThirdEdge.Edge(), aFourthEdge.Edge() );
158     
159     TopoDS_Wire aSectProfileWire = aMakeWire.Wire();
160     
161     BRepBuilderAPI_MakeFace aMakeFace( aSectProfileWire, Standard_True );
162     aMakeFace.Build();
163     if( aMakeFace.IsDone() )
164     {
165       a2dShellBuilder.Add( a2dShell, aMakeFace.Face() );
166     }
167
168     aPrevFirstPoint = aCurFirstPoint;
169     aPrevLastPoint = aCurLastPoint;
170   }
171
172   SetTopShape( a2dShell );
173
174   // Construct the 3D presentation
175   /// TODO
176 }
177
178 bool HYDROData_Stream::SetHydraulicAxis( const Handle(HYDROData_PolylineXY)& theAxis )
179 {
180   Handle(HYDROData_PolylineXY) aPrevAxis = GetHydraulicAxis();
181
182   if ( theAxis.IsNull() )
183   {
184     RemoveHydraulicAxis();
185     return !aPrevAxis.IsNull();
186   }
187
188   if ( IsEqual( aPrevAxis, theAxis ) )
189     return false;
190
191   TopoDS_Wire aHydraulicWire = TopoDS::Wire( theAxis->GetShape() );
192   if ( aHydraulicWire.IsNull() )
193     return false; // The polyline must be a single wire
194
195   SetReferenceObject( theAxis, DataTag_HydraulicAxis );
196
197   // Update the order of profiles
198   updateProfilesOrder();
199
200   // Indicate model of the need to update the stream presentation
201   SetToUpdate( true );
202
203   return true;
204 }
205
206 Handle(HYDROData_PolylineXY) HYDROData_Stream::GetHydraulicAxis() const
207 {
208   return Handle(HYDROData_PolylineXY)::DownCast( 
209            GetReferenceObject( DataTag_HydraulicAxis ) );
210 }
211
212 void HYDROData_Stream::RemoveHydraulicAxis()
213 {
214   Handle(HYDROData_PolylineXY) aPrevAxis = GetHydraulicAxis();
215   if ( aPrevAxis.IsNull() )
216     return;
217
218   ClearReferenceObjects( DataTag_HydraulicAxis );
219
220   // We remove the reference profiles
221   RemoveProfiles();
222
223   // Indicate model of the need to update the stream presentation
224   SetToUpdate( true );
225 }
226
227 bool HYDROData_Stream::HasIntersection( const Handle(HYDROData_Profile)& theProfile, const TopoDS_Face& thePlane,
228                                                                            Standard_Real& outPar ) const
229 {
230   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
231   if ( theProfile.IsNull() || aHydAxis.IsNull() )
232     return false; 
233
234   TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() ); //guide line
235   TopoDS_Wire aProfileWire = TopoDS::Wire( theProfile->GetTopShape() );
236   if ( aHydraulicWire.IsNull() || aProfileWire.IsNull() )
237     return false;
238
239   // TODO
240   //return true; // temporary
241   BRepProj_Projection aProjector (aProfileWire, thePlane, gp::OZ().Direction());
242   if(!aProjector.IsDone())
243     return false;
244   TopoDS_Shape aPrjProfile = aProjector.Shape();
245   if(aPrjProfile.IsNull())
246     return false;
247   TopoDS_Vertex aV1, aV2;
248   if(aPrjProfile.ShapeType() == TopAbs_EDGE)
249           TopExp::Vertices(TopoDS::Edge(aPrjProfile), aV1, aV2);          
250   else if(aPrjProfile.ShapeType() == TopAbs_WIRE)  
251           TopExp::Vertices(TopoDS::Wire(aPrjProfile), aV1, aV2);          
252   else if(aPrjProfile.ShapeType() == TopAbs_COMPOUND){
253     TopExp_Explorer anExp(aPrjProfile, TopAbs_WIRE);
254         if(anExp.More()) {
255                 TopExp::Vertices(TopoDS::Wire(anExp.Current()), aV1, aV2);        
256         } else {
257           anExp.Init(aPrjProfile, TopAbs_EDGE);
258           if(anExp.More()) {
259                 TopExp::Vertices(TopoDS::Edge(anExp.Current()), aV1, aV2);        
260           }
261         }
262   }
263   if(aV1.IsNull() || aV2.IsNull())
264         return false;
265   gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
266   gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
267   aPnt1.SetZ(0.0);
268   aPnt2.SetZ(0.0);
269   BRepBuilderAPI_MakeEdge aMk(aPnt1, aPnt2); 
270   if(!aMk.IsDone())
271     return false;
272   const TopoDS_Edge& anEdg2 = aMk.Edge();//Section edge
273   Standard_Integer aNum(0);
274   
275   TopExp_Explorer anExplo(aHydraulicWire, TopAbs_EDGE);
276   for(;anExplo.More();anExplo.Next()) aNum++;
277   // check for self-intersection
278   const Standard_Real SquareTolerance = Precision::Confusion()*Precision::Confusion();
279   Standard_Boolean hasInt(false);
280   Standard_Real aSqDist(DBL_MAX);
281   Standard_Integer anIndx(0);
282   BRepExtrema_ExtCC aCC;
283   aCC.Initialize(anEdg2);
284   outPar = 0.0;
285   anExplo.Init(aHydraulicWire, TopAbs_EDGE);
286   for(Standard_Integer j=1;anExplo.More();anExplo.Next(),j++) {
287         const TopoDS_Edge& anEdg1 = TopoDS::Edge(anExplo.Current());
288         if(anEdg1.IsNull())
289           continue;     
290         Standard_Boolean hasSol(false);
291         aCC.Perform(anEdg1);
292     if(aCC.IsDone()) {
293         // find minimal dist
294     for(Standard_Integer i=1; i<= aCC.NbExt();i++)
295       if(aCC.SquareDistance(i) < aSqDist) {
296         aSqDist = aCC.SquareDistance(i);
297         anIndx = i;
298                 hasSol = true;          
299           }  
300         }
301         if(hasSol) {   
302                 if(aSqDist <= SquareTolerance) { // hasInt
303         const gp_Pnt& aPnt = aCC.PointOnE1(anIndx);
304         if(aNum > 1) {
305           TopExp::Vertices(anEdg1, aV1, aV2, Standard_True);
306                   outPar += BRep_Tool::Pnt(aV1).Distance(aPnt);
307             } else {
308           Standard_Real aPar = aCC.ParameterOnE1(anIndx);
309                   outPar = aPar;
310             }
311                 hasInt = true;
312             break;
313                 } else {
314                   // no ints-n
315         if(aNum > 1) {
316           TopExp::Vertices(anEdg1, aV1, aV2);
317               outPar += BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
318             }
319           }
320         } else if(aNum > 1) {
321           TopExp::Vertices(anEdg1, aV1, aV2);
322               outPar += BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
323         }
324   }
325   if(hasInt)
326     return true;
327   return false;
328 }
329
330 bool HYDROData_Stream::AddProfile( const Handle(HYDROData_Profile)& theProfile )
331 {
332   if ( theProfile.IsNull() )
333     return false;  
334   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
335   if ( aHydAxis.IsNull() )
336     return false; 
337   TopoDS_Face aPlane;
338   if(!BuildFace(aHydAxis, aPlane))
339     return false;
340   Standard_Real aPar(.0);
341   if ( HasReference( theProfile, DataTag_Profile ) || !HasIntersection( theProfile, aPlane, aPar ) )
342     return false; // Object is already in reference list or it has no intersection
343   
344   insertProfileInToOrder( theProfile );
345   
346   // Indicate model of the need to update the stream presentation
347   SetToUpdate( true );
348
349   return true;
350 }
351
352 HYDROData_SequenceOfObjects HYDROData_Stream::GetProfiles() const
353 {
354   return GetReferenceObjects( DataTag_Profile );
355 }
356
357 bool HYDROData_Stream::RemoveProfile( const Handle(HYDROData_Profile)& theProfile )
358 {
359   if ( theProfile.IsNull() || !HasReference( theProfile, DataTag_Profile ) )
360     return false;
361
362   RemoveReferenceObject( theProfile->Label(), DataTag_Profile );
363
364   // Indicate model of the need to update the stream presentation
365   SetToUpdate( true );
366
367   return true;
368 }
369
370 void HYDROData_Stream::RemoveProfiles()
371 {
372   bool anIsToUpdate = IsMustBeUpdated() || NbReferenceObjects( DataTag_Profile ) > 0;
373
374   ClearReferenceObjects( DataTag_Profile );
375
376   // Indicate model of the need to update the stream presentation
377   SetToUpdate( anIsToUpdate );
378 }
379
380 void HYDROData_Stream::insertProfileInToOrder( const Handle(HYDROData_Profile)& theProfile )
381 {
382   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
383   if ( theProfile.IsNull() || aHydAxis.IsNull() )
384     return; 
385
386   TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() );
387   TopoDS_Wire aProfileWire = TopoDS::Wire( theProfile->GetTopShape() );
388   if ( aHydraulicWire.IsNull() || aProfileWire.IsNull() )
389     return;
390
391   // TODO
392   AddReferenceObject( theProfile, DataTag_Profile ); // temporary for testing only
393 }
394
395 bool HYDROData_Stream::BuildFace( const Handle(HYDROData_PolylineXY)& theHydAxis, TopoDS_Face& thePlane) const
396 {
397   if ( theHydAxis.IsNull() ) return false;
398   TopoDS_Wire aHydraulicWire = TopoDS::Wire( theHydAxis->GetShape() );
399   if(aHydraulicWire.IsNull()) return false;
400   gp_Ax2 aX2(gp::XOY());
401   gp_Ax3 aX3(aX2);
402   gp_Pln aPln(aX3);   
403   Bnd_Box B;
404   BRepBndLib::Add(aHydraulicWire,B);
405   Standard_Real axmin,aymin,azmin,axmax,aymax,azmax;
406   B.Get(axmin,aymin,azmin,axmax,aymax,azmax);
407   BRepBuilderAPI_MakeFace aMkr(aPln, axmin-500., axmax+500., aymin-500., aymax+500.); // to be tuned later according max/ Profile deviation
408   if(!aMkr.IsDone() || aMkr.Shape().IsNull()) return false;
409   thePlane = TopoDS::Face(aMkr.Shape());
410   return true;
411 }
412 void HYDROData_Stream::updateProfilesOrder()
413 {
414   HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
415   if ( aRefProfiles.IsEmpty() )
416     return;
417
418   // At first we remove all profiles from order
419   RemoveProfiles();
420
421   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
422   if ( aHydAxis.IsNull() )
423     return; 
424   TopoDS_Face aPlane;
425   if(!BuildFace(aHydAxis, aPlane))
426     return;
427   Standard_Real aPar(.0);
428 #ifdef DEB_HASINT
429   BRep_Builder aBB;
430   TopoDS_Compound aCmp;
431   aBB.MakeCompound(aCmp);
432 #endif
433   HYDROData_DataMapOfRealOfHDProfile aDM;  
434   TColStd_ListOfReal aList;
435   HYDROData_SequenceOfObjects::Iterator anIter( aRefProfiles );
436   for (int i = 1 ; anIter.More(); anIter.Next(), i++ )
437   {
438     Handle(HYDROData_Profile) aProfile =
439       Handle(HYDROData_Profile)::DownCast( anIter.Value() );
440 #ifdef DEB_HASINT
441   TopoDS_Wire aProfileWire = TopoDS::Wire( aProfile->GetTopShape() );
442   aBB.Add( aCmp, aProfileWire);
443 #endif
444     if ( aProfile.IsNull() || !HasIntersection( aProfile, aPlane, aPar ) )
445       continue;
446         aDM.Bind(aPar, aProfile);
447         aList.Append(aPar);
448     //insertProfileInToOrder( aProfile );
449   }
450    // sorting
451   if(aList.Extent() > 1) {
452    TColStd_Array1OfReal anArr(1, aList.Extent());  
453    TColStd_ListIteratorOfListOfReal it(aList);
454    for (int j=1;it.More();it.Next(), j++)
455      anArr(j) = it.Value();
456    TCollection_CompareOfReal Compar;
457    SortTools_QuickSortOfReal::Sort( anArr, Compar);
458    for (int j = 1; j <= anArr.Length(); j++) {
459      const Standard_Real aKey =  anArr(j);
460      const Handle(HYDROData_Profile)& aProfile = aDM.Find(aKey);
461      insertProfileInToOrder( aProfile );
462    }
463   } else if(aList.Extent() == 1) {
464      const Standard_Real aKey = aList.Last();
465      const Handle(HYDROData_Profile)& aProfile = aDM.Find(aKey);
466      insertProfileInToOrder( aProfile );
467   } 
468
469 #ifdef DEB_HASINT
470   TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() );
471   BRepTools::Write(aHydraulicWire, "Path.brep");
472   BRepTools::Write(aCmp, "Prof.brep");
473 #endif
474 }
475