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