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