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