Salome HOME
Bugs #113, 114: use polylines with several section and immersible zones made of such...
[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_Polyline.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 void HYDROData_CalculationCase::SplitGeometryObjects()
133 {
134   // At first we remove previously created regions
135   RemoveRegions();
136
137   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
138   if ( aDocument.IsNull() )
139     return;
140
141   Handle(HYDROData_Polyline) aBoundaryPolyline = GetBoundaryPolyline();
142   HYDROData_SequenceOfObjects aGeomObjects = GetGeometryObjects();
143   if ( aGeomObjects.IsEmpty() )
144     return;
145
146   HYDROData_SplitToZonesTool::SplitDataList aSplitedZones =
147     HYDROData_SplitToZonesTool::SplitToZones( aGeomObjects, aBoundaryPolyline );
148   if ( aSplitedZones.isEmpty() )
149     return;
150
151   QString aRegsPref = CALCULATION_REGIONS_PREF;
152   QString aZonesPref = CALCULATION_ZONES_PREF;
153
154   // Create result regions for case, by default one zone for one region
155   HYDROData_SplitToZonesTool::SplitDataListIterator anIter( aSplitedZones );
156   while( anIter.hasNext() )
157   {
158     const HYDROData_SplitToZonesTool::SplitData& aSplitData = anIter.next();
159
160     // Create new region
161     Handle(HYDROData_Region) aRegion = addNewRegion();
162
163     QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
164     aRegion->SetName( aRegionName );
165
166     // Add the zone for region
167     Handle(HYDROData_Zone) aRegionZone = aRegion->addNewZone();
168
169     QString aZoneName = HYDROData_Tool::GenerateObjectName( aDocument, aZonesPref );
170     aRegionZone->SetName( aZoneName );
171
172     aRegionZone->SetShape( aSplitData.Face() );
173
174     // Add the reference object for zone
175     for ( int i = 0, n = aSplitData.ObjectNames.length(); i < n; ++i )
176     {
177       const QString& anObjName = aSplitData.ObjectNames.at( i );
178       
179       Handle(HYDROData_Object) aRefObject = Handle(HYDROData_Object)::DownCast(
180         HYDROData_Tool::FindObjectByName( aDocument, anObjName ) );
181       if ( aRefObject.IsNull() )
182         continue;
183
184       aRegionZone->AddGeometryObject( aRefObject );
185     }
186   }
187
188   // The splitted data is up to date
189   SetToUpdate( false );
190 }
191
192 bool HYDROData_CalculationCase::AddGeometryObject( const Handle(HYDROData_Object)& theObject )
193 {
194   if ( !HYDROData_Tool::IsGeometryObject( theObject ) )
195     return false; // Wrong type of object
196
197   if ( HasReference( theObject, DataTag_GeometryObject ) )
198     return false; // Object is already in reference list
199
200   AddReferenceObject( theObject, DataTag_GeometryObject );
201   
202   // Indicate model of the need to update zones splitting
203   SetToUpdate( true );
204
205   return true;
206 }
207
208 HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetGeometryObjects() const
209 {
210   return GetReferenceObjects( DataTag_GeometryObject );
211 }
212
213 void HYDROData_CalculationCase::RemoveGeometryObject( const Handle(HYDROData_Object)& theObject )
214 {
215   if ( theObject.IsNull() )
216     return;
217
218   RemoveReferenceObject( theObject->Label(), DataTag_GeometryObject );
219
220   // Indicate model of the need to update zones splitting
221   SetToUpdate( true );
222 }
223
224 void HYDROData_CalculationCase::RemoveGeometryObjects()
225 {
226   ClearReferenceObjects( DataTag_GeometryObject );
227
228   // Indicate model of the need to update zones splitting
229   SetToUpdate( true );
230 }
231
232 void HYDROData_CalculationCase::SetBoundaryPolyline( const Handle(HYDROData_Polyline)& thePolyline )
233 {
234   Handle(HYDROData_Polyline) aPrevPolyline = GetBoundaryPolyline();
235
236   SetReferenceObject( thePolyline, DataTag_Polyline );
237
238   // Indicate model of the need to update zones splitting
239   SetToUpdate( !IsEqual( aPrevPolyline, thePolyline ) || IsMustBeUpdated() );
240 }
241
242 Handle(HYDROData_Polyline) HYDROData_CalculationCase::GetBoundaryPolyline() const
243 {
244   return Handle(HYDROData_Polyline)::DownCast( 
245            GetReferenceObject( DataTag_Polyline ) );
246 }
247
248 void HYDROData_CalculationCase::RemoveBoundaryPolyline()
249 {
250   Handle(HYDROData_Polyline) aPrevPolyline = GetBoundaryPolyline();
251
252   ClearReferenceObjects( DataTag_Polyline );
253
254   // Indicate model of the need to update zones splitting
255   SetToUpdate( !aPrevPolyline.IsNull() || IsMustBeUpdated() );
256 }
257
258 Handle(HYDROData_Region) HYDROData_CalculationCase::AddNewRegion( const Handle(HYDROData_Zone)& theZone )
259 {
260   Handle(HYDROData_Region) aNewRegion = addNewRegion();
261   if ( aNewRegion.IsNull() )
262     return aNewRegion;
263
264   // Generate new name for new region
265   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
266   if ( !aDocument.IsNull() )
267   {
268     QString aRegsPref = CALCULATION_REGIONS_PREF;
269
270     QString aNewRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
271     aNewRegion->SetName( aNewRegionName );
272   }
273
274   aNewRegion->AddZone( theZone );
275
276   return aNewRegion;
277 }
278
279 bool HYDROData_CalculationCase::AddRegion( const Handle(HYDROData_Region)& theRegion )
280 {
281   if ( theRegion.IsNull() )
282     return false;
283   
284   if ( HasReference( theRegion, DataTag_Region ) )
285     return false; // Object is already in reference list
286
287   // Move the region from other calculation
288   Handle(HYDROData_CalculationCase) aFatherCalc = 
289     Handle(HYDROData_CalculationCase)::DownCast( theRegion->GetFatherObject() );
290   if ( !aFatherCalc.IsNull() && aFatherCalc->Label() != myLab )
291   {
292     Handle(HYDROData_Region) aNewRegion = addNewRegion();
293     theRegion->CopyTo( aNewRegion );
294
295     aFatherCalc->RemoveRegion( theRegion );
296
297     theRegion->SetLabel( aNewRegion->Label() );
298   }
299   else
300   {
301     AddReferenceObject( theRegion, DataTag_Region );
302   }
303
304   return true;
305 }
306
307 HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetRegions() const
308 {
309   return GetReferenceObjects( DataTag_Region );
310 }
311
312 void HYDROData_CalculationCase::UpdateRegionsOrder()
313 {
314   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
315   if ( aDocument.IsNull() )
316     return;
317
318   HYDROData_SequenceOfObjects aRegions = GetRegions();
319
320   HYDROData_SequenceOfObjects::Iterator anIter( aRegions );
321   for ( ; anIter.More(); anIter.Next() )
322   {
323     Handle(HYDROData_Region) aRegion =
324       Handle(HYDROData_Region)::DownCast( anIter.Value() );
325     if ( aRegion.IsNull() )
326       continue;
327
328     aRegion->SetName( "" );
329   }
330
331   QString aRegsPref = CALCULATION_REGIONS_PREF;
332
333   anIter.Init( 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     QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
342     aRegion->SetName( aRegionName );
343   }
344 }
345
346 void HYDROData_CalculationCase::RemoveRegion( const Handle(HYDROData_Region)& theRegion )
347 {
348   if ( theRegion.IsNull() )
349     return;
350
351   RemoveReferenceObject( theRegion->Label(), DataTag_Region );
352
353   // Remove region from data model
354   Handle(HYDROData_CalculationCase) aFatherCalc = 
355     Handle(HYDROData_CalculationCase)::DownCast( theRegion->GetFatherObject() );
356   if ( !aFatherCalc.IsNull() && aFatherCalc->Label() == myLab )
357     theRegion->Remove();
358 }
359
360 void HYDROData_CalculationCase::RemoveRegions()
361 {
362   ClearReferenceObjects( DataTag_Region );
363   myLab.FindChild( DataTag_ChildRegion ).ForgetAllAttributes( true );
364 }
365
366 Handle(HYDROData_Region) HYDROData_CalculationCase::addNewRegion()
367 {
368   TDF_Label aNewLab = myLab.FindChild( DataTag_ChildRegion ).NewChild();
369
370   Handle(HYDROData_Region) aNewRegion =
371     Handle(HYDROData_Region)::DownCast( HYDROData_Iterator::CreateObject( aNewLab, KIND_REGION ) );
372   AddRegion( aNewRegion );
373
374   return aNewRegion;
375 }
376
377 TopoDS_Shell HYDROData_CalculationCase::GetShell()
378 {
379   TopoDS_Shell aShell;
380
381   TopTools_ListOfShape aFacesList;
382
383   // Make shell containing all region shapes
384   BRepBuilderAPI_Sewing aSewing( Precision::Confusion()*10.0 );
385
386   HYDROData_SequenceOfObjects aCaseRegions = GetRegions();
387   HYDROData_SequenceOfObjects::Iterator aRegionIter( aCaseRegions );
388   for ( ; aRegionIter.More(); aRegionIter.Next() ) {
389     Handle(HYDROData_Region) aRegion =
390       Handle(HYDROData_Region)::DownCast( aRegionIter.Value() );
391     if( aRegion.IsNull() ) {
392       continue;
393     }
394
395     TopoDS_Shape aRegionShape = aRegion->GetShape();
396     if( !aRegionShape.IsNull() ) {
397       TopExp_Explorer anExp( aRegionShape, TopAbs_FACE );
398       if ( anExp.More() ) {
399         for ( ; anExp.More(); anExp.Next() ) {
400           TopoDS_Face aFace = TopoDS::Face( anExp.Current() );
401           if ( !aFace.IsNull() ) {
402             aFacesList.Append( aFace );
403             aSewing.Add( aFace );
404           }
405         }
406       } else {
407         if ( aRegionShape.ShapeType() == TopAbs_FACE ) {
408           aFacesList.Append( aRegionShape );
409         }
410         aSewing.Add( aRegionShape );
411       }
412     }
413   } // regions iterator
414   
415   aSewing.Perform();
416   TopoDS_Shape aSewedShape = aSewing.SewedShape();
417
418   if ( aSewedShape.ShapeType() == TopAbs_FACE && aCaseRegions.Length() ==1 ) {
419     // create shell from one face
420     BRep_Builder aBuilder;
421     aBuilder.MakeShell( aShell );
422     aBuilder.Add( aShell, aSewedShape);
423   } else {
424     TopExp_Explorer anExpShells( aSewedShape, TopAbs_SHELL );
425     Standard_Integer aNbOfShells = 0;
426     for ( ; anExpShells.More(); anExpShells.Next() ) {
427       aShell = TopoDS::Shell( anExpShells.Current() );
428       aNbOfShells++;
429     }
430
431     if ( aNbOfShells != 1 ) {
432       aShell.Nullify();
433       BRep_Builder aBuilder;
434       aBuilder.MakeShell( aShell );
435
436       TopExp_Explorer anExpFaces( aSewedShape, TopAbs_FACE );
437       for ( ; anExpFaces.More(); anExpFaces.Next() ) {
438         TopoDS_Face aFace = TopoDS::Face( anExpFaces.Current() );
439         if ( !aFace.IsNull() ) {
440           aBuilder.Add( aShell, aFace );
441         }
442       }
443     }
444   }
445
446   if ( !aShell.IsNull() ) {
447     TopTools_IndexedMapOfShape aMapOfFaces;
448     TopExp::MapShapes( aShell, TopAbs_FACE, aMapOfFaces );
449     if ( aMapOfFaces.Extent() != aFacesList.Extent() ) {
450       aShell.Nullify();
451       BRep_Builder aBuilder;
452       aBuilder.MakeShell( aShell );
453
454       TopTools_ListIteratorOfListOfShape anIter( aFacesList );
455       for ( ; anIter.More(); anIter.Next() ) {
456         TopoDS_Face aFace = TopoDS::Face( anIter.Value() );
457         aBuilder.Add( aShell, aFace );
458       }
459     }
460   }
461
462 /* TODO: old version
463   // Make shell
464   BRep_Builder aBuilder;
465   aBuilder.MakeShell( aShell );
466
467   // Make shell containing all region shapes
468   HYDROData_SequenceOfObjects aCaseRegions = GetRegions();
469   HYDROData_SequenceOfObjects::Iterator aRegionIter( aCaseRegions );
470   for ( ; aRegionIter.More(); aRegionIter.Next() ) {
471     Handle(HYDROData_Region) aRegion =
472       Handle(HYDROData_Region)::DownCast( aRegionIter.Value() );
473     if( aRegion.IsNull() ) {
474       continue;
475     }
476
477     TopoDS_Shape aRegionShape = aRegion->GetShape();
478
479     // Add shape (face or shell) corresponding to the region into the shell
480     if( !aRegionShape.IsNull() ) {
481       if ( aRegionShape.ShapeType() == TopAbs_FACE ) {
482         aBuilder.Add( aShell, aRegionShape );
483       } else {
484         TopExp_Explorer anExp( aRegionShape, TopAbs_FACE );
485         for( ; anExp.More(); anExp.Next() ) {
486           TopoDS_Face aFace = TopoDS::Face( anExp.Current() );
487           if( !aFace.IsNull() ) {
488             aBuilder.Add( aShell, aFace );
489           }
490         }
491       }
492     }
493   } // regions iterator
494 */
495
496   // Nullify shell if it is empty
497   if ( !aShell.IsNull() && !TopoDS_Iterator(aShell).More() ) {
498     aShell.Nullify();
499   }
500
501   return aShell;
502 }
503
504