Salome HOME
#589: new interpolation algorithm for polylines
[modules/hydro.git] / src / HYDROData / HYDROData_PolylineXY.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_PolylineXY.h"
20
21 #include "HYDROData_BSplineOperation.h"
22 #include "HYDROData_Document.h"
23 #include "HYDROData_ShapesTool.h"
24 #include "HYDROData_Tool.h"
25
26 #include <BRep_Builder.hxx>
27 #include <BRepBuilderAPI_MakeEdge.hxx>
28 #include <BRepBuilderAPI_MakeWire.hxx>
29 #include <BRepBuilderAPI_MakePolygon.hxx>
30 #include <BRepBuilderAPI_MakeFace.hxx>
31 #include <BRepOffsetAPI_NormalProjection.hxx>
32
33 #include <GEOMBase.h>
34
35 #include <GeomAPI_ProjectPointOnCurve.hxx>
36 #include <GeomAdaptor_Curve.hxx>
37 #include <Geom_Line.hxx>
38 #include <Geom_BSplineCurve.hxx>
39
40 #include <GCPnts_AbscissaPoint.hxx>
41
42 #include <ImageComposer_MetaTypes.h>
43
44 #include <gp_Pnt.hxx>
45 #include <gp_XY.hxx>
46 #include <gp_Pln.hxx>
47
48 #include <NCollection_Map.hxx>
49
50 #include <TCollection_ExtendedString.hxx>
51
52 #include <TDataStd_ListIteratorOfListOfByte.hxx>
53 #include <TColStd_ListIteratorOfListOfInteger.hxx>
54 #include <TColStd_ListIteratorOfListOfReal.hxx>
55
56 #include <TColStd_Array1OfReal.hxx>
57
58 #include <TDataStd_AsciiString.hxx>
59 #include <TDataStd_BooleanList.hxx>
60 #include <TDataStd_ExtStringList.hxx>
61 #include <TDataStd_IntegerList.hxx>
62 #include <TDataStd_ListIteratorOfListOfExtendedString.hxx>
63 #include <TDataStd_RealList.hxx>
64 #include <TDataStd_UAttribute.hxx>
65
66 #include <TopoDS_Iterator.hxx>
67 #include <TopTools_ListIteratorOfListOfShape.hxx>
68 #include <TopTools_HSequenceOfShape.hxx>
69 #include <TopExp_Explorer.hxx>
70 #include <ShapeAnalysis_FreeBounds.hxx>
71 #include <TopoDS.hxx>
72
73 #include <QColor>
74 #include <QPainterPath>
75 #include <QVariant>
76
77 static const Standard_GUID GUID_IS_UNEDITABLE("e5799736-9030-4051-91a4-2e58321fa153");
78
79 const double LOCAL_SELECTION_TOLERANCE = 0.0001;
80
81 TCollection_AsciiString getUniqueSectionName( const NCollection_Sequence<TCollection_AsciiString>& theNamesSeq )
82 {
83   NCollection_Map<TCollection_AsciiString> aNamesMap;
84
85   for ( int i = 1, n = theNamesSeq.Size(); i <= n; ++i )
86   {
87     const TCollection_AsciiString& aSectName = theNamesSeq.Value( i );
88     aNamesMap.Add( aSectName );
89   }
90
91   TCollection_AsciiString aResName;
92
93   int aPrefIdx = 1;
94   do
95   {
96     aResName = TCollection_AsciiString( "Section_" ) + aPrefIdx;
97     ++aPrefIdx;
98   }
99   while ( aNamesMap.Contains( aResName ) );
100
101   return aResName;
102 }
103
104 TCollection_AsciiString getUniqueSectionName( const Handle(TDataStd_ExtStringList)& theNamesList )
105 {
106   NCollection_Sequence<TCollection_AsciiString> aNamesSeq;
107
108   TDataStd_ListIteratorOfListOfExtendedString aNamesIter( theNamesList->List() );
109   for ( ; aNamesIter.More(); aNamesIter.Next() )
110     aNamesSeq.Append( aNamesIter.Value() );
111
112   return getUniqueSectionName( aNamesSeq );
113 }
114
115 IMPLEMENT_STANDARD_HANDLE(HYDROData_PolylineXY, HYDROData_IPolyline)
116 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_PolylineXY, HYDROData_IPolyline)
117
118 HYDROData_PolylineXY::HYDROData_PolylineXY()
119 : HYDROData_IPolyline()
120 {
121 }
122
123 HYDROData_PolylineXY::~HYDROData_PolylineXY()
124 {
125 }
126
127 QStringList HYDROData_PolylineXY::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
128 {
129   QStringList aResList = dumpObjectCreation( theTreatedObjects );
130   QString aPolylineName = GetObjPyName();
131
132   // Set the wire color
133   QStringList aWireColorDef;
134
135   QColor aWireColor = GetWireColor();
136   setPythonObjectColor( aWireColorDef, aWireColor, DefaultWireColor(), "SetWireColor" );
137   
138   if ( !aWireColorDef.isEmpty() )
139   {
140     aResList << aWireColorDef;
141     aResList << QString( "" );
142   }
143
144   bool anIsEditable = IsEditable();
145   if ( !anIsEditable )
146   {
147     // If polyline is not editable we try to import the shape from geom
148     TCollection_AsciiString aGeomObjectEntry = GetGeomObjectEntry();
149     if ( !aGeomObjectEntry.IsEmpty() )
150     {
151       QString aSalomeObjName = HYDROData_Tool::GenerateNameForPython( theTreatedObjects, "polyline_sobj" );
152       aResList << QString( "%1 = salome.myStudy.FindObjectID( \"%2\" );" )
153                   .arg( aSalomeObjName ).arg( aGeomObjectEntry.ToCString() );
154
155       aResList << QString( "%1.ImportFromGeomIOR( %2.GetIOR() );" )
156                   .arg( aPolylineName ).arg( aSalomeObjName );
157
158       aResList << QString( "%1.SetGeomObjectEntry( \"%2\" );" )
159                   .arg( aPolylineName ).arg( aGeomObjectEntry.ToCString() );
160     }
161   }
162   else
163   {
164     // Set polilyne data
165     NCollection_Sequence<TCollection_AsciiString>           aSectNames;
166     NCollection_Sequence<HYDROData_PolylineXY::SectionType> aSectTypes;
167     NCollection_Sequence<bool>                              aSectClosures;
168     GetSections( aSectNames, aSectTypes, aSectClosures );
169
170     for ( int i = 1, n = aSectNames.Size(); i <= n; ++i )
171     {
172       const TCollection_AsciiString& aSectName = aSectNames.Value( i );
173       const SectionType& aSectType = aSectTypes.Value( i );
174       bool aSectClosure = aSectClosures.Value( i );
175
176       aResList << QString( "%1.AddSection( \"%2\", %3, %4 );" ).arg( aPolylineName )
177                   .arg( aSectName.ToCString() ).arg( aSectType ).arg( aSectClosure );
178
179       HYDROData_IPolyline::PointsList aSectPointsList = GetPoints( i - 1 );
180       for ( int k = 1, aNbPoints = aSectPointsList.Size(); k <= aNbPoints; ++k )
181       {
182         const Point& aSectPoint = aSectPointsList.Value( k );
183
184         QString anXStr = QString::number( aSectPoint.X(), 'f', 2 );
185         QString anYStr = QString::number( aSectPoint.Y(), 'f', 2 );
186         aResList << QString( "%1.AddPoint( %2, gp_XY( %3, %4 ) );" ).arg( aPolylineName )
187           .arg( i - 1 ).arg( anXStr ).arg( anYStr );
188       }
189     }
190   }
191   aResList << QString( "" );
192   aResList << QString( "%1.Update();" ).arg( aPolylineName );
193   aResList << QString( "" );
194
195   return aResList;
196 }
197
198 QVariant HYDROData_PolylineXY::GetDataVariant()
199 {
200   QPainterPath aPath = GetPainterPath();
201
202   QVariant aVarData;
203   aVarData.setValue<QPainterPath>( aPath );
204   
205   return aVarData;
206 }
207
208 QColor HYDROData_PolylineXY::DefaultWireColor()
209 {
210   return QColor( Qt::red );
211 }
212
213 bool HYDROData_PolylineXY::ImportFromGeomIOR( const TCollection_AsciiString& theIOR )
214 {
215   if ( theIOR.IsEmpty() )
216     return false;
217
218   TopoDS_Shape aShape = GEOMBase::GetShapeFromIOR( theIOR.ToCString() );
219   if ( aShape.IsNull() )
220     return false;
221
222   return ImportShape( aShape );
223 }
224
225 void HYDROData_PolylineXY::SetGeomObjectEntry( const TCollection_AsciiString& theEntry )
226 {
227   TDataStd_AsciiString::Set( myLab.FindChild( DataTag_GeomObjectEntry ), theEntry );
228 }
229
230 TCollection_AsciiString HYDROData_PolylineXY::GetGeomObjectEntry() const
231 {
232   TCollection_AsciiString aRes;
233
234   TDF_Label aLabel = myLab.FindChild( DataTag_GeomObjectEntry, false );
235   if ( !aLabel.IsNull() )
236   {
237     Handle(TDataStd_AsciiString) anAsciiStr;
238     if ( aLabel.FindAttribute( TDataStd_AsciiString::GetID(), anAsciiStr ) )
239       aRes = anAsciiStr->Get();
240   }
241
242   return aRes;
243 }
244
245 TopoDS_Shape HYDROData_PolylineXY::GetShape() const
246 {
247   return getPolylineShape();
248 }
249
250 bool convertEdgeToSection( const TopoDS_Edge&                                       theEdge,
251                            NCollection_Sequence<TCollection_AsciiString>&           theSectNames,
252                            NCollection_Sequence<HYDROData_PolylineXY::SectionType>& theSectTypes,
253                            NCollection_Sequence<bool>&                              theSectClosures,
254                            NCollection_Sequence<HYDROData_PolylineXY::PointsList>&  theSectPoints,
255                            const bool                                               theIsCanBeClosed )
256 {
257   Standard_Real aFirst = 0.0, aLast = 0.0;
258   Handle(Geom_Curve) anEdgeGeomCurve = BRep_Tool::Curve( theEdge, aFirst, aLast );
259   if ( anEdgeGeomCurve.IsNull() )
260     return false;
261
262   TCollection_AsciiString aSectName = getUniqueSectionName( theSectNames );
263   bool anIsEdgeClosed = anEdgeGeomCurve->IsClosed();
264
265   HYDROData_PolylineXY::SectionType aSectionType = HYDROData_PolylineXY::SECTION_POLYLINE;
266   HYDROData_PolylineXY::PointsList aPointsList;
267
268   if ( anEdgeGeomCurve->IsKind( STANDARD_TYPE(Geom_Line) ) )
269   {
270     Handle(Geom_Line) aGeomLine = Handle(Geom_Line)::DownCast( anEdgeGeomCurve );
271
272     gp_Pnt aFirstPoint, aLastPoint;
273     aGeomLine->D0( aFirst, aFirstPoint );
274     aGeomLine->D0( aLast, aLastPoint );
275
276     HYDROData_PolylineXY::Point aSectFirstPoint( aFirstPoint.X(), aFirstPoint.Y() );
277     aPointsList.Append( aSectFirstPoint );
278
279     HYDROData_PolylineXY::Point aSectLastPoint( aLastPoint.X(), aLastPoint.Y() );
280     aPointsList.Append( aSectLastPoint );
281   }
282   else if ( anEdgeGeomCurve->IsKind( STANDARD_TYPE(Geom_BSplineCurve) ) )
283   {
284     aSectionType = HYDROData_PolylineXY::SECTION_SPLINE;
285
286     Handle(Geom_BSplineCurve) aGeomSpline = 
287       Handle(Geom_BSplineCurve)::DownCast( anEdgeGeomCurve );
288
289     int aNbKnots = aGeomSpline->NbKnots();
290
291     TColStd_Array1OfReal aSplineKnots( 1, aNbKnots );
292     aGeomSpline->Knots( aSplineKnots );
293
294     // Decrease the number of imported knots because of last one 
295     // knot is the closing point which are the start point
296     if ( anIsEdgeClosed ) aNbKnots--;
297
298     for ( int i = 1; i <= aNbKnots; ++i )
299     {
300       const Standard_Real& aKnot = aSplineKnots.Value( i );
301
302       gp_Pnt aPoint;
303       aGeomSpline->D0( aKnot, aPoint );
304
305       HYDROData_PolylineXY::Point aSectPoint( aPoint.X(), aPoint.Y() );
306       aPointsList.Append( aSectPoint );
307     }
308   }
309   else
310   {
311     // Other curve types are not supported
312     return false;
313   }
314
315   if ( aPointsList.IsEmpty() )
316     return false;
317
318   theSectNames.Append( aSectName );
319   theSectTypes.Append( aSectionType );
320   theSectClosures.Append( anIsEdgeClosed );
321   theSectPoints.Append( aPointsList );
322
323   return true;
324 }
325
326 bool HYDROData_PolylineXY::ImportShape( const TopoDS_Shape& theShape )
327 {
328   if ( theShape.IsNull() )
329     return false;
330
331   RemoveSections();
332
333   bool anIsCanBeImported = false;
334
335   NCollection_Sequence<TCollection_AsciiString> aSectNames;
336   NCollection_Sequence<SectionType>             aSectTypes;
337   NCollection_Sequence<bool>                    aSectClosures;
338   NCollection_Sequence<PointsList>              aSectPoints;
339
340   if ( theShape.ShapeType() == TopAbs_EDGE )
341   {
342     TopoDS_Edge anEdge = TopoDS::Edge( theShape );
343     anIsCanBeImported = convertEdgeToSection( anEdge, aSectNames, aSectTypes, aSectClosures, aSectPoints, true );
344   }
345   else if ( theShape.ShapeType() == TopAbs_WIRE )
346   {
347     TopTools_SequenceOfShape anEdges;
348     HYDROData_ShapesTool::ExploreShapeToShapes( theShape, TopAbs_EDGE, anEdges );
349
350     anIsCanBeImported = !anEdges.IsEmpty();
351     for ( int i = 1, n = anEdges.Length(); i <= n && anIsCanBeImported; ++i )
352     {
353       TopoDS_Edge aWireEdge = TopoDS::Edge( anEdges.Value( i ) );
354       anIsCanBeImported = convertEdgeToSection( aWireEdge, aSectNames, aSectTypes, aSectClosures, aSectPoints, false );
355     }
356   }
357
358   if ( anIsCanBeImported )
359   {
360     for ( int i = 1, n = aSectNames.Length(); i <= n; ++i )
361     {
362       const TCollection_AsciiString& aSectName = aSectNames.Value( i );
363       const SectionType& aSectType = aSectTypes.Value( i );
364       bool anIsSectionClosed = aSectClosures.Value( i );
365       const PointsList& aSectPointsList = aSectPoints( i );
366
367       AddSection( aSectName, aSectType, anIsSectionClosed );
368       SetPoints( i - 1, aSectPointsList );
369     }
370   }
371   else
372   {
373     TopoDS_Shape aShape = theShape;
374
375     if ( theShape.ShapeType() == TopAbs_EDGE )
376     {
377       // We make the wire from incoming edge because of other algorithms
378       // are waiting at least the wire from polyline
379       TopoDS_Edge anEdge = TopoDS::Edge( theShape );
380       BRepBuilderAPI_MakeWire aMakeWire( anEdge );
381       aMakeWire.Build();
382       if ( aMakeWire.IsDone() )
383         aShape = aMakeWire.Wire();
384     }
385
386     gp_Pln aPlane( gp_Pnt( 0, 0, 0 ), gp_Dir( 0, 0, 1 ) );
387     BRepBuilderAPI_MakeFace aMakeFace( aPlane );
388     aMakeFace.Build();
389     BRepOffsetAPI_NormalProjection aProj( aMakeFace.Face() );
390     aProj.Add( aShape );
391     aProj.Build();
392     TopoDS_Shape aResult;
393     if( aProj.IsDone() )
394       aResult = aProj.Shape();
395
396     setPolylineShape( aResult );
397   }
398
399   setEditable( anIsCanBeImported );
400
401   return true;
402 }
403
404 TopoDS_Wire HYDROData_PolylineXY::BuildWire( const SectionType&                  theType,
405                                              const bool&                         theIsClosed,
406                                              const NCollection_Sequence<gp_XYZ>& thePoints )
407 {
408   TopoDS_Wire aWire;
409   if( theType == SECTION_POLYLINE )
410   {
411     int aNbPoints = thePoints.Length();
412     BRepBuilderAPI_MakePolygon aMakeWire;
413     for ( int i = 1, n = aNbPoints; i <= n ; ++i )
414     {
415       gp_XYZ aPoint = thePoints.Value( i );
416       gp_Pnt aPnt( aPoint.X(), aPoint.Y(), aPoint.Z() );
417       aMakeWire.Add( aPnt );
418     }
419     if( theIsClosed && ( aNbPoints > 2 ) )
420       aMakeWire.Close();
421
422     if ( aMakeWire.IsDone() )
423       aWire = aMakeWire.Wire();
424   }
425   else //if( theType == PolylineSection::SECTION_SPLINE )
426   {
427     BRepBuilderAPI_MakeWire aMakeWire;
428
429     if ( thePoints.Size() > 1 )
430     {
431       Handle(Geom_BSplineCurve) aCurve = 
432         HYDROData_BSplineOperation::ComputeCurve( thePoints, theIsClosed, LOCAL_SELECTION_TOLERANCE );
433
434       TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aCurve ).Edge();
435       aMakeWire.Add( anEdge );
436     }
437     aMakeWire.Build();
438     if ( aMakeWire.IsDone() )
439       aWire = aMakeWire;
440   }
441
442   return aWire;
443 }
444
445 void HYDROData_PolylineXY::BuildPainterPath( QPainterPath&                       thePath,
446                                              const SectionType&                  theType,
447                                              const bool&                         theIsClosed,
448                                              const NCollection_Sequence<gp_XYZ>& thePoints )
449 {
450   if ( thePoints.IsEmpty() )
451     return;
452
453   if ( theType == SECTION_POLYLINE )
454   {
455     const gp_XYZ& aFirstPoint = thePoints.Value( 1 );
456     thePath.moveTo( aFirstPoint.X(), aFirstPoint.Y() );
457
458     for( int i = 2, n = thePoints.Size(); i <= n; ++i )
459     {
460       const gp_XYZ& aSectPoint = thePoints.Value( i );
461
462       thePath.lineTo( aSectPoint.X(), aSectPoint.Y() );
463     }
464
465     if( theIsClosed )
466       thePath.closeSubpath();
467   }
468   else
469   {
470     Handle(Geom_BSplineCurve) aCurve = 
471       HYDROData_BSplineOperation::ComputeCurve( thePoints, theIsClosed, LOCAL_SELECTION_TOLERANCE );
472     HYDROData_BSplineOperation::ComputePath( aCurve, thePath );
473   }
474 }
475
476 void HYDROData_PolylineXY::Update()
477 {
478   if ( !IsEditable() )
479   {
480     // If polyline is not editable we no need to update it wire
481     SetToUpdate( false );
482     return;
483   }
484
485   HYDROData_IPolyline::Update();
486
487   NCollection_Sequence<TCollection_AsciiString>           aSectNames;
488   NCollection_Sequence<HYDROData_PolylineXY::SectionType> aSectTypes;
489   NCollection_Sequence<bool>                              aSectClosures;
490   GetSections( aSectNames, aSectTypes, aSectClosures );
491
492   BRepBuilderAPI_MakeWire aMakeWire;
493
494   TopTools_ListOfShape aSectionWiresList;
495
496   for ( int aSectionId = 1, aNbSects = aSectNames.Size(); aSectionId <= aNbSects; aSectionId++ )
497   {
498     TCollection_AsciiString aSectName = aSectNames.Value( aSectionId );
499     SectionType aSectionType = aSectTypes.Value( aSectionId );
500     bool anIsSectionClosed = aSectClosures.Value( aSectionId );
501
502     PointsList aSectPointsList = GetPoints( aSectionId - 1 );
503     if ( aSectPointsList.IsEmpty() )
504       continue;
505     
506     NCollection_Sequence<gp_XYZ> aPoints;
507     for( int i = 1, n = aSectPointsList.Size(); i <= n; ++i )
508     {
509       const Point& aSectPoint = aSectPointsList.Value( i );
510
511       gp_XYZ aPoint( aSectPoint.X(), aSectPoint.Y(), 0.0 );
512       aPoints.Append( aPoint );
513     }
514
515     TopoDS_Wire aSectionWire = BuildWire( aSectionType, anIsSectionClosed, aPoints );
516     if ( !aSectionWire.IsNull() ) {
517       aSectionWiresList.Append( aSectionWire );
518       aMakeWire.Add( aSectionWire );
519     }
520   }
521 // all input wires in the <aSectionWiresList>
522   Handle(TopTools_HSequenceOfShape) aSeqWires = new TopTools_HSequenceOfShape;
523   Handle(TopTools_HSequenceOfShape) aSeqEdges = new TopTools_HSequenceOfShape;
524   TopTools_ListIteratorOfListOfShape it(aSectionWiresList);
525   for(;it.More();it.Next())
526   {
527     TopExp_Explorer it2(it.Value(), TopAbs_EDGE);
528     for(;it2.More();it2.Next()) 
529       aSeqEdges->Append(it2.Current());
530   }
531
532   BRep_Builder aBB;
533   TopoDS_Compound aCmp;
534   TopoDS_Shape aResult;
535   aBB.MakeCompound(aCmp);
536   if(aSeqEdges->Length() >1)
537   {
538     ShapeAnalysis_FreeBounds::ConnectEdgesToWires(aSeqEdges,1E-5,Standard_False,aSeqWires);
539
540     if( aSeqWires->Length()==1 )
541       aResult = aSeqWires->Value( 1 );
542     else
543     {
544       for (Standard_Integer i = 1; i <= aSeqWires->Length();i++)
545       {
546         const TopoDS_Shape& aS1 = aSeqWires->Value(i);
547         aBB.Add(aCmp, aS1);
548       }
549       aResult = aCmp;
550     }
551   }
552   else if (aSeqEdges->Length() == 1)
553   {
554     BRepBuilderAPI_MakeWire mkWire (TopoDS::Edge(aSeqEdges->Value(1)));
555     if (mkWire.IsDone())
556       aResult = mkWire.Wire();
557   }
558
559   setPolylineShape( aResult );
560 }
561
562 bool HYDROData_PolylineXY::IsHas2dPrs() const
563 {
564   return true;
565 }
566
567 bool HYDROData_PolylineXY::IsEditable() const
568 {
569   return !myLab.IsAttribute( GUID_IS_UNEDITABLE );
570 }
571
572 void HYDROData_PolylineXY::setEditable( const bool theIsEditable )
573 {
574   if ( !theIsEditable )
575     TDataStd_UAttribute::Set( myLab, GUID_IS_UNEDITABLE );
576   else
577     myLab.ForgetAttribute( GUID_IS_UNEDITABLE );
578 }
579
580 /**
581  * Returns true if polyline is closed
582  */
583 bool HYDROData_PolylineXY::IsClosed( const bool theIsSimpleCheck ) const
584 {
585   bool anIsClosed = false;
586
587   TopoDS_Shape aShape = GetShape();
588   if ( aShape.IsNull() )
589     return anIsClosed;
590
591   TopTools_SequenceOfShape aWires;
592   HYDROData_ShapesTool::ExploreShapeToShapes( aShape, TopAbs_WIRE, aWires );
593
594   int aNbWires = aWires.Length();
595   if ( theIsSimpleCheck )
596   {
597     anIsClosed = aNbWires > 0;
598     for ( int i = 1; i <= aNbWires && anIsClosed; ++i )
599     {
600       const TopoDS_Shape& aWire = aWires.Value( i );
601       anIsClosed = BRep_Tool::IsClosed( aWire );
602     }
603   }
604   else
605   {
606     anIsClosed = aNbWires == 1 && BRep_Tool::IsClosed( aWires.First() );
607   }
608
609   return anIsClosed;
610 }
611
612 double HYDROData_PolylineXY::GetDistance( const int theSectionIndex,
613                                           const int thePointIndex ) const
614 {
615   double aResDistance = -1;
616   if ( theSectionIndex < 0 || theSectionIndex >= NbSections() )
617     return aResDistance;
618
619   if ( thePointIndex == 0 )
620     return 0.0;
621
622   SectionType aSectionType = GetSectionType( theSectionIndex );
623   bool anIsSectionClosed = IsClosedSection( theSectionIndex );
624   PointsList aSectPointsList = GetPoints( theSectionIndex );
625   if ( thePointIndex < 0 || thePointIndex >= aSectPointsList.Size()  )
626     return aResDistance;
627
628   if ( aSectionType == SECTION_POLYLINE )
629   {
630     aResDistance = 0.0;
631   
632     Point aPrevPoint = aSectPointsList.Value( 1 );
633     for ( int i = 2, aNbPoints = aSectPointsList.Size(); i <= aNbPoints; ++i )
634     {
635       const Point& aSectPoint = aSectPointsList.Value( i );
636       aResDistance += gp_Pnt2d( aPrevPoint ).Distance( aSectPoint );
637       aPrevPoint = aSectPoint;
638
639       if ( thePointIndex == i - 1 )
640         break;
641     }
642   }
643   else
644   {
645     gp_XYZ aPointToTest;
646
647     int aSectNbPoints = aSectPointsList.Size();
648     NCollection_Sequence<gp_XYZ> aPoints;
649     for( int i = 1 ; i <= aSectNbPoints; ++i )
650     {
651       const Point& aSectPoint = aSectPointsList.Value( i );
652
653       gp_XYZ aPoint( aSectPoint.X(), aSectPoint.Y(), 0.0 );
654       aPoints.Append( aPoint );
655
656       if ( thePointIndex == i - 1 )
657         aPointToTest = aPoint;
658     }
659
660     Handle(Geom_BSplineCurve) aCurve = 
661       HYDROData_BSplineOperation::ComputeCurve( aPoints, anIsSectionClosed, LOCAL_SELECTION_TOLERANCE );
662
663     Quantity_Parameter aFirstParam = aCurve->FirstParameter();
664     Quantity_Parameter aSecondParam = aCurve->LastParameter();
665
666     if ( thePointIndex != aSectNbPoints - 1 )
667     {
668       GeomAPI_ProjectPointOnCurve aProject( aPointToTest, aCurve );
669       aSecondParam = aProject.LowerDistanceParameter();
670     }
671
672     GeomAdaptor_Curve anAdap( aCurve );
673     
674     aResDistance = GCPnts_AbscissaPoint::Length( anAdap, aFirstParam, aSecondParam );
675   }
676
677   return aResDistance;
678 }
679
680 int HYDROData_PolylineXY::NbSections() const
681 {
682   Handle(TDataStd_ExtStringList) aNamesList;
683   Handle(TDataStd_IntegerList)   aTypesList;
684   Handle(TDataStd_BooleanList)   aClosuresList;
685   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
686
687   return !aClosuresList.IsNull() ? aClosuresList->Extent() : 0;
688 }
689
690 void HYDROData_PolylineXY::AddSection( const TCollection_AsciiString& theSectName,
691                                        const SectionType              theSectionType,
692                                        const bool                     theIsClosed )
693 {
694   Handle(TDataStd_ExtStringList) aNamesList;
695   Handle(TDataStd_IntegerList)   aTypesList;
696   Handle(TDataStd_BooleanList)   aClosuresList;
697   getSectionsLists( aNamesList, aTypesList, aClosuresList );
698
699   TCollection_ExtendedString aSectName( theSectName );
700   if ( aSectName.Length() <= 0 )
701     aSectName = getUniqueSectionName( aNamesList );
702
703   aNamesList->Append( aSectName );
704   aTypesList->Append( theSectionType );
705   aClosuresList->Append( theIsClosed );
706
707   SetToUpdate( true );
708 }
709
710 TCollection_AsciiString HYDROData_PolylineXY::GetSectionName( const int theSectionIndex ) const
711 {
712   TCollection_AsciiString aResName;
713
714   Handle(TDataStd_ExtStringList) aNamesList;
715   Handle(TDataStd_IntegerList) aTypesList;
716   Handle(TDataStd_BooleanList) aClosuresList;
717   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
718   if ( aNamesList.IsNull() || theSectionIndex >= aNamesList->Extent() )
719     return aResName;
720
721   TDataStd_ListIteratorOfListOfExtendedString aNamesIter( aNamesList->List() );
722   for ( int i = 0; aNamesIter.More() && i != theSectionIndex; aNamesIter.Next(), ++i );
723
724   if ( aNamesIter.More() )
725     aResName = aNamesIter.Value();
726
727   return aResName;
728 }
729
730 void HYDROData_PolylineXY::SetSectionName( const int                      theSectionIndex, 
731                                            const TCollection_AsciiString& theSectionName )
732 {
733   Handle(TDataStd_ExtStringList) aNamesList;
734   Handle(TDataStd_IntegerList) aTypesList;
735   Handle(TDataStd_BooleanList) aClosuresList;
736   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
737   if ( aNamesList.IsNull() || theSectionIndex >= aNamesList->Extent() )
738     return;
739
740   TDataStd_ListOfExtendedString anOldNamesList;
741   anOldNamesList = aNamesList->List();
742
743   // Refill the existing list
744   aNamesList->Clear();
745
746   TCollection_ExtendedString aNewSectName = theSectionName;
747
748   TDataStd_ListIteratorOfListOfExtendedString aNamesIter( anOldNamesList );
749   for ( int i = 0; aNamesIter.More(); aNamesIter.Next(), ++i )
750     aNamesList->Append( i == theSectionIndex ? aNewSectName : aNamesIter.Value() );
751
752   SetToUpdate( true );
753 }
754
755 HYDROData_PolylineXY::SectionType HYDROData_PolylineXY::GetSectionType( const int theSectionIndex ) const
756 {
757   Handle(TDataStd_ExtStringList) aNamesList;
758   Handle(TDataStd_IntegerList) aTypesList;
759   Handle(TDataStd_BooleanList) aClosuresList;
760   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
761   if ( aTypesList.IsNull() || theSectionIndex >= aTypesList->Extent() )
762     return SECTION_POLYLINE;
763
764   TColStd_ListIteratorOfListOfInteger aTypesIter( aTypesList->List() );
765   for ( int i = 0; aTypesIter.More() && i != theSectionIndex; aTypesIter.Next(), ++i );
766
767   return aTypesIter.More() ? (SectionType)aTypesIter.Value() : SECTION_POLYLINE;
768 }
769
770 void HYDROData_PolylineXY::SetSectionType( const int         theSectionIndex, 
771                                            const SectionType theSectionType )
772 {
773   Handle(TDataStd_ExtStringList) aNamesList;
774   Handle(TDataStd_IntegerList) aTypesList;
775   Handle(TDataStd_BooleanList) aClosuresList;
776   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
777   if ( aTypesList.IsNull() || theSectionIndex >= aTypesList->Extent() )
778     return;
779
780   TColStd_ListOfInteger anOldTypesList;
781   anOldTypesList = aTypesList->List();
782
783   // Refill the existing list
784   aTypesList->Clear();
785
786   TColStd_ListIteratorOfListOfInteger aTypesIter( anOldTypesList );
787   for ( int i = 0; aTypesIter.More(); aTypesIter.Next(), ++i )
788     aTypesList->Append( i == theSectionIndex ? theSectionType : aTypesIter.Value() );
789
790   SetToUpdate( true );
791 }
792
793 bool HYDROData_PolylineXY::IsClosedSection( const int theSectionIndex ) const
794 {
795   Handle(TDataStd_ExtStringList) aNamesList;
796   Handle(TDataStd_IntegerList) aTypesList;
797   Handle(TDataStd_BooleanList) aClosuresList;
798   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
799   if ( aClosuresList.IsNull() || theSectionIndex >= aClosuresList->Extent() )
800     return false;
801
802   TDataStd_ListIteratorOfListOfByte aClosuresIter( aClosuresList->List() );
803   for ( int i = 0; aClosuresIter.More() && i != theSectionIndex; aClosuresIter.Next(), ++i );
804
805   return aClosuresIter.More() ? (bool)aClosuresIter.Value() : false;
806 }
807
808 void HYDROData_PolylineXY::SetSectionClosed( const int  theSectionIndex, 
809                                              const bool theIsClosed )
810 {
811   Handle(TDataStd_ExtStringList) aNamesList;
812   Handle(TDataStd_IntegerList) aTypesList;
813   Handle(TDataStd_BooleanList) aClosuresList;
814   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
815   if ( aClosuresList.IsNull() || theSectionIndex >= aClosuresList->Extent() )
816     return;
817
818   TDataStd_ListOfByte anOldClosuresList;
819   anOldClosuresList = aClosuresList->List();
820
821   // Refill the existing list
822   aClosuresList->Clear();
823
824   TDataStd_ListIteratorOfListOfByte aClosuresIter( anOldClosuresList );
825   for ( int i = 0; aClosuresIter.More(); aClosuresIter.Next(), ++i )
826     aClosuresList->Append( i == theSectionIndex ? theIsClosed : (bool)aClosuresIter.Value() );
827
828   SetToUpdate( true );
829 }
830
831 void HYDROData_PolylineXY::GetSections( NCollection_Sequence<TCollection_AsciiString>& theSectNames,
832                                         NCollection_Sequence<SectionType>&             theSectTypes,
833                                         NCollection_Sequence<bool>&                    theSectClosures ) const
834 {
835   theSectNames.Clear();
836   theSectTypes.Clear();
837   theSectClosures.Clear();
838
839   Handle(TDataStd_ExtStringList) aNamesList;
840   Handle(TDataStd_IntegerList) aTypesList;
841   Handle(TDataStd_BooleanList) aClosuresList;
842   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
843   if ( aNamesList.IsNull() || aTypesList.IsNull() || aClosuresList.IsNull() )
844     return;
845
846   TDataStd_ListIteratorOfListOfExtendedString aNamesIter( aNamesList->List() );
847   TColStd_ListIteratorOfListOfInteger aTypesIter( aTypesList->List() );
848   TDataStd_ListIteratorOfListOfByte aClosuresIter( aClosuresList->List() );
849   for ( ; aNamesIter.More() && aTypesIter.More() && aClosuresIter.More();
850           aNamesIter.Next(), aTypesIter.Next(), aClosuresIter.Next() )
851   {
852     const TCollection_ExtendedString& aSectName = aNamesIter.Value();
853     SectionType aSectType = (SectionType)aTypesIter.Value();
854     bool aSectClosures = aClosuresIter.Value();
855
856     theSectNames.Append( aSectName );
857     theSectTypes.Append( aSectType );
858     theSectClosures.Append( aSectClosures );
859   }
860 }
861
862 void HYDROData_PolylineXY::RemoveSection( const int theSectionIndex )
863 {
864   Handle(TDataStd_ExtStringList) aNamesList;
865   Handle(TDataStd_IntegerList)   aTypesList;
866   Handle(TDataStd_BooleanList)   aClosuresList;
867   getSectionsLists( aNamesList, aTypesList, aClosuresList, false );
868   if ( aNamesList.IsNull() || theSectionIndex >= aNamesList->Extent() )
869     return;
870
871   if ( aNamesList->Extent() == 1 )
872   {
873     removeSectionsLists();
874     removePointsLists();
875   }
876   else
877   {
878     TDataStd_ListOfExtendedString anOldNamesList;
879     anOldNamesList = aNamesList->List();
880
881     TColStd_ListOfInteger anOldTypesList;
882     anOldTypesList = aTypesList->List();
883
884     TDataStd_ListOfByte anOldClosuresList;
885     anOldClosuresList = aClosuresList->List();
886
887     // Refill the existing lists
888     aNamesList->Clear();
889     aTypesList->Clear();
890     aClosuresList->Clear();
891
892     TDataStd_ListIteratorOfListOfExtendedString aNamesIter( anOldNamesList );
893     TColStd_ListIteratorOfListOfInteger aTypesIter( anOldTypesList );
894     TDataStd_ListIteratorOfListOfByte aClosuresIter( anOldClosuresList );
895     for ( int i = 0; aNamesIter.More() && aTypesIter.More() && aClosuresIter.More();
896                      aNamesIter.Next(), aTypesIter.Next(), aClosuresIter.Next(), ++i )
897     {
898       if ( i == theSectionIndex )
899         continue; // skip index to remove
900
901       aNamesList->Append( aNamesIter.Value() );
902       aTypesList->Append( aTypesIter.Value() );
903       aClosuresList->Append( (bool)aClosuresIter.Value() );
904     }
905
906     // Remove points that belongs to removed section
907     removePointsLists( theSectionIndex );
908   }
909
910   SetToUpdate( true );
911 }
912
913 void HYDROData_PolylineXY::RemoveSections()
914 {
915   removeSectionsLists();
916   removePointsLists();
917   SetToUpdate( true );
918 }
919
920 void HYDROData_PolylineXY::AddPoint( const int    theSectionIndex,
921                                      const Point& thePoint,
922                                      const int    thePointIndex )
923 {
924   Handle(TDataStd_RealList) aListX, aListY;
925   getPointsLists( theSectionIndex, aListX, aListY );
926
927   if ( thePointIndex < 0 || thePointIndex >= aListX->Extent() )
928   {
929     aListX->Append( thePoint.X() );
930     aListY->Append( thePoint.Y() );
931   }
932   else
933   {
934     TColStd_ListOfReal anOldListX;
935     anOldListX = aListX->List();
936
937     TColStd_ListOfReal anOldListY;
938     anOldListY = aListY->List();
939
940     // Refill the existing lists
941     aListX->Clear();
942     aListY->Clear();
943
944     TColStd_ListIteratorOfListOfReal anIterX( anOldListX );
945     TColStd_ListIteratorOfListOfReal anIterY( anOldListY );
946     for ( int i = 0; anIterX.More() && anIterY.More(); anIterX.Next(), anIterY.Next(), ++i )
947     {
948       double aCoordX = anIterX.Value();
949       double aCoordY = anIterY.Value();
950
951       if ( i == thePointIndex )
952       {
953         // Insert our new point
954         aListX->Append( thePoint.X() );
955         aListY->Append( thePoint.Y() );
956       }
957
958       aListX->Append( aCoordX );
959       aListY->Append( aCoordY );
960     }
961   }
962
963   SetToUpdate( true );
964 }
965
966 void HYDROData_PolylineXY::SetPoint( const int    theSectionIndex,
967                                      const Point& thePoint,
968                                      const int    thePointIndex )
969 {
970   Handle(TDataStd_RealList) aListX, aListY;
971   getPointsLists( theSectionIndex, aListX, aListY );
972
973   if ( thePointIndex < 0 )
974   {
975     aListX->Prepend( thePoint.X() );
976     aListY->Prepend( thePoint.Y() );
977   }
978   else if ( thePointIndex >= aListX->Extent() )
979   {
980     aListX->Append( thePoint.X() );
981     aListY->Append( thePoint.Y() );
982   }
983   else
984   {
985     TColStd_ListOfReal anOldListX;
986     anOldListX = aListX->List();
987
988     TColStd_ListOfReal anOldListY;
989     anOldListY = aListY->List();
990
991     // Refill the existing lists
992     aListX->Clear();
993     aListY->Clear();
994
995     TColStd_ListIteratorOfListOfReal anIterX( anOldListX );
996     TColStd_ListIteratorOfListOfReal anIterY( anOldListY );
997     for ( int i = 0; anIterX.More() && anIterY.More(); anIterX.Next(), anIterY.Next(), ++i )
998     {
999       double aCoordX = anIterX.Value();
1000       double aCoordY = anIterY.Value();
1001
1002       if ( i == thePointIndex )
1003       {
1004         // Insert our new point instead of old one
1005         aCoordX = thePoint.X();
1006         aCoordY = thePoint.Y();
1007       }
1008
1009       aListX->Append( aCoordX );
1010       aListY->Append( aCoordY );
1011     }
1012   }
1013
1014   SetToUpdate( true );
1015 }
1016
1017 void HYDROData_PolylineXY::SetPoints( const int         theSectionIndex,
1018                                       const PointsList& thePoints )
1019 {
1020   Handle(TDataStd_RealList) aListX, aListY;
1021   getPointsLists( theSectionIndex, aListX, aListY );
1022
1023   aListX->Clear();
1024   aListY->Clear();
1025
1026   for ( int i = 1, n = thePoints.Length(); i <= n; ++i )
1027   {
1028     const Point& aPoint = thePoints.Value( i );
1029     aListX->Append( aPoint.X() );
1030     aListY->Append( aPoint.Y() );
1031   }
1032 }
1033
1034 void HYDROData_PolylineXY::RemovePoint( const int theSectionIndex,
1035                                         const int thePointIndex )
1036 {
1037   Handle(TDataStd_RealList) aListX, aListY;
1038   getPointsLists( theSectionIndex, aListX, aListY, false );
1039   if ( aListX.IsNull() || aListY.IsNull() || aListX->IsEmpty() )
1040     return;
1041
1042   if ( aListX->Extent() == 1 )
1043   {
1044     removePointsLists( theSectionIndex );
1045   }
1046   else
1047   {
1048     TColStd_ListOfReal anOldListX;
1049     anOldListX = aListX->List();
1050
1051     TColStd_ListOfReal anOldListY;
1052     anOldListY = aListY->List();
1053
1054     // Refill the existing lists
1055     aListX->Clear();
1056     aListY->Clear();
1057
1058     TColStd_ListIteratorOfListOfReal anIterX( anOldListX );
1059     TColStd_ListIteratorOfListOfReal anIterY( anOldListY );
1060     for ( int i = 0; anIterX.More() && anIterY.More(); anIterX.Next(), anIterY.Next(), ++i )
1061     {
1062       if ( i == thePointIndex )
1063         continue; // skip index to remove
1064
1065       aListX->Append( anIterX.Value() );
1066       aListY->Append( anIterY.Value() );
1067     }
1068   }
1069
1070   SetToUpdate( true );
1071 }
1072
1073 HYDROData_PolylineXY::PointsList HYDROData_PolylineXY::GetPoints( const int theSectionIndex ) const
1074 {
1075   PointsList aResList;
1076
1077   Handle(TDataStd_RealList) aListX, aListY;
1078   getPointsLists( theSectionIndex, aListX, aListY, false );
1079   if ( aListX.IsNull() || aListY.IsNull() || aListX->IsEmpty() )
1080     return aResList;
1081
1082   TColStd_ListIteratorOfListOfReal anIterX( aListX->List() );
1083   TColStd_ListIteratorOfListOfReal anIterY( aListY->List() );
1084   for ( ; anIterX.More() && anIterY.More(); anIterX.Next(), anIterY.Next() )
1085   {
1086     Point aPoint( anIterX.Value(), anIterY.Value() );
1087     aResList.Append( aPoint );
1088   }
1089
1090   return aResList;
1091 }
1092
1093 QPainterPath HYDROData_PolylineXY::GetPainterPath() const
1094 {
1095   QPainterPath aPath;
1096
1097   NCollection_Sequence<TCollection_AsciiString>           aSectNames;
1098   NCollection_Sequence<HYDROData_PolylineXY::SectionType> aSectTypes;
1099   NCollection_Sequence<bool>                              aSectClosures;
1100   GetSections( aSectNames, aSectTypes, aSectClosures );
1101
1102   for ( int aSectionId = 1, aNbSects = aSectNames.Size(); aSectionId <= aNbSects; aSectionId++ )
1103   {
1104     TCollection_AsciiString aSectName = aSectNames.Value( aSectionId );
1105     SectionType aSectionType = aSectTypes.Value( aSectionId );
1106     bool anIsSectionClosed = aSectClosures.Value( aSectionId );
1107
1108     PointsList aSectPointsList = GetPoints( aSectionId - 1 );
1109     if ( aSectPointsList.IsEmpty() )
1110       continue;
1111
1112     NCollection_Sequence<gp_XYZ> aPoints;
1113     for( int i = 1, n = aSectPointsList.Size(); i <= n; ++i )
1114     {
1115       const Point& aSectPoint = aSectPointsList.Value( i );
1116
1117       gp_XYZ aPoint( aSectPoint.X(), aSectPoint.Y(), 0.0 );
1118       aPoints.Append( aPoint );
1119     }
1120
1121     BuildPainterPath( aPath, aSectionType, anIsSectionClosed, aPoints );
1122   }
1123
1124   return aPath;
1125 }
1126
1127 void HYDROData_PolylineXY::UpdateLocalCS( double theDx, double theDy )
1128 {
1129   NCollection_Sequence<TCollection_AsciiString>           aSectNames;
1130   NCollection_Sequence<HYDROData_PolylineXY::SectionType> aSectTypes;
1131   NCollection_Sequence<bool>                              aSectClosures;
1132   GetSections( aSectNames, aSectTypes, aSectClosures );
1133
1134   gp_XY aDelta( theDx, theDy );
1135   for ( int i = 0, aNbSects = aSectNames.Size(); i < aNbSects; i++ )
1136   {
1137     PointsList aPoints = GetPoints( i );
1138     for( int j = 1, n = aPoints.Size(); j <= n; ++j )
1139     {
1140       Point& aPoint = aPoints.ChangeValue( j );
1141       aPoint += aDelta;
1142     }
1143     SetPoints( i, aPoints );
1144   }
1145   SetToUpdate( true );
1146 }
1147
1148 void HYDROData_PolylineXY::Transform( const QTransform& theTrsf )
1149 {
1150   NCollection_Sequence<TCollection_AsciiString>           aSectNames;
1151   NCollection_Sequence<HYDROData_PolylineXY::SectionType> aSectTypes;
1152   NCollection_Sequence<bool>                              aSectClosures;
1153   GetSections( aSectNames, aSectTypes, aSectClosures );
1154
1155   for ( int i = 0, aNbSects = aSectNames.Size(); i < aNbSects; i++ ) {
1156     PointsList aPoints = GetPoints( i );
1157     for( int j = 1, n = aPoints.Size(); j <= n; ++j ) {
1158       Point& aPoint = aPoints.ChangeValue( j );
1159
1160       QPointF aTrsfPoint = theTrsf.map( QPointF( aPoint.X(), aPoint.Y() ) );
1161
1162       aPoint.SetX( aTrsfPoint.x() );
1163       aPoint.SetY( aTrsfPoint.y() );
1164     }
1165     SetPoints( i, aPoints );
1166   }
1167
1168   Update();
1169 }
1170