Salome HOME
6.12.2013.Fix of HasIntersection method.
[modules/hydro.git] / src / HYDROData / HYDROData_CalculationCase.cxx
1
2 #include "HYDROData_CalculationCase.h"
3
4 #include "HYDROData_ArtificialObject.h"
5 #include "HYDROData_Document.h"
6 #include "HYDROData_Iterator.h"
7 #include "HYDROData_NaturalObject.h"
8 #include "HYDROData_PolylineXY.h"
9 #include "HYDROData_SplitToZonesTool.h"
10 #include "HYDROData_Region.h"
11 #include "HYDROData_Tool.h"
12 #include "HYDROData_Zone.h"
13
14 #include <TopoDS.hxx>
15 #include <TopoDS_Shell.hxx>
16 #include <BRep_Builder.hxx>
17 #include <BRepBuilderAPI_Sewing.hxx>
18 #include <TopExp_Explorer.hxx>
19 #include <TopExp.hxx>
20 #include <TopTools_ListOfShape.hxx>
21 #include <TopTools_ListIteratorOfListOfShape.hxx>
22
23 #define CALCULATION_REGIONS_PREF GetName() + "_Reg"
24 #define CALCULATION_ZONES_PREF GetName() + "_Zone"
25
26 #define PYTHON_CALCULATION_ID "KIND_CALCULATION"
27
28 IMPLEMENT_STANDARD_HANDLE(HYDROData_CalculationCase, HYDROData_Entity)
29 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_CalculationCase, HYDROData_Entity)
30
31 HYDROData_CalculationCase::HYDROData_CalculationCase()
32 : HYDROData_Entity()
33 {
34 }
35
36 HYDROData_CalculationCase::~HYDROData_CalculationCase()
37 {
38 }
39
40 void HYDROData_CalculationCase::SetName( const QString& theName )
41 {
42   QString anOldCaseName = GetName();
43   if ( anOldCaseName != theName )
44   {
45     HYDROData_SequenceOfObjects aRegions = GetRegions();
46
47     HYDROData_SequenceOfObjects::Iterator anIter( aRegions );
48     for ( ; anIter.More(); anIter.Next() )
49     {
50       Handle(HYDROData_Region) aRegion =
51         Handle(HYDROData_Region)::DownCast( anIter.Value() );
52       if ( aRegion.IsNull() )
53         continue;
54
55       QString aRegionName = aRegion->GetName();
56       if ( aRegionName.startsWith( anOldCaseName ) )
57       {
58         aRegionName.replace( anOldCaseName, theName );
59         aRegion->SetName( aRegionName );
60       }
61
62       HYDROData_SequenceOfObjects aZones = aRegion->GetZones();
63       HYDROData_SequenceOfObjects::Iterator anIter( aZones );
64       for ( ; anIter.More(); anIter.Next() )
65       {
66         Handle(HYDROData_Zone) aRegZone =
67           Handle(HYDROData_Zone)::DownCast( anIter.Value() );
68         if ( aRegZone.IsNull() )
69           continue;
70
71         QString aRegionZoneName = aRegZone->GetName();
72         if ( aRegionZoneName.startsWith( anOldCaseName ) )
73         {
74           aRegionZoneName.replace( anOldCaseName, theName );
75           aRegZone->SetName( aRegionZoneName );
76         }
77       }
78     }
79   }
80
81   HYDROData_Entity::SetName( theName );
82 }
83
84 QStringList HYDROData_CalculationCase::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
85 {
86   QStringList aResList;
87
88   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
89   if ( aDocument.IsNull() )
90     return aResList;
91                              
92   QString aDocName = aDocument->GetDocPyName();
93   QString aCalculName = GetName();
94
95   aResList << QString( "%1 = %2.CreateObject( %3 );" )
96               .arg( aCalculName ).arg( aDocName ).arg( PYTHON_CALCULATION_ID );
97   aResList << QString( "%1.SetName( \"%2\" );" )
98               .arg( aCalculName ).arg( aCalculName );
99   aResList << QString( "" );
100
101   HYDROData_SequenceOfObjects aGeomObjects = GetGeometryObjects();
102   HYDROData_SequenceOfObjects::Iterator anIter( aGeomObjects );
103   for ( ; anIter.More(); anIter.Next() )
104   {
105     Handle(HYDROData_Object) aRefGeomObj =
106       Handle(HYDROData_Object)::DownCast( anIter.Value() );
107     if ( !aRefGeomObj.IsNull() )
108       setPythonReferenceObject( theTreatedObjects, aResList, aRefGeomObj, "AddGeometryObject" );
109   }
110   aResList << QString( "" );
111
112   aResList << QString( "%1.SplitGeometryObjects();" ).arg( aCalculName );
113   aResList << QString( "" );
114
115   // Now we restore the regions and zones order
116   HYDROData_SequenceOfObjects aRegions = GetRegions();
117   anIter.Init( aRegions );
118   for ( ; anIter.More(); anIter.Next() )
119   {
120     Handle(HYDROData_Region) aRegion =
121       Handle(HYDROData_Region)::DownCast( anIter.Value() );
122     if ( aRegion.IsNull() )
123       continue;
124
125     QString aRegionName = aRegion->GetName();
126     // TODO
127   }
128
129   return aResList;
130 }
131
132 HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetAllReferenceObjects() const
133 {
134   HYDROData_SequenceOfObjects aResSeq = HYDROData_Entity::GetAllReferenceObjects();
135
136   Handle(HYDROData_PolylineXY) aBoundaryPolyline = GetBoundaryPolyline();
137   if ( !aBoundaryPolyline.IsNull() )
138     aResSeq.Append( aBoundaryPolyline );
139
140   HYDROData_SequenceOfObjects aSeqOfRegions = GetRegions();
141   aResSeq.Append( aSeqOfRegions );
142
143   return aResSeq;
144 }
145
146 void HYDROData_CalculationCase::Update()
147 {
148   HYDROData_Entity::Update();
149
150   // At first we remove previously created regions
151   RemoveRegions();
152
153   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
154   if ( aDocument.IsNull() )
155     return;
156
157   Handle(HYDROData_PolylineXY) aBoundaryPolyline = GetBoundaryPolyline();
158   HYDROData_SequenceOfObjects aGeomObjects = GetGeometryObjects();
159   if ( aGeomObjects.IsEmpty() )
160     return;
161
162   HYDROData_SplitToZonesTool::SplitDataList aSplitedZones =
163     HYDROData_SplitToZonesTool::SplitToZones( aGeomObjects, aBoundaryPolyline );
164   if ( aSplitedZones.isEmpty() )
165     return;
166
167   QString aRegsPref = CALCULATION_REGIONS_PREF;
168   QString aZonesPref = CALCULATION_ZONES_PREF;
169
170   // Create result regions for case, by default one zone for one region
171   HYDROData_SplitToZonesTool::SplitDataListIterator anIter( aSplitedZones );
172   while( anIter.hasNext() )
173   {
174     const HYDROData_SplitToZonesTool::SplitData& aSplitData = anIter.next();
175
176     // Create new region
177     Handle(HYDROData_Region) aRegion = addNewRegion();
178
179     QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
180     aRegion->SetName( aRegionName );
181
182     // Add the zone for region
183     Handle(HYDROData_Zone) aRegionZone = aRegion->addNewZone();
184
185     QString aZoneName = HYDROData_Tool::GenerateObjectName( aDocument, aZonesPref );
186     aRegionZone->SetName( aZoneName );
187
188     aRegionZone->SetShape( aSplitData.Face() );
189
190     // Add the reference object for zone
191     for ( int i = 0, n = aSplitData.ObjectNames.length(); i < n; ++i )
192     {
193       const QString& anObjName = aSplitData.ObjectNames.at( i );
194       
195       Handle(HYDROData_Object) aRefObject = Handle(HYDROData_Object)::DownCast(
196         HYDROData_Tool::FindObjectByName( aDocument, anObjName ) );
197       if ( aRefObject.IsNull() )
198         continue;
199
200       aRegionZone->AddGeometryObject( aRefObject );
201     }
202   }
203 }
204
205 bool HYDROData_CalculationCase::AddGeometryObject( const Handle(HYDROData_Object)& theObject )
206 {
207   if ( !HYDROData_Tool::IsGeometryObject( theObject ) )
208     return false; // Wrong type of object
209
210   if ( HasReference( theObject, DataTag_GeometryObject ) )
211     return false; // Object is already in reference list
212
213   AddReferenceObject( theObject, DataTag_GeometryObject );
214   
215   // Indicate model of the need to update zones splitting
216   SetToUpdate( true );
217
218   return true;
219 }
220
221 HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetGeometryObjects() const
222 {
223   return GetReferenceObjects( DataTag_GeometryObject );
224 }
225
226 void HYDROData_CalculationCase::RemoveGeometryObject( const Handle(HYDROData_Object)& theObject )
227 {
228   if ( theObject.IsNull() )
229     return;
230
231   RemoveReferenceObject( theObject->Label(), DataTag_GeometryObject );
232
233   // Indicate model of the need to update zones splitting
234   SetToUpdate( true );
235 }
236
237 void HYDROData_CalculationCase::RemoveGeometryObjects()
238 {
239   ClearReferenceObjects( DataTag_GeometryObject );
240
241   // Indicate model of the need to update zones splitting
242   SetToUpdate( true );
243 }
244
245 void HYDROData_CalculationCase::SetBoundaryPolyline( const Handle(HYDROData_PolylineXY)& thePolyline )
246 {
247   Handle(HYDROData_PolylineXY) aPrevPolyline = GetBoundaryPolyline();
248
249   SetReferenceObject( thePolyline, DataTag_Polyline );
250
251   // Indicate model of the need to update zones splitting
252   SetToUpdate( !IsEqual( aPrevPolyline, thePolyline ) || IsMustBeUpdated() );
253 }
254
255 Handle(HYDROData_PolylineXY) HYDROData_CalculationCase::GetBoundaryPolyline() const
256 {
257   return Handle(HYDROData_PolylineXY)::DownCast( 
258            GetReferenceObject( DataTag_Polyline ) );
259 }
260
261 void HYDROData_CalculationCase::RemoveBoundaryPolyline()
262 {
263   Handle(HYDROData_PolylineXY) aPrevPolyline = GetBoundaryPolyline();
264
265   ClearReferenceObjects( DataTag_Polyline );
266
267   // Indicate model of the need to update zones splitting
268   SetToUpdate( !aPrevPolyline.IsNull() || IsMustBeUpdated() );
269 }
270
271 Handle(HYDROData_Region) HYDROData_CalculationCase::AddNewRegion( const Handle(HYDROData_Zone)& theZone )
272 {
273   Handle(HYDROData_Region) aNewRegion = addNewRegion();
274   if ( aNewRegion.IsNull() )
275     return aNewRegion;
276
277   // Generate new name for new region
278   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
279   if ( !aDocument.IsNull() )
280   {
281     QString aRegsPref = CALCULATION_REGIONS_PREF;
282
283     QString aNewRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
284     aNewRegion->SetName( aNewRegionName );
285   }
286
287   aNewRegion->AddZone( theZone );
288
289   return aNewRegion;
290 }
291
292 bool HYDROData_CalculationCase::AddRegion( const Handle(HYDROData_Region)& theRegion )
293 {
294   if ( theRegion.IsNull() )
295     return false;
296   
297   if ( HasReference( theRegion, DataTag_Region ) )
298     return false; // Object is already in reference list
299
300   // Move the region from other calculation
301   Handle(HYDROData_CalculationCase) aFatherCalc = 
302     Handle(HYDROData_CalculationCase)::DownCast( theRegion->GetFatherObject() );
303   if ( !aFatherCalc.IsNull() && aFatherCalc->Label() != myLab )
304   {
305     Handle(HYDROData_Region) aNewRegion = addNewRegion();
306     theRegion->CopyTo( aNewRegion );
307
308     aFatherCalc->RemoveRegion( theRegion );
309
310     theRegion->SetLabel( aNewRegion->Label() );
311   }
312   else
313   {
314     AddReferenceObject( theRegion, DataTag_Region );
315   }
316
317   return true;
318 }
319
320 HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetRegions() const
321 {
322   return GetReferenceObjects( DataTag_Region );
323 }
324
325 void HYDROData_CalculationCase::UpdateRegionsOrder()
326 {
327   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
328   if ( aDocument.IsNull() )
329     return;
330
331   HYDROData_SequenceOfObjects aRegions = GetRegions();
332
333   HYDROData_SequenceOfObjects::Iterator anIter( aRegions );
334   for ( ; anIter.More(); anIter.Next() )
335   {
336     Handle(HYDROData_Region) aRegion =
337       Handle(HYDROData_Region)::DownCast( anIter.Value() );
338     if ( aRegion.IsNull() )
339       continue;
340
341     aRegion->SetName( "" );
342   }
343
344   QString aRegsPref = CALCULATION_REGIONS_PREF;
345
346   anIter.Init( aRegions );
347   for ( ; anIter.More(); anIter.Next() )
348   {
349     Handle(HYDROData_Region) aRegion =
350       Handle(HYDROData_Region)::DownCast( anIter.Value() );
351     if ( aRegion.IsNull() )
352       continue;
353
354     QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
355     aRegion->SetName( aRegionName );
356   }
357 }
358
359 void HYDROData_CalculationCase::RemoveRegion( const Handle(HYDROData_Region)& theRegion )
360 {
361   if ( theRegion.IsNull() )
362     return;
363
364   RemoveReferenceObject( theRegion->Label(), DataTag_Region );
365
366   // Remove region from data model
367   Handle(HYDROData_CalculationCase) aFatherCalc = 
368     Handle(HYDROData_CalculationCase)::DownCast( theRegion->GetFatherObject() );
369   if ( !aFatherCalc.IsNull() && aFatherCalc->Label() == myLab )
370     theRegion->Remove();
371 }
372
373 void HYDROData_CalculationCase::RemoveRegions()
374 {
375   ClearReferenceObjects( DataTag_Region );
376   myLab.FindChild( DataTag_ChildRegion ).ForgetAllAttributes( true );
377 }
378
379 Handle(HYDROData_Region) HYDROData_CalculationCase::addNewRegion()
380 {
381   TDF_Label aNewLab = myLab.FindChild( DataTag_ChildRegion ).NewChild();
382
383   Handle(HYDROData_Region) aNewRegion =
384     Handle(HYDROData_Region)::DownCast( HYDROData_Iterator::CreateObject( aNewLab, KIND_REGION ) );
385   AddRegion( aNewRegion );
386
387   return aNewRegion;
388 }
389
390 TopoDS_Shell HYDROData_CalculationCase::GetShell()
391 {
392   TopoDS_Shell aShell;
393
394   TopTools_ListOfShape aFacesList;
395
396   // Make shell containing all region shapes
397   BRepBuilderAPI_Sewing aSewing( Precision::Confusion()*10.0 );
398
399   HYDROData_SequenceOfObjects aCaseRegions = GetRegions();
400   HYDROData_SequenceOfObjects::Iterator aRegionIter( aCaseRegions );
401   for ( ; aRegionIter.More(); aRegionIter.Next() ) {
402     Handle(HYDROData_Region) aRegion =
403       Handle(HYDROData_Region)::DownCast( aRegionIter.Value() );
404     if( aRegion.IsNull() ) {
405       continue;
406     }
407
408     TopoDS_Shape aRegionShape = aRegion->GetShape();
409     if( !aRegionShape.IsNull() ) {
410       if ( aRegionShape.ShapeType() == TopAbs_FACE ) {
411         TopoDS_Face aFace = TopoDS::Face( aRegionShape );
412         if ( !aFace.IsNull() ) {
413           aFacesList.Append( aFace );
414           aSewing.Add( aFace );
415         }
416       } else {
417         TopExp_Explorer anExp( aRegionShape, TopAbs_FACE );
418         for ( ; anExp.More(); anExp.Next() ) {
419           TopoDS_Face aFace = TopoDS::Face( anExp.Current() );
420           if ( !aFace.IsNull() ) {
421             aFacesList.Append( aFace );
422             aSewing.Add( aFace );
423           }
424         }
425       }
426     }
427   } // regions iterator
428   
429   aSewing.Perform();
430   TopoDS_Shape aSewedShape = aSewing.SewedShape();
431
432   if ( !aSewedShape.IsNull() )
433   {
434     if ( aSewedShape.ShapeType() == TopAbs_FACE && aCaseRegions.Length() ==1 ) {
435       // create shell from one face
436       BRep_Builder aBuilder;
437       aBuilder.MakeShell( aShell );
438       aBuilder.Add( aShell, aSewedShape);
439     } else {
440       TopExp_Explorer anExpShells( aSewedShape, TopAbs_SHELL );
441       Standard_Integer aNbOfShells = 0;
442       for ( ; anExpShells.More(); anExpShells.Next() ) {
443         aShell = TopoDS::Shell( anExpShells.Current() );
444         aNbOfShells++;
445       }
446
447       if ( aNbOfShells != 1 ) {
448         aShell.Nullify();
449         BRep_Builder aBuilder;
450         aBuilder.MakeShell( aShell );
451
452         TopExp_Explorer anExpFaces( aSewedShape, TopAbs_FACE );
453         for ( ; anExpFaces.More(); anExpFaces.Next() ) {
454           TopoDS_Face aFace = TopoDS::Face( anExpFaces.Current() );
455           if ( !aFace.IsNull() ) {
456             aBuilder.Add( aShell, aFace );
457           }
458         }
459       }
460     }
461   }
462
463   if ( !aShell.IsNull() ) {
464     TopTools_IndexedMapOfShape aMapOfFaces;
465     TopExp::MapShapes( aShell, TopAbs_FACE, aMapOfFaces );
466     if ( aMapOfFaces.Extent() != aFacesList.Extent() ) {
467       aShell.Nullify();
468       BRep_Builder aBuilder;
469       aBuilder.MakeShell( aShell );
470
471       TopTools_ListIteratorOfListOfShape anIter( aFacesList );
472       for ( ; anIter.More(); anIter.Next() ) {
473         TopoDS_Face aFace = TopoDS::Face( anIter.Value() );
474         aBuilder.Add( aShell, aFace );
475       }
476     }
477   }
478
479 /* TODO: old version
480   // Make shell
481   BRep_Builder aBuilder;
482   aBuilder.MakeShell( aShell );
483
484   // Make shell containing all region shapes
485   HYDROData_SequenceOfObjects aCaseRegions = GetRegions();
486   HYDROData_SequenceOfObjects::Iterator aRegionIter( aCaseRegions );
487   for ( ; aRegionIter.More(); aRegionIter.Next() ) {
488     Handle(HYDROData_Region) aRegion =
489       Handle(HYDROData_Region)::DownCast( aRegionIter.Value() );
490     if( aRegion.IsNull() ) {
491       continue;
492     }
493
494     TopoDS_Shape aRegionShape = aRegion->GetShape();
495
496     // Add shape (face or shell) corresponding to the region into the shell
497     if( !aRegionShape.IsNull() ) {
498       if ( aRegionShape.ShapeType() == TopAbs_FACE ) {
499         aBuilder.Add( aShell, aRegionShape );
500       } else {
501         TopExp_Explorer anExp( aRegionShape, TopAbs_FACE );
502         for( ; anExp.More(); anExp.Next() ) {
503           TopoDS_Face aFace = TopoDS::Face( anExp.Current() );
504           if( !aFace.IsNull() ) {
505             aBuilder.Add( aShell, aFace );
506           }
507         }
508       }
509     }
510   } // regions iterator
511 */
512
513   // Nullify shell if it is empty
514   if ( !aShell.IsNull() && !TopoDS_Iterator(aShell).More() ) {
515     aShell.Nullify();
516   }
517
518   return aShell;
519 }
520
521