Salome HOME
6308af1403ff6020573c5c2fba0934802dc8045b
[modules/hydro.git] / src / HYDROData / HYDROData_Profile.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_Profile.h"
20
21 #include "HYDROData_Document.h"
22 #include "HYDROData_Iterator.h"
23 #include "HYDROData_Tool.h"
24 #include "HYDROData_PolylineXY.h"
25
26 #include <BRepBuilderAPI_MakeEdge.hxx>
27 #include <BRepBuilderAPI_MakeWire.hxx>
28 #include <BRepBuilderAPI_MakePolygon.hxx>
29
30 #include <BRepExtrema_ExtCC.hxx>
31
32 #include <BRep_Tool.hxx>
33
34 #include <gp_Lin.hxx>
35 #include <gp_XY.hxx>
36 #include <gp_XYZ.hxx>
37 #include <gp_Pnt2d.hxx>
38
39 #include <TDataStd_AsciiString.hxx>
40 #include <TDataStd_RealArray.hxx>
41
42 #include <TopoDS.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Wire.hxx>
45 #include <TopoDS_Iterator.hxx>
46
47 #include <OSD_File.hxx>
48 #include <OSD_Protection.hxx>
49
50 #include <QColor>
51 #include <QStringList>
52
53 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Profile, HYDROData_Object)
54
55 HYDROData_Profile::HYDROData_Profile()
56 : HYDROData_Object( Geom_3d )
57 {
58 }
59
60 HYDROData_Profile::~HYDROData_Profile()
61 {
62 }
63
64 QStringList HYDROData_Profile::DumpToPython( const QString&       thePyScriptPath,
65                                              MapOfTreatedObjects& theTreatedObjects ) const
66 {
67   QStringList aResList = dumpObjectCreation( theTreatedObjects );
68   QString aProfileName = GetObjPyName();
69
70   //TCollection_AsciiString aFilePath = GetFilePath();
71   //if ( !aFilePath.IsEmpty() ) 
72   //{
73   //  aResList << QString( "%1.ImportFromFile( \"%2\" )" )
74   //            .arg( aName ).arg( aFilePath.ToCString() );
75   //}
76
77   bool anIsValidProfile = IsValid();
78   
79   QStringList aPntsDefinition;
80   QString aPntsListName = HYDROData_Tool::GenerateNameForPython( theTreatedObjects, "profile_points" );
81
82   QString aGap = QString().fill( ' ', aPntsListName.length() + 5 );
83   if ( anIsValidProfile )
84   {
85     HYDROData_Profile::ProfilePoints aPointsList = GetProfilePoints( true );
86     for ( int k = 1, aNbPoints = aPointsList.Size(); k <= aNbPoints; ++k )
87     {
88       const ProfilePoint& aPoint = aPointsList.Value( k );
89       aPntsDefinition << QString( aGap + "gp_XYZ( %1, %2, %3 )%4" )
90                          .arg( aPoint.X() ).arg( aPoint.Y() ).arg( aPoint.Z() )
91                          .arg( ( k < aNbPoints ? "," : "" ) );
92     }
93   }
94   else
95   {
96     HYDROData_IPolyline::PointsList aPointsList = GetParametricPoints();
97     for ( int k = 1, aNbPoints = aPointsList.Size(); k <= aNbPoints; ++k )
98     {
99       const HYDROData_IPolyline::Point& aPoint = aPointsList.Value( k );
100       aPntsDefinition << QString( aGap + "gp_XY( %1, %2 )%3" )
101                          .arg( aPoint.X() ).arg( aPoint.Y() )
102                          .arg( ( k < aNbPoints ? "," : "" ) );
103     }
104   }
105
106   if ( !aPntsDefinition.isEmpty() )
107   {
108     QString& aFirstStr = aPntsDefinition.first();
109     aFirstStr = aFirstStr.trimmed();
110     aFirstStr.prepend( QString( "%1 = [ " ).arg( aPntsListName ) );
111     
112     aPntsDefinition.last().append( " ];" );
113
114     aResList << aPntsDefinition;
115     
116     aResList << QString( "%1.%3( %2 )" )
117                 .arg( aProfileName ).arg( aPntsListName )
118                 .arg( anIsValidProfile ? "SetProfilePoints" : "SetParametricPoints" );
119   
120     aResList << QString( "" );
121   }
122
123   // Set a polyline type if it is not default
124   Handle(HYDROData_ProfileUZ) aPrf = GetProfileUZ( false );
125   if ( !aPrf.IsNull() )
126   {
127     HYDROData_IPolyline::SectionType aSecType = aPrf->GetSectionType( 0 );
128     if ( aSecType != HYDROData_IPolyline::SECTION_POLYLINE )
129     {
130       aResList << QString( "%1.GetProfileUZ().SetSectionType( 0, %2 )" )
131                   .arg( aProfileName ).arg( "HYDROData_IPolyline.SECTION_SPLINE" );
132       aResList << QString( "" );
133     }
134   }
135
136   aResList << QString( "%1.Update()" ).arg( aProfileName );
137   aResList << QString( "" );
138
139   return aResList;
140 }
141
142 TopoDS_Shape HYDROData_Profile::GetTopShape() const
143 {
144   TopoDS_Wire aWire;
145
146   gp_XY aFirstPoint, aLastPoint;
147   if ( !GetLeftPoint( aFirstPoint, false ) || !GetRightPoint( aLastPoint, false ) )
148     return aWire;
149
150   gp_Pnt aPnt1( aFirstPoint.X(), aFirstPoint.Y(), 0 );
151   gp_Pnt aPnt2( aLastPoint.X(),  aLastPoint.Y(),  0 );
152
153   BRepBuilderAPI_MakeEdge aMakeEdge( aPnt1, aPnt2 );
154   TopoDS_Edge anEdge = aMakeEdge;
155
156   BRepBuilderAPI_MakeWire aMakeWire( anEdge );
157   aWire = aMakeWire;
158
159   return aWire;
160 }
161
162 TopoDS_Shape HYDROData_Profile::GetShape3D() const
163 {
164   TopoDS_Shape aShape = HYDROData_Object::GetShape3D();
165   if( aShape.IsNull() )
166     aShape = CreateProfileWire( true );
167   return aShape;
168 }
169
170 TopoDS_Shape HYDROData_Profile::CreateProfileWire( bool canUseDefaultPoints ) const
171 {
172   TopoDS_Wire aWire;
173   Handle(HYDROData_ProfileUZ) aProfile = GetProfileUZ( false );
174   if ( !aProfile.IsNull() )
175   {
176     ProfilePoints aProfilePoints = GetProfilePoints( false, canUseDefaultPoints );
177     HYDROData_IPolyline::SectionType aSectionType = aProfile->GetSectionType( 0 );
178
179     aWire = HYDROData_PolylineXY::BuildWire( aSectionType, false, aProfilePoints );
180   }
181   return aWire;
182 }
183
184 void HYDROData_Profile::Update()
185 {
186   HYDROData_Object::Update();
187
188   TopoDS_Shape aShape = CreateProfileWire( true );
189   SetShape3D( aShape );
190 }
191
192 QColor HYDROData_Profile::DefaultFillingColor() const
193 {
194   return QColor( Qt::transparent );
195 }
196
197 QColor HYDROData_Profile::DefaultBorderColor() const
198 {
199   return QColor( Qt::black );
200 }
201
202 bool HYDROData_Profile::IsValid() const
203 {
204   gp_XY aFirstPoint, aLastPoint;
205   if ( !GetLeftPoint( aFirstPoint, false ) || !GetRightPoint( aLastPoint, false ) )
206     return false;
207
208   int aNbPoints = NbPoints();
209   return aNbPoints > 1;
210 }
211
212 void HYDROData_Profile::SetLeftPoint( const gp_XY& theGPoint, bool IsConvertFromGlobal )
213 {
214   TDF_Label aLabel = myLab.FindChild( DataTag_FirstPoint );
215   if ( aLabel.IsNull() )
216     return;
217
218   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( Label() );
219   gp_XY aLPoint = theGPoint;
220   if( IsConvertFromGlobal )
221     aDoc->Transform( aLPoint, true );
222
223   Handle(TDataStd_RealArray) anArray;
224   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
225     anArray = TDataStd_RealArray::Set( aLabel, 0, 1 );
226
227   anArray->SetValue( 0, aLPoint.X() );
228   anArray->SetValue( 1, aLPoint.Y() );
229
230   Changed( Geom_3d );
231 }
232
233 bool HYDROData_Profile::GetLeftPoint( gp_XY& thePoint, bool IsConvertToGlobal,
234                                       bool CanUseDefault ) const
235 {
236   HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints();
237   if ( aParametricPoints.Length() < 2 )
238     return false;
239
240   thePoint = GetParametricPoints().First();
241
242   //thePoint.SetX( 0 );
243   thePoint.SetY( 0 ); //default left point of not-georeferenced profile
244   TDF_Label aLabel = myLab.FindChild( DataTag_FirstPoint, false );
245   if ( aLabel.IsNull() )
246   {
247     return CanUseDefault;
248   }
249
250   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( myLab );
251   Handle(TDataStd_RealArray) anArray;
252   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
253   {
254     return CanUseDefault;
255   }
256
257   thePoint.SetX( anArray->Value( 0 ) );
258   thePoint.SetY( anArray->Value( 1 ) );
259
260   if( IsConvertToGlobal )
261     aDoc->Transform( thePoint, false );
262
263   return true;
264 }
265
266 void HYDROData_Profile::SetRightPoint( const gp_XY& theGPoint, bool IsConvertFromGlobal )
267 {
268   TDF_Label aLabel = myLab.FindChild( DataTag_LastPoint );
269
270   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( Label() );
271   gp_XY aLPoint = theGPoint;
272   if( IsConvertFromGlobal )
273     aDoc->Transform( aLPoint, true );
274
275   Handle(TDataStd_RealArray) anArray;
276   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
277     anArray = TDataStd_RealArray::Set( aLabel, 0, 1 );
278
279   anArray->SetValue( 0, aLPoint.X() );
280   anArray->SetValue( 1, aLPoint.Y() );
281
282   Changed( Geom_3d );
283 }
284
285 bool HYDROData_Profile::GetRightPoint( gp_XY& thePoint, bool IsConvertToGlobal,
286                                        bool CanUseDefault ) const
287 {
288   HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints();
289   if ( aParametricPoints.Length() < 2 )
290     return false;
291
292   thePoint = GetParametricPoints().Last();
293   thePoint.SetY( 0 );
294
295   TDF_Label aLabel = myLab.FindChild( DataTag_LastPoint, false );
296   if ( aLabel.IsNull() )
297   {
298     return CanUseDefault;
299   }
300
301   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( myLab );
302   Handle(TDataStd_RealArray) anArray;
303   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), anArray ) )
304   {
305     return CanUseDefault;
306   }
307
308   thePoint.SetX( anArray->Value( 0 ) );
309   thePoint.SetY( anArray->Value( 1 ) );
310
311   if( IsConvertToGlobal )
312     aDoc->Transform( thePoint, false );
313
314   return true;
315 }
316
317 void HYDROData_Profile::Invalidate()
318 {
319   TDF_Label aFirstLabel = myLab.FindChild( DataTag_FirstPoint, false );
320   if ( !aFirstLabel.IsNull() )
321     aFirstLabel.ForgetAllAttributes();
322
323   TDF_Label aLastLabel = myLab.FindChild( DataTag_LastPoint, false );
324   if ( !aLastLabel.IsNull() )
325     aLastLabel.ForgetAllAttributes();
326
327   Changed( Geom_3d );
328 }
329
330 Handle(HYDROData_ProfileUZ) HYDROData_Profile::GetProfileUZ( const bool theIsCreate ) const
331 {
332   Handle(HYDROData_ProfileUZ) aProfileUZ;
333
334   TDF_Label aLabel = myLab.FindChild( DataTag_ChildProfileUZ, theIsCreate );
335   if ( aLabel.IsNull() )
336     return aProfileUZ;
337
338   aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast( HYDROData_Iterator::Object( aLabel ) );
339   if ( aProfileUZ.IsNull() && theIsCreate )
340   {
341     aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast(
342       HYDROData_Iterator::CreateObject( aLabel, KIND_PROFILEUZ ) );
343   }
344
345   return aProfileUZ;
346 }
347
348 int HYDROData_Profile::NbPoints() const
349 {
350   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
351   return aProfileUZ.IsNull() ? 0 : aProfileUZ->NbPoints();
352 }
353
354 void HYDROData_Profile::RemovePoints()
355 {
356   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
357   if ( !aProfileUZ.IsNull() )
358   {
359     aProfileUZ->RemoveSections();
360     Changed( Geom_3d );
361   }
362 }
363
364 void HYDROData_Profile::SetParametricPoints( const HYDROData_ProfileUZ::PointsList& thePoints )
365 {
366   RemovePoints();
367
368   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ();
369   for ( int i = 1, n = thePoints.Length(); i <= n ; ++i )
370   {
371     const HYDROData_ProfileUZ::Point& aPoint = thePoints.Value( i );
372     aProfileUZ->AddPoint( 0, aPoint );
373   }
374
375   Changed( Geom_3d );
376 }
377
378 HYDROData_ProfileUZ::PointsList HYDROData_Profile::GetParametricPoints() const
379 {
380   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ( false );
381   return aProfileUZ.IsNull() ? HYDROData_ProfileUZ::PointsList() : aProfileUZ->GetPoints();
382 }
383
384 void HYDROData_Profile::SetProfilePoints( const ProfilePoints& thePoints, bool IsConvertFromGlobal )
385 {
386   RemovePoints();
387   if ( thePoints.Length() < 2 )
388     return;
389
390   gp_XY aFirstPoint, aLastPoint;
391
392   Handle(HYDROData_Document) aDoc = HYDROData_Document::Document( Label() );
393   Handle(HYDROData_ProfileUZ) aProfileUZ = GetProfileUZ();
394   for ( int i = 1, n = thePoints.Length(); i <= n ; ++i )
395   {
396     ProfilePoint aPoint = thePoints.Value( i );
397     if( IsConvertFromGlobal )
398       aDoc->Transform( aPoint, true );
399
400     gp_XY aPointXY( aPoint.X(), aPoint.Y() );
401
402     if ( i == 1 )
403       aFirstPoint = aPointXY;
404     else if ( i == n )
405       aLastPoint = aPointXY;
406
407     double aDistance = gp_Pnt2d( aFirstPoint ).Distance( aPointXY );
408     
409     HYDROData_ProfileUZ::Point aParPoint( aDistance, aPoint.Z() );
410     aProfileUZ->AddPoint( 0, aParPoint );
411   }
412
413   SetLeftPoint( aFirstPoint, false );//already converted to local CS
414   SetRightPoint( aLastPoint, false );
415 }
416
417 HYDROData_Profile::ProfilePoints HYDROData_Profile::GetProfilePoints
418   ( bool IsConvertToGlobal, bool CanUseDefaultLeftRight ) const
419 {
420   ProfilePoints aResPoints;
421
422   gp_XY aFirstPoint, aLastPoint;
423   if ( !GetLeftPoint( aFirstPoint, IsConvertToGlobal, CanUseDefaultLeftRight ) ||
424        !GetRightPoint( aLastPoint, IsConvertToGlobal, CanUseDefaultLeftRight ) )
425     return aResPoints;
426
427   HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints();
428   if ( aParametricPoints.Length() < 2 )
429     return aResPoints;
430
431   const HYDROData_ProfileUZ::Point& aFirstParPoint = aParametricPoints.First();
432   const HYDROData_ProfileUZ::Point& aLastParPoint = aParametricPoints.Last();
433
434   double aFullLength = aLastPoint.X() - aFirstPoint.X();
435   double aParFullLength = aLastParPoint.X() - aFirstParPoint.X();
436
437   // Add first point as is
438   aResPoints.Append( ProfilePoint( aFirstPoint.X(), aFirstPoint.Y(), aFirstParPoint.Y() ) );
439
440   // Compute all other points
441   for ( int i = 2, n = aParametricPoints.Length(); i < n ; ++i )
442   {
443     const HYDROData_ProfileUZ::Point& aParPoint = aParametricPoints.Value( i );
444
445     double aParPointDist = aParPoint.X() - aFirstParPoint.X();
446     double aRatio = aParPointDist / aParFullLength;
447
448     double aParX = aFirstPoint.X() * (1-aRatio) + aLastPoint.X() * aRatio;
449     double aParY = aFirstPoint.Y() * (1-aRatio) + aLastPoint.Y() * aRatio;
450
451     ProfilePoint aCompPoint( aParX, aParY, aParPoint.Y() );
452     aResPoints.Append( aCompPoint );
453   }
454
455   // Add last point as is
456   aResPoints.Append( ProfilePoint( aLastPoint.X(), aLastPoint.Y(), aLastParPoint.Y() ) );
457
458   return aResPoints;
459 }
460
461 void HYDROData_Profile::SetFilePath( const TCollection_AsciiString& theFilePath )
462 {
463   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_FilePath ), theFilePath );
464 }
465
466 TCollection_AsciiString HYDROData_Profile::GetFilePath() const
467 {
468   TCollection_AsciiString aRes;
469
470   Handle(TDataStd_AsciiString) anAsciiStr;
471   if ( myLab.FindChild( DataTag_FilePath ).FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
472     aRes = anAsciiStr->Get();
473
474   return aRes;
475 }
476
477 int HYDROData_Profile::ImportFromFile( const Handle(HYDROData_Document)& theDoc,
478                                        const TCollection_AsciiString&    theFileName,
479                                        NCollection_Sequence<int>&        theBadProfilesIds )
480 {
481   if ( theDoc.IsNull() || theFileName.IsEmpty() )
482     return 0;
483
484   OSD_File aFile( theFileName );
485   if ( !aFile.IsReadable() )
486     return 0;
487
488   aFile.Open( OSD_ReadOnly, OSD_Protection() );
489   if ( !aFile.IsOpen() )
490     return 0;
491
492   NCollection_Sequence<Handle(HYDROData_Profile)> aCreatedProfiles;
493
494   int aProfileId = 1;
495   Handle(HYDROData_Profile) aNewProfile;
496   for ( ; !aFile.IsAtEnd(); ++aProfileId )
497   {
498     if ( aNewProfile.IsNull() )
499       aNewProfile = Handle(HYDROData_Profile)::DownCast( theDoc->CreateObject( KIND_PROFILE ) );
500     
501     bool anIsRead = false;
502     if ( aNewProfile->ImportFromFile( aFile, &anIsRead ) )
503     {
504       aCreatedProfiles.Append( aNewProfile );
505       aNewProfile.Nullify();
506     }
507     else if ( anIsRead )
508     {
509       theBadProfilesIds.Append( aProfileId );
510     }
511   }
512
513   if ( !aNewProfile.IsNull() )
514     aNewProfile->Remove();
515
516   // Close the file
517   aFile.Close();
518
519   for ( int i = 1, n = aCreatedProfiles.Length(); i <= n ; ++i )
520   {
521     Handle(HYDROData_Profile) aProfile = aCreatedProfiles.Value( i );
522
523     QString aProfileName = HYDROData_Tool::GenerateObjectName( theDoc, "Profile" );
524     aProfile->SetName( aProfileName );
525
526     aProfile->SetFilePath( theFileName );
527
528     aProfile->SetBorderColor( aProfile->DefaultBorderColor() );
529   }
530
531   return aCreatedProfiles.Length();
532 }
533
534 bool HYDROData_Profile::ImportFromFile( const TCollection_AsciiString& theFileName,
535                                         bool*                          theIsRead )
536 {
537   if ( theIsRead )
538     *theIsRead = false;
539
540   // Try to open the file
541   OSD_File aFile( theFileName );
542   if ( !aFile.IsReadable() )
543     return false;
544
545   aFile.Open( OSD_ReadOnly, OSD_Protection() );
546   if ( !aFile.IsOpen() )
547     return false;
548
549   bool aRes = ImportFromFile( aFile, theIsRead );
550
551   // Close the file
552   aFile.Close();
553
554   if ( aRes )
555   {
556     // Update file path
557     SetFilePath( theFileName );
558   }
559
560   return aRes;
561 }
562
563 bool HYDROData_Profile::ImportFromFile( OSD_File& theFile,
564                                         bool*     theIsRead )
565 {
566   if ( theIsRead )
567     *theIsRead = false;
568
569   if ( !theFile.IsOpen() )
570     return false;
571
572   bool aRes = true;
573
574   bool anIsParametric = false;
575   bool anIsGeoref     = false;
576
577   HYDROData_ProfileUZ::PointsList aPointsUZ;
578   ProfilePoints                   aPointsXYZ;
579
580   double aPrevVal = -DBL_MAX;
581   while ( !theFile.IsAtEnd() )
582   {
583     Standard_Integer aNbRead = 0;
584     TCollection_AsciiString aLine;
585     theFile.ReadLine( aLine, 1024, aNbRead );
586
587     aLine.LeftAdjust(); aLine.RightAdjust();
588     if ( aLine.IsEmpty() )
589     {
590       if ( !anIsParametric && !anIsGeoref )
591         continue; // Definition is not started yet
592
593       break; // Next profile started
594     }
595
596     // Set flag of read status to true
597     if ( theIsRead )
598       *theIsRead = true;
599
600     TCollection_AsciiString aValX = aLine.Token( " \t", 1 );
601     TCollection_AsciiString aValY = aLine.Token( " \t", 2 );
602     TCollection_AsciiString aValZ = aLine.Token( " \t", 3 );
603
604     if ( aValX.IsEmpty() || !aValX.IsRealValue() ||
605          aValY.IsEmpty() || !aValY.IsRealValue() )
606     {
607       aRes = false;
608       break;
609     }
610
611     if ( !anIsParametric && !anIsGeoref )
612     {
613       anIsParametric = aValZ.IsEmpty();
614       anIsGeoref = !aValZ.IsEmpty();
615     }
616
617     double aCoordX = aValX.RealValue();
618     double aCoordY = aValY.RealValue();
619
620     if ( HYDROData_Tool::IsNan( aCoordX ) || HYDROData_Tool::IsInf( aCoordX ) ||
621          HYDROData_Tool::IsNan( aCoordY ) || HYDROData_Tool::IsInf( aCoordY ) )
622       aRes = false;
623
624     if ( anIsParametric )
625     {
626       if ( aCoordX < aPrevVal )
627       {
628         // Move back readed line
629         theFile.Seek( -( aNbRead + 1 ), OSD_FromHere );
630         break;
631       }
632
633       HYDROData_ProfileUZ::Point aPoint( aCoordX, aCoordY );
634       aPointsUZ.Append( aPoint );
635
636       aPrevVal = aCoordX;
637     }
638     else
639     {
640       if ( aValZ.IsEmpty() || !aValZ.IsRealValue() )
641       {
642         aRes = false;
643         break;
644       }
645
646       double aCoordZ = aValZ.RealValue();
647       if ( HYDROData_Tool::IsNan( aCoordZ ) || HYDROData_Tool::IsInf( aCoordZ ) )
648         aRes = false;
649
650       ProfilePoint aPoint( aCoordX, aCoordY, aCoordZ );
651       aPointsXYZ.Append( aPoint );
652     }
653   }
654   
655   aRes = aRes && ( anIsParametric && !aPointsUZ.IsEmpty() || 
656                    anIsGeoref && !aPointsXYZ.IsEmpty() );
657   if ( aRes )
658   {
659     // Update profile points
660     if ( anIsParametric )
661     {
662       SetParametricPoints( aPointsUZ );
663     }
664     else if ( anIsGeoref )
665     {
666       SetProfilePoints( aPointsXYZ, true );
667     }
668
669     Update();
670   }
671
672   return aRes;
673 }
674
675 void HYDROData_Profile::UpdateLocalCS( double theDx, double theDy )
676 {
677   gp_XY aDelta( theDx, theDy );
678   gp_XY aPnt;
679
680   GetLeftPoint( aPnt, false );
681   aPnt += aDelta;
682   SetLeftPoint( aPnt, false );
683
684   GetRightPoint( aPnt, false );
685   aPnt += aDelta;
686   SetRightPoint( aPnt, false );
687 }
688
689 HYDROData_Profile::ProfilePoint HYDROData_Profile::GetBottomPoint() const
690 {
691   ProfilePoint aBottom;
692
693   // Get parametric points
694   HYDROData_ProfileUZ::PointsList aParametricPoints = GetParametricPoints();
695   if ( aParametricPoints.Length() < 1 ) {
696     return aBottom;
697   }
698
699   // Calculate midvalue for U parameter
700   Standard_Real anUMidValue = aParametricPoints.First().X();
701   Standard_Real anUMinValue = anUMidValue;
702   Standard_Real anUMaxValue = anUMidValue;
703
704   for ( int i = 2, aNbPoints = aParametricPoints.Size(); i <= aNbPoints; i++ ) {
705     const HYDROData_IPolyline::Point& aParPoint = aParametricPoints.Value( i );
706     Standard_Real anU = aParPoint.X();
707
708     if ( anU < anUMinValue ) {
709       anUMinValue = anU;
710     } else if ( anU > anUMaxValue ) {
711       anUMaxValue = anU;
712     }
713   }
714
715   anUMidValue = ( anUMinValue + anUMaxValue ) / 2;
716
717   // Find index of the parametric point with minimal Z value
718   int aBottomIndex = 1;
719   HYDROData_IPolyline::Point aParBottom = aParametricPoints.First();
720
721   for ( int i = 2, aNbPoints = aParametricPoints.Size(); i <= aNbPoints; i++ ) {
722     const HYDROData_IPolyline::Point& aParPoint = aParametricPoints.Value( i );
723     if ( aParPoint.Y() < aParBottom.Y() ) {
724       aBottomIndex = i;
725       aParBottom = aParPoint;
726     } else if ( aParPoint.Y() == aParBottom.Y() ) {
727       // Check which point is neares to the U = 0.5
728       if ( fabs( aParPoint.X() - anUMidValue ) < fabs( aParBottom.X() - anUMidValue ) ) {
729         aBottomIndex = i;
730         aParBottom = aParPoint;
731       }
732     }
733   }
734
735   // Find the corresponding profile point
736   ProfilePoints aProfilePoints = GetProfilePoints( false );
737   if ( aBottomIndex >= 1 && aBottomIndex <= aProfilePoints.Length() ) {
738     aBottom = aProfilePoints.Value( aBottomIndex );
739   }
740
741   return aBottom;
742 }
743
744  HYDROData_Profile::ProfilePoint HYDROData_Profile::GetMiddlePoint( bool CanUseDefault ) const
745  {
746    ProfilePoint aMiddlePoint;
747   
748    gp_XY aLeftPnt, aRightPnt;
749    if ( GetLeftPoint( aLeftPnt, true, CanUseDefault ) && GetRightPoint( aRightPnt, true, CanUseDefault ) ) {
750      gp_XYZ aPnt1( aLeftPnt.X(), aLeftPnt.Y(), 0. );
751      gp_XYZ aPnt2( aRightPnt.X(), aRightPnt.Y(), 0. );
752      gp_Pnt aMiddlePoint2d( 0.5 * ( aPnt1 + aPnt2 ) ); 
753
754      gp_Lin aMidLin( aMiddlePoint2d, gp::DZ() );
755      TopoDS_Edge aMidEdge = BRepLib_MakeEdge( aMidLin );
756
757      TopoDS_Iterator anIt( TopoDS::Wire( GetShape3D() )  );
758      for ( ; anIt.More(); anIt.Next()) {
759        const TopoDS_Edge& anEdge = TopoDS::Edge( anIt.Value() );
760
761        /*
762        Standard_Real aStart, anEnd;
763        Handle(Geom_Curve) aCurve = BRep_Tool::Curve( anEdge, aStart, anEnd );
764        gp_Pnt aMiddlePointOnCurve = aCurve->Value( ( aStart + anEnd ) / 2 );
765        */
766
767        BRepExtrema_ExtCC ExtremaEE( aMidEdge, anEdge);
768        if (ExtremaEE.IsDone() && ExtremaEE.NbExt() != 0) {
769          for ( Standard_Integer i = 1; i <= ExtremaEE.NbExt(); i++ ) {
770            if ( ExtremaEE.SquareDistance(i) <= Precision::Confusion() ) {
771              aMiddlePoint = ExtremaEE.PointOnE1(i).XYZ();
772              break;
773            }
774          }
775        }
776      }
777    }
778
779    return aMiddlePoint;
780  }