Salome HOME
patch for crash in channel
[modules/hydro.git] / src / HYDROData / HYDROData_Profile.cxx
1
2 #include "HYDROData_Profile.h"
3
4 #include "HYDROData_Document.h"
5 #include "HYDROData_Iterator.h"
6 #include "HYDROData_Tool.h"
7 #include "HYDROData_PolylineXY.h"
8
9 #include <boost/math/special_functions/fpclassify.hpp>
10
11 #include <BRepBuilderAPI_MakeEdge.hxx>
12 #include <BRepBuilderAPI_MakeWire.hxx>
13 #include <BRepBuilderAPI_MakePolygon.hxx>
14
15 #include <gp_XY.hxx>
16 #include <gp_XYZ.hxx>
17 #include <gp_Pnt2d.hxx>
18
19 #include <TDataStd_AsciiString.hxx>
20 #include <TDataStd_RealArray.hxx>
21
22 #include <TopoDS_Edge.hxx>
23 #include <TopoDS_Wire.hxx>
24
25 #include <OSD_File.hxx>
26 #include <OSD_Protection.hxx>
27
28 #include <QColor>
29 #include <QStringList>
30
31 IMPLEMENT_STANDARD_HANDLE(HYDROData_Profile, HYDROData_Object)
32 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Profile, HYDROData_Object)
33
34 HYDROData_Profile::HYDROData_Profile()
35 : HYDROData_Object()
36 {
37 }
38
39 HYDROData_Profile::~HYDROData_Profile()
40 {
41 }
42
43 QStringList HYDROData_Profile::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
44 {
45   QStringList aResList = dumpObjectCreation( theTreatedObjects );
46   QString aProfileName = GetObjPyName();
47
48   //TCollection_AsciiString aFilePath = GetFilePath();
49   //if ( !aFilePath.IsEmpty() ) 
50   //{
51   //  aResList << QString( "%1.ImportFromFile( \"%2\" );" )
52   //            .arg( aName ).arg( aFilePath.ToCString() );
53   //}
54
55   bool anIsValidProfile = IsValid();
56   
57   QStringList aPntsDefinition;
58   QString aPntsListName = HYDROData_Tool::GenerateNameForPython( theTreatedObjects, "profile_points" );
59
60   QString aGap = QString().fill( ' ', aPntsListName.length() + 5 );
61   if ( anIsValidProfile )
62   {
63     HYDROData_Profile::ProfilePoints aPointsList = GetProfilePoints();
64     for ( int k = 1, aNbPoints = aPointsList.Size(); k <= aNbPoints; ++k )
65     {
66       const ProfilePoint& aPoint = aPointsList.Value( k );
67       aPntsDefinition << QString( aGap + "gp_XYZ( %1, %2, %3 )%4" )
68                          .arg( aPoint.X() ).arg( aPoint.Y() ).arg( aPoint.Z() )
69                          .arg( ( k < aNbPoints ? "," : "" ) );
70     }
71   }
72   else
73   {
74     HYDROData_IPolyline::PointsList aPointsList = GetParametricPoints();
75     for ( int k = 1, aNbPoints = aPointsList.Size(); k <= aNbPoints; ++k )
76     {
77       const HYDROData_IPolyline::Point& aPoint = aPointsList.Value( k );
78       aPntsDefinition << QString( aGap + "gp_XY( %1, %2 )%3" )
79                          .arg( aPoint.X() ).arg( aPoint.Y() )
80                          .arg( ( k < aNbPoints ? "," : "" ) );
81     }
82   }
83
84   if ( !aPntsDefinition.isEmpty() )
85   {
86     QString& aFirstStr = aPntsDefinition.first();
87     aFirstStr = aFirstStr.trimmed();
88     aFirstStr.prepend( QString( "%1 = [ " ).arg( aPntsListName ) );
89     
90     aPntsDefinition.last().append( " ];" );
91
92     aResList << aPntsDefinition;
93     
94     aResList << QString( "%1.%3( %2 );" )
95                 .arg( aProfileName ).arg( aPntsListName )
96                 .arg( anIsValidProfile ? "SetProfilePoints" : "SetParametricPoints" );
97   
98     aResList << QString( "" );
99   }
100
101   // Set a polyline type if it is not default
102   Handle(HYDROData_ProfileUZ) aPrf = GetProfileUZ( false );
103   if ( !aPrf.IsNull() )
104   {
105     HYDROData_IPolyline::SectionType aSecType = aPrf->GetSectionType( 0 );
106     if ( aSecType != HYDROData_IPolyline::SECTION_POLYLINE )
107     {
108       aResList << QString( "%1.GetProfileUZ().SetSectionType( 0, %2 );" )
109                   .arg( aProfileName ).arg( "HYDROData_IPolyline.SECTION_SPLINE" );
110       aResList << QString( "" );
111     }
112   }
113
114   aResList << QString( "%1.Update();" ).arg( aProfileName );
115   aResList << QString( "" );
116
117   return aResList;
118 }
119
120 TopoDS_Shape HYDROData_Profile::GetTopShape() const
121 {
122   TopoDS_Wire aWire;
123
124   gp_XY aFirstPoint, aLastPoint;
125   if ( !GetLeftPoint( aFirstPoint ) || !GetRightPoint( aLastPoint ) )
126     return aWire;
127
128   gp_Pnt aPnt1( aFirstPoint.X(), aFirstPoint.Y(), 0 );
129   gp_Pnt aPnt2( aLastPoint.X(),  aLastPoint.Y(),  0 );
130
131   BRepBuilderAPI_MakeEdge aMakeEdge( aPnt1, aPnt2 );
132   TopoDS_Edge anEdge = aMakeEdge;
133
134   BRepBuilderAPI_MakeWire aMakeWire( anEdge );
135   aWire = aMakeWire;
136
137   return aWire;
138 }
139
140 TopoDS_Shape HYDROData_Profile::GetShape3D() const
141 {
142   return getShape3D();
143 }
144
145 void HYDROData_Profile::Update()
146 {
147   HYDROData_Object::Update();
148
149   TopoDS_Wire aWire;
150   Handle(HYDROData_ProfileUZ) aProfile = GetProfileUZ( false );
151   if ( !aProfile.IsNull() )
152   {
153     ProfilePoints aProfilePoints = GetProfilePoints();
154     HYDROData_IPolyline::SectionType aSectionType = aProfile->GetSectionType( 0 );
155
156     aWire = HYDROData_PolylineXY::BuildWire( aSectionType, false, aProfilePoints );
157   }
158   SetShape3D( aWire );
159 }
160
161 QColor HYDROData_Profile::DefaultFillingColor()
162 {
163   return QColor( Qt::transparent );
164 }
165
166 QColor HYDROData_Profile::DefaultBorderColor()
167 {
168   return QColor( Qt::black );
169 }
170
171 QColor HYDROData_Profile::getDefaultFillingColor() const
172 {
173   return DefaultFillingColor();
174 }
175
176 QColor HYDROData_Profile::getDefaultBorderColor() const
177 {
178   return DefaultBorderColor();
179 }
180
181 bool HYDROData_Profile::IsValid() const
182 {
183   gp_XY aFirstPoint, aLastPoint;
184   if ( !GetLeftPoint( aFirstPoint ) || !GetRightPoint( aLastPoint ) )
185     return false;
186
187   int aNbPoints = NbPoints();
188   return aNbPoints > 1;
189 }
190
191 void HYDROData_Profile::SetLeftPoint( const gp_XY& thePoint )
192 {
193   TDF_Label aLabel = myLab.FindChild( DataTag_FirstPoint );
194
195   Handle(TDataStd_RealArray) anArray;
196   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
197     anArray = TDataStd_RealArray::Set( aLabel, 0, 1 );
198
199   anArray->SetValue( 0, thePoint.X() );
200   anArray->SetValue( 1, thePoint.Y() );
201
202   SetToUpdate( true );
203 }
204
205 bool HYDROData_Profile::GetLeftPoint( gp_XY& thePoint ) const
206 {
207   TDF_Label aLabel = myLab.FindChild( DataTag_FirstPoint, false );
208   if ( aLabel.IsNull() )
209     return false;
210
211   Handle(TDataStd_RealArray) anArray;
212   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
213     return false;
214
215   thePoint.SetX( anArray->Value( 0 ) );
216   thePoint.SetY( anArray->Value( 1 ) );
217
218   return true;
219 }
220
221 void HYDROData_Profile::SetRightPoint( const gp_XY& thePoint )
222 {
223   TDF_Label aLabel = myLab.FindChild( DataTag_LastPoint );
224
225   Handle(TDataStd_RealArray) anArray;
226   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
227     anArray = TDataStd_RealArray::Set( aLabel, 0, 1 );
228
229   anArray->SetValue( 0, thePoint.X() );
230   anArray->SetValue( 1, thePoint.Y() );
231
232   SetToUpdate( true );
233 }
234
235 bool HYDROData_Profile::GetRightPoint( gp_XY& thePoint ) const
236 {
237   TDF_Label aLabel = myLab.FindChild( DataTag_LastPoint, false );
238   if ( aLabel.IsNull() )
239     return false;
240
241   Handle(TDataStd_RealArray) anArray;
242   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
243     return false;
244
245   thePoint.SetX( anArray->Value( 0 ) );
246   thePoint.SetY( anArray->Value( 1 ) );
247
248   return true;
249 }
250
251 void HYDROData_Profile::Invalidate()
252 {
253   TDF_Label aFirstLabel = myLab.FindChild( DataTag_FirstPoint, false );
254   if ( !aFirstLabel.IsNull() )
255     aFirstLabel.ForgetAllAttributes();
256
257   TDF_Label aLastLabel = myLab.FindChild( DataTag_LastPoint, false );
258   if ( !aLastLabel.IsNull() )
259     aLastLabel.ForgetAllAttributes();
260
261   SetToUpdate( true );
262 }
263
264 Handle(HYDROData_ProfileUZ) HYDROData_Profile::GetProfileUZ( const bool theIsCreate ) const
265 {
266   Handle(HYDROData_ProfileUZ) aProfileUZ;
267
268   TDF_Label aLabel = myLab.FindChild( DataTag_ChildProfileUZ, theIsCreate );
269   if ( aLabel.IsNull() )
270     return aProfileUZ;
271
272   aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast( HYDROData_Iterator::Object( aLabel ) );
273   if ( aProfileUZ.IsNull() && theIsCreate )
274   {
275     aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast(
276       HYDROData_Iterator::CreateObject( aLabel, KIND_PROFILEUZ ) );
277   }
278
279   return aProfileUZ;
280 }
281
282 int HYDROData_Profile::NbPoints() const
283 {
284   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
285   return aProfileUZ.IsNull() ? 0 : aProfileUZ->NbPoints();
286 }
287
288 void HYDROData_Profile::RemovePoints()
289 {
290   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
291   if ( !aProfileUZ.IsNull() )
292   {
293     aProfileUZ->RemoveSections();
294     SetToUpdate( true );
295   }
296 }
297
298 void HYDROData_Profile::SetParametricPoints( const HYDROData_ProfileUZ::PointsList& thePoints )
299 {
300   RemovePoints();
301
302   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ();
303   for ( int i = 1, n = thePoints.Length(); i <= n ; ++i )
304   {
305     const HYDROData_ProfileUZ::Point& aPoint = thePoints.Value( i );
306     aProfileUZ->AddPoint( 0, aPoint );
307   }
308
309   SetToUpdate( true );
310 }
311
312 HYDROData_ProfileUZ::PointsList HYDROData_Profile::GetParametricPoints() const
313 {
314   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
315   return aProfileUZ.IsNull() ? HYDROData_ProfileUZ::PointsList() : aProfileUZ->GetPoints();
316 }
317
318 void HYDROData_Profile::SetProfilePoints( const ProfilePoints& thePoints )
319 {
320   RemovePoints();
321   if ( thePoints.Length() < 2 )
322     return;
323
324   gp_XY aFirstPoint, aLastPoint;
325
326   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ();
327   for ( int i = 1, n = thePoints.Length(); i <= n ; ++i )
328   {
329     const ProfilePoint& aPoint = thePoints.Value( i );
330     gp_XY aPointXY( aPoint.X(), aPoint.Y() );
331
332     if ( i == 1 )
333       aFirstPoint = aPointXY;
334     else if ( i == n )
335       aLastPoint = aPointXY;
336
337     double aDistance = gp_Pnt2d( aFirstPoint ).Distance( aPointXY );
338     
339     HYDROData_ProfileUZ::Point aParPoint( aDistance, aPoint.Z() );
340     aProfileUZ->AddPoint( 0, aParPoint );
341   }
342
343   SetLeftPoint( aFirstPoint );
344   SetRightPoint( aLastPoint );
345 }
346
347 HYDROData_Profile::ProfilePoints HYDROData_Profile::GetProfilePoints() const
348 {
349   ProfilePoints aResPoints;
350
351   gp_XY aFirstPoint, aLastPoint;
352   if ( !GetLeftPoint( aFirstPoint ) || !GetRightPoint( aLastPoint ) )
353     return aResPoints;
354
355   HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints();
356   if ( aParametricPoints.Length() < 2 )
357     return aResPoints;
358
359   const HYDROData_ProfileUZ::Point& aFirstParPoint = aParametricPoints.First();
360   const HYDROData_ProfileUZ::Point& aLastParPoint = aParametricPoints.Last();
361
362   double aGeoDistance = gp_Pnt2d( aFirstPoint ).Distance( aLastPoint );
363   double aParCommonDist = gp_Pnt2d( aFirstParPoint.X(), 0 ).Distance( gp_Pnt2d( aLastParPoint.X(), 0 ) );
364
365   // Add first point as is
366   aResPoints.Append( ProfilePoint( aFirstPoint.X(), aFirstPoint.Y(), aFirstParPoint.Y() ) );
367
368   // Compute all other points
369   for ( int i = 2, n = aParametricPoints.Length(); i < n ; ++i )
370   {
371     const HYDROData_ProfileUZ::Point& aParPoint = aParametricPoints.Value( i );
372
373     double aParPointDist = gp_Pnt2d( aFirstParPoint.X(), 0 ).Distance( gp_Pnt2d( aParPoint.X(), 0 ) );
374     
375     double aParLen = ( aParPointDist / aParCommonDist ) * aGeoDistance;
376
377     double aRatio = aParLen / ( aGeoDistance - aParLen );
378
379     double aParX = ( aFirstPoint.X() + aRatio * aLastPoint.X() ) / ( 1 + aRatio );
380     double aParY = ( aFirstPoint.Y() + aRatio * aLastPoint.Y() ) / ( 1 + aRatio );
381
382     ProfilePoint aCompPoint( aParX, aParY, aParPoint.Y() );
383     aResPoints.Append( aCompPoint );
384   }
385
386   // Add last point as is
387   aResPoints.Append( ProfilePoint( aLastPoint.X(), aLastPoint.Y(), aLastParPoint.Y() ) );
388
389   return aResPoints;
390 }
391
392 void HYDROData_Profile::SetFilePath( const TCollection_AsciiString& theFilePath )
393 {
394   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_FilePath ), theFilePath );
395 }
396
397 TCollection_AsciiString HYDROData_Profile::GetFilePath() const
398 {
399   TCollection_AsciiString aRes;
400
401   Handle(TDataStd_AsciiString) anAsciiStr;
402   if ( myLab.FindChild( DataTag_FilePath ).FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
403     aRes = anAsciiStr->Get();
404
405   return aRes;
406 }
407
408 int HYDROData_Profile::ImportFromFile( const Handle(HYDROData_Document)& theDoc,
409                                        const TCollection_AsciiString&    theFileName,
410                                        NCollection_Sequence<int>&        theBadProfilesIds )
411 {
412   if ( theDoc.IsNull() || theFileName.IsEmpty() )
413     return 0;
414
415   OSD_File aFile( theFileName );
416   if ( !aFile.IsReadable() )
417     return 0;
418
419   aFile.Open( OSD_ReadOnly, OSD_Protection() );
420   if ( !aFile.IsOpen() )
421     return 0;
422
423   NCollection_Sequence<Handle(HYDROData_Profile)> aCreatedProfiles;
424
425   int aProfileId = 1;
426   Handle(HYDROData_Profile) aNewProfile;
427   for ( ; !aFile.IsAtEnd(); ++aProfileId )
428   {
429     if ( aNewProfile.IsNull() )
430       aNewProfile = Handle(HYDROData_Profile)::DownCast( theDoc->CreateObject( KIND_PROFILE ) );
431     
432     bool anIsRead = false;
433     if ( aNewProfile->ImportFromFile( aFile, &anIsRead ) )
434     {
435       aCreatedProfiles.Append( aNewProfile );
436       aNewProfile.Nullify();
437     }
438     else if ( anIsRead )
439     {
440       theBadProfilesIds.Append( aProfileId );
441     }
442   }
443
444   if ( !aNewProfile.IsNull() )
445     aNewProfile->Remove();
446
447   // Close the file
448   aFile.Close();
449
450   for ( int i = 1, n = aCreatedProfiles.Length(); i <= n ; ++i )
451   {
452     Handle(HYDROData_Profile) aProfile = aCreatedProfiles.Value( i );
453
454     QString aProfileName = HYDROData_Tool::GenerateObjectName( theDoc, "Profile" );
455     aProfile->SetName( aProfileName );
456
457     aProfile->SetFilePath( theFileName );
458
459     aProfile->SetBorderColor( HYDROData_Profile::DefaultBorderColor() );
460   }
461
462   return aCreatedProfiles.Length();
463 }
464
465 bool HYDROData_Profile::ImportFromFile( const TCollection_AsciiString& theFileName,
466                                         bool*                          theIsRead )
467 {
468   if ( theIsRead )
469     *theIsRead = false;
470
471   // Try to open the file
472   OSD_File aFile( theFileName );
473   if ( !aFile.IsReadable() )
474     return false;
475
476   aFile.Open( OSD_ReadOnly, OSD_Protection() );
477   if ( !aFile.IsOpen() )
478     return false;
479
480   bool aRes = ImportFromFile( aFile, theIsRead );
481
482   // Close the file
483   aFile.Close();
484
485   if ( aRes )
486   {
487     // Update file path
488     SetFilePath( theFileName );
489   }
490
491   return aRes;
492 }
493
494 bool HYDROData_Profile::ImportFromFile( OSD_File& theFile,
495                                         bool*     theIsRead )
496 {
497   if ( theIsRead )
498     *theIsRead = false;
499
500   if ( !theFile.IsOpen() )
501     return false;
502
503   bool aRes = true;
504
505   bool anIsParametric = false;
506   bool anIsGeoref     = false;
507
508   HYDROData_ProfileUZ::PointsList aPointsUZ;
509   ProfilePoints                   aPointsXYZ;
510
511   double aPrevVal = -DBL_MAX;
512   while ( !theFile.IsAtEnd() )
513   {
514     Standard_Integer aNbRead = 0;
515     TCollection_AsciiString aLine;
516     theFile.ReadLine( aLine, 1024, aNbRead );
517
518     aLine.LeftAdjust(); aLine.RightAdjust();
519     if ( aLine.IsEmpty() )
520     {
521       if ( !anIsParametric && !anIsGeoref )
522         continue; // Definition is not started yet
523
524       break; // Next profile started
525     }
526
527     // Set flag of read status to true
528     if ( theIsRead )
529       *theIsRead = true;
530
531     TCollection_AsciiString aValX = aLine.Token( " \t", 1 );
532     TCollection_AsciiString aValY = aLine.Token( " \t", 2 );
533     TCollection_AsciiString aValZ = aLine.Token( " \t", 3 );
534
535     if ( aValX.IsEmpty() || !aValX.IsRealValue() ||
536          aValY.IsEmpty() || !aValY.IsRealValue() )
537     {
538       aRes = false;
539       break;
540     }
541
542     if ( !anIsParametric && !anIsGeoref )
543     {
544       anIsParametric = aValZ.IsEmpty();
545       anIsGeoref = !aValZ.IsEmpty();
546     }
547
548     double aCoordX = aValX.RealValue();
549     double aCoordY = aValY.RealValue();
550
551     if ( boost::math::isnan( aCoordX ) || boost::math::isinf( aCoordX ) ||
552          boost::math::isnan( aCoordY ) || boost::math::isinf( aCoordY ) )
553       aRes = false;
554
555     if ( anIsParametric )
556     {
557       if ( aCoordX < aPrevVal )
558       {
559         // Move back readed line
560         theFile.Seek( -( aNbRead + 1 ), OSD_FromHere );
561         break;
562       }
563
564       HYDROData_ProfileUZ::Point aPoint( aCoordX, aCoordY );
565       aPointsUZ.Append( aPoint );
566
567       aPrevVal = aCoordX;
568     }
569     else
570     {
571       if ( aValZ.IsEmpty() || !aValZ.IsRealValue() )
572       {
573         aRes = false;
574         break;
575       }
576
577       double aCoordZ = aValZ.RealValue();
578       if ( boost::math::isnan( aCoordZ ) || boost::math::isinf( aCoordZ ) )
579         aRes = false;
580
581       ProfilePoint aPoint( aCoordX, aCoordY, aCoordZ );
582       aPointsXYZ.Append( aPoint );
583     }
584   }
585   
586   aRes = aRes && ( anIsParametric && !aPointsUZ.IsEmpty() || 
587                    anIsGeoref && !aPointsXYZ.IsEmpty() );
588   if ( aRes )
589   {
590     // Update profile points
591     if ( anIsParametric )
592     {
593       SetParametricPoints( aPointsUZ );
594     }
595     else if ( anIsGeoref )
596     {
597       SetProfilePoints( aPointsXYZ );
598     }
599
600     Update();
601   }
602
603   return aRes;
604 }
605
606
607