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