Salome HOME
refs #430: incorrect coordinates in dump polyline
[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( true );
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, false ) || !GetRightPoint( aLastPoint, false ) )
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( false );
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, false ) || !GetRightPoint( aLastPoint, false ) )
185     return false;
186
187   int aNbPoints = NbPoints();
188   return aNbPoints > 1;
189 }
190
191 void HYDROData_Profile::SetLeftPoint( const gp_XY& theGPoint, bool IsConvertFromGlobal )
192 {
193   TDF_Label aLabel = myLab.FindChild( DataTag_FirstPoint );
194   if ( aLabel.IsNull() )
195     return;
196
197   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( Label() );
198   gp_XY aLPoint = theGPoint;
199   if( IsConvertFromGlobal )
200     aDoc->Transform( aLPoint, true );
201
202   Handle(TDataStd_RealArray) anArray;
203   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
204     anArray = TDataStd_RealArray::Set( aLabel, 0, 1 );
205
206   anArray->SetValue( 0, aLPoint.X() );
207   anArray->SetValue( 1, aLPoint.Y() );
208
209   SetToUpdate( true );
210 }
211
212 bool HYDROData_Profile::GetLeftPoint( gp_XY& thePoint, bool IsConvertToGlobal ) const
213 {
214   TDF_Label aLabel = myLab.FindChild( DataTag_FirstPoint, false );
215   if ( aLabel.IsNull() )
216     return false;
217
218   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( myLab );
219   Handle(TDataStd_RealArray) anArray;
220   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
221     return false;
222
223   thePoint.SetX( anArray->Value( 0 ) );
224   thePoint.SetY( anArray->Value( 1 ) );
225
226   if( IsConvertToGlobal )
227     aDoc->Transform( thePoint, false );
228
229   return true;
230 }
231
232 void HYDROData_Profile::SetRightPoint( const gp_XY& theGPoint, bool IsConvertFromGlobal )
233 {
234   TDF_Label aLabel = myLab.FindChild( DataTag_LastPoint );
235
236   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( Label() );
237   gp_XY aLPoint = theGPoint;
238   if( IsConvertFromGlobal )
239     aDoc->Transform( aLPoint, true );
240
241   Handle(TDataStd_RealArray) anArray;
242   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
243     anArray = TDataStd_RealArray::Set( aLabel, 0, 1 );
244
245   anArray->SetValue( 0, aLPoint.X() );
246   anArray->SetValue( 1, aLPoint.Y() );
247
248   SetToUpdate( true );
249 }
250
251 bool HYDROData_Profile::GetRightPoint( gp_XY& thePoint, bool IsConvertToGlobal ) const
252 {
253   TDF_Label aLabel = myLab.FindChild( DataTag_LastPoint, false );
254   if ( aLabel.IsNull() )
255     return false;
256
257   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( myLab );
258   Handle(TDataStd_RealArray) anArray;
259   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
260     return false;
261
262   thePoint.SetX( anArray->Value( 0 ) );
263   thePoint.SetY( anArray->Value( 1 ) );
264
265   if( IsConvertToGlobal )
266     aDoc->Transform( thePoint, false );
267
268   return true;
269 }
270
271 void HYDROData_Profile::Invalidate()
272 {
273   TDF_Label aFirstLabel = myLab.FindChild( DataTag_FirstPoint, false );
274   if ( !aFirstLabel.IsNull() )
275     aFirstLabel.ForgetAllAttributes();
276
277   TDF_Label aLastLabel = myLab.FindChild( DataTag_LastPoint, false );
278   if ( !aLastLabel.IsNull() )
279     aLastLabel.ForgetAllAttributes();
280
281   SetToUpdate( true );
282 }
283
284 Handle(HYDROData_ProfileUZ) HYDROData_Profile::GetProfileUZ( const bool theIsCreate ) const
285 {
286   Handle(HYDROData_ProfileUZ) aProfileUZ;
287
288   TDF_Label aLabel = myLab.FindChild( DataTag_ChildProfileUZ, theIsCreate );
289   if ( aLabel.IsNull() )
290     return aProfileUZ;
291
292   aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast( HYDROData_Iterator::Object( aLabel ) );
293   if ( aProfileUZ.IsNull() && theIsCreate )
294   {
295     aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast(
296       HYDROData_Iterator::CreateObject( aLabel, KIND_PROFILEUZ ) );
297   }
298
299   return aProfileUZ;
300 }
301
302 int HYDROData_Profile::NbPoints() const
303 {
304   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
305   return aProfileUZ.IsNull() ? 0 : aProfileUZ->NbPoints();
306 }
307
308 void HYDROData_Profile::RemovePoints()
309 {
310   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
311   if ( !aProfileUZ.IsNull() )
312   {
313     aProfileUZ->RemoveSections();
314     SetToUpdate( true );
315   }
316 }
317
318 void HYDROData_Profile::SetParametricPoints( const HYDROData_ProfileUZ::PointsList& thePoints )
319 {
320   RemovePoints();
321
322   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ();
323   for ( int i = 1, n = thePoints.Length(); i <= n ; ++i )
324   {
325     const HYDROData_ProfileUZ::Point& aPoint = thePoints.Value( i );
326     aProfileUZ->AddPoint( 0, aPoint );
327   }
328
329   SetToUpdate( true );
330 }
331
332 HYDROData_ProfileUZ::PointsList HYDROData_Profile::GetParametricPoints() const
333 {
334   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
335   return aProfileUZ.IsNull() ? HYDROData_ProfileUZ::PointsList() : aProfileUZ->GetPoints();
336 }
337
338 void HYDROData_Profile::SetProfilePoints( const ProfilePoints& thePoints, bool IsConvertFromGlobal )
339 {
340   RemovePoints();
341   if ( thePoints.Length() < 2 )
342     return;
343
344   gp_XY aFirstPoint, aLastPoint;
345
346   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( Label() );
347   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ();
348   for ( int i = 1, n = thePoints.Length(); i <= n ; ++i )
349   {
350     ProfilePoint aPoint = thePoints.Value( i );
351     if( IsConvertFromGlobal )
352       aDoc->Transform( aPoint, true );
353
354     gp_XY aPointXY( aPoint.X(), aPoint.Y() );
355
356     if ( i == 1 )
357       aFirstPoint = aPointXY;
358     else if ( i == n )
359       aLastPoint = aPointXY;
360
361     double aDistance = gp_Pnt2d( aFirstPoint ).Distance( aPointXY );
362     
363     HYDROData_ProfileUZ::Point aParPoint( aDistance, aPoint.Z() );
364     aProfileUZ->AddPoint( 0, aParPoint );
365   }
366
367   SetLeftPoint( aFirstPoint, false );//already converted to local CS
368   SetRightPoint( aLastPoint, false );
369 }
370
371 HYDROData_Profile::ProfilePoints HYDROData_Profile::GetProfilePoints( bool IsConvertToGlobal ) const
372 {
373   ProfilePoints aResPoints;
374
375   gp_XY aFirstPoint, aLastPoint;
376   if ( !GetLeftPoint( aFirstPoint, IsConvertToGlobal ) ||
377        !GetRightPoint( aLastPoint, IsConvertToGlobal ) )
378     return aResPoints;
379
380   HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints();
381   if ( aParametricPoints.Length() < 2 )
382     return aResPoints;
383
384   const HYDROData_ProfileUZ::Point& aFirstParPoint = aParametricPoints.First();
385   const HYDROData_ProfileUZ::Point& aLastParPoint = aParametricPoints.Last();
386
387   double aGeoDistance = gp_Pnt2d( aFirstPoint ).Distance( aLastPoint );
388   double aParCommonDist = gp_Pnt2d( aFirstParPoint.X(), 0 ).Distance( gp_Pnt2d( aLastParPoint.X(), 0 ) );
389
390   // Add first point as is
391   aResPoints.Append( ProfilePoint( aFirstPoint.X(), aFirstPoint.Y(), aFirstParPoint.Y() ) );
392
393   // Compute all other points
394   for ( int i = 2, n = aParametricPoints.Length(); i < n ; ++i )
395   {
396     const HYDROData_ProfileUZ::Point& aParPoint = aParametricPoints.Value( i );
397
398     double aParPointDist = gp_Pnt2d( aFirstParPoint.X(), 0 ).Distance( gp_Pnt2d( aParPoint.X(), 0 ) );
399     
400     double aParLen = ( aParPointDist / aParCommonDist ) * aGeoDistance;
401
402     double aRatio = aParLen / ( aGeoDistance - aParLen );
403
404     double aParX = ( aFirstPoint.X() + aRatio * aLastPoint.X() ) / ( 1 + aRatio );
405     double aParY = ( aFirstPoint.Y() + aRatio * aLastPoint.Y() ) / ( 1 + aRatio );
406
407     ProfilePoint aCompPoint( aParX, aParY, aParPoint.Y() );
408     aResPoints.Append( aCompPoint );
409   }
410
411   // Add last point as is
412   aResPoints.Append( ProfilePoint( aLastPoint.X(), aLastPoint.Y(), aLastParPoint.Y() ) );
413
414   return aResPoints;
415 }
416
417 void HYDROData_Profile::SetFilePath( const TCollection_AsciiString& theFilePath )
418 {
419   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_FilePath ), theFilePath );
420 }
421
422 TCollection_AsciiString HYDROData_Profile::GetFilePath() const
423 {
424   TCollection_AsciiString aRes;
425
426   Handle(TDataStd_AsciiString) anAsciiStr;
427   if ( myLab.FindChild( DataTag_FilePath ).FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
428     aRes = anAsciiStr->Get();
429
430   return aRes;
431 }
432
433 int HYDROData_Profile::ImportFromFile( const Handle(HYDROData_Document)& theDoc,
434                                        const TCollection_AsciiString&    theFileName,
435                                        NCollection_Sequence<int>&        theBadProfilesIds )
436 {
437   if ( theDoc.IsNull() || theFileName.IsEmpty() )
438     return 0;
439
440   OSD_File aFile( theFileName );
441   if ( !aFile.IsReadable() )
442     return 0;
443
444   aFile.Open( OSD_ReadOnly, OSD_Protection() );
445   if ( !aFile.IsOpen() )
446     return 0;
447
448   NCollection_Sequence<Handle(HYDROData_Profile)> aCreatedProfiles;
449
450   int aProfileId = 1;
451   Handle(HYDROData_Profile) aNewProfile;
452   for ( ; !aFile.IsAtEnd(); ++aProfileId )
453   {
454     if ( aNewProfile.IsNull() )
455       aNewProfile = Handle(HYDROData_Profile)::DownCast( theDoc->CreateObject( KIND_PROFILE ) );
456     
457     bool anIsRead = false;
458     if ( aNewProfile->ImportFromFile( aFile, &anIsRead ) )
459     {
460       aCreatedProfiles.Append( aNewProfile );
461       aNewProfile.Nullify();
462     }
463     else if ( anIsRead )
464     {
465       theBadProfilesIds.Append( aProfileId );
466     }
467   }
468
469   if ( !aNewProfile.IsNull() )
470     aNewProfile->Remove();
471
472   // Close the file
473   aFile.Close();
474
475   for ( int i = 1, n = aCreatedProfiles.Length(); i <= n ; ++i )
476   {
477     Handle(HYDROData_Profile) aProfile = aCreatedProfiles.Value( i );
478
479     QString aProfileName = HYDROData_Tool::GenerateObjectName( theDoc, "Profile" );
480     aProfile->SetName( aProfileName );
481
482     aProfile->SetFilePath( theFileName );
483
484     aProfile->SetBorderColor( HYDROData_Profile::DefaultBorderColor() );
485   }
486
487   return aCreatedProfiles.Length();
488 }
489
490 bool HYDROData_Profile::ImportFromFile( const TCollection_AsciiString& theFileName,
491                                         bool*                          theIsRead )
492 {
493   if ( theIsRead )
494     *theIsRead = false;
495
496   // Try to open the file
497   OSD_File aFile( theFileName );
498   if ( !aFile.IsReadable() )
499     return false;
500
501   aFile.Open( OSD_ReadOnly, OSD_Protection() );
502   if ( !aFile.IsOpen() )
503     return false;
504
505   bool aRes = ImportFromFile( aFile, theIsRead );
506
507   // Close the file
508   aFile.Close();
509
510   if ( aRes )
511   {
512     // Update file path
513     SetFilePath( theFileName );
514   }
515
516   return aRes;
517 }
518
519 bool HYDROData_Profile::ImportFromFile( OSD_File& theFile,
520                                         bool*     theIsRead )
521 {
522   if ( theIsRead )
523     *theIsRead = false;
524
525   if ( !theFile.IsOpen() )
526     return false;
527
528   bool aRes = true;
529
530   bool anIsParametric = false;
531   bool anIsGeoref     = false;
532
533   HYDROData_ProfileUZ::PointsList aPointsUZ;
534   ProfilePoints                   aPointsXYZ;
535
536   double aPrevVal = -DBL_MAX;
537   while ( !theFile.IsAtEnd() )
538   {
539     Standard_Integer aNbRead = 0;
540     TCollection_AsciiString aLine;
541     theFile.ReadLine( aLine, 1024, aNbRead );
542
543     aLine.LeftAdjust(); aLine.RightAdjust();
544     if ( aLine.IsEmpty() )
545     {
546       if ( !anIsParametric && !anIsGeoref )
547         continue; // Definition is not started yet
548
549       break; // Next profile started
550     }
551
552     // Set flag of read status to true
553     if ( theIsRead )
554       *theIsRead = true;
555
556     TCollection_AsciiString aValX = aLine.Token( " \t", 1 );
557     TCollection_AsciiString aValY = aLine.Token( " \t", 2 );
558     TCollection_AsciiString aValZ = aLine.Token( " \t", 3 );
559
560     if ( aValX.IsEmpty() || !aValX.IsRealValue() ||
561          aValY.IsEmpty() || !aValY.IsRealValue() )
562     {
563       aRes = false;
564       break;
565     }
566
567     if ( !anIsParametric && !anIsGeoref )
568     {
569       anIsParametric = aValZ.IsEmpty();
570       anIsGeoref = !aValZ.IsEmpty();
571     }
572
573     double aCoordX = aValX.RealValue();
574     double aCoordY = aValY.RealValue();
575
576     if ( boost::math::isnan( aCoordX ) || boost::math::isinf( aCoordX ) ||
577          boost::math::isnan( aCoordY ) || boost::math::isinf( aCoordY ) )
578       aRes = false;
579
580     if ( anIsParametric )
581     {
582       if ( aCoordX < aPrevVal )
583       {
584         // Move back readed line
585         theFile.Seek( -( aNbRead + 1 ), OSD_FromHere );
586         break;
587       }
588
589       HYDROData_ProfileUZ::Point aPoint( aCoordX, aCoordY );
590       aPointsUZ.Append( aPoint );
591
592       aPrevVal = aCoordX;
593     }
594     else
595     {
596       if ( aValZ.IsEmpty() || !aValZ.IsRealValue() )
597       {
598         aRes = false;
599         break;
600       }
601
602       double aCoordZ = aValZ.RealValue();
603       if ( boost::math::isnan( aCoordZ ) || boost::math::isinf( aCoordZ ) )
604         aRes = false;
605
606       ProfilePoint aPoint( aCoordX, aCoordY, aCoordZ );
607       aPointsXYZ.Append( aPoint );
608     }
609   }
610   
611   aRes = aRes && ( anIsParametric && !aPointsUZ.IsEmpty() || 
612                    anIsGeoref && !aPointsXYZ.IsEmpty() );
613   if ( aRes )
614   {
615     // Update profile points
616     if ( anIsParametric )
617     {
618       SetParametricPoints( aPointsUZ );
619     }
620     else if ( anIsGeoref )
621     {
622       SetProfilePoints( aPointsXYZ, true );
623     }
624
625     Update();
626   }
627
628   return aRes;
629 }
630
631 void HYDROData_Profile::UpdateLocalCS( double theDx, double theDy )
632 {
633   gp_XY aDelta( theDx, theDy );
634   gp_XY aPnt;
635
636   GetLeftPoint( aPnt, false );
637   aPnt += aDelta;
638   SetLeftPoint( aPnt, false );
639
640   GetRightPoint( aPnt, false );
641   aPnt += aDelta;
642   SetRightPoint( aPnt, false );
643 }
644
645