Salome HOME
Merge remote-tracking branch 'origin/BR_DEMO' into BR_2017
[modules/hydro.git] / src / HYDROData / HYDROData_Tool.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_Tool.h>
20 #include <HYDROData_ArtificialObject.h>
21 #include <HYDROData_Document.h>
22 #include <HYDROData_Entity.h>
23 #include <HYDROData_Iterator.h>
24 #include <HYDROData_NaturalObject.h>
25 #include <HYDROData_ShapesGroup.h>
26 #include <QColor>
27 #include <QFile>
28 #include <QStringList>
29 #include <QTextStream>
30 #include <BRep_Tool.hxx>
31 #include <BRepAdaptor_Surface.hxx>
32 #include <BRepTopAdaptor_FClass2d.hxx>
33 #include <ElSLib.hxx>
34 #include <Geom_Curve.hxx>
35 #include <gp_Pln.hxx>
36 #include <Quantity_Color.hxx>
37 #include <TopExp_Explorer.hxx>
38 #include <TopoDS.hxx>
39 #include <TopoDS_Face.hxx>
40 #include <TopoDS_Shape.hxx>
41 #include <TopoDS_Wire.hxx>
42 #include <limits>
43 #include <math.h>
44
45
46 #include <BRepTools.hxx>
47 #include <NCollection_Map.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopoDS_Face.hxx>
50 #include <TopTools_ShapeMapHasher.hxx>
51 #include <BRep_Builder.hxx>
52 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
53 #include <TopExp.hxx>
54 #include <NCollection_List.hxx>
55 #include <TopTools_ListIteratorOfListOfShape.hxx>
56
57 static int aMaxNameId = INT_MAX;
58 void HYDROData_Tool::WriteStringsToFile( QFile&             theFile,
59                                          const QStringList& theStrings,
60                                          const QString&     theSep )
61 {
62   if ( !theFile.isOpen() || theStrings.isEmpty() )
63     return;
64   
65   QString aWriteStr = theStrings.join( theSep );
66   if ( aWriteStr.isEmpty() )
67     return;
68
69   QTextStream anOutStream( &theFile );
70   anOutStream << aWriteStr.toUtf8() << theSep << theSep;
71 }
72
73 QString HYDROData_Tool::GenerateObjectName( const Handle(HYDROData_Document)& theDoc,
74                                             const QString&                    thePrefix,
75                                             const QStringList&                theUsedNames,
76                                             const bool                        theIsTryToUsePurePrefix )
77 {
78   QStringList aNamesList( theUsedNames );
79
80   // Collect all used names in the document
81   HYDROData_Iterator anIter( theDoc );
82   for( ; anIter.More(); anIter.Next() )
83   {
84     Handle(HYDROData_Entity) anObject = anIter.Current();
85     if( anObject.IsNull() )
86       continue;
87
88     QString anObjName = anObject->GetName();
89     if ( anObjName.isEmpty() )
90       continue;
91
92     aNamesList.append( anObjName );
93   }
94
95   QString aName;
96
97   if ( theIsTryToUsePurePrefix && !aNamesList.contains( thePrefix ) ) {
98     aName = thePrefix;
99   } else {
100     int anId = 1;
101     while( anId < aMaxNameId )
102     {
103       aName = QString( "%1_%2" ).arg( thePrefix ).arg( QString::number( anId++ ) );
104
105       // check that there are no other objects with the same name in the document
106       if ( !aNamesList.contains( aName ) )
107         break;
108     }
109   }
110
111   return aName;
112 }
113
114 bool HYDROData_Tool::IsGeometryObject( const Handle(HYDROData_Entity)& theObject )
115 {
116   if ( theObject.IsNull() )
117     return false;
118   
119   return theObject->IsKind( STANDARD_TYPE(HYDROData_ArtificialObject) ) ||
120          theObject->IsKind( STANDARD_TYPE(HYDROData_NaturalObject) );
121 }
122
123 void HYDROData_Tool::UpdateChildObjectName( const QString&                  theOldStr,
124                                             const QString&                  theNewStr,
125                                             const Handle(HYDROData_Entity)& theObject )
126 {
127   if ( theObject.IsNull() )
128     return;
129
130   QString anObjName = theObject->GetName();
131   if ( theOldStr.isEmpty() )
132   {
133     while ( anObjName.startsWith( '_' ) )
134       anObjName.remove( 0, 1 );
135
136     anObjName.prepend( theNewStr + "_" );
137   }
138   else if ( anObjName.startsWith( theOldStr ) )
139   {
140     anObjName.replace( 0, theOldStr.length(), theNewStr );
141   }
142   else
143     return;
144
145   theObject->SetName( anObjName );
146 }
147
148 QString HYDROData_Tool::GenerateNameForPython( const MapOfTreatedObjects& theTreatedObjects,
149                                                const QString&             thePrefix )
150 {
151   QString aName = thePrefix;
152   if ( !theTreatedObjects.contains( aName ) )
153     return aName;
154
155   int anId = 1;
156   while( anId < aMaxNameId )
157   {
158     aName = QString( "%1_%2" ).arg( thePrefix ).arg( QString::number( anId++ ) );
159
160     // check that there are no other objects with the same name
161     if ( !theTreatedObjects.contains( aName ) )
162       break;
163   }
164
165   return aName;
166 }
167 //======================================================================================================
168 TopAbs_State HYDROData_Tool::ComputePointState( const gp_XY& theXY, const TopoDS_Face& theFace )
169 {
170   TopAbs_State aState(TopAbs_UNKNOWN);
171   if(theFace.IsNull()) return aState;  
172   Standard_Real aTol = BRep_Tool::Tolerance(theFace);
173   BRepAdaptor_Surface Ads ( theFace, Standard_False );
174   Standard_Real toluv = Min ( Ads.UResolution(aTol), Ads.VResolution(aTol) ); 
175   const gp_Pln& aPlane = Ads.Surface().Plane();
176   gp_Pnt aPnt(theXY.X(), theXY.Y(), 0.);
177   Standard_Real aU1, aV1;
178   ElSLib::Parameters(aPlane,aPnt, aU1, aV1);
179   BRepTopAdaptor_FClass2d aClassifier( theFace, toluv ); 
180   aState = aClassifier.Perform( gp_Pnt2d(aU1, aV1), Standard_False );
181   return aState;
182 }
183
184 double HYDROData_Tool::GetAltitudeForEdge( const TopoDS_Edge& theEdge,
185                                            const gp_XY& thePoint,
186                                            double theParameterTolerance,
187                                            double theSquareDistanceTolerance,
188                                            double theInvalidAltitude )
189 {
190   double aFirst, aLast;
191   Handle(Geom_Curve) aCurve = BRep_Tool::Curve( theEdge, aFirst, aLast );
192   if( aCurve.IsNull() )
193     return theInvalidAltitude;
194
195   gp_Pnt aFirstPnt, aLastPnt;
196
197   aCurve->D0( aFirst, aFirstPnt );
198   aCurve->D0( aLast, aLastPnt );
199
200   gp_Pnt2d aFirstPnt2d( aFirstPnt.X(), aFirstPnt.Y() );
201   gp_Pnt2d aLastPnt2d( aLastPnt.X(), aLastPnt.Y() );
202
203   double aFirstDist = 0;
204   double aLastDist = aFirstPnt2d.SquareDistance( aLastPnt2d );
205   double aNecDist = aFirstPnt2d.SquareDistance( thePoint );
206
207   while( fabs( aLast - aFirst ) > theParameterTolerance )
208   {
209     double aMid = ( aFirst + aLast ) / 2;
210     gp_Pnt aMidPnt;
211     aCurve->D0( aMid, aMidPnt );
212     double aDist = aFirstPnt2d.SquareDistance( gp_Pnt2d( aMidPnt.X(), aMidPnt.Y() ) );
213
214     if( aDist < aNecDist )
215       aFirst = aMid;
216     else
217       aLast = aMid;
218   }
219
220   double aMid = ( aFirst + aLast ) / 2;
221   gp_Pnt aMidPnt;
222   aCurve->D0( aMid, aMidPnt );
223
224   gp_Pnt2d aMidPnt2d( aMidPnt.X(), aMidPnt.Y() );
225   if( aMidPnt2d.SquareDistance( thePoint ) < theSquareDistanceTolerance )
226     return aMidPnt.Z();
227   else
228     return theInvalidAltitude;
229 }
230
231 double HYDROData_Tool::GetAltitudeForWire( const TopoDS_Wire& theWire,
232                                            const gp_XY& thePoint,
233                                            double theParameterTolerance,
234                                            double theSquareDistanceTolerance,
235                                            double theInvalidAltitude )
236 {
237   TopExp_Explorer anExp( theWire, TopAbs_EDGE );
238   for( ; anExp.More(); anExp.Next() )
239   {
240     double anAltitude = GetAltitudeForEdge( TopoDS::Edge( anExp.Current() ), thePoint,
241       theParameterTolerance, theSquareDistanceTolerance, theInvalidAltitude );
242     if( anAltitude != theInvalidAltitude )
243       return anAltitude;
244   }
245   return theInvalidAltitude;
246 }
247
248 TopoDS_Shape HYDROData_Tool::getFirstShapeFromGroup( const HYDROData_SequenceOfObjects& theGroups,
249                                                      const int                          theGroupId )
250 {
251   TopoDS_Shape aResShape;
252   if ( theGroupId < 1 || theGroupId > theGroups.Length() )
253     return aResShape;
254
255   Handle(HYDROData_ShapesGroup) aGroup =
256     Handle(HYDROData_ShapesGroup)::DownCast( theGroups.Value( theGroupId ) );
257   if ( aGroup.IsNull() )
258     return aResShape;
259
260   TopTools_SequenceOfShape aGroupShapes;
261   aGroup->GetShapes( aGroupShapes );
262
263   if ( !aGroupShapes.IsEmpty() )
264     aResShape = aGroupShapes.First();
265
266   return aResShape;
267 }
268
269 TCollection_ExtendedString HYDROData_Tool::toExtString( const QString& theStr )
270 {
271   TCollection_ExtendedString aRes;
272   if( !theStr.isEmpty() )
273   {
274           Standard_ExtString extStr = new Standard_ExtCharacter[ ( theStr.length() + 1 ) * 2 ];
275           memcpy( (void*)extStr, theStr.unicode(), theStr.length() * 2 );
276           ((short*)extStr)[theStr.length()] = '\0';
277     aRes = TCollection_ExtendedString( extStr );
278           delete [] extStr;
279   }
280   return aRes;
281 }
282
283 QString HYDROData_Tool::toQString( const TCollection_ExtendedString& theStr )
284 {
285   return QString( (QChar*)theStr.ToExtString(), theStr.Length() );
286 }
287
288 Quantity_Color HYDROData_Tool::toOccColor( const QColor& theColor )
289 {
290   double r = theColor.red() / 255.0;
291   double g = theColor.green() / 255.0;
292   double b = theColor.blue() / 255.0;
293
294   return Quantity_Color( r, g, b, Quantity_TOC_RGB );
295 }
296
297 QColor HYDROData_Tool::toQtColor( const Quantity_Color& theColor )
298 {
299   int r = 255 * theColor.Red();
300   int g = 255 * theColor.Green();
301   int b = 255 * theColor.Blue();
302   return QColor( r, g, b );
303 }
304
305 bool HYDROData_Tool::IsNan( double theValue )
306 {
307 #ifdef WIN32
308   return _isnan( theValue );
309 #else
310   return isnan( theValue );
311 #endif
312 }
313
314 bool HYDROData_Tool::IsInf( double theValue )
315 {
316 #ifdef WIN32
317   return (!_finite( theValue  ) );
318 #else
319   return isinf( theValue );
320 #endif  
321 }
322
323 static void MakeShellG(const NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher>& FG,
324   TopoDS_Shape& outSh)
325 {
326   BRep_Builder bb;
327   NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher>::Iterator itFG(FG);
328   if (FG.Extent() > 1)
329   {
330     //face nb > 1 => make shell
331     TopoDS_Shell outShell;
332     bb.MakeShell(outShell);
333     for (;itFG.More();itFG.Next())
334       bb.Add(outShell, itFG.Value());
335     outSh = outShell;
336   }
337   else if (FG.Extent() == 1)
338   {
339     outSh = itFG.Value(); //one face
340   }
341 }
342
343 TopoDS_Shape HYDROData_Tool::RebuildCmp(const TopoDS_Shape& in)
344 {
345   TopTools_IndexedDataMapOfShapeListOfShape mE2LF;
346   TopExp::MapShapesAndAncestors(in, TopAbs_EDGE, TopAbs_FACE, mE2LF);
347   if (mE2LF.IsEmpty())
348     return TopoDS_Shape();
349   NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher> dfm;
350   //TopExp::MapShapes(aFuseShape, TopAbs_FACE, dfm);
351   TopExp_Explorer expf(in, TopAbs_FACE);
352   for (;expf.More(); expf.Next())
353     dfm.Add(TopoDS::Face(expf.Current()));
354
355   int nbF = dfm.Extent();
356   TopExp_Explorer exp_f(in, TopAbs_FACE);
357   const TopoDS_Face& FF = TopoDS::Face(exp_f.Current());
358   NCollection_List<TopoDS_Face> CurrFS;
359   NCollection_List<TopoDS_Face> NeighFS;
360   NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher> PrF;
361   CurrFS.Append(FF);
362   NCollection_List<NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher>> GL_F;
363   NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher> OneGr;
364   bool end = false;
365   while (!end)
366   {
367     NCollection_List<TopoDS_Face>::Iterator it_currfs(CurrFS);
368     NeighFS.Clear();
369     for (;it_currfs.More();it_currfs.Next())
370     {
371       const TopoDS_Face& CF = it_currfs.Value();
372       TopExp_Explorer exp_edge(CF, TopAbs_EDGE);
373       for (;exp_edge.More();exp_edge.Next())
374       {
375         const TopoDS_Shape& CE = exp_edge.Current();
376         const TopTools_ListOfShape& lsf = mE2LF.FindFromKey(CE);
377         TopTools_ListIteratorOfListOfShape ls_it(lsf); //always one face (since all faces are planar)
378         for (;ls_it.More();ls_it.Next())
379         {
380           const TopoDS_Face& F = TopoDS::Face(ls_it.Value());
381           if (F.IsSame(CF))
382             continue;
383           if (!PrF.Contains(F))
384           {
385             OneGr.Add(F);
386             NeighFS.Append(F);
387             PrF.Add(F);
388           }
389         }
390       }
391       OneGr.Add(CF);
392       PrF.Add(CF);
393     }
394     if (NeighFS.IsEmpty())
395     {
396       GL_F.Append(OneGr);
397       OneGr.Clear();
398       dfm.Subtract(PrF);
399       if (dfm.IsEmpty())
400         end = true;
401       else
402       {
403         NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher>::Iterator itDm(dfm);
404         const TopoDS_Face& nsh = itDm.Key();
405         NeighFS.Append(nsh);
406       }
407     }
408     CurrFS = NeighFS;
409   }
410
411   TopoDS_Shape sh;
412
413   if (GL_F.Extent() > 1)
414   {
415     TopoDS_Compound cmp;
416     NCollection_List<NCollection_Map<TopoDS_Face, TopTools_ShapeMapHasher>>::Iterator itGL_F(GL_F);  
417     BRep_Builder bb;
418     bb.MakeCompound(cmp);
419     for (;itGL_F.More();itGL_F.Next())
420     {
421       MakeShellG(itGL_F.Value(), sh);
422       if (!sh.IsNull())
423         bb.Add(cmp, sh);
424     }
425     return  cmp;
426   }
427   else if (GL_F.Extent() == 1)
428   {
429     MakeShellG(GL_F.First(), sh);
430     return sh;
431   }
432   
433 }
434
435
436 std::ostream& operator<<( std::ostream& theStream, const QString& theText )
437 {
438   theStream << theText.toStdString();
439   return theStream;
440 }
441
442 std::ostream& operator<<( std::ostream& theStream, const QColor& theColor )
443 {
444   theStream << "[" << theColor.red() << ", " << theColor.green() << ", " << theColor.blue() << "]";
445   return theStream;
446 }
447
448 std::ostream& operator<<( std::ostream& theStream, const TopoDS_Shape& theShape )
449 {
450   theStream << "[" << theShape.TShape().operator->() << "]";
451   return theStream;
452 }
453
454 std::ostream& operator<<( std::ostream& theStream, const TopoDS_Face& theFace )
455 {
456   theStream << "[" << theFace.TShape().operator->() << "]";
457   return theStream;
458 }
459
460 std::ostream& operator<<( std::ostream& theStream, const gp_XY& theXY )
461 {
462   theStream << "(" << theXY.X() << "; " << theXY.Y() << ")";
463   return theStream;
464 }
465
466 bool operator == ( const gp_XY& thePoint1, const gp_XY& thePoint2 )
467 {
468   const double EPS = 1E-3;
469   return
470     fabs( thePoint1.X() - thePoint2.X() ) < EPS &&
471     fabs( thePoint1.Y() - thePoint2.Y() ) < EPS;
472
473 }