Salome HOME
80c005cc4ad8b8ff1e6a443e587074745221b421
[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 TopoDS_Shape HYDROData_Region::GetShape( HYDROData_ShapesGroup::SeqOfGroupsDefs* theSeqOfGroups, const TopTools_SequenceOfShape* IntSh ) const
248 {
249   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfGroups;
250   HYDROData_ShapesGroup::SeqOfGroupsDefs aSeqOfUsedGroups;
251   if ( theSeqOfGroups )
252     aSeqOfGroups = *theSeqOfGroups;
253
254 #ifdef DEB_GET_REGION_SHAPE
255   HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfGroups );
256 #endif
257
258   TopoDS_Shape aResShape;
259
260   // Unite the region zones (each zone is a face) into one face (united face)
261   // If the zones can't be united into the single face - unite them into shell
262
263   // Collect the list of region faces
264   TopTools_ListOfShape aRegionFacesList;
265
266   HYDROData_SequenceOfObjects aZones = GetZones();
267   HYDROData_SequenceOfObjects::Iterator aZoneIter( aZones );
268   TopTools_IndexedMapOfShape AllE;
269   TopTools_IndexedMapOfShape IE; //int edges
270
271   for ( ; aZoneIter.More(); aZoneIter.Next() )
272   {
273     Handle(HYDROData_Zone) aZone =
274       Handle(HYDROData_Zone)::DownCast( aZoneIter.Value() );
275     if ( aZone.IsNull() )
276       continue;
277
278     TopoDS_Shape aZoneShape = aZone->GetShape();
279     if ( aZoneShape.IsNull() || aZoneShape.ShapeType() != TopAbs_FACE )
280       continue;
281
282     TopoDS_Face aZoneFace = TopoDS::Face( aZoneShape );
283     aRegionFacesList.Append( aZoneFace );
284     TopExp::MapShapes(aZoneFace, TopAbs_EDGE, AllE); // collect all edges
285     getUsedGroups( aZoneFace, aSeqOfGroups, aSeqOfUsedGroups );
286   } // zones iterator
287
288   for (int i = 1; i <= IntSh->Length(); i++)
289   {
290     const TopoDS_Shape& CS = (*IntSh)(i);
291     if (AllE.Contains(CS))
292       IE.Add(CS);
293   }
294   
295   if ( aRegionFacesList.IsEmpty() )
296     return aResShape;
297
298   TopoDS_Face aRegionFace;
299
300   if ( aRegionFacesList.Extent() == 1 )
301   {
302     aResShape = TopoDS::Face( aRegionFacesList.First() );
303   }
304   else
305   {
306 #ifdef DEB_GET_REGION_SHAPE
307     HYDROData_ShapesGroup::GroupDefinition::Dump( std::cout, aSeqOfUsedGroups );
308 #endif
309
310     // Try to fuse all region faces into one common face
311     TopoDS_Shape aFuseShape;
312     TopTools_ListIteratorOfListOfShape aFaceIter( aRegionFacesList );
313     for ( ; aFaceIter.More(); aFaceIter.Next() )
314     {
315       if ( aFuseShape.IsNull() )
316       {
317         aFuseShape = aFaceIter.Value();
318         continue;
319       }
320
321       BRepAlgoAPI_Fuse aFuse( aFuseShape, aFaceIter.Value() );
322       if ( !aFuse.IsDone() )
323       {
324         aFuseShape.Nullify();
325         break;
326       }
327
328       aFuseShape = aFuse.Shape();
329
330       //update history of internal edges
331       TopTools_IndexedMapOfShape DIE;
332       TopTools_ListOfShape newSh1, newSh2;
333       for (int i = 1; i <= IE.Extent(); i++)
334       {
335         const TopoDS_Shape& CSH = IE(i);
336         newSh1.Clear();
337         newSh2.Clear();
338         newSh1 = aFuse.Modified(CSH);
339         if (newSh1.IsEmpty())
340         {
341           newSh2 = aFuse.Generated(CSH);
342           if (newSh2.IsEmpty())
343             DIE.Add(CSH);
344           else
345             for (TopTools_ListIteratorOfListOfShape lt(newSh2); lt.More(); lt.Next())
346               if (!lt.Value().IsNull())
347                  DIE.Add(lt.Value());
348         }
349         else
350         {
351           for (TopTools_ListIteratorOfListOfShape lt(newSh1); lt.More(); lt.Next())
352             if (!lt.Value().IsNull())
353               DIE.Add(lt.Value());
354         }
355       }
356       IE = DIE;
357       //update groups
358       HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &aFuse );
359     } // faces iterator
360
361 #ifdef DEB_GET_REGION_SHAPE
362     HYDROData_ShapesTool::DumpShapeSubShapes( std::cout, "Fused face edges:", aFuseShape, TopAbs_EDGE );
363 #endif
364
365     aFuseShape = HYDROData_Tool::RebuildCmp(aFuseShape);
366
367     BRep_Builder BB;
368     TopoDS_Face DF;
369     if (!IE.IsEmpty())
370     {
371       //add dummy face to existing shell
372       //this face contains all internal edges
373       //USD algo will skip such edges and will not perform unifying through them 
374       //(more than 2 faces are connected to one edge + non same domain surfaces)
375       TopoDS_Wire DW;
376       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
377       BB.MakeFace(DF, DPl, Precision::Confusion());
378       BB.MakeWire(DW);
379       for (int i = 1; i <= IE.Extent(); i++)
380         BB.Add(DW, IE(i));
381       BB.Add(DF, DW);
382       BB.Add(aFuseShape, DF);
383     }
384
385     ShapeUpgrade_UnifySameDomain unif( aFuseShape, Standard_False, Standard_True, Standard_False );
386     unif.Build();
387     TopoDS_Shape anUnitedShape;
388     const TopoDS_Shape& out = unif.Shape();
389
390     HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &unif );
391
392     if (!IE.IsEmpty())
393     {
394       //remove dummy face from shell; shell becomes valid
395       const TopoDS_Shape& NDF = unif.History()->Modified(DF).First();
396       BRepTools_ReShape ReShaper;
397       ReShaper.Remove(NDF);
398       anUnitedShape = ReShaper.Apply(out);
399       HYDROData_ShapesGroup::GroupDefinition::Update( &aSeqOfUsedGroups, &ReShaper );
400     }
401     else
402       anUnitedShape = out;
403
404     TopTools_SequenceOfShape aShapeFaces;
405     HYDROData_ShapesTool::ExploreShapeToShapes( anUnitedShape, TopAbs_FACE, aShapeFaces );
406     if ( aShapeFaces.Length() == 1 ) //it should be either face or compound of faces (?)
407     {
408       const TopoDS_Face& CF = TopoDS::Face( aShapeFaces.Value( 1 ));
409       aResShape = CF;
410     }
411     else
412     {
413       TopTools_SequenceOfShape aShapeShells;
414       HYDROData_ShapesTool::ExploreShapeToShapes( anUnitedShape, TopAbs_SHELL, aShapeShells );
415       if (aShapeShells.Length() == 1)
416         aResShape = TopoDS::Shell(aShapeShells(1));
417       else
418         aResShape = anUnitedShape;
419     }
420
421     // Update the sequence of groups
422     if ( theSeqOfGroups )
423     {
424       HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator aUsedIter( aSeqOfUsedGroups );
425       for ( ; aUsedIter.More(); aUsedIter.Next() )
426       {
427         const HYDROData_ShapesGroup::GroupDefinition& aUsedGroupDef = aUsedIter.Value();
428         if ( aUsedGroupDef.Shapes.IsEmpty() )
429           continue;
430
431         HYDROData_ShapesGroup::SeqOfGroupsDefs::Iterator anOriIter( aSeqOfGroups );
432         for ( ; anOriIter.More(); anOriIter.Next() )
433         {
434           HYDROData_ShapesGroup::GroupDefinition& anOriGroupDef = anOriIter.ChangeValue();
435           if ( anOriGroupDef.Name != aUsedGroupDef.Name )
436             continue;
437
438           HYDROData_ShapesTool::AddShapes( anOriGroupDef.Shapes, aUsedGroupDef.Shapes );
439           break;
440         }
441       }
442
443       *theSeqOfGroups = aSeqOfGroups;
444     }
445   }
446
447   return aResShape;
448 }
449
450 QStringList HYDROData_Region::DumpToPython( const QString&       thePyScriptPath,
451                                             MapOfTreatedObjects& theTreatedObjects,
452                                             QString              defRegName ) const
453 {
454   QStringList aResList;
455
456   // Find region
457   findPythonReferenceObject( aResList, defRegName );
458
459   // Add zones
460   HYDROData_SequenceOfObjects aZones = GetZones();
461   HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
462   for ( ; aZonesIter.More(); aZonesIter.Next() ) {
463     Handle(HYDROData_Zone) aZone =
464       Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
465     if ( aZone.IsNull() ) {
466       continue;
467     }
468     
469     // find zone
470     aZone->findPythonReferenceObject( aResList );
471     theTreatedObjects.insert( aZone->GetName(), aZone );
472     
473     // set zone merge type
474     QString aMergeTypeStr;
475     HYDROData_Zone::MergeType aMergeType = aZone->GetMergeType();
476     if ( aMergeType == HYDROData_Zone::Merge_ZMIN ) {
477       aMergeTypeStr = "HYDROData_Zone.Merge_ZMIN";
478     } else if ( aMergeType == HYDROData_Zone::Merge_ZMAX ) {
479       aMergeTypeStr = "HYDROData_Zone.Merge_ZMAX";
480     } else if ( aMergeType == HYDROData_Zone::Merge_Object ) {
481       aMergeTypeStr = "HYDROData_Zone.Merge_Object";
482     }
483
484     if ( !aMergeTypeStr.isEmpty() ) {
485       aResList << QString( "%1.SetMergeType( %2 )" ).arg( aZone->GetObjPyName() ).arg( aMergeTypeStr );
486     }
487     if ( aMergeType == HYDROData_Zone::Merge_Object ) {
488       Handle(HYDROData_Entity) aMergeObject = aZone->GetMergeObject();
489       if ( !aMergeObject.IsNull() ) {
490         aMergeObject->findPythonReferenceObject( aResList );
491         aResList << QString( "%1.SetMergeObject( %2 )" ).arg( aZone->GetObjPyName() )
492                                                         .arg( aMergeObject->GetObjPyName() );
493       }
494     }
495     // set color
496     QColor zoneColor = aZone->GetColor(Qt::darkBlue);
497     aResList << QString( "%1.SetColor( QColor( %2, %3, %4 ))" )
498                  .arg( aZone->GetObjPyName() ).arg( zoneColor.red() ).arg( zoneColor.green() ).arg( zoneColor.blue() );
499     // add zone
500     setPythonReferenceObject( thePyScriptPath, theTreatedObjects, aResList, aZone, "AddZone" );
501
502   }
503
504   return aResList;
505 }
506
507 bool HYDROData_Region::IsSubmersible() const
508 {
509   HYDROData_SequenceOfObjects aZones = GetZones();
510   HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
511   for ( ; aZonesIter.More(); aZonesIter.Next() )
512   {
513     Handle(HYDROData_Zone) aZone =
514       Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
515     if ( !aZone->IsSubmersible() )
516       return false; //if one of zones is not submersible the region is considered as not submersible
517   }
518   return true;
519 }