]> SALOME platform Git repositories - modules/hydro.git/blob - src/HYDROData/HYDROData_Bathymetry.cxx
Salome HOME
precision auto
[modules/hydro.git] / src / HYDROData / HYDROData_Bathymetry.cxx
1
2 #include "HYDROData_Bathymetry.h"
3 #include "HYDROData_Document.h"
4 #include "HYDROData_Tool.h"
5 #include "HYDROData_PolylineXY.h"
6
7 #include <boost/math/special_functions/fpclassify.hpp>
8
9 #include <gp_XY.hxx>
10 #include <gp_XYZ.hxx>
11
12 #include <TDataStd_RealArray.hxx>
13 #include <TDataStd_AsciiString.hxx>
14 #include <TDataStd_Integer.hxx>
15
16 #include <QFile>
17 #include <QFileInfo>
18 #include <QPointF>
19 #include <QPolygonF>
20 #include <QStringList>
21
22 #include <math.h>
23
24 // #define _TIMER
25 #ifdef _TIMER
26 #include <OSD_Timer.hxx>
27 #endif
28
29 #define _DEVDEBUG_
30 #include "HYDRO_trace.hxx"
31
32 IMPLEMENT_STANDARD_HANDLE(HYDROData_Bathymetry, HYDROData_IAltitudeObject)
33 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Bathymetry, HYDROData_IAltitudeObject)
34
35 //HYDROData_QuadtreeNode* HYDROData_Bathymetry::myQuadtree = 0;
36 std::map<int, HYDROData_QuadtreeNode*> HYDROData_Bathymetry::myQuadtrees;
37
38 HYDROData_Bathymetry::HYDROData_Bathymetry()
39 : HYDROData_IAltitudeObject()
40 {
41   //DEBTRACE("HYDROData_Bathymetry constructor start " << this);
42 //  if (! myQuadtree)
43 //    myQuadtree = new HYDROData_QuadtreeNode(0, 30, 5, 0.);
44   //DEBTRACE("HYDROData_Bathymetry constructor end   " << this);
45 }
46
47 HYDROData_Bathymetry::~HYDROData_Bathymetry()
48 {
49   //DEBTRACE("HYDROData_Bathymetry destructor start " << this);
50 //  if (myQuadtree)
51 //    delete myQuadtree;
52 //      Nodes_3D::iterator it = myListOfNodes.begin();
53 //      for( ; it != myListOfNodes.end(); ++it)
54 //              delete *it;
55 //    myListOfNodes.clear();
56 }
57
58 QStringList HYDROData_Bathymetry::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
59 {
60   QStringList aResList = dumpObjectCreation( theTreatedObjects );
61   QString aBathymetryName = GetObjPyName();
62
63   aResList << QString( "%1.SetAltitudesInverted( %2 );" )
64               .arg( aBathymetryName ).arg( IsAltitudesInverted() );
65
66   TCollection_AsciiString aFilePath = GetFilePath();
67   aResList << QString( "%1.ImportFromFile( \"%2\" );" )
68               .arg( aBathymetryName ).arg( aFilePath.ToCString() );
69
70   aResList << QString( "" );
71   aResList << QString( "%1.Update();" ).arg( aBathymetryName );
72   aResList << QString( "" );
73
74   return aResList;
75 }
76
77 void HYDROData_Bathymetry::SetAltitudePoints( const AltitudePoints& thePoints )
78 {
79   RemoveAltitudePoints();
80
81   if ( thePoints.IsEmpty() )
82     return;
83
84   // Save coordinates
85   Handle(TDataStd_RealArray) aCoordsArray = 
86     TDataStd_RealArray::Set( myLab.FindChild( DataTag_AltitudePoints ), 0, thePoints.Length() * 3 - 1 );
87
88   AltitudePoints::Iterator anIter( thePoints );
89   for ( int i = 0 ; anIter.More(); ++i, anIter.Next() )
90   {
91     const AltitudePoint& aPoint = anIter.Value();
92
93     aCoordsArray->SetValue( i * 3, aPoint.X() );
94     aCoordsArray->SetValue( i * 3 + 1, aPoint.Y() );
95     aCoordsArray->SetValue( i * 3 + 2, aPoint.Z() );
96   }
97
98   SetToUpdate( true );
99 }
100
101 HYDROData_Bathymetry::AltitudePoints HYDROData_Bathymetry::GetAltitudePoints() const
102 {
103   AltitudePoints aPoints;
104
105   TDF_Label aLabel = myLab.FindChild( DataTag_AltitudePoints, false );
106   if ( aLabel.IsNull() )
107     return aPoints;
108
109   Handle(TDataStd_RealArray) aCoordsArray;
110   if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), aCoordsArray ) )
111     return aPoints;
112
113   for ( int i = aCoordsArray->Lower(), n = aCoordsArray->Upper(); i <= n; )
114   {
115     if ( i + 3 > n + 1 )
116       break;
117
118     AltitudePoint aPoint;
119     aPoint.SetX( aCoordsArray->Value( i++ ) );
120     aPoint.SetY( aCoordsArray->Value( i++ ) );
121     aPoint.SetZ( aCoordsArray->Value( i++ ) );
122
123     aPoints.Append( aPoint );
124   }
125
126   return aPoints;
127 }
128
129 HYDROData_QuadtreeNode* HYDROData_Bathymetry::GetQuadtreeNodes() const
130 {
131   TDF_Label aLabel = myLab.FindChild(DataTag_AltitudePoints, false);
132   if (aLabel.IsNull())
133     return 0;
134   int labkey = myLab.Tag();
135   int altkey = aLabel.Tag();
136   //DEBTRACE("GetQuadtreeNodes this labkey altkey "<<this<<" "<<labkey<<" "<<altkey);
137 //  if (myQuadtree->isEmpty() )
138   if (myQuadtrees.find(labkey) == myQuadtrees.end())
139     {
140       DEBTRACE("GetQuadtreeNodes init " << this << " " << labkey);
141       HYDROData_QuadtreeNode* aQuadtree = new HYDROData_QuadtreeNode(0, 30, 5, 0.);
142       myQuadtrees[labkey] = aQuadtree;
143       TDF_Label aLabel = myLab.FindChild(DataTag_AltitudePoints, false);
144       if (aLabel.IsNull())
145         return 0;
146
147       Handle(TDataStd_RealArray) aCoordsArray;
148       if (!aLabel.FindAttribute(TDataStd_RealArray::GetID(), aCoordsArray))
149         return 0;
150
151       Nodes_3D* aListOfNodes = new Nodes_3D();
152
153       for (int i = aCoordsArray->Lower(), n = aCoordsArray->Upper(); i <= n;)
154         {
155           if (i + 3 > n + 1)
156             break;
157
158           double x = aCoordsArray->Value(i++);
159           double y = aCoordsArray->Value(i++);
160           double z = aCoordsArray->Value(i++);
161           gp_XYZ* aPoint = new gp_XYZ(x, y, z);
162           aListOfNodes->push_back(aPoint);
163         }
164       DEBTRACE("  GetQuadtreeNodes call setNodesAndCompute");
165       aQuadtree->setNodesAndCompute(aListOfNodes);
166       return aQuadtree;
167     }
168   else
169     return myQuadtrees[labkey];
170 }
171
172 void HYDROData_Bathymetry::RemoveAltitudePoints()
173 {
174   TDF_Label aLabel = myLab.FindChild(DataTag_AltitudePoints, false);
175   if (!aLabel.IsNull())
176     {
177       aLabel.ForgetAllAttributes();
178       SetToUpdate(true);
179     }
180 }
181
182 void interpolateAltitudeForPoints( const gp_XY&                               thePoint,
183                                    const HYDROData_Bathymetry::AltitudePoint& theFirstPoint,
184                                    const HYDROData_Bathymetry::AltitudePoint& theSecPoint,
185                                    HYDROData_Bathymetry::AltitudePoint&       theResPoint,
186                                    const bool&                                theIsVertical )
187 {
188   double aCoordX = thePoint.X();
189   double aCoordY = thePoint.Y();
190
191   if ( theIsVertical )
192   {
193     aCoordX = theFirstPoint.X();
194
195     if ( !ValuesEquals( theFirstPoint.X(), theSecPoint.X() ) )
196     {
197       // Recalculate X coordinate by equation of line from two points
198       aCoordX = ( ( ( thePoint.Y() - theFirstPoint.Y() ) * ( theSecPoint.X() - theFirstPoint.X() ) ) /
199                   ( theSecPoint.Y() - theFirstPoint.Y() ) ) + theFirstPoint.X();
200     }
201   }
202   else
203   {
204     aCoordY = theFirstPoint.Y();
205
206     if ( !ValuesEquals( theFirstPoint.Y(), theSecPoint.Y() ) )
207     {
208       // Recalculate y by equation of line from two points
209       aCoordY = ( ( ( thePoint.X() - theFirstPoint.X() ) * ( theSecPoint.Y() - theFirstPoint.Y() ) ) /
210                   ( theSecPoint.X() - theFirstPoint.X() ) ) + theFirstPoint.Y();
211     }
212   }
213
214   theResPoint.SetX( aCoordX );
215   theResPoint.SetY( aCoordY );
216
217   // Calculate coefficient for interpolation
218   double aLength = Sqrt( Pow( theSecPoint.Y() - theFirstPoint.Y(), 2 ) +
219                          Pow( theSecPoint.X() - theFirstPoint.X(), 2 ) );
220
221   double aInterCoeff = 0;
222   if ( aLength != 0 )
223    aInterCoeff = ( theSecPoint.Z() - theFirstPoint.Z() ) / aLength;
224
225
226   double aNewLength = Sqrt( Pow( theResPoint.Y() - theFirstPoint.Y(), 2 ) +
227                             Pow( theResPoint.X() - theFirstPoint.X(), 2 ) );
228
229   // Calculate interpolated value
230   double aResVal = theFirstPoint.Z() + aInterCoeff * aNewLength;
231
232   theResPoint.SetZ( aResVal );
233 }
234
235 double HYDROData_Bathymetry::GetAltitudeForPoint(const gp_XY& thePoint) const
236 {
237   //DEBTRACE("GetAltitudeForPoint p(" << thePoint.X() << ", " << thePoint.Y() << ")");
238   double anInvalidAltitude = GetInvalidAltitude();
239   double aResAltitude = anInvalidAltitude;
240
241   HYDROData_QuadtreeNode* aQuadtree = GetQuadtreeNodes();
242   if (!aQuadtree)
243     {
244       DEBTRACE("  no Quadtree");
245       return aResAltitude;
246     }
247
248   std::map<double, const gp_XYZ*> dist2nodes;
249   aQuadtree->NodesAround(thePoint, dist2nodes, aQuadtree->getPrecision());
250   while (dist2nodes.size() == 0)
251     {
252       aQuadtree->setPrecision(aQuadtree->getPrecision() *2);
253       DEBTRACE("adjust precision to: " << aQuadtree->getPrecision());
254       aQuadtree->NodesAround(thePoint, dist2nodes, aQuadtree->getPrecision());
255     }
256   aQuadtree->NodesAround(thePoint, dist2nodes, 5.0);
257   if (dist2nodes.size())
258     {
259       std::map<double, const gp_XYZ*>::const_iterator it = dist2nodes.begin();
260       aResAltitude = it->second->Z();
261       DEBTRACE("  number of points found: " << dist2nodes.size() << " nearest z: " << aResAltitude);
262     }
263   else
264     {
265       DEBTRACE("  number of points found: 0");
266     }
267
268   return aResAltitude;
269   
270
271 //  AltitudePoints anAltitudePoints = GetAltitudePoints();
272 //  if ( anAltitudePoints.IsEmpty() )
273 //    return aResAltitude;
274 //
275 //  QPolygonF aBoundingRect;
276 //
277 //  // Boundary plane
278 //  // [ 0 (top-left) ]          [ 1 (top-right) ]
279 //  //                  thePoint
280 //  // [ 2 (bot-left) ]          [ 3 (bot-right) ]
281 //  AltitudePoint aBounds[ 4 ] = { AltitudePoint( -DBL_MAX, -DBL_MAX, anInvalidAltitude ),
282 //                                 AltitudePoint(  DBL_MAX, -DBL_MAX, anInvalidAltitude ),
283 //                                 AltitudePoint( -DBL_MAX,  DBL_MAX, anInvalidAltitude ),
284 //                                 AltitudePoint(  DBL_MAX,  DBL_MAX, anInvalidAltitude ) };
285 //
286 //  AltitudePoints::Iterator anIter( anAltitudePoints );
287 //  for ( ; anIter.More(); anIter.Next() )
288 //  {
289 //    const AltitudePoint& aPoint = anIter.Value();
290 //
291 //    double aDeltaX = Abs( aPoint.X() ) - Abs( thePoint.X() );
292 //    double aDeltaY = Abs( aPoint.Y() ) - Abs( thePoint.Y() );
293 //
294 //    if ( ValuesEquals( aDeltaX, 0.0 ) ) // Both left and right sides
295 //    {
296 //      if ( ValuesEquals( aDeltaY, 0.0 ) ) // Both top and bottom sides
297 //      {
298 //        aResAltitude = aPoint.Z();
299 //        return aResAltitude;
300 //      }
301 //      else if ( aDeltaY < 0 ) // top side
302 //      {
303 //        // top border
304 //        if ( ValuesMoreEquals( aPoint.X(), aBounds[ 0 ].X() ) && ValuesMoreEquals( aPoint.Y(), aBounds[ 0 ].Y() ) )
305 //          aBounds[ 0 ] = aPoint;
306 //        if ( ValuesLessEquals( aPoint.X(), aBounds[ 1 ].X() ) && ValuesMoreEquals( aPoint.Y(), aBounds[ 1 ].Y() ) )
307 //          aBounds[ 1 ] = aPoint;
308 //      }
309 //      else
310 //      {
311 //        // bottom border
312 //        if ( ValuesMoreEquals( aPoint.X(), aBounds[ 2 ].X() ) && ValuesLessEquals( aPoint.Y(), aBounds[ 2 ].Y() ) )
313 //          aBounds[ 2 ] = aPoint;
314 //        if ( ValuesLessEquals( aPoint.X(), aBounds[ 3 ].X() ) && ValuesLessEquals( aPoint.Y(), aBounds[ 3 ].Y() ) )
315 //          aBounds[ 3 ] = aPoint;
316 //      }
317 //    }
318 //    else if ( aDeltaX < 0 ) // left side
319 //    {
320 //      if ( ValuesEquals( aDeltaY, 0.0 ) )
321 //      {
322 //        // Left border
323 //        if ( ValuesMoreEquals( aPoint.X(), aBounds[ 0 ].X() ) && ValuesMoreEquals( aPoint.Y(), aBounds[ 0 ].Y() ) )
324 //          aBounds[ 0 ] = aPoint;
325 //        if ( ValuesMoreEquals( aPoint.X(), aBounds[ 2 ].X() ) && ValuesLessEquals( aPoint.Y(), aBounds[ 2 ].Y() ) )
326 //          aBounds[ 2 ] = aPoint;
327 //      }
328 //      else if ( aDeltaY < 0 )
329 //      {
330 //        // top left corner
331 //        if ( ValuesMoreEquals( aPoint.X(), aBounds[ 0 ].X() ) && ValuesMoreEquals( aPoint.Y(), aBounds[ 0 ].Y() ) )
332 //          aBounds[ 0 ] = aPoint;
333 //      }
334 //      else
335 //      {
336 //        // bottom left corner
337 //        if ( ValuesMoreEquals( aPoint.X(), aBounds[ 2 ].X() ) && ValuesLessEquals( aPoint.Y(), aBounds[ 2 ].Y() ) )
338 //          aBounds[ 2 ] = aPoint;
339 //      }
340 //    }
341 //    else // right side
342 //    {
343 //      if ( ValuesEquals( aDeltaY, 0.0 ) )
344 //      {
345 //        // Right border
346 //        if ( ValuesLessEquals( aPoint.X(), aBounds[ 1 ].X() ) && ValuesMoreEquals( aPoint.Y(), aBounds[ 1 ].Y() ) )
347 //          aBounds[ 1 ] = aPoint;
348 //        if ( ValuesLessEquals( aPoint.X(), aBounds[ 3 ].X() ) && ValuesLessEquals( aPoint.Y(), aBounds[ 3 ].Y() ) )
349 //          aBounds[ 3 ] = aPoint;
350 //      }
351 //      else if ( aDeltaY < 0 )
352 //      {
353 //        // top right corner
354 //        if ( ValuesLessEquals( aPoint.X(), aBounds[ 1 ].X() ) && ValuesMoreEquals( aPoint.Y(), aBounds[ 1 ].Y() ) )
355 //          aBounds[ 1 ] = aPoint;
356 //      }
357 //      else
358 //      {
359 //        // bottom right corner
360 //        if ( ValuesLessEquals( aPoint.X(), aBounds[ 3 ].X() ) && ValuesLessEquals( aPoint.Y(), aBounds[ 3 ].Y() ) )
361 //          aBounds[ 3 ] = aPoint;
362 //      }
363 //    }
364 //
365 //    // Update bounding rectangle of our global grid
366 //    aBoundingRect << QPointF( aPoint.X(), aPoint.Y() );
367 //  }
368 //
369 //  const double LIMIT = 1E300;
370 //  if( fabs( aBounds[ 0 ].X() ) > LIMIT || fabs( aBounds[ 0 ].Y() ) > LIMIT ||
371 //      fabs( aBounds[ 1 ].X() ) > LIMIT || fabs( aBounds[ 1 ].Y() ) > LIMIT ||
372 //      fabs( aBounds[ 2 ].X() ) > LIMIT || fabs( aBounds[ 2 ].Y() ) > LIMIT ||
373 //      fabs( aBounds[ 3 ].X() ) > LIMIT || fabs( aBounds[ 3 ].Y() ) > LIMIT )
374 //    return anInvalidAltitude;
375 //
376 //
377 //  // Check if requested point is inside of our bounding rectangle
378 //  if ( !aBoundingRect.boundingRect().contains( thePoint.X(), thePoint.Y() ) )
379 //    return aResAltitude;
380 //
381 //  // Calculate result altitude for point
382 //  AltitudePoint aFirstPoint( aBounds[ 0 ] ), aSecPoint( aBounds[ 1 ] );
383 //
384 //  // At first we merge top and bottom borders
385 //  if ( aBounds[ 0 ].Y() != aBounds[ 2 ].Y() || aBounds[ 0 ].X() != aBounds[ 2 ].X() )
386 //    interpolateAltitudeForPoints( thePoint, aBounds[ 0 ], aBounds[ 2 ], aFirstPoint, true );
387 //
388 //  if ( aBounds[ 1 ].Y() != aBounds[ 3 ].Y() || aBounds[ 1 ].X() != aBounds[ 3 ].X() )
389 //    interpolateAltitudeForPoints( thePoint, aBounds[ 1 ], aBounds[ 3 ], aSecPoint, true );
390 //
391 //  AltitudePoint aResPoint( aFirstPoint );
392 //
393 //  // At last we merge left and right borders
394 //  if ( aFirstPoint.Y() != aSecPoint.Y() || aFirstPoint.X() != aSecPoint.X() )
395 //    interpolateAltitudeForPoints( thePoint, aFirstPoint, aSecPoint, aResPoint, false );
396 //
397 //  aResAltitude = aResPoint.Z();
398 //
399 //  return aResAltitude;
400 }
401
402 void HYDROData_Bathymetry::SetFilePath( const TCollection_AsciiString& theFilePath )
403 {
404   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_FilePath ), theFilePath );
405 }
406
407 TCollection_AsciiString HYDROData_Bathymetry::GetFilePath() const
408 {
409   TCollection_AsciiString aRes;
410
411   TDF_Label aLabel = myLab.FindChild( DataTag_FilePath, false );
412   if ( !aLabel.IsNull() )
413   {
414     Handle(TDataStd_AsciiString) anAsciiStr;
415     if ( aLabel.FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
416       aRes = anAsciiStr->Get();
417   }
418
419   return aRes;
420 }
421
422 void HYDROData_Bathymetry::SetAltitudesInverted( const bool theIsInverted,
423                                                  const bool theIsUpdate )
424 {
425   bool anIsAltitudesInverted = IsAltitudesInverted();
426   if ( anIsAltitudesInverted == theIsInverted )
427     return;
428
429   TDataStd_Integer::Set( myLab.FindChild( DataTag_AltitudesInverted ), (Standard_Integer)theIsInverted );
430
431   SetToUpdate( true );
432
433   if ( !theIsUpdate )
434     return;
435
436   // Update altitude points
437   AltitudePoints anAltitudePoints = GetAltitudePoints();
438   if ( anAltitudePoints.IsEmpty() )
439     return;
440
441   AltitudePoints::Iterator anIter( anAltitudePoints );
442   for ( ; anIter.More(); anIter.Next() )
443   {
444     AltitudePoint& aPoint = anIter.ChangeValue();
445     aPoint.SetZ( aPoint.Z() * -1 );
446   }
447
448   SetAltitudePoints( anAltitudePoints );
449 }
450
451 bool HYDROData_Bathymetry::IsAltitudesInverted() const
452 {
453   bool aRes = false;
454
455   TDF_Label aLabel = myLab.FindChild( DataTag_AltitudesInverted, false );
456   if ( !aLabel.IsNull() )
457   {
458     Handle(TDataStd_Integer) anIntVal;
459     if ( aLabel.FindAttribute( TDataStd_Integer::GetID(), anIntVal ) )
460       aRes = (bool)anIntVal->Get();
461   }
462
463   return aRes;
464 }
465
466 bool HYDROData_Bathymetry::ImportFromFile( const TCollection_AsciiString& theFileName )
467 {
468   // Try to open the file
469   QFile aFile( theFileName.ToCString() );
470   if ( !aFile.exists() || !aFile.open( QIODevice::ReadOnly ) )
471     return false;
472
473   bool aRes = false;
474
475   QString aFileSuf = QFileInfo( aFile ).suffix().toLower();
476
477   AltitudePoints aPoints;
478
479   // Try to import the file
480   if ( aFileSuf == "xyz" )
481     aRes = importFromXYZFile( aFile, aPoints );
482
483   // Close the file
484   aFile.close();
485   
486
487   // Convert from global to local CS
488   Handle_HYDROData_Document aDoc = HYDROData_Document::Document( myLab );
489   AltitudePoints::Iterator anIter( aPoints );
490   for ( ; anIter.More(); anIter.Next() )
491   {
492     AltitudePoint& aPoint = anIter.ChangeValue();
493     aDoc->Transform( aPoint, true );
494   }
495
496   if ( aRes )
497   {
498     // Update file path and altitude points of this Bathymetry
499     SetFilePath( theFileName );
500     SetAltitudePoints( aPoints );
501   }
502
503   return aRes && !aPoints.IsEmpty();
504 }
505
506 bool HYDROData_Bathymetry::importFromXYZFile( QFile&          theFile,
507                                               AltitudePoints& thePoints ) const
508 {
509   if ( !theFile.isOpen() )
510     return false;
511
512   // Strings in file is written as:
513   //  1. X(float) Y(float) Z(float)
514   //  2. X(float) Y(float) Z(float)
515   //  ...
516
517 #ifdef _TIMER
518   OSD_Timer aTimer;
519   aTimer.Start();
520 #endif
521
522   bool anIsAltitudesInverted = IsAltitudesInverted();
523   while ( !theFile.atEnd() )
524   {
525     QString aLine = theFile.readLine().simplified();
526     if ( aLine.isEmpty() )
527       continue;
528
529     QStringList aValues = aLine.split( ' ', QString::SkipEmptyParts );
530     if ( aValues.length() < 3 )
531       return false;
532
533     AltitudePoint aPoint;
534     
535     QString anX = aValues.value( 0 );
536     QString anY = aValues.value( 1 );
537     QString aZ  = aValues.value( 2 );
538
539     bool isXOk = false, isYOk = false, isZOk = false;
540
541     aPoint.SetX( anX.toDouble( &isXOk ) );
542     aPoint.SetY( anY.toDouble( &isYOk ) );
543     aPoint.SetZ( aZ.toDouble( &isZOk ) );
544
545     if ( !isXOk || !isYOk || !isZOk )
546       return false;
547
548     if ( boost::math::isnan( aPoint.X() ) || boost::math::isinf( aPoint.X() ) ||
549          boost::math::isnan( aPoint.Y() ) || boost::math::isinf( aPoint.Y() ) ||
550          boost::math::isnan( aPoint.Z() ) || boost::math::isinf( aPoint.Z() ) )
551       return false;
552
553     // Invert the z value if requested
554     if ( anIsAltitudesInverted )
555       aPoint.SetZ( -aPoint.Z() );
556
557     thePoints.Append( aPoint );
558   }
559
560 #ifdef _TIMER
561   aTimer.Stop();
562   std::ofstream stream( "W:/HYDRO/WORK/log.txt", std::ofstream::out );
563   aTimer.Show( stream );
564 #endif
565
566   return true;
567 }
568
569
570 Handle_HYDROData_PolylineXY HYDROData_Bathymetry::CreateBoundaryPolyline() const
571 {
572   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
573   Handle_HYDROData_PolylineXY aResult = 
574     Handle_HYDROData_PolylineXY::DownCast( aDocument->CreateObject( KIND_POLYLINEXY ) );
575
576   if( aResult.IsNull() )
577     return aResult;
578
579   //search free name
580   QString aPolylinePref = GetName() + "_Boundary";
581   QString aPolylineName = HYDROData_Tool::GenerateObjectName( aDocument, aPolylinePref );
582   aResult->SetName( aPolylineName );
583
584   double Xmin = 0.0, Xmax = 0.0, Ymin = 0.0, Ymax = 0.0;
585   bool isFirst = true;
586   AltitudePoints aPoints = GetAltitudePoints();
587
588   AltitudePoints::Iterator anIter( aPoints );
589   for ( ; anIter.More(); anIter.Next() )
590   {
591     const AltitudePoint& aPoint = anIter.Value();
592
593     double x = aPoint.X(), y = aPoint.Y();
594     if( isFirst || x<Xmin )
595       Xmin = x;
596     if( isFirst || x>Xmax )
597       Xmax = x;
598     if( isFirst || y<Ymin )
599       Ymin = y;
600     if( isFirst || y>Ymax )
601       Ymax = y;
602     isFirst = false;
603   }
604
605   aResult->AddSection( "bound", HYDROData_IPolyline::SECTION_POLYLINE, true );
606   aResult->AddPoint( 0, HYDROData_IPolyline::Point( Xmin, Ymin ) );
607   aResult->AddPoint( 0, HYDROData_IPolyline::Point( Xmin, Ymax ) );
608   aResult->AddPoint( 0, HYDROData_IPolyline::Point( Xmax, Ymax ) );
609   aResult->AddPoint( 0, HYDROData_IPolyline::Point( Xmax, Ymin ) );
610   aResult->Update();
611
612   return aResult;
613 }
614
615 void HYDROData_Bathymetry::UpdateLocalCS( double theDx, double theDy )
616 {
617   gp_XYZ aDelta( theDx, theDy, 0 );
618   AltitudePoints aPoints = GetAltitudePoints();
619   AltitudePoints::Iterator anIter( aPoints );
620   for ( int i = 0 ; anIter.More(); ++i, anIter.Next() )
621   {
622     AltitudePoint& aPoint = anIter.ChangeValue();
623     aPoint += aDelta;
624   }
625   SetAltitudePoints( aPoints );
626 }
627