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