Salome HOME
6f7ecb62f9f9c33612944b1759fbf06421fedb44
[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_Edge.hxx>
35 #include <TopoDS_Face.hxx>
36 #include <TopoDS_Iterator.hxx>
37 #include <TopoDS_Shell.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40 #include <BOPAlgo_PaveFiller.hxx>
41 #include <BRepTools.hxx>
42 #include <TopExp_Explorer.hxx>
43 #include <ShapeUpgrade_UnifySameDomain.hxx>
44
45 #include <QFile>
46 #include <QString>
47 #include <QTextStream>
48
49 const char TELEMAC_FORMAT = 'f';
50 const int TELEMAC_PRECISION = 3;
51
52
53 IMPLEMENT_STANDARD_HANDLE(HYDROData_LandCoverMap, HYDROData_Entity)
54 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_LandCoverMap, HYDROData_Entity)
55
56 class HYDROData_MapOfFaceToStricklerType : public NCollection_IndexedDataMap<TopoDS_Face, QString>
57 {
58 };
59
60 /**
61   Constructor
62   @param theMap the land cover map to iterate through
63 */
64 HYDROData_LandCoverMap::Iterator::Iterator( const HYDROData_LandCoverMap& theMap )
65 {
66   Init( theMap );
67 }
68
69 HYDROData_LandCoverMap::Iterator::Iterator( const Handle( HYDROData_LandCoverMap )& theMap )
70 {
71   if( theMap.IsNull() )
72   {
73     myIterator = 0;
74     myIndex = -1;
75   }
76   else
77     Init( *theMap );
78 }
79
80 /**
81   Initialize the iterator
82   @param theMap the land cover map to iterate through
83 */
84 void HYDROData_LandCoverMap::Iterator::Init( const HYDROData_LandCoverMap& theMap )
85 {
86   TopoDS_Shape aShape = theMap.GetShape();
87   if( aShape.IsNull() )
88     myIterator = 0;
89   else
90     myIterator = new TopoDS_Iterator( aShape );
91   myIndex = 0;
92   theMap.myLab.FindChild( DataTag_Types ).FindAttribute( TDataStd_ExtStringArray::GetID(), myArray );
93 }
94
95 /**
96   Destructor
97 */
98 HYDROData_LandCoverMap::Iterator::~Iterator()
99 {
100   delete myIterator;
101 }
102
103 /**
104   Return if the iterator has more elements
105   @return if the iterator has more elements
106 */
107 bool HYDROData_LandCoverMap::Iterator::More() const
108 {
109   return !myArray.IsNull() && myIterator && myIterator->More();
110 }
111
112 /**
113   Move iterator to the next element
114 */
115 void HYDROData_LandCoverMap::Iterator::Next()
116 {
117   if( myIterator )
118   {
119     myIterator->Next();
120     myIndex++;
121   }
122 }
123
124 /**
125   Get the current land cover (face)
126   @return the land cover's face
127 */
128 TopoDS_Face HYDROData_LandCoverMap::Iterator::Face() const
129 {
130   if( myIterator )
131     return TopoDS::Face( myIterator->Value() );
132   else
133     return TopoDS_Face();
134 }
135
136 /**
137   Get the current land cover's Strickler type 
138   @return the land cover's Strickler type 
139 */
140 QString HYDROData_LandCoverMap::Iterator::StricklerType() const
141 {
142   if( myArray.IsNull() || myIndex < myArray->Lower() || myIndex > myArray->Upper() )
143     return "";
144   else
145     return HYDROData_Tool::toQString( myArray->Value( myIndex ) );
146 }
147
148 /**
149   Constructor
150 */
151 HYDROData_LandCoverMap::HYDROData_LandCoverMap()
152   : HYDROData_Entity( Geom_No )
153 {
154 }
155
156 /**
157   Destructor
158 */
159 HYDROData_LandCoverMap::~HYDROData_LandCoverMap()
160 {
161 }
162
163 /**
164   Get object's kind
165   @return object's kind
166 */
167 const ObjectKind HYDROData_LandCoverMap::GetKind() const
168 {
169   return KIND_LAND_COVER_MAP;
170 }
171
172 /**
173   Import the land cover map from QGIS
174   @param theFileName the name of file
175   @return if the import is successful
176 */
177 bool HYDROData_LandCoverMap::ImportQGIS( const QString& theFileName )
178 {
179   //TODO
180   return false;
181 }
182
183 /**
184   Export the land cover map to QGIS
185   @param theFileName the name of file
186   @return if the export is successful
187 */
188 bool HYDROData_LandCoverMap::ExportQGIS( const QString& theFileName ) const
189 {
190   //TODO
191   return false;
192 }
193
194 void EdgeDiscretization( const TopoDS_Edge& theEdge, 
195                          NCollection_IndexedMap<gp_Pnt>& theVerticesMap,
196                          QList<int>& theVerticesIds )
197 {
198   //TODO
199 }
200
201 /**
202   Export the land cover map for the solver (Telemac)
203   @param theFileName the name of file
204   @return if the export is successful
205 */
206 bool HYDROData_LandCoverMap::ExportTelemac( const QString& theFileName ) const
207 {
208   TopoDS_Shell aShell;  //TODO: unite all the faces of land covers into the shell
209
210   NCollection_IndexedMap<gp_Pnt> aVerticesMap;
211   NCollection_IndexedDataMap< TopoDS_Edge, QList<int> > anEdgesMap;
212   NCollection_IndexedDataMap< TopoDS_Face, QList<int> > aFacesMap;
213
214   // add into the map all edges existing in the shell
215   TopExp_Explorer anExp1( aShell, TopAbs_EDGE );
216   for( ; anExp1.More(); anExp1.Next() )
217   {
218     TopoDS_Edge anEdge = TopoDS::Edge( anExp1.Current() );
219     QList<int> aVerticesIdsList;
220     EdgeDiscretization( anEdge, aVerticesMap, aVerticesIdsList );
221     anEdgesMap.Add( anEdge, aVerticesIdsList );
222   }
223
224   // add into the map all faces existing in the shell and correspondence between face and edges ids
225   TopExp_Explorer anExp2( aShell, TopAbs_FACE );
226   for( ; anExp2.More(); anExp2.Next() )
227   {
228     TopoDS_Face aFace = TopoDS::Face( anExp2.Current() );
229     TopExp_Explorer anExp3( aFace, TopAbs_EDGE );
230     QList<int> anEdgesIdsList;
231     for( ; anExp3.More(); anExp3.Next() )
232     {
233       TopoDS_Edge anEdge = TopoDS::Edge( anExp3.Current() );
234       int anEdgeId = anEdgesMap.FindIndex( anEdge );
235       anEdgesIdsList.append( anEdgeId );
236     }
237     aFacesMap.Add( aFace, anEdgesIdsList );
238   }
239
240   QFile aFile( theFileName );
241   if( !aFile.open( QFile::WriteOnly | QFile::Text ) )
242     return false;
243
244   QTextStream aStream( &aFile );
245   aStream << "# nodes\n";
246   NCollection_IndexedMap<gp_Pnt>::Iterator anIt1( aVerticesMap );
247   for( ; anIt1.More(); anIt1.Next() )
248   {
249     gp_Pnt aPnt = anIt1.Value();
250     aStream << QString::number( aPnt.X(), TELEMAC_FORMAT, TELEMAC_PRECISION );
251     aStream << " ";
252     aStream << QString::number( aPnt.Y(), TELEMAC_FORMAT, TELEMAC_PRECISION );
253     aStream << " ";
254     aStream << QString::number( aPnt.Z(), TELEMAC_FORMAT, TELEMAC_PRECISION );
255     aStream << "\n";
256   }
257   aStream << "\n";
258
259   aStream << "# edges\n";
260   NCollection_IndexedDataMap< TopoDS_Edge, QList<int> >::Iterator anIt2( anEdgesMap );
261   for( ; anIt2.More(); anIt2.Next() )
262   {
263     QList<int> aVerticesIds = anIt2.Value();
264     foreach( int anId, aVerticesIds )
265       aStream << anId << " ";
266     aStream << "\n";
267   }
268   aStream << "\n";
269
270   aStream << "# faces\n";
271   NCollection_IndexedDataMap< TopoDS_Face, QList<int> >::Iterator anIt3( aFacesMap );
272   for( ; anIt3.More(); anIt3.Next() )
273   {
274     QList<int> anEdgesIds = anIt3.Value();
275     foreach( int anId, anEdgesIds )
276       aStream << anId << " ";
277     aStream << "\n";
278   }
279   aStream << "\n";
280
281   aFile.close();
282   return true;
283 }
284
285 /**
286   Add a new object as land cover
287   @param theObject the object to add as land cover
288   @param theType the Strickler type for the new land cover
289   @return if the addition is successful
290 */
291 bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_Object )& theObject, const QString& theType )
292 {
293   if( theObject.IsNull() )
294     return false;
295
296   TopoDS_Shape aShape = theObject->GetTopShape();
297   if( aShape.ShapeType()!=TopAbs_FACE )
298     return false;
299
300   TopoDS_Face aFace = TopoDS::Face( aShape );
301   return LocalPartition( aFace, theType );
302 }
303
304 /**
305   Add a new polyline as land cover
306   @param thePolyline the polyline to add as land cover
307   @param theType the Strickler type for the new land cover
308   @return if the addition is successful
309 */
310 bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_PolylineXY )& thePolyline, const QString& theType )
311 {
312   if( thePolyline.IsNull() )
313     return false;
314
315   TopoDS_Shape aShape = thePolyline->GetShape();
316   if( aShape.ShapeType()!=TopAbs_WIRE )
317     return false;
318
319   TopoDS_Wire aWire = TopoDS::Wire( aShape );
320   if( !aWire.Closed() )
321     return false;
322
323   TopoDS_Face aFace = BRepBuilderAPI_MakeFace( aWire, Standard_True ).Face();
324   return LocalPartition( aFace, theType );
325 }
326
327 /**
328   Remove the given face from land cover map
329   @param theFace the face to be removed
330   @return if the removing is successful
331 */
332 bool HYDROData_LandCoverMap::Remove( const TopoDS_Face& theFace )
333 {
334   TopTools_ListOfShape aList;
335   aList.Append( theFace );
336   return Remove( aList );
337 }
338
339 /**
340   Remove the given faces from land cover map
341   @param theFacesToRemove the face list to be removed
342   @return if the removing is successful
343 */
344 bool HYDROData_LandCoverMap::Remove( const TopTools_ListOfShape& theFacesToRemove )
345 {
346   HYDROData_MapOfFaceToStricklerType aFacesToRemove, aNewFaces;
347   TopTools_ListIteratorOfListOfShape aFIt( theFacesToRemove );
348   for( ; aFIt.More(); aFIt.Next() )
349   {
350     TopoDS_Shape aShape = aFIt.Value();
351     if( aShape.ShapeType()==TopAbs_FACE )
352       aFacesToRemove.Add( TopoDS::Face( aShape ), "" );
353   }
354
355   Iterator anIt( *this );
356   for( ; anIt.More(); anIt.Next() )
357     if( !aFacesToRemove.Contains( anIt.Face() ) )
358       aNewFaces.Add( anIt.Face(), anIt.StricklerType() );
359
360   StoreLandCovers( aNewFaces );
361   return true;
362 }
363
364 /**
365   Split the land cover map by the given polyline
366   @param thePolyline the tool polyline to split the land cover map
367   @return if the removing is successful
368 */
369 bool HYDROData_LandCoverMap::Split( const Handle( HYDROData_PolylineXY )& thePolyline )
370 {
371   if( thePolyline.IsNull() )
372     return false;
373
374   TopoDS_Shape aShape = thePolyline->GetShape();
375   return LocalPartition( aShape, "" );
376 }
377
378 /**
379   Merge the given faces in the land cover
380   @param theFaces the faces to merge in the land cover map
381   @param theType the Strickler type for the merged land cover
382   @return if the merge is successful
383 */
384 bool HYDROData_LandCoverMap::Merge( const TopTools_ListOfShape& theFaces, const QString& theType )
385 {
386   // 1. to remove the merged faces from the current map
387   Remove( theFaces );
388
389   // 2. to fuse the faces into the new face
390   /*BOPAlgo_PaveFiller aPF;
391   aPF.SetArguments( theFaces );
392   aPF.SetFuzzyValue( 1E-2 ); 
393   aPF.SetRunParallel( Standard_False );
394   aPF.Perform();
395   int iErr = aPF.ErrorStatus();
396   if( iErr )
397     return false;
398
399   BOPAlgo_BOP aBOP;
400   aBOP.SetArguments( theFaces );
401   aBOP.SetOperation( BOPAlgo_FUSE );
402   aBOP.SetRunParallel( Standard_False );
403   aBOP.PerformWithFiller(aPF);
404   iErr = aBOP.ErrorStatus();
405   if( iErr )
406     return false;
407
408   TopoDS_Shape aMergedShape = aBOP.Shape();
409   if( aMergedShape.ShapeType()!=TopAbs_FACE )
410     return false;*/
411
412  
413   ////
414   TopoDS_Shape MergedFace;
415   MergeFaces(theFaces, true, MergedFace);
416   //BRepTools::Write(aMergedShape, "c:/sh_.brep");
417
418   // 3. to add the face into the map
419   return LocalPartition( TopoDS_Face( /*aMergedShape*/ ), theType );
420 }
421
422 bool HYDROData_LandCoverMap::MergeFaces(const TopTools_ListOfShape& theFaces, bool IsToUnify, TopoDS_Shape& outSh)
423 {
424   int iErr;
425   TopTools_ListIteratorOfListOfShape aIt;
426   BOPCol_ListOfShape aLC;
427   aIt.Initialize(theFaces);
428   for (; aIt.More(); aIt.Next()) {
429     const TopoDS_Shape& aS=aIt.Value();
430     aLC.Append(aS);
431   }
432   BOPAlgo_PaveFiller aPF;
433   aPF.SetArguments(aLC);
434   aPF.SetRunParallel(Standard_False);
435   aPF.SetFuzzyValue(1e-02);
436
437   aPF.Perform();
438   iErr=aPF.ErrorStatus();
439   if (iErr)
440     return false;
441
442   BOPAlgo_Builder aBuilder;
443   aIt.Initialize(theFaces);
444   for (; aIt.More(); aIt.Next()) {
445     const TopoDS_Shape& aS=aIt.Value();
446     aBuilder.AddArgument(aS);
447   }
448
449   aBuilder.PerformWithFiller(aPF); 
450   iErr = aBuilder.ErrorStatus();
451   if (iErr)
452     return false;
453   const TopoDS_Shape& aMergedShape=aBuilder.Shape();
454
455   //
456   BRep_Builder BB;
457   TopoDS_Shell she; 
458   BB.MakeShell(she); 
459   she.Closed(Standard_False);
460   TopExp_Explorer ff(aMergedShape, TopAbs_FACE);
461   for(; ff.More(); ff.Next()) 
462   {
463     const TopoDS_Face& F = TopoDS::Face(ff.Current());
464     if (F.IsNull()) 
465       continue;
466     if (F.ShapeType() == TopAbs_FACE) {
467       BB.Add(she, F);
468       she.Closed (Standard_False);
469     }
470   }
471
472   if (IsToUnify)
473   {
474     ShapeUpgrade_UnifySameDomain USD;
475     USD.Initialize(she);
476     USD.Build();
477     outSh = USD.Shape();
478   }
479   else
480   {
481     outSh = she;
482   }
483
484   ff.Init(outSh, TopAbs_FACE);
485   int i = 0;
486   TopoDS_Face OneF;
487   for(; ff.More(); ff.Next(), i++) 
488     OneF = TopoDS::Face(ff.Current());
489   if (i == 1)
490     outSh = OneF;
491
492   return true;
493
494 }
495
496 /**
497   Get the shape of the land cover map
498 */
499 TopoDS_Shape HYDROData_LandCoverMap::GetShape() const
500 {
501   return HYDROData_Entity::GetShape( DataTag_Shape );
502 }
503
504 /**
505   Set the shape of the land cover map
506   @param theShape the new shape for the land cover map
507 */
508 void HYDROData_LandCoverMap::SetShape( const TopoDS_Shape& theShape )
509 {
510   HYDROData_Entity::SetShape( DataTag_Shape, theShape );
511 }
512
513 /**
514   Perform the local partition algorithm on the land cover
515   @param theNewShape the new shape to add into the land cover
516   @param theNewType the new Strickler type for the new land cover
517   @return if the local partition is successful
518 */
519 bool HYDROData_LandCoverMap::LocalPartition( const TopoDS_Shape& theNewShape, const QString& theNewType )
520 {
521   if( theNewShape.IsNull() )
522     return false;
523
524   BOPCol_ListOfShape aShapesList;
525   BOPAlgo_PaveFiller aPaveFiller;
526   HYDROData_MapOfFaceToStricklerType aNewFaces;
527
528   // add faces to shapes list
529   Iterator anIt( *this );
530   for( ; anIt.More(); anIt.Next() )
531     aShapesList.Append( anIt.Face() );
532   aShapesList.Append( theNewShape );
533
534   if( aShapesList.Size()==1 && theNewShape.ShapeType()==TopAbs_FACE )
535   {
536     aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType );
537     StoreLandCovers( aNewFaces );
538     return true;
539   }
540
541   // prepare pave filler
542   aPaveFiller.SetArguments( aShapesList );
543   aPaveFiller.Perform();
544   Standard_Integer anError = aPaveFiller.ErrorStatus();
545   if( anError )
546     return false;
547
548   // add faces to builder
549   BOPAlgo_Builder aBuilder;
550   anIt.Init( *this );
551   for( ; anIt.More(); anIt.Next() )
552     aBuilder.AddArgument( anIt.Face() );
553   aBuilder.AddArgument( theNewShape );
554
555   // perform the partition with the pave filler
556   aBuilder.PerformWithFiller( aPaveFiller );
557   anError = aBuilder.ErrorStatus();
558   if( anError )
559     return false;
560
561   // analysis of the history
562   //     a. to fill map of shapes which come from the new face
563   NCollection_IndexedMap<TopoDS_Shape> aShapesFromNewFace;
564   //std::cout << "new: " << theNewShape << " " << theNewType << std::endl;
565   TopTools_ListOfShape aModified = aBuilder.Modified( theNewShape );
566   TopTools_ListIteratorOfListOfShape aMIt( aModified );
567   for( ; aMIt.More(); aMIt.Next() )
568   {
569     //std::cout << "   " << aMIt.Value() << std::endl;
570     aShapesFromNewFace.Add( aMIt.Value() );
571   }
572
573   //     b. to fill map of parts except parts from new face
574   anIt.Init( *this );
575   for( ; anIt.More(); anIt.Next() )
576   {
577     QString aSType = anIt.StricklerType();
578     //std::cout << anIt.Face() << " " << anIt.StricklerType() << std::endl;
579     TopTools_ListOfShape aModified = aBuilder.Modified( anIt.Face() );
580     TopTools_ListIteratorOfListOfShape aMIt( aModified );
581     for( ; aMIt.More(); aMIt.Next() )
582     {
583       TopoDS_Shape aShape = aMIt.Value();
584       bool isFace = aShape.ShapeType()==TopAbs_FACE;
585       bool isAlsoFromNew = aShapesFromNewFace.Contains( aShape );
586       //std::cout << "   " << aShape << " " << isAlsoFromNew << std::endl;
587       if( isFace && !isAlsoFromNew )
588         aNewFaces.Add( TopoDS::Face( aShape ), aSType );
589     }
590   }
591
592   //     c. add the new shape if it is face with its type
593   if( theNewShape.ShapeType()==TopAbs_FACE )
594     aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType );
595   
596   // convert map of shape to type to compound and list of types
597   StoreLandCovers( aNewFaces );
598   return true;
599 }
600
601 /**
602   Replace the set of land covers in the land cover map
603   @param theMap the map of shape (face) to Strickler type (string)
604 */
605 void HYDROData_LandCoverMap::StoreLandCovers( const HYDROData_MapOfFaceToStricklerType& theMap )
606 {
607   TopoDS_Compound aCompound;
608   BRep_Builder aCompoundBuilder;
609   aCompoundBuilder.MakeCompound( aCompound );
610
611   int n = theMap.Size();
612   Handle( TDataStd_ExtStringArray ) aTypes = 
613     TDataStd_ExtStringArray::Set( myLab.FindChild( DataTag_Types ), 0, n-1, Standard_True );
614   HYDROData_MapOfFaceToStricklerType::Iterator aNFIt( theMap );
615   for( int i=0; aNFIt.More(); aNFIt.Next(), i++ )
616   {
617     TopoDS_Face aFace = aNFIt.Key();
618     QString aType = aNFIt.Value();
619     aCompoundBuilder.Add( aCompound, aFace );
620     aTypes->SetValue( i, HYDROData_Tool::toExtString( aType ) );
621   }
622
623   SetShape( aCompound );
624 }
625
626 /**
627   Find the land cover for the given point
628   @param thePoint the point laying in some land cover
629   @param theType the returned type
630   @return the found land cover's face
631 */
632 TopoDS_Face HYDROData_LandCoverMap::FindByPoint( const gp_Pnt2d& thePoint, QString& theType ) const
633 {
634   //TODO: some more optimal algorithm
635   Iterator anIt( *this );
636   for( ; anIt.More(); anIt.Next() )
637     if( HYDROData_Tool::ComputePointState( thePoint.XY(), anIt.Face() ) == TopAbs_IN )
638     {
639       theType = anIt.StricklerType();
640       return anIt.Face();
641     }
642
643   theType = "";
644   return TopoDS_Face();
645 }