Salome HOME
debug of tests for DTM
[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 #include <QColor>
48
49 //#define DEB_GET_REGION_SHAPE
50
51 IMPLEMENT_STANDARD_HANDLE(HYDROData_Region, HYDROData_Entity)
52 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Region, HYDROData_Entity)
53
54
55 HYDROData_Region::HYDROData_Region()
56  : HYDROData_Entity( Geom_2d )
57 {
58 }
59
60 HYDROData_Region::~HYDROData_Region()
61 {
62 }
63
64 bool HYDROData_Region::CanBeUpdated() const
65 {
66   return false;
67 }
68
69 void HYDROData_Region::Remove()
70 {
71   Handle(HYDROData_CalculationCase) aFatherCalc = 
72     Handle(HYDROData_CalculationCase)::DownCast( GetFatherObject() );
73
74   HYDROData_Entity::Remove();
75
76   if ( !aFatherCalc.IsNull() )
77     aFatherCalc->UpdateRegionsOrder();
78 }
79
80 bool HYDROData_Region::CanRemove()
81 {
82   return false;
83 }
84
85 HYDROData_SequenceOfObjects HYDROData_Region::GetAllReferenceObjects() const
86 {
87   HYDROData_SequenceOfObjects aResSeq = HYDROData_Entity::GetAllReferenceObjects();
88
89   HYDROData_SequenceOfObjects aSeqOfZones = GetZones();
90   aResSeq.Append( aSeqOfZones );
91
92   return aResSeq;
93 }
94
95 bool HYDROData_Region::AddZone( const Handle(HYDROData_Zone)& theZone )
96 {
97   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
98
99   if ( theZone.IsNull() )
100     return false;
101   
102   if ( HasReference( theZone, DataTag_Zone ) )
103     return false; // Object is already in reference list
104
105   // Move the zone from other region
106   Handle(HYDROData_Region) aFatherRegion = 
107     Handle(HYDROData_Region)::DownCast( theZone->GetFatherObject() );
108   if ( !aFatherRegion.IsNull() && aFatherRegion->Label() != myLab )
109   {
110     Handle(HYDROData_Zone) aNewZone = addNewZone( aDocument, "", TopoDS_Face(), QStringList() );
111     theZone->CopyTo( aNewZone, false );
112
113     // To prevent changing of stored shape
114     aNewZone->SetShape( theZone->GetShape() );
115
116     aFatherRegion->RemoveZone( theZone );
117
118     theZone->SetLabel( aNewZone->Label() );
119   }
120   else
121   {
122     AddReferenceObject( theZone, DataTag_Zone );
123   }
124
125   return true;
126 }
127
128 HYDROData_SequenceOfObjects HYDROData_Region::GetZones() const
129 {
130   return GetReferenceObjects( DataTag_Zone );
131 }
132
133 void HYDROData_Region::RemoveZone( const Handle(HYDROData_Zone)& theZone )
134 {
135   if ( theZone.IsNull() )
136     return;
137
138   RemoveReferenceObject( theZone->Label(), DataTag_Zone );
139
140   // Remove zone from data model
141   Handle(HYDROData_Region) aFatherRegion = 
142     Handle(HYDROData_Region)::DownCast( theZone->GetFatherObject() );
143   if ( !aFatherRegion.IsNull() && aFatherRegion->Label() == myLab )
144     theZone->Remove();
145
146   // If the last zone has been removed from region we remove this region
147   HYDROData_SequenceOfObjects aRefZones = GetZones();
148   if ( aRefZones.IsEmpty() )
149     Remove();
150 }
151
152 void HYDROData_Region::RemoveZones()
153 {
154   ClearReferenceObjects( DataTag_Zone );
155   myLab.FindChild( DataTag_ChildZone ).ForgetAllAttributes( true );
156 }
157
158 Handle(HYDROData_Zone) HYDROData_Region::addNewZone( const Handle(HYDROData_Document)& theDoc,
159                                                      const QString& thePrefix,
160                                                      const TopoDS_Face& theFace,
161                                                      const QStringList& theRefObjects )
162 {
163   TDF_Label aNewLab = myLab.FindChild( DataTag_ChildZone ).NewChild();
164
165   Handle(HYDROData_Zone) aNewZone =
166     Handle(HYDROData_Zone)::DownCast( HYDROData_Iterator::CreateObject( aNewLab, KIND_ZONE ) );
167   AddZone( aNewZone );
168
169   QString aZoneName = HYDROData_Tool::GenerateObjectName( theDoc, thePrefix );
170   aNewZone->SetName( aZoneName );
171
172   aNewZone->SetShape( theFace );
173
174   // Add the reference object for zone
175   for ( int i = 0, n = theRefObjects.length(); i < n; ++i )
176   {
177     const QString& anObjName = theRefObjects.at( i );
178     Handle(HYDROData_Entity) aRefObject = theDoc->FindObjectByName( anObjName );
179     if ( aRefObject.IsNull() )
180       continue;
181
182     aNewZone->AddObject( aRefObject );
183   }
184
185   return aNewZone;
186 }
187
188 void getUsedGroups( const TopoDS_Shape&                     theShape,
189                     HYDROData_ShapesGroup::SeqOfGroupsDefs& theOriGroups,
190                     HYDROData_ShapesGroup::SeqOfGroupsDefs& theUsedGroups )
191 {
192 #ifdef DEB_GET_REGION_SHAPE
193   HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Zone face edges:", theShape, TopAbs_EDGE );
194 #endif
195
196   TopTools_IndexedMapOfShape aMapOfSubShapes;
197   TopExp::MapShapes( theShape, TopAbs_EDGE, aMapOfSubShapes );
198
199   HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anIter( theOriGroups );
200   for ( ; anIter.More(); anIter.Next() )
201   {
202     HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anIter.ChangeValue();
203     if ( anOriGroupDef.Shapes.IsEmpty() )
204       continue;
205
206     for ( int i = 1; i <= anOriGroupDef.Shapes.Length(); ++i )
207     {
208       TopoDS_Shape aGroupEdge = anOriGroupDef.Shapes.Value( i );
209       
210       int aShapeIndex = aMapOfSubShapes.FindIndex( aGroupEdge );
211       if ( aShapeIndex <= 0 )
212         continue;
213
214       anOriGroupDef.Shapes.Remove( i );
215       --i;
216
217       bool anIsAdded = false;
218
219       HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( theUsedGroups );
220       for ( ; aUsedIter.More(); aUsedIter.Next() )
221       {
222         HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.ChangeValue();
223         if ( aUsedGroupDef.Name != anOriGroupDef.Name )
224           continue;
225
226         aUsedGroupDef.Shapes.Append( aGroupEdge );
227         anIsAdded = true;
228         break;
229       }
230
231       if ( !anIsAdded )
232       {
233         HYDROData_ShapesGroup::GroupDefinition aUsedGroupDef;
234         aUsedGroupDef.Name = anOriGroupDef.Name;
235         aUsedGroupDef.Shapes.Append( aGroupEdge );
236         theUsedGroups.Append( aUsedGroupDef );
237       }
238     }
239   }
240 }
241
242 TopoDS_Shape HYDROData_Region::GetShape( HYDROData_ShapesGroup::SeqOfGroupsDefs* theSeqOfGroups ) const
243 {
244   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfGroups;
245   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfUsedGroups;
246   if ( theSeqOfGroups )
247     aSeqOfGroups = *theSeqOfGroups;
248
249 #ifdef DEB_GET_REGION_SHAPE
250   HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfGroups );
251 #endif
252
253   TopoDS_Shape aResShape;
254
255   // Unite the region zones (each zone is a face) into one face (united face)
256   // If the zones can't be united into the single face - unite them into shell
257
258   // Collect the list of region faces
259   TopTools_ListOfShape aRegionFacesList;
260
261   HYDROData_SequenceOfObjects aZones = GetZones();
262   HYDROData_SequenceOfObjects::Iterator aZoneIter( aZones );
263   for ( ; aZoneIter.More(); aZoneIter.Next() )
264   {
265     Handle(HYDROData_Zone) aZone =
266       Handle(HYDROData_Zone)::DownCast( aZoneIter.Value() );
267     if ( aZone.IsNull() )
268       continue;
269
270     TopoDS_Shape aZoneShape = aZone->GetShape();
271     if ( aZoneShape.IsNull() || aZoneShape.ShapeType() != TopAbs_FACE )
272       continue;
273
274     TopoDS_Face aZoneFace = TopoDS::Face( aZoneShape );
275     aRegionFacesList.Append( aZoneFace );
276
277     getUsedGroups( aZoneFace, aSeqOfGroups, aSeqOfUsedGroups );
278   } // zones iterator
279   
280   if ( aRegionFacesList.IsEmpty() )
281     return aResShape;
282
283   // The unite region face
284   TopoDS_Face aRegionFace;
285
286   if ( aRegionFacesList.Extent() == 1 )
287   {
288     aRegionFace = TopoDS::Face( aRegionFacesList.First() );
289   }
290   else
291   {
292 #ifdef DEB_GET_REGION_SHAPE
293     HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfUsedGroups );
294 #endif
295
296     // Try to fuse all region faces into one common face
297     TopoDS_Shape aFuseShape;
298     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
299     for ( ; aFaceIter.More(); aFaceIter.Next() )
300     {
301       if ( aFuseShape.IsNull() )
302       {
303         aFuseShape = aFaceIter.Value();
304         continue;
305       }
306
307       BRepAlgoAPI_Fuse aFuse( aFuseShape, aFaceIter.Value() );
308       if ( !aFuse.IsDone() )
309       {
310         aFuseShape.Nullify();
311         break;
312       }
313
314       aFuseShape = aFuse.Shape();
315       HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &aFuse );
316     } // faces iterator
317
318 #ifdef DEB_GET_REGION_SHAPE
319     HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Fused face edges:", aFuseShape, TopAbs_EDGE );
320 #endif
321
322     // Check the result of fuse operation
323     if ( !aFuseShape.IsNull() )
324     {
325       ShapeUpgrade_UnifySameDomain anUnifier( aFuseShape );
326       anUnifier.Build();
327
328       const TopoDS_Shape& anUnitedShape = anUnifier.Shape();
329
330       TopTools_SequenceOfShape aShapeFaces;
331       HYDROData_ShapesTool::ExploreShapeToShapes( anUnitedShape, TopAbs_FACE, aShapeFaces );
332       if ( aShapeFaces.Length() == 1 )
333       {
334         aRegionFace = TopoDS::Face( aShapeFaces.Value( 1 ) );
335
336 #ifdef DEB_GET_REGION_SHAPE
337         HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Result face edges:", aRegionFace, TopAbs_EDGE );
338 #endif
339
340         HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &anUnifier );
341
342         // Update the sequence of groups
343         if ( theSeqOfGroups )
344         {
345           HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( aSeqOfUsedGroups );
346           for ( ; aUsedIter.More(); aUsedIter.Next() )
347           {
348             const HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.Value();
349             if ( aUsedGroupDef.Shapes.IsEmpty() )
350               continue;
351
352             HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anOriIter( aSeqOfGroups );
353             for ( ; anOriIter.More(); anOriIter.Next() )
354             {
355               HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anOriIter.ChangeValue();
356               if ( anOriGroupDef.Name != aUsedGroupDef.Name )
357                 continue;
358
359               HYDROData_ShapesTool::AddShapes( anOriGroupDef.Shapes, aUsedGroupDef.Shapes );
360               break;
361             }
362           }
363
364           *theSeqOfGroups = aSeqOfGroups;
365         }
366       }
367     }
368   }
369
370   if ( !aRegionFace.IsNull() )
371   {
372     // result shape is a face
373     aResShape = aRegionFace;
374   }
375   else
376   {
377     // result shape is a shell
378     TopoDS_Shell aShell;
379     BRep_Builder aBuilder;
380     aBuilder.MakeShell( aShell );
381
382     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
383     for ( ; aFaceIter.More(); aFaceIter.Next() )
384       aBuilder.Add( aShell, aFaceIter.Value() );
385
386     aResShape = aShell;
387   }
388   
389   return aResShape;
390 }
391
392 QStringList HYDROData_Region::DumpToPython( const QString&       thePyScriptPath,
393                                             MapOfTreatedObjects& theTreatedObjects,
394                                             QString              defRegName ) const
395 {
396   QStringList aResList;
397
398   // Find region
399   findPythonReferenceObject( aResList, defRegName );
400
401   // Add zones
402   HYDROData_SequenceOfObjects aZones = GetZones();
403   HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
404   for ( ; aZonesIter.More(); aZonesIter.Next() ) {
405     Handle(HYDROData_Zone) aZone =
406       Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
407     if ( aZone.IsNull() ) {
408       continue;
409     }
410     
411     // find zone
412     aZone->findPythonReferenceObject( aResList );
413     theTreatedObjects.insert( aZone->GetName(), aZone );
414     
415     // set zone merge type
416     QString aMergeTypeStr;
417     HYDROData_Zone::MergeType aMergeType = aZone->GetMergeType();
418     if ( aMergeType == HYDROData_Zone::Merge_ZMIN ) {
419       aMergeTypeStr = "HYDROData_Zone.Merge_ZMIN";
420     } else if ( aMergeType == HYDROData_Zone::Merge_ZMAX ) {
421       aMergeTypeStr = "HYDROData_Zone.Merge_ZMAX";
422     } else if ( aMergeType == HYDROData_Zone::Merge_Object ) {
423       aMergeTypeStr = "HYDROData_Zone.Merge_Object";
424     }
425
426     if ( !aMergeTypeStr.isEmpty() ) {
427       aResList << QString( "%1.SetMergeType( %2 )" ).arg( aZone->GetObjPyName() ).arg( aMergeTypeStr );
428     }
429     if ( aMergeType == HYDROData_Zone::Merge_Object ) {
430       Handle(HYDROData_Entity) aMergeObject = aZone->GetMergeObject();
431       if ( !aMergeObject.IsNull() ) {
432         aMergeObject->findPythonReferenceObject( aResList );
433         aResList << QString( "%1.SetMergeObject( %2 )" ).arg( aZone->GetObjPyName() )
434                                                         .arg( aMergeObject->GetObjPyName() );
435       }
436     }
437     // set color
438     QColor zoneColor = aZone->GetColor(Qt::darkBlue);
439     aResList << QString( "%1.SetColor( QColor( %2, %3, %4 ))" )
440                  .arg( aZone->GetObjPyName() ).arg( zoneColor.red() ).arg( zoneColor.green() ).arg( zoneColor.blue() );
441     // add zone
442     setPythonReferenceObject( thePyScriptPath, theTreatedObjects, aResList, aZone, "AddZone" );
443
444   }
445
446   return aResList;
447 }
448
449 bool HYDROData_Region::IsSubmersible() const
450 {
451   HYDROData_SequenceOfObjects aZones = GetZones();
452   HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
453   for ( ; aZonesIter.More(); aZonesIter.Next() )
454   {
455     Handle(HYDROData_Zone) aZone =
456       Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
457     if ( !aZone->IsSubmersible() )
458       return false; //if one of zones is not submersible the region is considered as not submersible
459   }
460   return true;
461 }