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