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