Salome HOME
c7064889eeaa7c07bc4515f41761d5ac566cfef7
[modules/hydro.git] / src / HYDROData / HYDROData_LandCoverMap.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_LandCoverMap.h>
20 #include <HYDROData_Object.h>
21 #include <HYDROData_PolylineXY.h>
22 #include <HYDROData_Tool.h>
23
24 #include <BOPAlgo_BOP.hxx>
25 #include <BOPAlgo_Builder.hxx>
26 #include <BOPAlgo_PaveFiller.hxx>
27 #include <BOPCol_ListOfShape.hxx>
28 #include <BRep_Builder.hxx>
29 #include <BRepAlgoAPI_Fuse.hxx>
30 #include <BRepBuilderAPI_MakeFace.hxx>
31 #include <NCollection_IndexedMap.hxx>
32 #include <TopoDS.hxx>
33 #include <TopoDS_Compound.hxx>
34 #include <TopoDS_Face.hxx>
35 #include <TopoDS_Iterator.hxx>
36 #include <TopoDS_Shell.hxx>
37 #include <TopTools_ListIteratorOfListOfShape.hxx>
38
39 #include <QString>
40
41 IMPLEMENT_STANDARD_HANDLE(HYDROData_LandCoverMap, HYDROData_Entity)
42 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_LandCoverMap, HYDROData_Entity)
43
44 class HYDROData_MapOfFaceToStricklerType : public NCollection_IndexedDataMap<TopoDS_Face, QString>
45 {
46 };
47
48 /**
49   Constructor
50   @param theMap the land cover map to iterate through
51 */
52 HYDROData_LandCoverMap::Iterator::Iterator( const HYDROData_LandCoverMap& theMap )
53 {
54   Init( theMap );
55 }
56
57 HYDROData_LandCoverMap::Iterator::Iterator( const Handle( HYDROData_LandCoverMap )& theMap )
58 {
59   if( theMap.IsNull() )
60   {
61     myIterator = 0;
62     myIndex = -1;
63   }
64   else
65     Init( *theMap );
66 }
67
68 /**
69   Initialize the iterator
70   @param theMap the land cover map to iterate through
71 */
72 void HYDROData_LandCoverMap::Iterator::Init( const HYDROData_LandCoverMap& theMap )
73 {
74   TopoDS_Shape aShape = theMap.GetShape();
75   if( aShape.IsNull() )
76     myIterator = 0;
77   else
78     myIterator = new TopoDS_Iterator( aShape );
79   myIndex = 0;
80   theMap.myLab.FindChild( DataTag_Types ).FindAttribute( TDataStd_ExtStringArray::GetID(), myArray );
81 }
82
83 /**
84   Destructor
85 */
86 HYDROData_LandCoverMap::Iterator::~Iterator()
87 {
88   delete myIterator;
89 }
90
91 /**
92   Return if the iterator has more elements
93   @return if the iterator has more elements
94 */
95 bool HYDROData_LandCoverMap::Iterator::More() const
96 {
97   return !myArray.IsNull() && myIterator && myIterator->More();
98 }
99
100 /**
101   Move iterator to the next element
102 */
103 void HYDROData_LandCoverMap::Iterator::Next()
104 {
105   if( myIterator )
106   {
107     myIterator->Next();
108     myIndex++;
109   }
110 }
111
112 /**
113   Get the current land cover (face)
114   @return the land cover's face
115 */
116 TopoDS_Face HYDROData_LandCoverMap::Iterator::Face() const
117 {
118   if( myIterator )
119     return TopoDS::Face( myIterator->Value() );
120   else
121     return TopoDS_Face();
122 }
123
124 /**
125   Get the current land cover's Strickler type 
126   @return the land cover's Strickler type 
127 */
128 QString HYDROData_LandCoverMap::Iterator::StricklerType() const
129 {
130   if( myArray.IsNull() || myIndex < myArray->Lower() || myIndex > myArray->Upper() )
131     return "";
132   else
133     return HYDROData_Tool::toQString( myArray->Value( myIndex ) );
134 }
135
136 /**
137   Constructor
138 */
139 HYDROData_LandCoverMap::HYDROData_LandCoverMap()
140   : HYDROData_Entity( Geom_No )
141 {
142 }
143
144 /**
145   Destructor
146 */
147 HYDROData_LandCoverMap::~HYDROData_LandCoverMap()
148 {
149 }
150
151 /**
152   Get object's kind
153   @return object's kind
154 */
155 const ObjectKind HYDROData_LandCoverMap::GetKind() const
156 {
157   return KIND_LAND_COVER_MAP;
158 }
159
160 /**
161   Import the land cover map from QGIS
162   @param theFileName the name of file
163   @return if the import is successful
164 */
165 bool HYDROData_LandCoverMap::ImportQGIS( const QString& theFileName )
166 {
167   //TODO
168   return false;
169 }
170
171 /**
172   Export the land cover map to QGIS
173   @param theFileName the name of file
174   @return if the export is successful
175 */
176 bool HYDROData_LandCoverMap::ExportQGIS( const QString& theFileName ) const
177 {
178   //TODO
179   return false;
180 }
181
182 /**
183   Export the land cover map for the solver (Telemac)
184   @param theFileName the name of file
185   @return if the export is successful
186 */
187 bool HYDROData_LandCoverMap::ExportTelemac( const QString& theFileName ) const
188 {
189   //TODO
190   return false;
191 }
192
193 /**
194   Add a new object as land cover
195   @param theObject the object to add as land cover
196   @param theType the Strickler type for the new land cover
197   @return if the addition is successful
198 */
199 bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_Object )& theObject, const QString& theType )
200 {
201   if( theObject.IsNull() )
202     return false;
203
204   TopoDS_Shape aShape = theObject->GetTopShape();
205   if( aShape.ShapeType()!=TopAbs_FACE )
206     return false;
207
208   TopoDS_Face aFace = TopoDS::Face( aShape );
209   return LocalPartition( aFace, theType );
210 }
211
212 /**
213   Add a new polyline as land cover
214   @param thePolyline the polyline to add as land cover
215   @param theType the Strickler type for the new land cover
216   @return if the addition is successful
217 */
218 bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_PolylineXY )& thePolyline, const QString& theType )
219 {
220   if( thePolyline.IsNull() )
221     return false;
222
223   TopoDS_Shape aShape = thePolyline->GetShape();
224   if( aShape.ShapeType()!=TopAbs_WIRE )
225     return false;
226
227   TopoDS_Wire aWire = TopoDS::Wire( aShape );
228   if( !aWire.Closed() )
229     return false;
230
231   TopoDS_Face aFace = BRepBuilderAPI_MakeFace( aWire, Standard_True ).Face();
232   return LocalPartition( aFace, theType );
233 }
234
235 /**
236   Remove the given face from land cover map
237   @param theFace the face to be removed
238   @return if the removing is successful
239 */
240 bool HYDROData_LandCoverMap::Remove( const TopoDS_Face& theFace )
241 {
242   TopTools_ListOfShape aList;
243   aList.Append( theFace );
244   return Remove( aList );
245 }
246
247 /**
248   Remove the given faces from land cover map
249   @param theFacesToRemove the face list to be removed
250   @return if the removing is successful
251 */
252 bool HYDROData_LandCoverMap::Remove( const TopTools_ListOfShape& theFacesToRemove )
253 {
254   HYDROData_MapOfFaceToStricklerType aFacesToRemove, aNewFaces;
255   TopTools_ListIteratorOfListOfShape aFIt( theFacesToRemove );
256   for( ; aFIt.More(); aFIt.Next() )
257   {
258     TopoDS_Shape aShape = aFIt.Value();
259     if( aShape.ShapeType()==TopAbs_FACE )
260       aFacesToRemove.Add( TopoDS::Face( aShape ), "" );
261   }
262
263   Iterator anIt( *this );
264   for( ; anIt.More(); anIt.Next() )
265     if( !aFacesToRemove.Contains( anIt.Face() ) )
266       aNewFaces.Add( anIt.Face(), anIt.StricklerType() );
267
268   StoreLandCovers( aNewFaces );
269   return true;
270 }
271
272 /**
273   Split the land cover map by the given polyline
274   @param thePolyline the tool polyline to split the land cover map
275   @return if the removing is successful
276 */
277 bool HYDROData_LandCoverMap::Split( const Handle( HYDROData_PolylineXY )& thePolyline )
278 {
279   if( thePolyline.IsNull() )
280     return false;
281
282   TopoDS_Shape aShape = thePolyline->GetShape();
283   return LocalPartition( aShape, "" );
284 }
285
286 /**
287   Merge the given faces in the land cover
288   @param theFaces the faces to merge in the land cover map
289   @param theType the Strickler type for the merged land cover
290   @return if the merge is successful
291 */
292 bool HYDROData_LandCoverMap::Merge( const TopTools_ListOfShape& theFaces, const QString& theType )
293 {
294   // 1. to remove the merged faces from the current map
295   Remove( theFaces );
296
297   // 2. to fuse the faces into the new face
298   BOPAlgo_PaveFiller aPF;
299   aPF.SetArguments( theFaces );
300   aPF.SetFuzzyValue( 1E-2 ); 
301   aPF.SetRunParallel( Standard_False );
302   aPF.Perform();
303   int iErr = aPF.ErrorStatus();
304   if( iErr )
305     return false;
306
307   BOPAlgo_BOP aBOP;
308   aBOP.SetArguments( theFaces );
309   aBOP.SetOperation( BOPAlgo_FUSE );
310   aBOP.SetRunParallel( Standard_False );
311   aBOP.PerformWithFiller(aPF);
312   iErr = aBOP.ErrorStatus();
313   if( iErr )
314     return false;
315
316   TopoDS_Shape aMergedShape = aBOP.Shape();
317   if( aMergedShape.ShapeType()!=TopAbs_FACE )
318     return false;
319
320   // 3. to add the face into the map
321   return LocalPartition( TopoDS::Face( aMergedShape ), theType );
322 }
323
324 /**
325   Get the shape of the land cover map
326 */
327 TopoDS_Shape HYDROData_LandCoverMap::GetShape() const
328 {
329   return HYDROData_Entity::GetShape( DataTag_Shape );
330 }
331
332 /**
333   Set the shape of the land cover map
334   @param theShape the new shape for the land cover map
335 */
336 void HYDROData_LandCoverMap::SetShape( const TopoDS_Shape& theShape )
337 {
338   HYDROData_Entity::SetShape( DataTag_Shape, theShape );
339 }
340
341 /**
342   Perform the local partition algorithm on the land cover
343   @param theNewShape the new shape to add into the land cover
344   @param theNewType the new Strickler type for the new land cover
345   @return if the local partition is successful
346 */
347 bool HYDROData_LandCoverMap::LocalPartition( const TopoDS_Shape& theNewShape, const QString& theNewType )
348 {
349   if( theNewShape.IsNull() )
350     return false;
351
352   BOPCol_ListOfShape aShapesList;
353   BOPAlgo_PaveFiller aPaveFiller;
354   HYDROData_MapOfFaceToStricklerType aNewFaces;
355
356   // add faces to shapes list
357   Iterator anIt( *this );
358   for( ; anIt.More(); anIt.Next() )
359     aShapesList.Append( anIt.Face() );
360   aShapesList.Append( theNewShape );
361
362   if( aShapesList.Size()==1 && theNewShape.ShapeType()==TopAbs_FACE )
363   {
364     aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType );
365     StoreLandCovers( aNewFaces );
366     return true;
367   }
368
369   // prepare pave filler
370   aPaveFiller.SetArguments( aShapesList );
371   aPaveFiller.Perform();
372   Standard_Integer anError = aPaveFiller.ErrorStatus();
373   if( anError )
374     return false;
375
376   // add faces to builder
377   BOPAlgo_Builder aBuilder;
378   anIt.Init( *this );
379   for( ; anIt.More(); anIt.Next() )
380     aBuilder.AddArgument( anIt.Face() );
381   aBuilder.AddArgument( theNewShape );
382
383   // perform the partition with the pave filler
384   aBuilder.PerformWithFiller( aPaveFiller );
385   anError = aBuilder.ErrorStatus();
386   if( anError )
387     return false;
388
389   // analysis of the history
390   //     a. to fill map of shapes which come from the new face
391   NCollection_IndexedMap<TopoDS_Shape> aShapesFromNewFace;
392   //std::cout << "new: " << theNewShape << " " << theNewType << std::endl;
393   TopTools_ListOfShape aModified = aBuilder.Modified( theNewShape );
394   TopTools_ListIteratorOfListOfShape aMIt( aModified );
395   for( ; aMIt.More(); aMIt.Next() )
396   {
397     //std::cout << "   " << aMIt.Value() << std::endl;
398     aShapesFromNewFace.Add( aMIt.Value() );
399   }
400
401   //     b. to fill map of parts except parts from new face
402   anIt.Init( *this );
403   for( ; anIt.More(); anIt.Next() )
404   {
405     QString aSType = anIt.StricklerType();
406     //std::cout << anIt.Face() << " " << anIt.StricklerType() << std::endl;
407     TopTools_ListOfShape aModified = aBuilder.Modified( anIt.Face() );
408     TopTools_ListIteratorOfListOfShape aMIt( aModified );
409     for( ; aMIt.More(); aMIt.Next() )
410     {
411       TopoDS_Shape aShape = aMIt.Value();
412       bool isFace = aShape.ShapeType()==TopAbs_FACE;
413       bool isAlsoFromNew = aShapesFromNewFace.Contains( aShape );
414       //std::cout << "   " << aShape << " " << isAlsoFromNew << std::endl;
415       if( isFace && !isAlsoFromNew )
416         aNewFaces.Add( TopoDS::Face( aShape ), aSType );
417     }
418   }
419
420   //     c. add the new shape if it is face with its type
421   if( theNewShape.ShapeType()==TopAbs_FACE )
422     aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType );
423   
424   // convert map of shape to type to compound and list of types
425   StoreLandCovers( aNewFaces );
426   return true;
427 }
428
429 /**
430   Replace the set of land covers in the land cover map
431   @param theMap the map of shape (face) to Strickler type (string)
432 */
433 void HYDROData_LandCoverMap::StoreLandCovers( const HYDROData_MapOfFaceToStricklerType& theMap )
434 {
435   TopoDS_Compound aCompound;
436   BRep_Builder aCompoundBuilder;
437   aCompoundBuilder.MakeCompound( aCompound );
438
439   int n = theMap.Size();
440   Handle( TDataStd_ExtStringArray ) aTypes = 
441     TDataStd_ExtStringArray::Set( myLab.FindChild( DataTag_Types ), 0, n-1, Standard_True );
442   HYDROData_MapOfFaceToStricklerType::Iterator aNFIt( theMap );
443   for( int i=0; aNFIt.More(); aNFIt.Next(), i++ )
444   {
445     TopoDS_Face aFace = aNFIt.Key();
446     QString aType = aNFIt.Value();
447     aCompoundBuilder.Add( aCompound, aFace );
448     aTypes->SetValue( i, HYDROData_Tool::toExtString( aType ) );
449   }
450
451   SetShape( aCompound );
452 }
453
454 /**
455   Find the land cover for the given point
456   @param thePoint the point laying in some land cover
457   @param theType the returned type
458   @return the found land cover's face
459 */
460 TopoDS_Face HYDROData_LandCoverMap::FindByPoint( const gp_Pnt2d& thePoint, QString& theType ) const
461 {
462   //TODO: some more optimal algorithm
463   Iterator anIt( *this );
464   for( ; anIt.More(); anIt.Next() )
465     if( HYDROData_Tool::ComputePointState( thePoint.XY(), anIt.Face() ) == TopAbs_IN )
466     {
467       theType = anIt.StricklerType();
468       return anIt.Face();
469     }
470
471   theType = "";
472   return TopoDS_Face();
473 }