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