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