Salome HOME
refs #482: new function for export calculation case
[modules/hydro.git] / src / HYDROData / HYDROData_Region.cxx
1
2 #include "HYDROData_Region.h"
3
4 #include "HYDROData_CalculationCase.h"
5 #include "HYDROData_Document.h"
6 #include "HYDROData_Iterator.h"
7 #include "HYDROData_Object.h"
8 #include "HYDROData_ShapesTool.h"
9 #include "HYDROData_Zone.h"
10 #include "HYDROData_Tool.h"
11
12 #include <TopoDS.hxx>
13 #include <TopoDS_Shape.hxx>
14 #include <TopoDS_Shell.hxx>
15 #include <TopoDS_Face.hxx>
16
17 #include <TopExp.hxx>
18
19 #include <TopTools_ListOfShape.hxx>
20 #include <TopTools_SequenceOfShape.hxx>
21 #include <TopTools_ListIteratorOfListOfShape.hxx>
22 #include <TopTools_IndexedMapOfShape.hxx>
23
24 #include <BRep_Builder.hxx>
25 #include <BRepAlgoAPI_Fuse.hxx>
26
27 #include <ShapeUpgrade_UnifySameDomain.hxx>
28
29 #include <QStringList>
30
31 //#define DEB_GET_REGION_SHAPE
32
33 IMPLEMENT_STANDARD_HANDLE(HYDROData_Region, HYDROData_Entity)
34 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Region, HYDROData_Entity)
35
36
37 HYDROData_Region::HYDROData_Region()
38  : HYDROData_Entity()
39 {
40 }
41
42 HYDROData_Region::~HYDROData_Region()
43 {
44 }
45
46 bool HYDROData_Region::CanBeUpdated() const
47 {
48   return false;
49 }
50
51 void HYDROData_Region::Remove()
52 {
53   Handle(HYDROData_CalculationCase) aFatherCalc = 
54     Handle(HYDROData_CalculationCase)::DownCast( GetFatherObject() );
55
56   HYDROData_Entity::Remove();
57
58   if ( !aFatherCalc.IsNull() )
59     aFatherCalc->UpdateRegionsOrder();
60 }
61
62 bool HYDROData_Region::CanRemove()
63 {
64   return false;
65 }
66
67 HYDROData_SequenceOfObjects HYDROData_Region::GetAllReferenceObjects() const
68 {
69   HYDROData_SequenceOfObjects aResSeq = HYDROData_Entity::GetAllReferenceObjects();
70
71   HYDROData_SequenceOfObjects aSeqOfZones = GetZones();
72   aResSeq.Append( aSeqOfZones );
73
74   return aResSeq;
75 }
76
77 bool HYDROData_Region::AddZone( const Handle(HYDROData_Zone)& theZone )
78 {
79   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
80
81   if ( theZone.IsNull() )
82     return false;
83   
84   if ( HasReference( theZone, DataTag_Zone ) )
85     return false; // Object is already in reference list
86
87   // Move the zone from other region
88   Handle(HYDROData_Region) aFatherRegion = 
89     Handle(HYDROData_Region)::DownCast( theZone->GetFatherObject() );
90   if ( !aFatherRegion.IsNull() && aFatherRegion->Label() != myLab )
91   {
92     Handle(HYDROData_Zone) aNewZone = addNewZone( aDocument, "", TopoDS_Face(), QStringList() );
93     theZone->CopyTo( aNewZone );
94
95     // To prevent changing of stored shape
96     aNewZone->SetShape( theZone->GetShape() );
97
98     aFatherRegion->RemoveZone( theZone );
99
100     theZone->SetLabel( aNewZone->Label() );
101   }
102   else
103   {
104     AddReferenceObject( theZone, DataTag_Zone );
105   }
106
107   return true;
108 }
109
110 HYDROData_SequenceOfObjects HYDROData_Region::GetZones() const
111 {
112   return GetReferenceObjects( DataTag_Zone );
113 }
114
115 void HYDROData_Region::RemoveZone( const Handle(HYDROData_Zone)& theZone )
116 {
117   if ( theZone.IsNull() )
118     return;
119
120   RemoveReferenceObject( theZone->Label(), DataTag_Zone );
121
122   // Remove zone from data model
123   Handle(HYDROData_Region) aFatherRegion = 
124     Handle(HYDROData_Region)::DownCast( theZone->GetFatherObject() );
125   if ( !aFatherRegion.IsNull() && aFatherRegion->Label() == myLab )
126     theZone->Remove();
127
128   // If the last zone has been removed from region we remove this region
129   HYDROData_SequenceOfObjects aRefZones = GetZones();
130   if ( aRefZones.IsEmpty() )
131     Remove();
132 }
133
134 void HYDROData_Region::RemoveZones()
135 {
136   ClearReferenceObjects( DataTag_Zone );
137   myLab.FindChild( DataTag_ChildZone ).ForgetAllAttributes( true );
138 }
139
140 Handle(HYDROData_Zone) HYDROData_Region::addNewZone( const Handle(HYDROData_Document)& theDoc,
141                                                      const QString& thePrefix,
142                                                      const TopoDS_Face& theFace,
143                                                      const QStringList& theRefObjects )
144 {
145   TDF_Label aNewLab = myLab.FindChild( DataTag_ChildZone ).NewChild();
146
147   Handle(HYDROData_Zone) aNewZone =
148     Handle(HYDROData_Zone)::DownCast( HYDROData_Iterator::CreateObject( aNewLab, KIND_ZONE ) );
149   AddZone( aNewZone );
150
151   QString aZoneName = HYDROData_Tool::GenerateObjectName( theDoc, thePrefix );
152   aNewZone->SetName( aZoneName );
153
154   aNewZone->SetShape( theFace );
155
156   // Add the reference object for zone
157   for ( int i = 0, n = theRefObjects.length(); i < n; ++i )
158   {
159     const QString& anObjName = theRefObjects.at( i );
160     Handle(HYDROData_Object) aRefObject = 
161       Handle(HYDROData_Object)::DownCast( theDoc->FindObjectByName( anObjName ) );
162     if ( aRefObject.IsNull() )
163       continue;
164
165     aNewZone->AddGeometryObject( aRefObject );
166   }
167
168   return aNewZone;
169 }
170
171 void getUsedGroups( const TopoDS_Shape&                     theShape,
172                     HYDROData_ShapesGroup::SeqOfGroupsDefs& theOriGroups,
173                     HYDROData_ShapesGroup::SeqOfGroupsDefs& theUsedGroups )
174 {
175 #ifdef DEB_GET_REGION_SHAPE
176   HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Zone face edges:", theShape, TopAbs_EDGE );
177 #endif
178
179   TopTools_IndexedMapOfShape aMapOfSubShapes;
180   TopExp::MapShapes( theShape, TopAbs_EDGE, aMapOfSubShapes );
181
182   HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anIter( theOriGroups );
183   for ( ; anIter.More(); anIter.Next() )
184   {
185     HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anIter.ChangeValue();
186     if ( anOriGroupDef.Shapes.IsEmpty() )
187       continue;
188
189     for ( int i = 1; i <= anOriGroupDef.Shapes.Length(); ++i )
190     {
191       TopoDS_Shape aGroupEdge = anOriGroupDef.Shapes.Value( i );
192       
193       int aShapeIndex = aMapOfSubShapes.FindIndex( aGroupEdge );
194       if ( aShapeIndex <= 0 )
195         continue;
196
197       anOriGroupDef.Shapes.Remove( i );
198       --i;
199
200       bool anIsAdded = false;
201
202       HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( theUsedGroups );
203       for ( ; aUsedIter.More(); aUsedIter.Next() )
204       {
205         HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.ChangeValue();
206         if ( aUsedGroupDef.Name != anOriGroupDef.Name )
207           continue;
208
209         aUsedGroupDef.Shapes.Append( aGroupEdge );
210         anIsAdded = true;
211         break;
212       }
213
214       if ( !anIsAdded )
215       {
216         HYDROData_ShapesGroup::GroupDefinition aUsedGroupDef;
217         aUsedGroupDef.Name = anOriGroupDef.Name;
218         aUsedGroupDef.Shapes.Append( aGroupEdge );
219         theUsedGroups.Append( aUsedGroupDef );
220       }
221     }
222   }
223 }
224
225 TopoDS_Shape HYDROData_Region::GetShape( HYDROData_ShapesGroup::SeqOfGroupsDefs* theSeqOfGroups ) const
226 {
227   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfGroups;
228   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfUsedGroups;
229   if ( theSeqOfGroups )
230     aSeqOfGroups = *theSeqOfGroups;
231
232 #ifdef DEB_GET_REGION_SHAPE
233   HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfGroups );
234 #endif
235
236   TopoDS_Shape aResShape;
237
238   // Unite the region zones (each zone is a face) into one face (united face)
239   // If the zones can't be united into the single face - unite them into shell
240
241   // Collect the list of region faces
242   TopTools_ListOfShape aRegionFacesList;
243
244   HYDROData_SequenceOfObjects aZones = GetZones();
245   HYDROData_SequenceOfObjects::Iterator aZoneIter( aZones );
246   for ( ; aZoneIter.More(); aZoneIter.Next() )
247   {
248     Handle(HYDROData_Zone) aZone =
249       Handle(HYDROData_Zone)::DownCast( aZoneIter.Value() );
250     if ( aZone.IsNull() )
251       continue;
252
253     TopoDS_Shape aZoneShape = aZone->GetShape();
254     if ( aZoneShape.IsNull() || aZoneShape.ShapeType() != TopAbs_FACE )
255       continue;
256
257     TopoDS_Face aZoneFace = TopoDS::Face( aZoneShape );
258     aRegionFacesList.Append( aZoneFace );
259
260     getUsedGroups( aZoneFace, aSeqOfGroups, aSeqOfUsedGroups );
261   } // zones iterator
262   
263   if ( aRegionFacesList.IsEmpty() )
264     return aResShape;
265
266   // The unite region face
267   TopoDS_Face aRegionFace;
268
269   if ( aRegionFacesList.Extent() == 1 )
270   {
271     aRegionFace = TopoDS::Face( aRegionFacesList.First() );
272   }
273   else
274   {
275 #ifdef DEB_GET_REGION_SHAPE
276     HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfUsedGroups );
277 #endif
278
279     // Try to fuse all region faces into one common face
280     TopoDS_Shape aFuseShape;
281     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
282     for ( ; aFaceIter.More(); aFaceIter.Next() )
283     {
284       if ( aFuseShape.IsNull() )
285       {
286         aFuseShape = aFaceIter.Value();
287         continue;
288       }
289
290       BRepAlgoAPI_Fuse aFuse( aFuseShape, aFaceIter.Value() );
291       if ( !aFuse.IsDone() )
292       {
293         aFuseShape.Nullify();
294         break;
295       }
296
297       aFuseShape = aFuse.Shape();
298       HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &aFuse );
299     } // faces iterator
300
301 #ifdef DEB_GET_REGION_SHAPE
302     HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Fused face edges:", aFuseShape, TopAbs_EDGE );
303 #endif
304
305     // Check the result of fuse operation
306     if ( !aFuseShape.IsNull() )
307     {
308       ShapeUpgrade_UnifySameDomain anUnifier( aFuseShape );
309       anUnifier.Build();
310
311       const TopoDS_Shape& anUnitedShape = anUnifier.Shape();
312
313       TopTools_SequenceOfShape aShapeFaces;
314       HYDROData_ShapesTool::ExploreShapeToShapes( anUnitedShape, TopAbs_FACE, aShapeFaces );
315       if ( aShapeFaces.Length() == 1 )
316       {
317         aRegionFace = TopoDS::Face( aShapeFaces.Value( 1 ) );
318
319 #ifdef DEB_GET_REGION_SHAPE
320         HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Result face edges:", aRegionFace, TopAbs_EDGE );
321 #endif
322
323         HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &anUnifier );
324
325         // Update the sequence of groups
326         if ( theSeqOfGroups )
327         {
328           HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( aSeqOfUsedGroups );
329           for ( ; aUsedIter.More(); aUsedIter.Next() )
330           {
331             const HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.Value();
332             if ( aUsedGroupDef.Shapes.IsEmpty() )
333               continue;
334
335             HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anOriIter( aSeqOfGroups );
336             for ( ; anOriIter.More(); anOriIter.Next() )
337             {
338               HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anOriIter.ChangeValue();
339               if ( anOriGroupDef.Name != aUsedGroupDef.Name )
340                 continue;
341
342               HYDROData_ShapesTool::AddShapes( anOriGroupDef.Shapes, aUsedGroupDef.Shapes );
343               break;
344             }
345           }
346
347           *theSeqOfGroups = aSeqOfGroups;
348         }
349       }
350     }
351   }
352
353   if ( !aRegionFace.IsNull() )
354   {
355     // result shape is a face
356     aResShape = aRegionFace;
357   }
358   else
359   {
360     // result shape is a shell
361     TopoDS_Shell aShell;
362     BRep_Builder aBuilder;
363     aBuilder.MakeShell( aShell );
364
365     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
366     for ( ; aFaceIter.More(); aFaceIter.Next() )
367       aBuilder.Add( aShell, aFaceIter.Value() );
368
369     aResShape = aShell;
370   }
371   
372   return aResShape;
373 }