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