Salome HOME
02c73ba80cb2fd315c7340c545074bf153ecf11a
[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_Builder.hxx>
25 #include <BOPAlgo_PaveFiller.hxx>
26 #include <BOPCol_ListOfShape.hxx>
27 #include <BRep_Builder.hxx>
28 #include <BRepAlgoAPI_Fuse.hxx>
29 #include <BRepBuilderAPI_MakeFace.hxx>
30 #include <NCollection_IndexedMap.hxx>
31 #include <TNaming_Builder.hxx>
32 #include <TNaming_NamedShape.hxx>
33 #include <TopoDS.hxx>
34 #include <TopoDS_Compound.hxx>
35 #include <TopoDS_Face.hxx>
36 #include <TopoDS_Iterator.hxx>
37 #include <TopoDS_Shell.hxx>
38 #include <TopTools_ListIteratorOfListOfShape.hxx>
39
40 #include <QString>
41
42 IMPLEMENT_STANDARD_HANDLE(HYDROData_LandCoverMap, HYDROData_Entity)
43 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_LandCoverMap, HYDROData_Entity)
44
45 class HYDROData_MapOfFaceToStricklerType : public NCollection_IndexedDataMap<TopoDS_Face, QString>
46 {
47 };
48
49 /**
50   Constructor
51   @param theMap the land cover map to iterate through
52 */
53 HYDROData_LandCoverMap::Iterator::Iterator( const HYDROData_LandCoverMap& theMap )
54 {
55   Init( theMap );
56 }
57
58 HYDROData_LandCoverMap::Iterator::Iterator( const Handle( HYDROData_LandCoverMap )& theMap )
59 {
60   if( theMap.IsNull() )
61   {
62     myIterator = 0;
63     myIndex = -1;
64   }
65   else
66     Init( *theMap );
67 }
68
69 /**
70   Initialize the iterator
71   @param theMap the land cover map to iterate through
72 */
73 void HYDROData_LandCoverMap::Iterator::Init( const HYDROData_LandCoverMap& theMap )
74 {
75   TopoDS_Shape aShape = theMap.GetShape();
76   if( aShape.IsNull() )
77     myIterator = 0;
78   else
79     myIterator = new TopoDS_Iterator( aShape );
80   myIndex = 0;
81   theMap.myLab.FindChild( DataTag_Types ).FindAttribute( TDataStd_ExtStringArray::GetID(), myArray );
82 }
83
84 /**
85   Destructor
86 */
87 HYDROData_LandCoverMap::Iterator::~Iterator()
88 {
89   delete myIterator;
90 }
91
92 /**
93   Return if the iterator has more elements
94   @return if the iterator has more elements
95 */
96 bool HYDROData_LandCoverMap::Iterator::More() const
97 {
98   return !myArray.IsNull() && myIterator && myIterator->More();
99 }
100
101 /**
102   Move iterator to the next element
103 */
104 void HYDROData_LandCoverMap::Iterator::Next()
105 {
106   if( myIterator )
107   {
108     myIterator->Next();
109     myIndex++;
110   }
111 }
112
113 /**
114   Get the current land cover (face)
115   @return the land cover's face
116 */
117 TopoDS_Face HYDROData_LandCoverMap::Iterator::Face() const
118 {
119   if( myIterator )
120     return TopoDS::Face( myIterator->Value() );
121   else
122     return TopoDS_Face();
123 }
124
125 /**
126   Get the current land cover's Strickler type 
127   @return the land cover's Strickler type 
128 */
129 QString HYDROData_LandCoverMap::Iterator::StricklerType() const
130 {
131   if( myArray.IsNull() || myIndex < myArray->Lower() || myIndex > myArray->Upper() )
132     return "";
133   else
134     return HYDROData_Tool::toQString( myArray->Value( myIndex ) );
135 }
136
137 /**
138   Constructor
139 */
140 HYDROData_LandCoverMap::HYDROData_LandCoverMap()
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   BRepAlgoAPI_Fuse aFuse;
299   aFuse.SetArguments( theFaces );
300   aFuse.Build();
301   if( !aFuse.IsDone() )
302     return false;
303
304   TopoDS_Shape aMergedShape = aFuse.Shape();
305   if( aMergedShape.ShapeType()!=TopAbs_FACE )
306     return false;
307
308   // 3. to add the face into the map
309   return LocalPartition( TopoDS::Face( aMergedShape ), theType );
310 }
311
312 /**
313   Get the shape of the land cover map
314 */
315 TopoDS_Shape HYDROData_LandCoverMap::GetShape() const
316 {
317   TDF_Label aLabel = myLab.FindChild( DataTag_Shape, false );
318   if ( !aLabel.IsNull() )
319   {
320     Handle(TNaming_NamedShape) aNamedShape;
321     if( aLabel.FindAttribute( TNaming_NamedShape::GetID(), aNamedShape ) )
322       return aNamedShape->Get();
323   }
324   return TopoDS_Shape();
325 }
326
327 /**
328   Set the shape of the land cover map
329   @param theShape the new shape for the land cover map
330 */
331 void HYDROData_LandCoverMap::SetShape( const TopoDS_Shape& theShape )
332 {
333   TNaming_Builder aBuilder( myLab.FindChild( DataTag_Shape ) );
334   aBuilder.Generated( theShape );
335 }
336
337 /**
338   Perform the local partition algorithm on the land cover
339   @param theNewShape the new shape to add into the land cover
340   @param theNewType the new Strickler type for the new land cover
341   @return if the local partition is successful
342 */
343 bool HYDROData_LandCoverMap::LocalPartition( const TopoDS_Shape& theNewShape, const QString& theNewType )
344 {
345   if( theNewShape.IsNull() )
346     return false;
347
348   BOPCol_ListOfShape aShapesList;
349   BOPAlgo_PaveFiller aPaveFiller;
350   HYDROData_MapOfFaceToStricklerType aNewFaces;
351
352   // add faces to shapes list
353   Iterator anIt( *this );
354   for( ; anIt.More(); anIt.Next() )
355     aShapesList.Append( anIt.Face() );
356   aShapesList.Append( theNewShape );
357
358   if( aShapesList.Size()==1 && theNewShape.ShapeType()==TopAbs_FACE )
359   {
360     aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType );
361     StoreLandCovers( aNewFaces );
362     return true;
363   }
364
365   // prepare pave filler
366   aPaveFiller.SetArguments( aShapesList );
367   aPaveFiller.Perform();
368   Standard_Integer anError = aPaveFiller.ErrorStatus();
369   if( anError )
370     return false;
371
372   // add faces to builder
373   BOPAlgo_Builder aBuilder;
374   anIt.Init( *this );
375   for( ; anIt.More(); anIt.Next() )
376     aBuilder.AddArgument( anIt.Face() );
377   aBuilder.AddArgument( theNewShape );
378
379   // perform the partition with the pave filler
380   aBuilder.PerformWithFiller( aPaveFiller );
381   anError = aBuilder.ErrorStatus();
382   if( anError )
383     return false;
384
385   // analysis of the history
386   //     a. to fill map of shapes which come from the new face
387   NCollection_IndexedMap<TopoDS_Shape> aShapesFromNewFace;
388   //std::cout << "new: " << theNewShape << " " << theNewType << std::endl;
389   TopTools_ListOfShape aModified = aBuilder.Modified( theNewShape );
390   TopTools_ListIteratorOfListOfShape aMIt( aModified );
391   for( ; aMIt.More(); aMIt.Next() )
392   {
393     //std::cout << "   " << aMIt.Value() << std::endl;
394     aShapesFromNewFace.Add( aMIt.Value() );
395   }
396
397   //     b. to fill map of parts except parts from new face
398   anIt.Init( *this );
399   for( ; anIt.More(); anIt.Next() )
400   {
401     QString aSType = anIt.StricklerType();
402     //std::cout << anIt.Face() << " " << anIt.StricklerType() << std::endl;
403     TopTools_ListOfShape aModified = aBuilder.Modified( anIt.Face() );
404     TopTools_ListIteratorOfListOfShape aMIt( aModified );
405     for( ; aMIt.More(); aMIt.Next() )
406     {
407       TopoDS_Shape aShape = aMIt.Value();
408       bool isFace = aShape.ShapeType()==TopAbs_FACE;
409       bool isAlsoFromNew = aShapesFromNewFace.Contains( aShape );
410       //std::cout << "   " << aShape << " " << isAlsoFromNew << std::endl;
411       if( isFace && !isAlsoFromNew )
412         aNewFaces.Add( TopoDS::Face( aShape ), aSType );
413     }
414   }
415
416   //     c. add the new shape if it is face with its type
417   if( theNewShape.ShapeType()==TopAbs_FACE )
418     aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType );
419   
420   // convert map of shape to type to compound and list of types
421   StoreLandCovers( aNewFaces );
422   return true;
423 }
424
425 /**
426   Replace the set of land covers in the land cover map
427   @param theMap the map of shape (face) to Strickler type (string)
428 */
429 void HYDROData_LandCoverMap::StoreLandCovers( const HYDROData_MapOfFaceToStricklerType& theMap )
430 {
431   TopoDS_Compound aCompound;
432   BRep_Builder aCompoundBuilder;
433   aCompoundBuilder.MakeCompound( aCompound );
434
435   int n = theMap.Size();
436   Handle( TDataStd_ExtStringArray ) aTypes = 
437     TDataStd_ExtStringArray::Set( myLab.FindChild( DataTag_Types ), 0, n-1, Standard_True );
438   HYDROData_MapOfFaceToStricklerType::Iterator aNFIt( theMap );
439   for( int i=0; aNFIt.More(); aNFIt.Next(), i++ )
440   {
441     TopoDS_Face aFace = aNFIt.Key();
442     QString aType = aNFIt.Value();
443     aCompoundBuilder.Add( aCompound, aFace );
444     aTypes->SetValue( i, HYDROData_Tool::toExtString( aType ) );
445   }
446
447   SetShape( aCompound );
448 }