Salome HOME
refs #651: wrapping for Python
[modules/hydro.git] / src / HYDROData / HYDROData_Region.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include "HYDROData_Region.h"
20
21 #include "HYDROData_CalculationCase.h"
22 #include "HYDROData_Document.h"
23 #include "HYDROData_Iterator.h"
24 #include "HYDROData_Object.h"
25 #include "HYDROData_ShapesTool.h"
26 #include "HYDROData_Zone.h"
27 #include "HYDROData_Tool.h"
28
29 #include <TopoDS.hxx>
30 #include <TopoDS_Shape.hxx>
31 #include <TopoDS_Shell.hxx>
32 #include <TopoDS_Face.hxx>
33
34 #include <TopExp.hxx>
35
36 #include <TopTools_ListOfShape.hxx>
37 #include <TopTools_SequenceOfShape.hxx>
38 #include <TopTools_ListIteratorOfListOfShape.hxx>
39 #include <TopTools_IndexedMapOfShape.hxx>
40
41 #include <BRep_Builder.hxx>
42 #include <BRepAlgoAPI_Fuse.hxx>
43
44 #include <ShapeUpgrade_UnifySameDomain.hxx>
45
46 #include <QStringList>
47
48 //#define DEB_GET_REGION_SHAPE
49
50 IMPLEMENT_STANDARD_HANDLE(HYDROData_Region, HYDROData_Entity)
51 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Region, HYDROData_Entity)
52
53
54 HYDROData_Region::HYDROData_Region()
55  : HYDROData_Entity( Geom_2d )
56 {
57 }
58
59 HYDROData_Region::~HYDROData_Region()
60 {
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   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
97
98   if ( theZone.IsNull() )
99     return false;
100   
101   if ( HasReference( theZone, DataTag_Zone ) )
102     return false; // Object is already in reference list
103
104   // Move the zone from other region
105   Handle(HYDROData_Region) aFatherRegion = 
106     Handle(HYDROData_Region)::DownCast( theZone->GetFatherObject() );
107   if ( !aFatherRegion.IsNull() && aFatherRegion->Label() != myLab )
108   {
109     Handle(HYDROData_Zone) aNewZone = addNewZone( aDocument, "", TopoDS_Face(), QStringList() );
110     theZone->CopyTo( aNewZone, false );
111
112     // To prevent changing of stored shape
113     aNewZone->SetShape( theZone->GetShape() );
114
115     aFatherRegion->RemoveZone( theZone );
116
117     theZone->SetLabel( aNewZone->Label() );
118   }
119   else
120   {
121     AddReferenceObject( theZone, DataTag_Zone );
122   }
123
124   return true;
125 }
126
127 HYDROData_SequenceOfObjects HYDROData_Region::GetZones() const
128 {
129   return GetReferenceObjects( DataTag_Zone );
130 }
131
132 void HYDROData_Region::RemoveZone( const Handle(HYDROData_Zone)& theZone )
133 {
134   if ( theZone.IsNull() )
135     return;
136
137   RemoveReferenceObject( theZone->Label(), DataTag_Zone );
138
139   // Remove zone from data model
140   Handle(HYDROData_Region) aFatherRegion = 
141     Handle(HYDROData_Region)::DownCast( theZone->GetFatherObject() );
142   if ( !aFatherRegion.IsNull() && aFatherRegion->Label() == myLab )
143     theZone->Remove();
144
145   // If the last zone has been removed from region we remove this region
146   HYDROData_SequenceOfObjects aRefZones = GetZones();
147   if ( aRefZones.IsEmpty() )
148     Remove();
149 }
150
151 void HYDROData_Region::RemoveZones()
152 {
153   ClearReferenceObjects( DataTag_Zone );
154   myLab.FindChild( DataTag_ChildZone ).ForgetAllAttributes( true );
155 }
156
157 Handle(HYDROData_Zone) HYDROData_Region::addNewZone( const Handle(HYDROData_Document)& theDoc,
158                                                      const QString& thePrefix,
159                                                      const TopoDS_Face& theFace,
160                                                      const QStringList& theRefObjects )
161 {
162   TDF_Label aNewLab = myLab.FindChild( DataTag_ChildZone ).NewChild();
163
164   Handle(HYDROData_Zone) aNewZone =
165     Handle(HYDROData_Zone)::DownCast( HYDROData_Iterator::CreateObject( aNewLab, KIND_ZONE ) );
166   AddZone( aNewZone );
167
168   QString aZoneName = HYDROData_Tool::GenerateObjectName( theDoc, thePrefix );
169   aNewZone->SetName( aZoneName );
170
171   aNewZone->SetShape( theFace );
172
173   // Add the reference object for zone
174   for ( int i = 0, n = theRefObjects.length(); i < n; ++i )
175   {
176     const QString& anObjName = theRefObjects.at( i );
177     Handle(HYDROData_Entity) aRefObject = theDoc->FindObjectByName( anObjName );
178     if ( aRefObject.IsNull() )
179       continue;
180
181     aNewZone->AddObject( aRefObject );
182   }
183
184   return aNewZone;
185 }
186
187 void getUsedGroups( const TopoDS_Shape&                     theShape,
188                     HYDROData_ShapesGroup::SeqOfGroupsDefs& theOriGroups,
189                     HYDROData_ShapesGroup::SeqOfGroupsDefs& theUsedGroups )
190 {
191 #ifdef DEB_GET_REGION_SHAPE
192   HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Zone face edges:", theShape, TopAbs_EDGE );
193 #endif
194
195   TopTools_IndexedMapOfShape aMapOfSubShapes;
196   TopExp::MapShapes( theShape, TopAbs_EDGE, aMapOfSubShapes );
197
198   HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anIter( theOriGroups );
199   for ( ; anIter.More(); anIter.Next() )
200   {
201     HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anIter.ChangeValue();
202     if ( anOriGroupDef.Shapes.IsEmpty() )
203       continue;
204
205     for ( int i = 1; i <= anOriGroupDef.Shapes.Length(); ++i )
206     {
207       TopoDS_Shape aGroupEdge = anOriGroupDef.Shapes.Value( i );
208       
209       int aShapeIndex = aMapOfSubShapes.FindIndex( aGroupEdge );
210       if ( aShapeIndex <= 0 )
211         continue;
212
213       anOriGroupDef.Shapes.Remove( i );
214       --i;
215
216       bool anIsAdded = false;
217
218       HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( theUsedGroups );
219       for ( ; aUsedIter.More(); aUsedIter.Next() )
220       {
221         HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.ChangeValue();
222         if ( aUsedGroupDef.Name != anOriGroupDef.Name )
223           continue;
224
225         aUsedGroupDef.Shapes.Append( aGroupEdge );
226         anIsAdded = true;
227         break;
228       }
229
230       if ( !anIsAdded )
231       {
232         HYDROData_ShapesGroup::GroupDefinition aUsedGroupDef;
233         aUsedGroupDef.Name = anOriGroupDef.Name;
234         aUsedGroupDef.Shapes.Append( aGroupEdge );
235         theUsedGroups.Append( aUsedGroupDef );
236       }
237     }
238   }
239 }
240
241 TopoDS_Shape HYDROData_Region::GetShape( HYDROData_ShapesGroup::SeqOfGroupsDefs* theSeqOfGroups ) const
242 {
243   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfGroups;
244   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfUsedGroups;
245   if ( theSeqOfGroups )
246     aSeqOfGroups = *theSeqOfGroups;
247
248 #ifdef DEB_GET_REGION_SHAPE
249   HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfGroups );
250 #endif
251
252   TopoDS_Shape aResShape;
253
254   // Unite the region zones (each zone is a face) into one face (united face)
255   // If the zones can't be united into the single face - unite them into shell
256
257   // Collect the list of region faces
258   TopTools_ListOfShape aRegionFacesList;
259
260   HYDROData_SequenceOfObjects aZones = GetZones();
261   HYDROData_SequenceOfObjects::Iterator aZoneIter( aZones );
262   for ( ; aZoneIter.More(); aZoneIter.Next() )
263   {
264     Handle(HYDROData_Zone) aZone =
265       Handle(HYDROData_Zone)::DownCast( aZoneIter.Value() );
266     if ( aZone.IsNull() )
267       continue;
268
269     TopoDS_Shape aZoneShape = aZone->GetShape();
270     if ( aZoneShape.IsNull() || aZoneShape.ShapeType() != TopAbs_FACE )
271       continue;
272
273     TopoDS_Face aZoneFace = TopoDS::Face( aZoneShape );
274     aRegionFacesList.Append( aZoneFace );
275
276     getUsedGroups( aZoneFace, aSeqOfGroups, aSeqOfUsedGroups );
277   } // zones iterator
278   
279   if ( aRegionFacesList.IsEmpty() )
280     return aResShape;
281
282   // The unite region face
283   TopoDS_Face aRegionFace;
284
285   if ( aRegionFacesList.Extent() == 1 )
286   {
287     aRegionFace = TopoDS::Face( aRegionFacesList.First() );
288   }
289   else
290   {
291 #ifdef DEB_GET_REGION_SHAPE
292     HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfUsedGroups );
293 #endif
294
295     // Try to fuse all region faces into one common face
296     TopoDS_Shape aFuseShape;
297     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
298     for ( ; aFaceIter.More(); aFaceIter.Next() )
299     {
300       if ( aFuseShape.IsNull() )
301       {
302         aFuseShape = aFaceIter.Value();
303         continue;
304       }
305
306       BRepAlgoAPI_Fuse aFuse( aFuseShape, aFaceIter.Value() );
307       if ( !aFuse.IsDone() )
308       {
309         aFuseShape.Nullify();
310         break;
311       }
312
313       aFuseShape = aFuse.Shape();
314       HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &aFuse );
315     } // faces iterator
316
317 #ifdef DEB_GET_REGION_SHAPE
318     HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Fused face edges:", aFuseShape, TopAbs_EDGE );
319 #endif
320
321     // Check the result of fuse operation
322     if ( !aFuseShape.IsNull() )
323     {
324       ShapeUpgrade_UnifySameDomain anUnifier( aFuseShape );
325       anUnifier.Build();
326
327       const TopoDS_Shape& anUnitedShape = anUnifier.Shape();
328
329       TopTools_SequenceOfShape aShapeFaces;
330       HYDROData_ShapesTool::ExploreShapeToShapes( anUnitedShape, TopAbs_FACE, aShapeFaces );
331       if ( aShapeFaces.Length() == 1 )
332       {
333         aRegionFace = TopoDS::Face( aShapeFaces.Value( 1 ) );
334
335 #ifdef DEB_GET_REGION_SHAPE
336         HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Result face edges:", aRegionFace, TopAbs_EDGE );
337 #endif
338
339         HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &anUnifier );
340
341         // Update the sequence of groups
342         if ( theSeqOfGroups )
343         {
344           HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( aSeqOfUsedGroups );
345           for ( ; aUsedIter.More(); aUsedIter.Next() )
346           {
347             const HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.Value();
348             if ( aUsedGroupDef.Shapes.IsEmpty() )
349               continue;
350
351             HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anOriIter( aSeqOfGroups );
352             for ( ; anOriIter.More(); anOriIter.Next() )
353             {
354               HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anOriIter.ChangeValue();
355               if ( anOriGroupDef.Name != aUsedGroupDef.Name )
356                 continue;
357
358               HYDROData_ShapesTool::AddShapes( anOriGroupDef.Shapes, aUsedGroupDef.Shapes );
359               break;
360             }
361           }
362
363           *theSeqOfGroups = aSeqOfGroups;
364         }
365       }
366     }
367   }
368
369   if ( !aRegionFace.IsNull() )
370   {
371     // result shape is a face
372     aResShape = aRegionFace;
373   }
374   else
375   {
376     // result shape is a shell
377     TopoDS_Shell aShell;
378     BRep_Builder aBuilder;
379     aBuilder.MakeShell( aShell );
380
381     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
382     for ( ; aFaceIter.More(); aFaceIter.Next() )
383       aBuilder.Add( aShell, aFaceIter.Value() );
384
385     aResShape = aShell;
386   }
387   
388   return aResShape;
389 }
390
391 QStringList HYDROData_Region::DumpToPython( const QString&       thePyScriptPath,
392                                             MapOfTreatedObjects& theTreatedObjects ) const
393 {
394   QStringList aResList;
395
396   // Find region
397   findPythonReferenceObject( theTreatedObjects, aResList );
398
399   // Add zones
400   HYDROData_SequenceOfObjects aZones = GetZones();
401   HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
402   for ( ; aZonesIter.More(); aZonesIter.Next() ) {
403     Handle(HYDROData_Zone) aZone =
404       Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
405     if ( aZone.IsNull() ) {
406       continue;
407     }
408     
409     // find zone
410     aZone->findPythonReferenceObject( theTreatedObjects, aResList );
411     theTreatedObjects.insert( aZone->GetName(), aZone );
412     
413     // set zone merge type
414     QString aMergeTypeStr;
415     HYDROData_Zone::MergeType aMergeType = aZone->GetMergeType();
416     if ( aMergeType == HYDROData_Zone::Merge_ZMIN ) {
417       aMergeTypeStr = "HYDROData_Zone.Merge_ZMIN";
418     } else if ( aMergeType == HYDROData_Zone::Merge_ZMAX ) {
419       aMergeTypeStr = "HYDROData_Zone.Merge_ZMAX";
420     } else if ( aMergeType == HYDROData_Zone::Merge_Object ) {
421       aMergeTypeStr = "HYDROData_Zone.Merge_Object";
422     }
423
424     if ( !aMergeTypeStr.isEmpty() ) {
425       aResList << QString( "%1.SetMergeType( %2 )" ).arg( aZone->GetObjPyName() ).arg( aMergeTypeStr );
426     }
427     if ( aMergeType == HYDROData_Zone::Merge_Object ) {
428       Handle(HYDROData_Entity) aMergeObject = aZone->GetMergeObject();
429       if ( !aMergeObject.IsNull() ) {
430         aMergeObject->findPythonReferenceObject( theTreatedObjects, aResList );
431         aResList << QString( "%1.SetMergeObject( %2 )" ).arg( aZone->GetObjPyName() )
432                                                         .arg( aMergeObject->GetObjPyName() );
433       }
434     }
435
436     // add zone
437     setPythonReferenceObject( thePyScriptPath, theTreatedObjects, aResList, aZone, "AddZone" );
438   }
439
440   return aResList;
441 }
442
443 bool HYDROData_Region::IsSubmersible() const
444 {
445   HYDROData_SequenceOfObjects aZones = GetZones();
446   HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
447   for ( ; aZonesIter.More(); aZonesIter.Next() )
448   {
449     Handle(HYDROData_Zone) aZone =
450       Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
451     if ( !aZone->IsSubmersible() )
452       return false; //if one of zones is not submersible the region is considered as not submersible
453   }
454   return true;
455 }