Salome HOME
7e48efb2d248b9313decbe1bea4cd1d41c1c7631
[modules/hydro.git] / src / HYDROData / HYDROData_SplitToZonesTool.cxx
1
2 #include "HYDROData_SplitToZonesTool.h"
3
4 #include "HYDROData_PolylineXY.h"
5
6 #include <BRepAlgoAPI_Common.hxx>
7 #include <BRepAlgoAPI_Cut.hxx>
8 #include <BRepBuilderAPI_MakeFace.hxx>
9
10 #include <TopExp_Explorer.hxx>
11 #include <TopoDS.hxx>
12 #include <TopoDS_Edge.hxx>
13 #include <TopoDS_Iterator.hxx>
14 #include <TopoDS_Wire.hxx>
15 #include <TopoDS_Iterator.hxx>
16 #include <BRepCheck_Analyzer.hxx>
17 #include <NCollection_IncAllocator.hxx>
18 #include <BOPAlgo_Builder.hxx>
19 #include <BOPAlgo_PaveFiller.hxx>
20 #include <NCollection_DataMap.hxx>
21 #include <TopTools_ListOfShape.hxx>
22 #include <TopTools_ListIteratorOfListOfShape.hxx>
23 #include <TopTools_ShapeMapHasher.hxx>
24 typedef NCollection_DataMap<TopoDS_Shape, TopTools_ListOfShape, TopTools_ShapeMapHasher> HYDROData_DataMapOfShapeListOfShape;
25 typedef HYDROData_DataMapOfShapeListOfShape::Iterator HYDROData_DataMapIteratorOfDataMapOfShapeListOfShape;
26 typedef NCollection_DataMap<TopoDS_Shape,  QStringList, TopTools_ShapeMapHasher> HYDROData_DataMapOfShapeListOfString;
27 typedef HYDROData_DataMapOfShapeListOfString::Iterator HYDROData_DataMapIteratorOfDataMapOfShapeListOfString;
28 #undef _NCollection_MapHasher
29
30 #define DEB_SPLIT_TO_ZONES 1
31 #ifdef DEB_SPLIT_TO_ZONES        
32 #include <BRepTools.hxx>
33 #endif
34 TopoDS_Face HYDROData_SplitToZonesTool::SplitData::Face() const
35 {
36   TopoDS_Face aResFace;
37
38   if( !Shape.IsNull() )
39   {
40     if ( Shape.ShapeType() == TopAbs_FACE )
41     {
42       aResFace = TopoDS::Face( Shape );
43     }
44     else if ( Shape.ShapeType() == TopAbs_WIRE )
45     {
46       BRepBuilderAPI_MakeFace aMakeFace( TopoDS::Wire( Shape ), Standard_True );
47       aMakeFace.Build();
48       if( aMakeFace.IsDone() )
49         aResFace = aMakeFace.Face();
50     }
51   }
52
53   return aResFace;
54 }
55
56 HYDROData_SplitToZonesTool::SplitDataList
57   HYDROData_SplitToZonesTool::Split( const HYDROData_SequenceOfObjects&  theObjectList,
58                                      const HYDROData_SequenceOfObjects&  theGroupsList,
59                                      const Handle(HYDROData_PolylineXY)& thePolyline )
60 {
61   SplitDataList anOutputSplitDataList;
62
63   // Preparation. 
64   // Collect the object shapes to split. InputDataList will contain elements which will hold shape & name_of_shape.
65   SplitDataList anInputSplitDataList;
66   for( int anIndex = 1, aLength = theObjectList.Length(); anIndex <= aLength; anIndex++ )
67   {
68     Handle(HYDROData_Object) aGeomObj = 
69       Handle(HYDROData_Object)::DownCast( theObjectList.Value( anIndex ) );
70     if( aGeomObj.IsNull() )
71       continue;
72
73     TopoDS_Shape aShape = aGeomObj->GetTopShape();
74     if ( aShape.IsNull() )
75       continue;  
76
77     if ( aShape.ShapeType() == TopAbs_COMPOUND ) {
78       // Create split data for each face contained in the compound
79       TopExp_Explorer anExp( aShape, TopAbs_FACE );
80       for ( ; anExp.More(); anExp.Next() ) {
81         const TopoDS_Face& aFace = TopoDS::Face( anExp.Current() );
82         if ( !aFace.IsNull() ) {
83           SplitData aSplitData( SplitData::Data_Zone, aFace, aGeomObj->GetName() );
84           anInputSplitDataList.append( aSplitData );
85         }
86       }
87     } else {
88       SplitData aSplitData( SplitData::Data_Zone, aShape, aGeomObj->GetName() );
89       anInputSplitDataList.append( aSplitData );
90     }
91   }
92   //
93   SplitDataList anInputGroupList;
94   for( int anIndex = 1; anIndex <= theGroupsList.Length(); anIndex++ )
95   {
96         Handle(HYDROData_Object) aGeomGroup = 
97       Handle(HYDROData_Object)::DownCast( theGroupsList.Value( anIndex ) );
98     if( aGeomGroup.IsNull() )
99       continue;
100         const TopoDS_Shape& aShape = aGeomGroup->GetTopShape();
101     if ( aShape.IsNull() )
102       continue;  
103     if ( aShape.ShapeType() == TopAbs_COMPOUND ) {    
104       TopExp_Explorer anExp( aShape, TopAbs_EDGE );
105       for ( ; anExp.More(); anExp.Next() ) {
106         const TopoDS_Edge& anEdge = TopoDS::Edge( anExp.Current() );
107         if ( !anEdge.IsNull() ) {
108           SplitData aSplitData( SplitData::Data_Edge, anEdge, aGeomGroup->GetName() );
109           anInputGroupList.append( aSplitData );
110         }
111           }
112         } else {
113       SplitData aSplitData( SplitData::Data_Edge, aShape, aGeomGroup->GetName() );
114       anInputGroupList.append( aSplitData );
115     }
116   }
117
118   HYDROData_DataMapOfShapeListOfString aDM3;
119   if(!anInputGroupList.isEmpty()) {     // Old edge ==> List_Of_Names
120     QStringList aListOfNames;
121     for (int i=0;i < anInputGroupList.size() ;i++) {
122       const TopoDS_Shape& aSh = anInputGroupList.at(i).Shape;   
123       aDM3.Bind(aSh, anInputGroupList.at(i).ObjectNames);        
124         }
125   }
126   // Step 1. Prepare Partition structures.
127   Handle(NCollection_BaseAllocator) pA1 = new NCollection_IncAllocator, pA2 = new NCollection_IncAllocator;
128   BOPAlgo_PaveFiller* aPaveFiller      = new BOPAlgo_PaveFiller(pA1);
129   BOPAlgo_Builder* aBuilder            = new BOPAlgo_Builder(pA2);
130   BOPCol_ListOfShape aLS;  
131   QStringList aListOfNames;
132   for (int i=0;i < anInputSplitDataList.size() ;i++) {
133         const TopoDS_Shape& aSh = anInputSplitDataList.at(i).Shape;     
134         aDM3.Bind(aSh, anInputSplitDataList.at(i).ObjectNames);
135     aLS.Append(aSh);    
136   }
137   aPaveFiller->SetArguments(aLS);
138   aPaveFiller->Perform();
139   Standard_Integer anErr = aPaveFiller->ErrorStatus();
140   if(anErr) 
141     return anOutputSplitDataList;
142   BOPDS_PDS pDS = aPaveFiller->PDS();
143   if (!pDS) 
144     return anOutputSplitDataList;
145   aBuilder->Clear();
146
147   // Step 2. Split faces 
148   BOPCol_ListIteratorOfListOfShape anIt(aPaveFiller->Arguments());
149   for (; anIt.More(); anIt.Next()) {
150     const TopoDS_Shape& aS = anIt.Value();
151     aBuilder->AddArgument(aS);
152   }
153   aBuilder->PerformWithFiller(*aPaveFiller);
154   anErr = aBuilder->ErrorStatus();
155   if(anErr) 
156     return anOutputSplitDataList;
157   const TopoDS_Shape& aResult = aBuilder->Shape();
158   if (aResult.IsNull()) 
159     return anOutputSplitDataList;
160   BRepCheck_Analyzer aCheck (aResult);
161   if(!aCheck.IsValid()) {
162 #ifdef DEB_SPLIT_TO_ZONES       
163     cout << "result is not valid" <<endl;        
164     BRepTools::Write(aResult, "SplitFacesNV.brep");  
165 #endif
166     return anOutputSplitDataList;
167   }
168 #ifdef DEB_SPLIT_TO_ZONES       
169   //BRepTools::Write(aResult, "SplitFacesV.brep");
170 #endif
171   
172   // Step 3. Collect history  
173   HYDROData_DataMapOfShapeListOfShape aDM1;
174   anIt.Init(aLS); 
175   //TCollection_AsciiString aNamM ("EdgM_");
176   //TCollection_AsciiString aNamG ("EdgG_");
177   for (int i =1;anIt.More();anIt.Next(),i++) {
178         const TopTools_ListOfShape& aListOfNew = aBuilder->Modified(anIt.Value());      
179     TopTools_ListOfShape aList;
180         TopTools_ListIteratorOfListOfShape it(aListOfNew);
181         for(;it.More();it.Next())       
182           aList.Append(it.Value());
183         // Bug in History: partition should give only modified entities! => temporary solution is used
184     const TopTools_ListOfShape& aListOfGen = aBuilder->Generated(anIt.Value());
185         it.Initialize(aListOfGen);    
186         for(;it.More();it.Next())     
187           aList.Append(it.Value());
188
189         aDM1.Bind(anIt.Value(), aList);
190         //TCollection_AsciiString aName;
191         if(!anInputGroupList.isEmpty()) { /* 1 */
192       aList.Clear();
193           TopExp_Explorer exp (anIt.Value(), TopAbs_EDGE);
194           for (int j =1;exp.More();exp.Next(),j++) {
195             const TopTools_ListOfShape& aListM = aBuilder->Modified(exp.Current());     
196                 //cout << "NB_EDGE_M = " << aListM.Extent() <<endl;
197                 it.Initialize(aListM);    
198                 for(int k=1;it.More();it.Next(),k++) {    
199               aList.Append(it.Value());
200                   //aName = aNamM + i + j +k +".brep";
201                   //BRepTools::Write(it.Value(),aName.ToCString());
202                 }
203                 const TopTools_ListOfShape& aListG = aBuilder->Generated(exp.Current());
204                 it.Initialize(aListG);    
205                 for(int k=1;it.More();it.Next(),k++)   {  
206               aList.Append(it.Value());
207                   //aName = aNamG + i + j +k +".brep";
208                  //BRepTools::Write(it.Value(),aName.ToCString());
209                 }
210                 //cout << "NB_EDGE = " << aList.Extent() <<endl;
211                 aDM1.Bind(exp.Current(), aList);
212           }      
213         }
214   }
215
216   // aDM2: NewShape ==> ListOfOldShapes
217   HYDROData_DataMapOfShapeListOfShape aDM2;
218   HYDROData_DataMapIteratorOfDataMapOfShapeListOfShape aMIt(aDM1);
219   for(;aMIt.More();aMIt.Next()) {
220         const TopoDS_Shape& aKey = aMIt.Key();
221         TopTools_ListOfShape aList;
222         aList.Append(aKey);
223         const TopTools_ListOfShape& aListOfNew = aMIt.Value();
224         TopTools_ListIteratorOfListOfShape it(aListOfNew);
225         for(;it.More();it.Next()) {
226           if(!aDM2.IsBound(it.Value()))
227             aDM2.Bind(it.Value(), aList);
228           else {
229                 TopTools_ListOfShape& aList = aDM2.ChangeFind(it.Value());
230                 aList.Prepend(aKey);
231           }
232         }
233   }
234   //cout << "DM2 Ext = " <<aDM2.Extent() <<endl;
235   // Step 4. Fill output structure.
236   aMIt.Initialize(aDM2);
237   for(int i =1;aMIt.More();aMIt.Next(),i++) {
238     SplitData aDestSplitData;
239         const TopoDS_Shape& aKey = aMIt.Key(); //new
240         aDestSplitData.Shape = aKey;
241         if(aKey.ShapeType() == TopAbs_FACE)
242           aDestSplitData.Type = SplitData::Data_Zone;
243         else
244       aDestSplitData.Type = SplitData::Data_Edge;
245
246         QStringList aListOfNames; // names processing
247     const TopTools_ListOfShape& aListOfOld = aMIt.Value();
248     TopTools_ListIteratorOfListOfShape it(aListOfOld);
249         for(;it.More();it.Next()) {     
250           const TopoDS_Shape& aSh = it.Value(); //old
251           if(aDM3.IsBound(aSh)) {
252             const QStringList& ObjectNames = aDM3.Find(aSh);
253                 aListOfNames.append(ObjectNames);
254           }      
255         }
256 /*      
257         if(aKey.ShapeType() == TopAbs_EDGE) {
258           QString aStr("EDGE_Of_Face_");
259           aStr = aStr.append(TCollection_AsciiString(i).ToCString());
260           const QStringList& ObjectNames = QStringList( aStr);
261           cout << "EDGE ==> " << ObjectNames.size() <<" " << aStr.toStdString()<<endl;
262           aListOfNames.append(ObjectNames);
263         }*/
264         aDestSplitData.ObjectNames = aListOfNames;  
265         anOutputSplitDataList.append(aDestSplitData);
266   }
267   //cout << "anOutputSplitDataList = " <<anOutputSplitDataList.size() <<endl;
268   return anOutputSplitDataList;
269
270   /*
271   SplitDataListIterator anInputIter( anInputSplitDataList );
272   while( anInputIter.hasNext() )
273   {
274     const SplitData& anInputSplitData = anInputIter.next();
275     if( anOutputSplitDataList.isEmpty() )
276       anOutputSplitDataList.append( anInputSplitData );
277     else
278     {
279       SplitDataList aSplitDataList;
280
281       SplitDataList aSrcSplitDataList;
282       aSrcSplitDataList.append( anInputSplitData );
283
284       SplitDataList aDestSplitDataList = anOutputSplitDataList;
285       anOutputSplitDataList.clear();
286
287       while( !aDestSplitDataList.isEmpty() )
288       {
289         SplitData aSrcSplitData = aSrcSplitDataList.last();
290
291         SplitData aDestSplitData = aDestSplitDataList.first();
292         aDestSplitDataList.pop_front();
293
294         SplitData aData1Subtracted, aData2Subtracted, aDataIntersected;
295         if( SplitTwoData( aSrcSplitData, aDestSplitData,
296                           aData1Subtracted, aData2Subtracted, aDataIntersected ) )
297           anOutputSplitDataList.append( aDataIntersected );
298         anOutputSplitDataList.append( aData2Subtracted );
299         aSrcSplitDataList.append( aData1Subtracted );
300       }
301
302       if( !aSrcSplitDataList.isEmpty() )
303         anOutputSplitDataList.append( aSrcSplitDataList.last() );
304     }
305   }
306
307   // Step 2. Take into account the boundary polyline.
308   if( !thePolyline.IsNull() )
309   {
310     TopoDS_Wire aWire = TopoDS::Wire( thePolyline->GetShape() );
311     if( !aWire.IsNull() )
312     {
313       BRepBuilderAPI_MakeFace aMakeFace( aWire, Standard_True );
314       aMakeFace.Build();
315       if( aMakeFace.IsDone() )
316       {
317         SplitData aBoundarySplitData( SplitData::Data_Zone, aMakeFace.Face(), "" );
318
319         SplitDataList aCutSplitDataList;
320         SplitDataListIterator anOutputIter( anOutputSplitDataList );
321         while( anOutputIter.hasNext() )
322         {
323           const SplitData& anOutputSplitData = anOutputIter.next();
324
325           SplitData aData1Subtracted, aData2Subtracted, aDataIntersected;
326           if( SplitTwoData( anOutputSplitData, aBoundarySplitData,
327                             aData1Subtracted, aData2Subtracted, aDataIntersected ) )
328             aCutSplitDataList.append( aDataIntersected );
329         }
330         anOutputSplitDataList = aCutSplitDataList;
331       }
332     }
333   }
334
335   // Step 3. Extract the separate regions.
336   SplitDataList anExtractedSplitDataList;
337   SplitDataListIterator anOutputIter( anOutputSplitDataList );
338   while( anOutputIter.hasNext() )
339   {
340     const SplitData& anOutputSplitData = anOutputIter.next();
341     anExtractedSplitDataList.append( ExtractSeparateData( anOutputSplitData ) );
342   }
343 */
344  // return anExtractedSplitDataList;
345 }
346
347 bool HYDROData_SplitToZonesTool::SplitTwoData( const SplitData& theData1,
348                                                const SplitData& theData2,
349                                                SplitData& theData1Subtracted,
350                                                SplitData& theData2Subtracted,
351                                                SplitData& theDataIntersected )
352 {
353   const TopoDS_Shape& aShape1 = theData1.Shape;
354   const TopoDS_Shape& aShape2 = theData2.Shape;
355
356   const QStringList& anObjectNames1 = theData1.ObjectNames;
357   const QStringList& anObjectNames2 = theData2.ObjectNames;
358
359   BRepAlgoAPI_Common aCommon( aShape1, aShape2 );
360   TopoDS_Shape aCommonShape = aCommon.Shape();
361   if( aCommonShape.IsNull() )
362   {
363     theData1Subtracted = theData1;
364     theData2Subtracted = theData2;
365     return false;
366   }
367
368   BRepAlgoAPI_Cut aCut1( aShape1, aShape2 );
369   TopoDS_Shape aCut1Shape = aCut1.Shape();
370
371   BRepAlgoAPI_Cut aCut2( aShape2, aShape1 );
372   TopoDS_Shape aCut2Shape = aCut2.Shape();
373
374   theData1Subtracted = SplitData( SplitData::Data_Zone, aCut1Shape, anObjectNames1 );
375   theData2Subtracted = SplitData( SplitData::Data_Zone, aCut2Shape, anObjectNames2 );
376   theDataIntersected = SplitData( SplitData::Data_Zone, aCommonShape, anObjectNames1 + anObjectNames2 );
377
378   return true;
379 }
380
381 HYDROData_SplitToZonesTool::SplitDataList
382 HYDROData_SplitToZonesTool::ExtractSeparateData( const SplitData& theData )
383 {
384   SplitDataList aSplitDataList;
385   TopExp_Explorer anExp( theData.Shape, TopAbs_FACE );
386   for( ; anExp.More(); anExp.Next() )
387   {
388     TopoDS_Shape aShape = anExp.Current();
389     if( aShape.ShapeType() == TopAbs_FACE )
390     {
391       TopoDS_Face aFace = TopoDS::Face( aShape );
392       if( !aFace.IsNull() )
393       {
394         SplitData aSplitData( SplitData::Data_Zone, aFace, theData.ObjectNames );
395         aSplitDataList.append( aSplitData );
396       }
397     }
398   }
399   return aSplitDataList;
400 }