Salome HOME
81ca954ef06511a52858254ea4766c6b5c77f5c6
[modules/hydro.git] / src / HYDROData / HYDROData_PolylineOperator.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_PolylineOperator.h>
20 #include <HYDROData_Document.h>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRep_Builder.hxx>
23 #include <BRepBuilderAPI_MakeEdge2d.hxx>
24 #include <BRepBuilderAPI_MakeWire.hxx>
25 #include <Extrema_ExtCC.hxx>
26 #include <Extrema_ExtPC.hxx>
27 #include <NCollection_Vector.hxx>
28 #include <Precision.hxx>
29 #include <ShapeAnalysis_TransferParametersProj.hxx>
30 #include <ShapeBuild_Edge.hxx>
31 #include <TopoDS.hxx>
32 #include <TopoDS_Edge.hxx>
33 #include <TopoDS_Wire.hxx>
34 #include <TopExp.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
37 #include <QString>
38
39 template<class T> void append( std::vector<T>& theList, const std::vector<T>& theList2 )
40 {
41   int aSize = theList.size();
42   int aNewSize = aSize + theList2.size();
43
44   if( aSize==aNewSize )
45     return;
46
47   theList.resize( aNewSize );
48   for( int i=aSize, j=0; i<aNewSize; i++, j++ )
49     theList[i] = theList2[j];
50 }
51
52 static Standard_Boolean WireToCurve(
53   const TopoDS_Wire& theWire,
54   NCollection_Vector<TopoDS_Edge>& theEdges,
55   Standard_Boolean& theIsClosed)
56 {
57   TopTools_IndexedDataMapOfShapeListOfShape aVertexToEdges;
58   TopExp::MapShapesAndAncestors(theWire,
59     TopAbs_VERTEX, TopAbs_EDGE, aVertexToEdges);
60   const Standard_Integer aVCount = aVertexToEdges.Extent();
61   if (aVCount == 0)
62   {
63     return Standard_False;
64   }
65
66   {
67     Standard_Integer aEndCount = 0;
68     for (Standard_Integer aVN = 1; aVN <= aVCount; ++aVN)
69     {
70       const Standard_Integer aEdgeCount =
71         aVertexToEdges.FindFromIndex(aVN).Extent();
72       if (aEdgeCount == 1)
73       {
74         ++aEndCount;
75       }
76       if (aEdgeCount > 2)
77       {
78         return Standard_False;
79       }
80     }
81     theIsClosed = (aEndCount == 0);
82     if (!theIsClosed && aEndCount != 2)
83     {
84       return Standard_False;
85     }
86   }
87
88   Standard_Integer aVN = 1;
89   if (!theIsClosed)
90   {
91     while (aVN <= aVCount &&
92       aVertexToEdges.FindFromIndex(aVN).Extent() == 2)
93     {
94       ++aVN;
95     }
96   }
97
98   TopTools_ListOfShape* aEdges = &aVertexToEdges.ChangeFromIndex(aVN);
99   while (!aEdges->IsEmpty())
100   {
101     const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
102     aEdges->RemoveFirst();
103     theEdges.Append(aEdge);
104     Standard_Integer aVN2 =
105       aVertexToEdges.FindIndex(TopExp::FirstVertex(aEdge));
106     if (aVN2 == aVN)
107     {
108       aVN2 = aVertexToEdges.FindIndex(TopExp::LastVertex(aEdge));
109     }
110     aVN = aVN2;
111
112     aEdges = &aVertexToEdges.ChangeFromIndex(aVN2);
113     if (aEdges->First().IsEqual(aEdge))
114     {
115       aEdges->RemoveFirst();
116     }
117     else
118     {
119       const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
120       aEdges->Clear();
121       aEdges->Append(aEdge);
122     }
123   }
124   return (!theIsClosed && theEdges.Size() == aVCount - 1) ||
125     (theIsClosed && theEdges.Size() == aVCount);
126 }
127
128 static void CurveToWire(
129   const NCollection_Vector<TopoDS_Edge>& theEdges, TopoDS_Wire& theWire)
130 {
131   BRep_Builder aBulder;
132   aBulder.MakeWire(theWire);
133   NCollection_Vector<TopoDS_Edge>::Iterator aEIt(theEdges);
134   for (; aEIt.More(); aEIt.Next())
135   {
136     aBulder.Add(theWire, aEIt.Value());
137   }
138 }
139
140 static void CurveToWire(
141   const NCollection_Vector<TopoDS_Edge>& theEdges1,
142   const NCollection_Vector<TopoDS_Edge>& theEdges2,
143   TopoDS_Wire& theWire)
144 {
145   BRep_Builder aBulder;
146   aBulder.MakeWire(theWire);
147   const NCollection_Vector<TopoDS_Edge>* aEdges[] = {&theEdges1, &theEdges2};
148   for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
149   {
150     NCollection_Vector<TopoDS_Edge>::Iterator aEIt(*aEdges[aEI]);
151     for (; aEIt.More(); aEIt.Next())
152     {
153       aBulder.Add(theWire, aEIt.Value());
154     }
155   }
156 }
157
158 static Standard_Real ProjectPointToCurve(
159   const gp_Pnt& thePoint,
160   const Adaptor3d_Curve& theCurve,
161   Standard_Real& theParameter)
162 {
163   Extrema_ExtPC aAlgo(thePoint, theCurve);
164   Standard_Integer aMinEN = -2;
165   Standard_Real aMinSqDist = DBL_MAX;
166   if (aAlgo.IsDone())
167   {
168     const Standard_Integer aECount = aAlgo.NbExt();
169     for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN)
170     {
171       const gp_Pnt& aP = aAlgo.Point(aEN).Value();
172       const Standard_Real aSqDist = thePoint.SquareDistance(aP);
173       if (aMinSqDist > aSqDist)
174       {
175         aMinSqDist = aSqDist;
176         aMinEN = aEN;
177       }
178     }
179   }
180
181   const Standard_Real aParams[] =
182     {theCurve.FirstParameter(), theCurve.LastParameter()};
183   const gp_Pnt aEnds[] =
184     {theCurve.Value(aParams[0]), theCurve.Value(aParams[1])};
185   const Standard_Real aSqDists[] =
186     {thePoint.SquareDistance(aEnds[0]), thePoint.SquareDistance(aEnds[1])};
187   for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
188   {
189     if (aMinSqDist > aSqDists[aEI])
190     {
191       aMinSqDist = aSqDists[aEI];
192       aMinEN = -aEI;
193     }
194   }
195
196   if (aMinEN <= 0)
197   {
198     theParameter = aParams[-aMinEN];
199     return aMinSqDist;
200   }
201
202   const Extrema_POnCurv& aPOnC = aAlgo.Point(aMinEN);
203   const gp_Pnt& aPoint = aPOnC.Value();
204   theParameter = aPOnC.Parameter();
205   for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
206   {
207     if (Abs(theParameter - aParams[aEI]) < Precision::PConfusion() ||
208       aPoint.SquareDistance(aEnds[aEI]) < Precision::SquareConfusion())
209     {
210       theParameter = aParams[aEI];
211     }
212   }
213   return aMinSqDist;
214 }
215
216 static Standard_Real ProjectPointToEdge(
217   const gp_Pnt& thePoint,
218   const TopoDS_Edge& theEdge,
219   Standard_Real& theParameter)
220 {
221   return ProjectPointToCurve(thePoint, BRepAdaptor_Curve(theEdge), theParameter);
222 }
223
224 static void SplitCurveByPoint(
225   const NCollection_Vector<TopoDS_Edge>& theEdges,
226   const Standard_Integer theEdgeIndex,
227   const Standard_Real theParameter,
228   NCollection_Vector<TopoDS_Edge>& theEdges1,
229   NCollection_Vector<TopoDS_Edge>& theEdges2)
230 {
231   for (Standard_Integer aEI = 0; aEI < theEdgeIndex; ++aEI)
232   {
233     theEdges1.Append(theEdges(aEI));
234   }
235
236   const TopoDS_Edge& aEdge = theEdges(theEdgeIndex);
237   BRepAdaptor_Curve aCurve(aEdge);
238   Standard_Integer aParamI = -1;
239   const Standard_Real aEdgeEndParams[] =
240     {aCurve.FirstParameter(), aCurve.LastParameter()};
241   if (Abs(theParameter - aEdgeEndParams[0]) < Precision::PConfusion())
242   {
243     aParamI = 0;
244   }
245   else if (Abs(theParameter - aEdgeEndParams[1]) < Precision::PConfusion())
246   {
247     aParamI = 1;
248   }
249
250   const TopAbs_Orientation aOrient = aEdge.Orientation();
251   if (aOrient == TopAbs_REVERSED)
252   {
253     aParamI ^= 1;
254   }
255
256   const Standard_Integer aECount = theEdges.Size();
257   if (aParamI == 0)
258   {
259     NCollection_Vector<TopoDS_Edge>* aEdges = (theEdgeIndex != 0) ? &theEdges1 : &theEdges2;
260     for (Standard_Integer aEI = theEdgeIndex; aEI < aECount; ++aEI)
261     {
262       aEdges->Append(theEdges(aEI));
263     }
264   }
265   else if (aParamI == 1)
266   {
267     theEdges1.Append(aEdge);
268     for (Standard_Integer aEI = theEdgeIndex; aEI < aECount; ++aEI)
269     {
270       theEdges2.Append(theEdges(aEI));
271     }
272   }
273   else
274   {
275     TopoDS_Edge aFE = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD));
276     ShapeAnalysis_TransferParametersProj aSATPP(aFE, TopoDS_Face());
277     aSATPP.SetMaxTolerance(Precision::Confusion());
278     TopoDS_Vertex aSplitV;
279     BRep_Builder().MakeVertex(
280       aSplitV, aCurve.Value(theParameter), Precision::Confusion());
281
282     TopoDS_Edge aEParts[] = {
283       ShapeBuild_Edge().CopyReplaceVertices(aFE, TopoDS_Vertex(),
284         TopoDS::Vertex(aSplitV.Oriented(TopAbs_REVERSED))),
285       ShapeBuild_Edge().CopyReplaceVertices(aFE, aSplitV, TopoDS_Vertex())};
286     ShapeBuild_Edge().CopyPCurves(aEParts[0], aFE);
287     ShapeBuild_Edge().CopyPCurves(aEParts[1], aFE);
288     BRep_Builder().SameRange(aEParts[0], Standard_False);
289     BRep_Builder().SameRange(aEParts[1], Standard_False);
290     BRep_Builder().SameParameter(aEParts[0], Standard_False);
291     BRep_Builder().SameParameter(aEParts[1], Standard_False);
292     aSATPP.TransferRange(aEParts[0],
293       aEdgeEndParams[0], theParameter, Standard_False);
294     aSATPP.TransferRange(aEParts[1],
295       theParameter, aEdgeEndParams[1], Standard_False);
296     aEParts[0].Orientation(aOrient);
297     aEParts[1].Orientation(aOrient);
298
299     const Standard_Integer aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1;
300     theEdges1.Append(aEParts[aFirstPI]);
301     theEdges2.Append(aEParts[1 - aFirstPI]);
302
303     for (Standard_Integer aEI = theEdgeIndex + 1; aEI < aECount; ++aEI)
304     {
305       theEdges2.Append(theEdges(aEI));
306     }
307   }
308 }
309
310 static void SplitCurveByPoints(
311   const NCollection_Vector<TopoDS_Edge>& theCurve,
312   const NCollection_Vector<NCollection_Sequence<Standard_Real> >& theParameters,
313   NCollection_Vector<NCollection_Vector<TopoDS_Edge> >& theSplittedCurves)
314 {
315   NCollection_Vector<TopoDS_Edge> aCurves[3];
316   aCurves[0] = theCurve;
317   Standard_Integer aCI = 0, aEI = 0;
318   NCollection_Vector<TopoDS_Edge>::Iterator aEIt(theCurve);
319   for (NCollection_Vector<NCollection_Sequence<Standard_Real> >::Iterator
320     aPLIt(theParameters); aPLIt.More(); ++aEI, aEIt.Next(), aPLIt.Next())
321   {
322     const Standard_Boolean isForward =
323       (aEIt.Value().Orientation() != TopAbs_REVERSED);
324     for (NCollection_Sequence<Standard_Real>::Iterator
325       aPIt(aPLIt.Value(), isForward); aPIt.More(); aPIt.Next())
326     {
327       const Standard_Integer aCI1 = (aCI + 1) % 3, aCI2 = (aCI + 2) % 3;
328       SplitCurveByPoint(aCurves[aCI], aEI,
329         aPIt.Value(), aCurves[aCI1], aCurves[aCI2]);
330       if (!aCurves[aCI2].IsEmpty())
331       {
332         theSplittedCurves.Append(aCurves[aCI1]);
333         aCurves[aCI].Clear();
334         aCI = aCI2;
335         aEI = 0;
336       }
337       aCurves[aCI1].Clear();
338     }
339   }
340   theSplittedCurves.Append(aCurves[aCI]);
341 }
342
343 static Standard_Integer AppendIntersectionPoint(
344   const Adaptor3d_Curve& theCurve,
345   const Standard_Real theParameter,
346   NCollection_Sequence<Standard_Real>& theParameters)
347 {
348   // Check the coincidence.
349   NCollection_Sequence<Standard_Real> aEndParams;
350   aEndParams.Append(theCurve.FirstParameter());
351   aEndParams.Append(theCurve.LastParameter());
352   NCollection_Sequence<Standard_Real>* aParams[] =
353     {&theParameters, &aEndParams};
354   const gp_Pnt aPoint = theCurve.Value(theParameter);
355   for (Standard_Integer aLI = 0; aLI < 2; ++aLI)
356   {
357     NCollection_Sequence<Standard_Real>::Iterator aPIt(*aParams[aLI]);
358     for (Standard_Integer aPI = 0; aPIt.More(); aPIt.Next(), ++aPI)
359     {
360       const Standard_Real aParam = aPIt.Value();
361       if (Abs(theParameter - aParam) < Precision::PConfusion() ||
362         aPoint.SquareDistance(theCurve.Value(aParam)) <=
363           Precision::SquareConfusion())
364       {
365         Standard_Integer aIntCount = 0;
366         if (aLI != 0)
367         {
368           if (aPI == 0)
369           {
370             theParameters.Prepend(aEndParams.First());
371           }
372           else
373           {
374             theParameters.Append(aEndParams.Last());
375           }
376           ++aIntCount;
377         }
378         return aIntCount;
379       }
380     }
381   }
382
383   // Calculate the position to insert.
384   NCollection_Sequence<Standard_Real>::Iterator aPIt(theParameters);
385   if (aPIt.More() && aPIt.Value() < theParameter)
386   {
387     NCollection_Sequence<Standard_Real>::Iterator aPIt2 = aPIt;
388     aPIt2.Next();
389     for (; aPIt2.More() && aPIt2.Value() < theParameter;
390       aPIt.Next(), aPIt2.Next());
391     theParameters.InsertAfter(aPIt, theParameter);
392   }
393   else
394   {
395     theParameters.Prepend(theParameter);
396   }
397   return 1;
398 }
399
400 static Standard_Integer IntersectEdge(
401   const TopoDS_Edge& theEdge1,
402   const TopoDS_Edge& theEdge2,
403   NCollection_Sequence<Standard_Real>& theParameters)
404 {
405   // Process the ends.
406   Standard_Integer aIntCount = 0;
407   BRepAdaptor_Curve aCurve1 = BRepAdaptor_Curve(theEdge1);
408   BRepAdaptor_Curve aCurve2 = BRepAdaptor_Curve(theEdge2);
409   const gp_Pnt aEndPs[] = {aCurve2.Value(aCurve2.FirstParameter()),
410     aCurve2.Value(aCurve2.LastParameter())};
411   for (Standard_Integer aPI = 0; aPI < 2; ++aPI)
412   {
413     Standard_Real aParameter;
414     if (ProjectPointToCurve(aEndPs[aPI], aCurve1, aParameter) <=
415       Precision::SquareConfusion())
416     {
417       AppendIntersectionPoint(aCurve1, aParameter, theParameters);
418     }
419   }
420
421   // Process the internal extrema.
422   Extrema_ExtCC aAlgo(aCurve1, aCurve2);
423   if (aAlgo.IsDone())
424   {
425     const Standard_Integer aECount = aAlgo.NbExt();
426     for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN)
427     {
428       Extrema_POnCurv aP1, aP2;
429       aAlgo.Points(aEN, aP1, aP2);
430       if (aP1.Value().SquareDistance(aP2.Value()) <=
431         Precision::SquareConfusion())
432       {
433         AppendIntersectionPoint(aCurve1, aP1.Parameter(), theParameters);
434       }
435     }
436   }
437   return aIntCount;
438 }
439
440 static Standard_Integer IntersectCurve(
441   const NCollection_Vector<TopoDS_Edge>& theEdges,
442   const TopoDS_Wire& theWire,
443   NCollection_Vector<NCollection_Sequence<Standard_Real> >& theParameters)
444 {
445   Standard_Integer aIntCount = 0;
446   const Standard_Integer aECount1 = theEdges.Size();
447   for (Standard_Integer aEI1 = 0; aEI1 < aECount1; ++aEI1)
448   {
449     const TopoDS_Edge& aEdge1 = theEdges(aEI1);
450     TopExp_Explorer aEIt2(theWire, TopAbs_EDGE);
451     for (; aEIt2.More(); aEIt2.Next())
452     {
453       aIntCount += IntersectEdge(aEdge1,
454         TopoDS::Edge(aEIt2.Current()), theParameters(aEI1));
455     }
456   }
457   return aIntCount;
458 }
459
460 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
461                                         const Handle( HYDROData_PolylineXY )& thePolyline,
462                                         const gp_Pnt2d& thePoint,
463                                         double theTolerance ) const
464 {
465   std::vector<gp_Pnt2d> aPointsList( 1 );
466   aPointsList[0] = thePoint;
467   std::vector<TopoDS_Wire> aCurves = GetWires( thePolyline );
468   bool isOK = true;
469   for( int i=0, n=aCurves.size(); i<n; i++ )
470   {
471     std::vector<TopoDS_Shape> aCurvesList = Split( aCurves[i], thePoint, theTolerance );
472     bool isLocalOK = CreatePolylines( theDoc, thePolyline->GetName(), aCurvesList, true );
473     isOK = isOK && isLocalOK;
474   }
475   return isOK;
476 }
477
478 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
479               const Handle( HYDROData_PolylineXY )& thePolyline,
480               const Handle( HYDROData_PolylineXY )& theTool,
481               double theTolerance ) const
482 {
483   HYDROData_SequenceOfObjects aSeq;
484   aSeq.Append( theTool );
485   return split( theDoc, thePolyline, aSeq, theTolerance, -1 );
486 }
487
488 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
489                                         const HYDROData_SequenceOfObjects& thePolylines,
490                                         double theTolerance )
491 {
492   int f = thePolylines.Lower(), l = thePolylines.Upper();
493   for( int i=f; i<=l; i++ )
494   {
495     Handle( HYDROData_PolylineXY ) aPolyline = Handle( HYDROData_PolylineXY )::DownCast( thePolylines.Value( i ) );
496     if( !split( theDoc, aPolyline, thePolylines, theTolerance, i ) )
497       return false;
498   }
499   return true;
500 }
501
502 bool HYDROData_PolylineOperator::Merge( const Handle( HYDROData_Document )& theDoc,
503                                         const QString& theName,
504                                         const HYDROData_SequenceOfObjects& thePolylines,
505                                         bool isConnectByNewSegment,
506                                         double theTolerance )
507 {
508   TopoDS_Shape aMergedPolyline;
509
510   int f = thePolylines.Lower(), l = thePolylines.Upper();
511   for( int i=f; i<=l; i++ )
512   {
513     Handle( HYDROData_PolylineXY ) aPolyline = Handle( HYDROData_PolylineXY )::DownCast( thePolylines.Value( i ) );
514     std::vector<TopoDS_Wire> aCurves = GetWires( aPolyline );
515     for( int j=0, m=aCurves.size(); j<m; j++ )
516       if( !Merge( aMergedPolyline, aCurves[j], isConnectByNewSegment, theTolerance ) )
517         return false;
518   }
519
520   std::vector<TopoDS_Shape> aShapes( 1 );
521   aShapes[0] = aMergedPolyline;
522   CreatePolylines( theDoc, theName, aShapes, false );
523
524   return true;
525 }
526
527 bool HYDROData_PolylineOperator::Merge( TopoDS_Shape& theShape, const TopoDS_Wire& theWire, 
528                                         bool isConnectByNewSegment, double theTolerance )
529 {
530   //TODO
531   return true;
532 }
533
534 bool HYDROData_PolylineOperator::split( const Handle( HYDROData_Document )& theDoc,
535                                         const Handle( HYDROData_PolylineXY )& thePolyline,
536                                         const HYDROData_SequenceOfObjects& theTools,
537                                         double theTolerance,
538                                         int theIgnoreIndex ) const
539 {
540   std::vector<TopoDS_Wire> aCurves = GetWires( thePolyline );
541   std::vector<TopoDS_Wire> aToolCurves;
542   for( int i=theTools.Lower(), n=theTools.Upper(); i<=n; i++ )
543     if( i!=theIgnoreIndex )
544     {
545       Handle( HYDROData_PolylineXY ) aToolPolyline = 
546         Handle( HYDROData_PolylineXY )::DownCast( theTools.Value( i ) );
547       append( aToolCurves, GetWires( aToolPolyline ) );
548     }
549
550   const int aPSCount = aCurves.size();
551   const int aTSCount = aToolCurves.size();
552   std::vector<TopoDS_Shape> aResult;
553   for (int aPSI = 0; aPSI < aPSCount; ++aPSI)
554   {
555     NCollection_Vector<TopoDS_Edge> aCurve;
556     Standard_Boolean aIsClosed;
557     if (!WireToCurve(aCurves[aPSI], aCurve, aIsClosed))
558     {
559       continue;
560     }
561
562     NCollection_Vector<NCollection_Sequence<Standard_Real> > aParams;
563     aParams.SetValue(aPSCount - 1, NCollection_Sequence<Standard_Real>());
564     for (int aTSI = 0; aTSI < aTSCount; ++aTSI)
565     {
566       IntersectCurve(aCurve, aToolCurves[aTSI], aParams);
567     }
568
569     NCollection_Vector<NCollection_Vector<TopoDS_Edge> > aSplittedCurves;
570     SplitCurveByPoints(aCurve, aParams, aSplittedCurves);
571
572     Standard_Boolean aIsClosed2 = aIsClosed;
573     if (aIsClosed2)
574     {
575       const NCollection_Sequence<Standard_Real>& aPs = aParams.First();
576       if (!aPs.IsEmpty())
577       {
578         const TopoDS_Edge& aEdge = aCurve.First();
579         const Standard_Boolean isForward =
580           (aEdge.Orientation() != TopAbs_REVERSED);
581         const Standard_Real aParam = isForward ? aPs.First() : aPs.Last();
582         BRepAdaptor_Curve aCurve(aEdge);
583         const Standard_Real aEndParam = isForward ?
584           aCurve.FirstParameter() : aCurve.LastParameter();
585         aIsClosed2 = (Abs(aParam - aEndParam) > Precision::PConfusion());
586       }
587
588       if (aIsClosed2)
589       {
590         const NCollection_Sequence<Standard_Real>& aPs = aParams.Last();
591         if (!aPs.IsEmpty())
592         {
593           const TopoDS_Edge& aEdge = aCurve.Last();
594           const Standard_Boolean isForward =
595             (aEdge.Orientation() != TopAbs_REVERSED);
596           const Standard_Real aParam = isForward ? aPs.Last() : aPs.First();
597           BRepAdaptor_Curve aCurve(aEdge);
598           const Standard_Real aEndParam = isForward ?
599             aCurve.LastParameter() : aCurve.FirstParameter();
600           aIsClosed2 = (Abs(aParam - aEndParam) >= Precision::PConfusion());
601         }
602       }
603     }
604
605     Standard_Integer aFSCI = 0, aLSCI = aSplittedCurves.Size() - 1;
606     if (aIsClosed2 && aFSCI < aLSCI)
607     {
608       TopoDS_Wire aWire;
609       CurveToWire(aSplittedCurves(aLSCI), aSplittedCurves(aFSCI), aWire);
610       aResult.push_back(aWire);
611       ++aFSCI;
612       --aLSCI;
613     }
614
615     for (Standard_Integer aSCI = aFSCI; aSCI <= aLSCI; ++aSCI)
616     {
617       TopoDS_Wire aWire;
618       CurveToWire(aSplittedCurves(aSCI), aWire);
619       aResult.push_back(aWire);
620     }
621   }
622
623   CreatePolylines(theDoc, thePolyline->GetName(), aResult, true);
624   return true;
625 }
626
627 std::vector<TopoDS_Wire> HYDROData_PolylineOperator::GetWires( const Handle( HYDROData_PolylineXY )& thePolyline )
628 {
629   std::vector<TopoDS_Wire> aResult;
630
631   TopoDS_Shape aShape = thePolyline->GetShape();
632
633   if( aShape.ShapeType()==TopAbs_WIRE )
634   {
635     aResult.push_back( TopoDS::Wire( aShape ) );
636   }
637   else
638   {
639     TopExp_Explorer anExp( aShape, TopAbs_WIRE );
640     for( ; anExp.More(); anExp.Next() )
641     {
642       aResult.push_back( TopoDS::Wire( anExp.Current() ) );
643     }
644   }
645   return aResult;
646 }
647
648 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const TopoDS_Wire& theWire,
649                                                              const gp_Pnt2d& thePoint,
650                                                              double theTolerance )
651 {
652   std::vector<TopoDS_Shape> aResult;
653   NCollection_Vector<TopoDS_Edge> aEdges;
654   Standard_Boolean isClosed;
655   if (!WireToCurve(theWire, aEdges, isClosed))
656   {
657     aResult.push_back(theWire);
658     return aResult;
659   }
660
661   const gp_Pnt aP(thePoint.X(), thePoint.Y(), 0);
662   Standard_Real aMinSqDist = DBL_MAX;
663   int aSEI = -1;
664   Standard_Real aSParam;
665   for (int aECount = aEdges.Size(), aEI = 0; aEI < aECount; ++aEI)
666   {
667     Standard_Real aParam;
668     const Standard_Real aSqDist =
669       ProjectPointToEdge(aP, aEdges(aEI), aParam);
670     if (aMinSqDist > aSqDist)
671     {
672       aMinSqDist = aSqDist;
673       aSEI = aEI;
674       aSParam = aParam;
675     }
676   }
677
678   NCollection_Vector<TopoDS_Edge> aEdges1, aEdges2;
679   SplitCurveByPoint(aEdges, aSEI, aSParam, aEdges1, aEdges2);
680   TopoDS_Wire aWire;
681   if (!isClosed)
682   {
683     CurveToWire(aEdges1, aWire);
684     if (!aEdges2.IsEmpty())
685     {
686       aResult.push_back(aWire);
687       CurveToWire(aEdges2, aWire);
688     }
689   }
690   else
691   {
692     if (!aEdges2.IsEmpty())
693     {
694       CurveToWire(aEdges2, aEdges1, aWire);
695     }
696     else
697     {
698       CurveToWire(aEdges1, aWire);
699     }
700   }
701   aResult.push_back(aWire);
702   return aResult;
703 }
704
705 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const TopoDS_Wire& theWire,
706                                                              const TopoDS_Wire& theTool,
707                                                              double theTolerance )
708 {
709   std::vector<TopoDS_Shape> aResult;
710   NCollection_Vector<TopoDS_Edge> aWEdges, aTEdges;
711   Standard_Boolean aIsWClosed, aIsTClosed;
712   if (!WireToCurve(theWire, aWEdges, aIsWClosed) ||
713     !WireToCurve(theTool, aTEdges, aIsTClosed))
714   {
715     return aResult;
716   }
717
718
719   //TODO
720   return aResult;
721 }
722
723 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const std::vector<TopoDS_Wire>& theWires,
724                                                              double theTolerance )
725 {
726   std::vector<TopoDS_Shape> aResult;
727   //TODO
728   return aResult;
729 }
730
731 bool HYDROData_PolylineOperator::CreatePolylines( const Handle( HYDROData_Document )& theDoc,
732                                                   const QString& theNamePrefix,
733                                                   const std::vector<TopoDS_Shape>& theShapes,
734                                                   bool isUseIndices )
735 {
736   if( theDoc.IsNull() )
737     return false;
738
739   int n = theShapes.size();
740   int anIndex = 1;
741   for( int i=0; i<n; i++ )
742   {
743     Handle( HYDROData_PolylineXY ) aPolyline = 
744       Handle( HYDROData_PolylineXY )::DownCast( theDoc->CreateObject( KIND_POLYLINEXY ) );
745     if( aPolyline.IsNull() )
746       return false;
747
748     aPolyline->SetShape( theShapes[i] );
749
750     if( isUseIndices )
751     {
752       QString aNewName = theNamePrefix + "_" + QString::number( anIndex );
753       if( theDoc->FindObjectByName( aNewName ).IsNull() )  // the object with such a name is not found
754         aPolyline->SetName( aNewName );
755       anIndex++;
756     }
757     else
758     {
759       aPolyline->SetName( theNamePrefix );
760     }
761   }
762   return true;
763 }