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