Salome HOME
debug split polylines, OK with type POLYLINE, still too many points with SPLINE
[modules/hydro.git] / src / HYDROData / HYDROData_TopoCurve.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_TopoCurve.h>
20
21 #include <Approx_Curve3d.hxx>
22 #include <BRep_Builder.hxx>
23 #include <BRepAdaptor_Curve.hxx>
24 #include <BRepAdaptor_HCurve.hxx>
25 #include <BRepBuilderAPI_MakeEdge.hxx>
26 #include <Extrema_ExtCC.hxx>
27 #include <Extrema_ExtPC.hxx>
28 #include <GeomAPI_Interpolate.hxx>
29 #include <Geom_BSplineCurve.hxx>
30 #include <Precision.hxx>
31 #include <ShapeAnalysis_TransferParametersProj.hxx>
32 #include <ShapeBuild_Edge.hxx>
33 #include <TColgp_Array1OfVec.hxx>
34 #include <TColgp_HArray1OfPnt.hxx>
35 #include <TColStd_HArray1OfBoolean.hxx>
36 #include <TopExp_Explorer.hxx>
37 #include <TopoDS.hxx>
38 #include <TopoDS_Wire.hxx>
39 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
40 #include <TopTools_ListOfShape.hxx>
41
42 #define _DEVDEBUG_
43 #include "HYDRO_trace.hxx"
44 #include <BRepTools.hxx>
45
46 //! The type is intended to traverse the container
47 //! either from the begin to the end or vice versa.
48 template<typename ContainerType, typename IteratorType>
49 class Iterator
50 {
51 private:
52   IteratorType myIterator; //!< The iterator.
53   IteratorType myIteratorLimit; //!< The iterator limit.
54
55   //! The pointer to the method to traverse the next item.
56   IteratorType& (IteratorType::*myNext)();
57
58 public:
59   //! The constructor.
60   Iterator(
61     const ContainerType& theContainer,
62     const bool theIsForward)
63   {
64     if (theIsForward)
65     {
66       myIterator = theContainer.begin();
67       myIteratorLimit = theContainer.end();
68       myNext = &IteratorType::operator++;
69     }
70     else
71     {
72       myIterator = --theContainer.end();
73       myIteratorLimit = --theContainer.begin();
74       myNext = &IteratorType::operator--;
75     }
76   }
77
78   //! Returna 'true' if the container contains not yet traversed item.
79   bool More() const
80   {
81     return myIterator != myIteratorLimit;
82   }
83
84   //! Traverses to the next item.
85   IteratorType& operator ++()
86   {
87     return (myIterator.*myNext)();
88   }
89
90   //! Returns the iterator.
91   IteratorType& operator *() {return myIterator;}
92 };
93
94 // Inserts the value after the position.
95 template<typename ItemType> static void InsertAfter(
96   const typename std::list<ItemType>::iterator& thePosition,
97   const ItemType& theValue,
98   std::list<ItemType>& theList)
99 {
100   typename std::list<ItemType>::iterator aEIt2 = thePosition;
101   if (++aEIt2 != theList.end())
102   {
103     theList.insert(aEIt2, theValue);
104   }
105   else
106   {
107     theList.push_back(theValue);
108   }
109 }
110
111 // Converts the curve to a smooth cubic B-spline using the deflection.
112 static Handle(Geom_BSplineCurve) BSpline(
113   const BRepAdaptor_Curve& theCurve, const double theDeflection)
114 {
115   Handle(BRepAdaptor_HCurve) aCurve = new BRepAdaptor_HCurve(theCurve);
116   Approx_Curve3d aConverter(aCurve, theDeflection, GeomAbs_C1, 4, 3);
117   Handle(Geom_BSplineCurve) aBSpline;
118   return aConverter.HasResult() ? aConverter.Curve() : aBSpline;
119 }
120
121 // Replaces the vertex of the edge considering the edge orientation.
122 static TopoDS_Edge ReplaceVertex(
123   const TopoDS_Edge& theEdge, const bool theIsEndVertex)
124 {
125   TopoDS_Vertex aVertices[] = {
126     TopExp::FirstVertex(theEdge, Standard_True),
127     TopExp::LastVertex(theEdge, Standard_True)};
128   aVertices[theIsEndVertex ? 1 : 0].EmptyCopy();
129   TopoDS_Edge aNewEdge = TopoDS::Edge(theEdge.Oriented(TopAbs_FORWARD));
130   aNewEdge =
131     ShapeBuild_Edge().CopyReplaceVertices(aNewEdge, aVertices[0], aVertices[1]);
132   aNewEdge.Orientation(theEdge.Orientation());
133   return aNewEdge;
134 }
135
136 // Projects the point to the curve.
137 static double ProjectPointToCurve(
138   const gp_XYZ& thePoint,
139   const Adaptor3d_Curve& theCurve,
140   double& theParameter)
141 {
142   // Calculate the nearest curve internal extremum.
143   Extrema_ExtPC aAlgo(thePoint, theCurve);
144   int aMinEN = -2;
145   double aMinSqDist = DBL_MAX;
146   if (aAlgo.IsDone())
147   {
148     const int aECount = aAlgo.NbExt();
149     for (int aEN = 1; aEN <= aECount; ++aEN)
150     {
151       const gp_XYZ& aP = aAlgo.Point(aEN).Value().XYZ();
152       const double aSqDist = (thePoint - aP).SquareModulus();
153       if (aMinSqDist > aSqDist)
154       {
155         aMinSqDist = aSqDist;
156         aMinEN = aEN;
157       }
158     }
159   }
160
161   // Calculate the nearest curve end extremum.
162   const double aParams[] =
163     {theCurve.FirstParameter(), theCurve.LastParameter()};
164   const gp_XYZ aEnds[] =
165     {theCurve.Value(aParams[0]).XYZ(), theCurve.Value(aParams[1]).XYZ()};
166   const double aSqDists[] = {
167     (thePoint - aEnds[0]).SquareModulus(),
168     (thePoint - aEnds[1]).SquareModulus()};
169   for (int aEI = 0; aEI < 2; ++aEI)
170   {
171     if (aMinSqDist > aSqDists[aEI])
172     {
173       aMinSqDist = aSqDists[aEI];
174       aMinEN = -aEI;
175     }
176   }
177
178   if (aMinEN <= 0)
179   {
180     theParameter = aParams[-aMinEN];
181     return aMinSqDist;
182   }
183
184   const Extrema_POnCurv& aPOnC = aAlgo.Point(aMinEN);
185   const gp_XYZ& aP = aPOnC.Value().XYZ();
186   theParameter = aPOnC.Parameter();
187   for (int aEI = 0; aEI < 2; ++aEI)
188   {
189     if (Abs(theParameter - aParams[aEI]) < Precision::PConfusion() ||
190       (aP - aEnds[aEI]).SquareModulus() < Precision::SquareConfusion())
191     {
192       theParameter = aParams[aEI];
193     }
194   }
195   return aMinSqDist;
196 }
197
198 // Projects the point to the edge.
199 static double ProjectPointToEdge(
200   const gp_XYZ& thePoint, const TopoDS_Edge& theEdge, double& theParameter)
201 {
202   return ProjectPointToCurve(thePoint, BRepAdaptor_Curve(theEdge), theParameter);
203 }
204
205 // Adds the parameter to the curve parameter list.
206 static int AddParameter(
207   const Adaptor3d_Curve& theCurve,
208   const double theParameter,
209   std::list<double>& theParameters)
210 {
211   // Check the coincidence.
212   std::list<double> aEndParams;
213   aEndParams.push_back(theCurve.FirstParameter());
214   aEndParams.push_back(theCurve.LastParameter());
215   std::list<double>* aParams[] = {&theParameters, &aEndParams};
216   const gp_XYZ aPoint = theCurve.Value(theParameter).XYZ();
217   for (int aLI = 0; aLI < 2; ++aLI)
218   {
219     std::list<double>::iterator aPIt = aParams[aLI]->begin();
220     std::list<double>::iterator aLastPIt = aParams[aLI]->end();
221     for (int aPI = 0; aPIt != aLastPIt; ++aPI, ++aPIt)
222     {
223       const double aParam = *aPIt;
224       if (Abs(theParameter - aParam) < Precision::PConfusion() ||
225         (theCurve.Value(aParam).XYZ() - aPoint).SquareModulus() <=
226           Precision::SquareConfusion())
227       {
228         int aIntCount = 0;
229         if (aLI != 0)
230         {
231           if (aPI == 0)
232           {
233             theParameters.push_front(aEndParams.front());
234           }
235           else
236           {
237             theParameters.push_back(aEndParams.back());
238           }
239           ++aIntCount;
240         }
241         return aIntCount;
242       }
243     }
244   }
245
246   // Calculate the position to insert.
247   std::list<double>::iterator aPIt = theParameters.begin();
248   std::list<double>::iterator aLastPIt = theParameters.end();
249   if (aPIt != aLastPIt && *aPIt < theParameter)
250   {
251     for (++aPIt; aPIt != aLastPIt && *aPIt < theParameter; ++aPIt);
252     if (aPIt != aLastPIt)
253     {
254       theParameters.insert(aPIt, theParameter);
255     }
256     else
257     {
258       theParameters.push_back(theParameter);
259     }
260   }
261   else
262   {
263     theParameters.push_front(theParameter);
264   }
265   return 1;
266 }
267
268 // Intersects the first curve by the second one and
269 // adds the intersection parameters to the ordered list.
270 static int IntersectCurve(
271   const Adaptor3d_Curve& theCurve1,
272   const Adaptor3d_Curve& theCurve2,
273   std::list<double>& theParameters)
274 {
275   // Process the ends.
276   int aIntCount = 0;
277   const gp_XYZ aEndPs[] = {
278     theCurve2.Value(theCurve2.FirstParameter()).XYZ(),
279     theCurve2.Value(theCurve2.LastParameter()).XYZ()};
280   for (int aPI = 0; aPI < 2; ++aPI)
281   {
282     double aParameter;
283     if (ProjectPointToCurve(aEndPs[aPI], theCurve1, aParameter) <=
284       Precision::SquareConfusion())
285     {
286       aIntCount += AddParameter(theCurve1, aParameter, theParameters);
287     }
288   }
289
290   // Process the internal extremums.
291   Extrema_ExtCC aAlgo(theCurve1, theCurve2);
292   if (aAlgo.IsDone())
293   {
294     const int aECount = aAlgo.NbExt();
295     for (int aEN = 1; aEN <= aECount; ++aEN)
296     {
297       Extrema_POnCurv aP1, aP2;
298       aAlgo.Points(aEN, aP1, aP2);
299       if (aP1.Value().SquareDistance(aP2.Value()) <=
300         Precision::SquareConfusion())
301       {
302         aIntCount += AddParameter(theCurve1, aP1.Parameter(), theParameters);
303       }
304     }
305   }
306   return aIntCount;
307 }
308
309 // Intersects the first edge by the second one and
310 // adds the intersection parameters to the ordered list.
311 static int IntersectEdge(
312   const TopoDS_Edge& theEdge1,
313   const TopoDS_Edge& theEdge2,
314   std::list<double>& theParameters)
315 {
316   BRepAdaptor_Curve aCurve1 = BRepAdaptor_Curve(theEdge1);
317   BRepAdaptor_Curve aCurve2 = BRepAdaptor_Curve(theEdge2);
318   return IntersectCurve(aCurve1, aCurve2, theParameters);
319 }
320
321 // Returns the curve tangent in the position: 0 - start, 1 - end.
322 static gp_XYZ Tangent(const Adaptor3d_Curve& theCurve, const int thePosition)
323 {
324   const Standard_Real aParam = (thePosition == 0) ?
325     theCurve.FirstParameter() : theCurve.LastParameter();
326   gp_Pnt aP;
327   gp_Vec aV;
328   theCurve.D1(aParam, aP, aV);
329   Standard_Real aNorm = aV.Magnitude();
330   aNorm = (aNorm >= Precision::PConfusion()) ? aNorm : 0;
331   return ((1 / aNorm) * aV).XYZ();
332 }
333
334 // Returns the edge tangent in the position: 0 - start, 1 - end.
335 static gp_XYZ Tangent(const TopoDS_Edge& theEdge, const int thePosition)
336 {
337   BRepAdaptor_Curve aCurve(theEdge);
338   return Tangent(BRepAdaptor_Curve(theEdge), thePosition);
339 }
340
341 static bool Interpolate(
342   const gp_XYZ thePoint1,
343   const gp_XYZ thePoint2,
344   const gp_XYZ theTangent1,
345   const gp_XYZ theTangent2,
346   Handle(Geom_BSplineCurve)& theBSpline)
347 {
348   Handle(TColgp_HArray1OfPnt) aPs = new TColgp_HArray1OfPnt(1, 2);
349   TColgp_Array1OfVec aTs(1, 2);
350   Handle(TColStd_HArray1OfBoolean) aTFs = new TColStd_HArray1OfBoolean(1, 2);
351   aPs->SetValue(1, thePoint1);
352   aPs->SetValue(2, thePoint2);
353   aTs.SetValue(1, theTangent1);
354   aTs.SetValue(2, theTangent2);
355   aTFs->SetValue(1, Standard_True);
356   aTFs->SetValue(2, Standard_True);
357   GeomAPI_Interpolate aInterpolator(aPs, Standard_False, 0);
358   aInterpolator.Load(aTs, aTFs, Standard_False);
359   aInterpolator.Perform();
360   const bool aResult = (aInterpolator.IsDone() == Standard_True);
361   if (aResult)
362   {
363     theBSpline = aInterpolator.Curve();
364   }
365   return aResult;
366 }
367
368 bool HYDROData_TopoCurve::Initialize(const TopoDS_Wire& theWire)
369 {
370   // Check for nonemptiness.
371   myEdges.clear();
372   TopTools_IndexedDataMapOfShapeListOfShape aVertexToEdges;
373   TopExp::MapShapesAndAncestors(theWire,
374     TopAbs_VERTEX, TopAbs_EDGE, aVertexToEdges);
375   const int aVCount = aVertexToEdges.Extent();
376   DEBTRACE("initialize VCount= "<< aVCount);
377   if (aVCount == 0)
378   {
379     return false;
380   }
381
382   // Check for 1 manifoldness.
383   bool isClosed = false;
384   {
385     int aEndCount = 0;
386     for (int aVN = 1; aVN <= aVCount; ++aVN)
387     {
388       const int aEdgeCount = aVertexToEdges.FindFromIndex(aVN).Extent();
389       if (aEdgeCount == 1)
390       {
391         ++aEndCount;
392       }
393       if (aEdgeCount > 2)
394       {
395         return false;
396       }
397     }
398     isClosed = (aEndCount == 0);
399     if (!isClosed && aEndCount != 2)
400     {
401       return false;
402     }
403   }
404
405   // Find the start.
406   int aVN = 1;
407   if (!isClosed)
408   {
409     for (; aVertexToEdges.FindFromIndex(aVN).Extent() == 2; ++aVN);
410     if (!aVertexToEdges.FindKey(aVN).IsEqual(TopExp::FirstVertex(
411       TopoDS::Edge(aVertexToEdges.FindFromIndex(aVN).First()), Standard_True)))
412     {
413       for (; aVertexToEdges.FindFromIndex(aVN).Extent() == 2; ++aVN);
414     }
415   }
416   else
417   {
418     TopTools_ListOfShape& aEdges = aVertexToEdges.ChangeFromIndex(1);
419     if (!aVertexToEdges.FindKey(aVN).IsEqual(
420       TopExp::FirstVertex(TopoDS::Edge(aEdges.First()), Standard_True)))
421     {
422       const TopoDS_Shape aEdge = aEdges.First();
423       aEdges.First() = aEdges.Last();
424       aEdges.Last() = aEdge;
425     }
426   }
427
428   // Calculate the edge order.
429   TopTools_ListOfShape* aEdges = &aVertexToEdges.ChangeFromIndex(aVN);
430   while (!aEdges->IsEmpty())
431   {
432     const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
433     aEdges->RemoveFirst();
434     myEdges.push_back(aEdge);
435     int aVN2 = aVertexToEdges.FindIndex(TopExp::FirstVertex(aEdge));
436     if (aVN2 == aVN)
437     {
438       aVN2 = aVertexToEdges.FindIndex(TopExp::LastVertex(aEdge));
439     }
440     aVN = aVN2;
441
442     aEdges = &aVertexToEdges.ChangeFromIndex(aVN2);
443     const TopoDS_Edge aEdge2 = TopoDS::Edge(aEdges->First());
444     if (aEdge2.IsEqual(aEdge))
445     {
446       aEdges->RemoveFirst();
447     }
448     else
449     {
450       aEdges->Clear();
451       aEdges->Append(aEdge2);
452     }
453   }
454
455   // Check for connectedness and free vertex.
456   return aVCount - myEdges.size() == (isClosed ? 0 : 1);
457 }
458
459 TopoDS_Wire HYDROData_TopoCurve::Wire() const
460 {
461   TopoDS_Wire aWire;
462   BRep_Builder aBuilder;
463   aBuilder.MakeWire(aWire);
464   std::list<TopoDS_Edge>::const_iterator aEItLast = myEdges.end();
465   std::list<TopoDS_Edge>::const_iterator aEIt = myEdges.begin();
466   for (; aEIt != aEItLast; ++aEIt)
467   {
468     aBuilder.Add(aWire, *aEIt);
469   }
470   return aWire;
471 }
472
473 bool HYDROData_TopoCurve::Cut(
474   const std::list<TopoDS_Edge>::iterator& theEdgePosition,
475   const double theParameter,
476   HYDROData_TopoCurve& theCurve)
477 {
478   bool aResult = false;
479
480   // Locate the edge.
481   std::list<TopoDS_Edge>::iterator aFirstEIt = myEdges.begin();
482   std::list<TopoDS_Edge>::iterator aEIt = aFirstEIt;
483   for (; aEIt != theEdgePosition; ++aEIt);
484
485   // Cut the edge.
486   TopoDS_Edge aEdge = *aEIt;
487   BRepAdaptor_Curve aCurve(aEdge);
488   int aParamI = -1;
489   const double aEdgeEndParams[] =
490     {aCurve.FirstParameter(), aCurve.LastParameter()};
491   if (Abs(theParameter - aEdgeEndParams[0]) < Precision::PConfusion())
492   {
493     aParamI = 0;
494   }
495   else if (Abs(theParameter - aEdgeEndParams[1]) < Precision::PConfusion())
496   {
497     aParamI = 1;
498   }
499   const TopAbs_Orientation aOrient = aEdge.Orientation();
500   if (aOrient == TopAbs_REVERSED)
501   {
502     aParamI ^= 1;
503   }
504   const bool isClosed = IsClosed();
505   DEBTRACE("aParamI: " << aParamI << " isClosed: "<< isClosed);
506   if (aParamI < 0)
507   {
508     aEdge.Orientation(TopAbs_FORWARD);
509     TopoDS_Vertex aSplitV1, aSplitV2;
510     BRep_Builder().MakeVertex(
511       aSplitV1, aCurve.Value(theParameter), Precision::Confusion());
512     BRep_Builder().MakeVertex(
513       aSplitV2, aCurve.Value(theParameter), Precision::Confusion());
514     TopoDS_Edge aEParts[] = {
515       ShapeBuild_Edge().CopyReplaceVertices(aEdge, TopoDS_Vertex(),
516         TopoDS::Vertex(aSplitV1.Oriented(TopAbs_REVERSED))),
517       ShapeBuild_Edge().CopyReplaceVertices(aEdge, aSplitV2, TopoDS_Vertex())};
518     ShapeBuild_Edge().CopyPCurves(aEParts[0], aEdge);
519     ShapeBuild_Edge().CopyPCurves(aEParts[1], aEdge);
520     BRep_Builder().SameRange(aEParts[0], Standard_False);
521     BRep_Builder().SameRange(aEParts[1], Standard_False);
522     BRep_Builder().SameParameter(aEParts[0], Standard_False);
523     BRep_Builder().SameParameter(aEParts[1], Standard_False);
524     ShapeAnalysis_TransferParametersProj aSATPP(aEdge, TopoDS_Face());
525     aSATPP.SetMaxTolerance(Precision::Confusion());
526     aSATPP.TransferRange(aEParts[0],
527       aEdgeEndParams[0], theParameter, Standard_False);
528     aSATPP.TransferRange(aEParts[1],
529       theParameter, aEdgeEndParams[1], Standard_False);
530     aEParts[0].Orientation(aOrient);
531     aEParts[1].Orientation(aOrient);
532
533     const int aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1;
534     *aEIt = aEParts[aFirstPI];
535     InsertAfter(aEIt, aEParts[1 - aFirstPI], myEdges);
536     ++aEIt;
537
538     aResult = true;
539   }
540   else
541   {
542     TopoDS_Edge aNewEdge = ReplaceVertex(aEdge, (aParamI == 0) ? false : true);
543     *aEIt = aNewEdge;
544     if (aParamI > 0)
545     {
546       ++aEIt;
547
548       std::list<TopoDS_Edge>::iterator aEdgePosition = theEdgePosition;
549       if (isClosed || ++aEdgePosition != myEdges.end())
550       {
551         aResult = true;
552       }
553     }
554     else
555     {
556       if (isClosed || theEdgePosition != aFirstEIt)
557       {
558         aResult = true;
559       }
560     }
561   }
562
563   // Calculate the curve parts.
564   std::list<TopoDS_Edge>::iterator aLastEIt = myEdges.end();
565   if (aEIt != aFirstEIt && aEIt != aLastEIt)
566   {
567     std::list<TopoDS_Edge>* aEdges = !isClosed ? &theCurve.myEdges : &myEdges;
568     aEdges->splice(aEdges->begin(), myEdges, aEIt, aLastEIt);
569   }
570
571   return aResult;
572 }
573
574 void HYDROData_TopoCurve::Cut(
575   const std::list<TopoDS_Edge>::const_iterator& theEdgePosition,
576   const double theParameter,
577   HYDROData_TopoCurve& theCurve1,
578   HYDROData_TopoCurve& theCurve2) const
579 {
580   theCurve1 = *this;
581   std::list<TopoDS_Edge>::const_iterator aEPos = myEdges.begin();
582   std::list<TopoDS_Edge>::iterator aEPos1 = theCurve1.myEdges.begin();
583   for (; aEPos != theEdgePosition; ++aEPos1, ++aEPos);
584   theCurve1.Cut(aEPos1, theParameter, theCurve2);
585 }
586
587 bool HYDROData_TopoCurve::Cut(
588   const std::deque<std::list<double> >& theParameters,
589   std::deque<HYDROData_TopoCurve>& theCurves) const
590 {
591   bool aResult = false;
592   HYDROData_TopoCurve aCurves[2];
593   aCurves[0] = *this;
594   int aCI = 0;
595   std::list<TopoDS_Edge>::iterator aEIt = aCurves[0].myEdges.begin();
596   std::deque<std::list<double> >::const_iterator aPLIt = theParameters.begin();
597   for (std::deque<std::list<double> >::const_iterator aLastPLIt =
598     theParameters.end(); aPLIt != aLastPLIt; ++aPLIt)
599   {
600     TopoDS_Edge aNextEdge;
601     {
602       std::list<TopoDS_Edge>::iterator aNextEIt = aEIt;
603       ++aNextEIt;
604       if (aNextEIt != aCurves[aCI].myEdges.end())
605       {
606         aNextEdge = *aNextEIt;
607       }
608     }
609
610     for (Iterator<std::list<double>, std::list<double>::const_iterator> aPIt(
611       *aPLIt, (aEIt->Orientation() != TopAbs_REVERSED)); aPIt.More(); ++aPIt)
612     {
613       const int aCI1 = 1 - aCI;
614       aResult |= aCurves[aCI].Cut(aEIt, **aPIt, aCurves[aCI1]);
615       if (!aCurves[aCI1].IsEmpty())
616       {
617         theCurves.push_back(HYDROData_TopoCurve());
618         theCurves.back().append(aCurves[aCI]);
619         aEIt = aCurves[aCI1].myEdges.begin();
620         aCI = aCI1;
621       }
622       else
623       {
624         aEIt = aCurves[aCI].myEdges.begin();
625       }
626     }
627
628     if (!aNextEdge.IsNull() && !aEIt->IsEqual(aNextEdge))
629     {
630       ++aEIt;
631     }
632   }
633   theCurves.push_back(aCurves[aCI]);
634   return aResult;
635 }
636
637 double HYDROData_TopoCurve::Project(
638   const gp_XYZ& thePoint,
639   std::list<TopoDS_Edge>::const_iterator& theEdgeIterator,
640   double& theParameter) const
641 {
642   double aMinSqDist = DBL_MAX;
643   std::list<TopoDS_Edge>::const_iterator aEIt = myEdges.begin();
644   std::list<TopoDS_Edge>::const_iterator aLastEIt = myEdges.end();
645   for (; aEIt != aLastEIt; ++aEIt)
646   {
647     double aParam;
648     const double aSqDist = ProjectPointToEdge(thePoint, *aEIt, aParam);
649     if (aMinSqDist > aSqDist)
650     {
651       aMinSqDist = aSqDist;
652       theEdgeIterator = aEIt;
653       theParameter = aParam;
654     }
655   }
656   return aMinSqDist;
657 }
658
659 int HYDROData_TopoCurve::Intersect(
660   const TopoDS_Wire& theWire,
661   std::deque<std::list<double> >& theParameters) const
662 {
663   std::string brepName = "theWireToIntersect";
664   brepName += ".brep";
665   BRepTools::Write( theWire, brepName.c_str() );
666
667   int aIntCount = 0;
668   theParameters.resize(myEdges.size());
669   std::list<TopoDS_Edge>::const_iterator aEIt = myEdges.begin();
670   std::list<TopoDS_Edge>::const_iterator aLastEIt = myEdges.end();
671   std::deque<std::list<double> >::iterator aPIt = theParameters.begin();
672   for (; aEIt != aLastEIt; ++aPIt, ++aEIt)
673   {
674     const TopoDS_Edge& aEdge = *aEIt;
675     std::list<double>& aParams = *aPIt;
676     TopExp_Explorer aEIt2(theWire, TopAbs_EDGE);
677     for (; aEIt2.More(); aEIt2.Next())
678     {
679       aIntCount += IntersectEdge(aEdge,TopoDS::Edge(aEIt2.Current()), aParams);
680     }
681   }
682   DEBTRACE("aIntCount " << aIntCount);
683   return aIntCount;
684 }
685
686 void HYDROData_TopoCurve::CloseCurve()
687 {
688   const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex(
689     myEdges.back(), Standard_True).Oriented(TopAbs_FORWARD));
690   TopoDS_Edge& aEdge = myEdges.front();
691   const TopoDS_Edge aForwardEdge = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD));
692   aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices(
693     aForwardEdge, aVertex, TopoDS_Vertex()).Oriented(aEdge.Orientation()));
694 }
695
696 void HYDROData_TopoCurve::Merge(
697   const int thePosition, HYDROData_TopoCurve& theCurve)
698 {
699   if (thePosition == 0)
700   {
701     const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex(
702       theCurve.myEdges.back(), Standard_True).Oriented(TopAbs_FORWARD));
703     TopoDS_Edge& aEdge = myEdges.front();
704     aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices(
705         TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), aVertex, TopoDS_Vertex()).
706       Oriented(aEdge.Orientation()));
707     prepend(theCurve);
708   }
709   else
710   {
711     const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::FirstVertex(
712       theCurve.myEdges.front(), Standard_True).Oriented(TopAbs_REVERSED));
713     TopoDS_Edge& aEdge = myEdges.back();
714     aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices(
715         TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), TopoDS_Vertex(), aVertex).
716       Oriented(aEdge.Orientation()));
717     append(theCurve);
718   }
719 }
720
721 void HYDROData_TopoCurve::Merge(
722   const double theTolerance, std::deque<HYDROData_TopoCurve>& theCurves)
723 {
724   // Process the curve closeness.
725   const double aSqTol = theTolerance * theTolerance;
726   const gp_XYZ aPs[] = {
727     BRep_Tool::Pnt(TopExp::FirstVertex(myEdges.front(), Standard_True)).XYZ(),
728     BRep_Tool::Pnt(TopExp::LastVertex(myEdges.back(), Standard_True)).XYZ()};
729   bool isClosed = IsClosed();
730   if (!isClosed && (aPs[0] - aPs[1]).SquareModulus() <= aSqTol)
731   {
732     CloseCurve();
733     isClosed = true;
734   }
735
736   // Find the merge places.
737   HYDROData_TopoCurve* aCurves[] = {NULL, NULL};
738   int aOrder = 0;
739   if (!isClosed)
740   {
741     std::deque<HYDROData_TopoCurve>::iterator aCIt = theCurves.begin();
742     std::deque<HYDROData_TopoCurve>::iterator aLastCIt = theCurves.end();
743     for (; aCIt != aLastCIt; ++aCIt)
744     {
745       HYDROData_TopoCurve& aCurve = *aCIt;
746       if (aCurve.IsEmpty() || aCurve.IsClosed())
747       {
748         continue;
749       }
750
751       const gp_XYZ aP1 = BRep_Tool::Pnt(
752         TopExp::FirstVertex(aCurve.myEdges.front(), Standard_True)).XYZ();
753       if (aCurves[0] == NULL && (aPs[1] - aP1).SquareModulus() <= aSqTol)
754       {
755         aCurves[0] = &aCurve;
756       }
757
758       const gp_XYZ aP2 = BRep_Tool::Pnt(
759         TopExp::LastVertex(aCurve.myEdges.back(), Standard_True)).XYZ();
760       if (aCurves[1] == NULL && (aPs[0] - aP2).SquareModulus() <= aSqTol)
761       {
762         aCurves[1] = &aCurve;
763         aOrder = (aCurves[0] == NULL) ? 1 : 0;
764       }
765     }
766   }
767
768   if (aCurves[0] == NULL && aCurves[1] == NULL)
769   {
770     theCurves.push_back(HYDROData_TopoCurve());
771     theCurves.back().append(*this);
772   }
773   else if (aCurves[1] == NULL)
774   {
775     aCurves[0]->Merge(0, *this);
776   }
777   else if (aCurves[0] == NULL)
778   {
779     aCurves[1]->Merge(1, *this);
780   }
781   else
782   {
783     aCurves[aOrder]->Merge(aOrder, *this);
784     if (aCurves[0] != aCurves[1])
785     {
786       aCurves[aOrder]->Merge(aOrder, *aCurves[1 - aOrder]);
787     }
788     else
789     {
790       aCurves[aOrder]->CloseCurve();
791     }
792   }
793 }
794
795 bool HYDROData_TopoCurve::Connect(
796   const Standard_Real theTolerance, std::deque<HYDROData_TopoCurve>& theCurves)
797 {
798   const double aSqTol = theTolerance * theTolerance;
799   const gp_XYZ aPs[] = {
800     BRep_Tool::Pnt(TopExp::FirstVertex(myEdges.front(), Standard_True)).XYZ(),
801     BRep_Tool::Pnt(TopExp::LastVertex(myEdges.back(), Standard_True)).XYZ()};
802   bool isClosed = IsClosed();
803   if (!isClosed && (aPs[0] - aPs[1]).SquareModulus() <= aSqTol)
804   {
805     CloseCurve();
806     isClosed = true;
807   }
808
809   if (!isClosed)
810   {
811     std::deque<HYDROData_TopoCurve>::iterator aCIt = theCurves.begin();
812     std::deque<HYDROData_TopoCurve>::iterator aLastCIt = theCurves.end();
813     for (; aCIt != aLastCIt; ++aCIt)
814     {
815       HYDROData_TopoCurve& aCurve2 = *aCIt;
816       if (aCurve2.IsEmpty() || aCurve2.IsClosed())
817       {
818         continue;
819       }
820
821       const TopoDS_Edge* aEdges2[] =
822         {&aCurve2.myEdges.front(), &aCurve2.myEdges.back()};
823       const gp_XYZ aPs2[] = {
824         BRep_Tool::Pnt(TopExp::FirstVertex(*aEdges2[0], Standard_True)).XYZ(),
825         BRep_Tool::Pnt(TopExp::LastVertex(*aEdges2[1], Standard_True)).XYZ()};
826       const double aSqDists[] =
827         {(aPs[1] - aPs2[0]).SquareModulus(), (aPs[0] - aPs2[1]).SquareModulus()};
828       const int aOrder = (aSqDists[0] <= aSqDists[1]) ? 0 : 1;
829       if (aSqDists[aOrder] > aSqTol)
830       {
831         const TopoDS_Edge& aEdge =
832           (aOrder == 0) ? myEdges.back() : myEdges.front();
833         const gp_XYZ aPs3[] = {aPs[1 - aOrder], aPs2[aOrder]};
834         const gp_XYZ aTs[] =
835           {Tangent(aEdge, 1 - aOrder), Tangent(*aEdges2[aOrder], aOrder)};
836         Handle(Geom_BSplineCurve) aBSpline;
837         if (!Interpolate(aPs3[aOrder], aPs3[1 - aOrder],
838           aTs[aOrder], aTs[1 - aOrder], aBSpline))
839         {
840           return false;
841         }
842
843         HYDROData_TopoCurve aECurve = BRepBuilderAPI_MakeEdge(aBSpline).Edge();
844         aCurve2.Merge(aOrder, aECurve);
845       }
846       aCurve2.Merge(aOrder, *this);
847       if (aSqDists[1 - aOrder] <= aSqTol)
848       {
849         aCurve2.CloseCurve();
850       }
851       return true;
852     }
853   }
854
855   theCurves.push_back(HYDROData_TopoCurve());
856   theCurves.back().append(*this);
857   return true;
858 }
859
860 int HYDROData_TopoCurve::BSplinePiecewiseCurve(
861   const double theDeflection, HYDROData_TopoCurve& theCurve) const
862 {
863   int aPieceCount = 0;
864   std::list<TopoDS_Edge>::const_iterator aLastEIt = myEdges.end();
865   std::list<TopoDS_Edge>::const_iterator aEIt = myEdges.begin();
866   TopoDS_Vertex aEndVertex;
867   TopoDS_Edge aPrevEdge;
868   for (; aEIt != aLastEIt; ++aEIt)
869   {
870     Handle(Geom_BSplineCurve) aBSpline =
871       ::BSpline(BRepAdaptor_Curve(*aEIt), theDeflection);
872     if (aBSpline.IsNull())
873     {
874       return 0;
875     }
876
877     if (aEIt->Orientation() == TopAbs_REVERSED)
878     {
879       aBSpline->Reverse();
880     }
881
882     TopoDS_Edge aEdge;
883     BRep_Builder().MakeEdge(aEdge, aBSpline, Precision::Confusion());
884     TopoDS_Vertex aVertex;
885     BRep_Builder().MakeVertex(aVertex,
886       aBSpline->Value(aBSpline->FirstParameter()), Precision::Confusion());
887     if (!aPrevEdge.IsNull())
888     {
889       BRep_Builder().Add(aPrevEdge, aVertex.Oriented(TopAbs_REVERSED));
890     }
891     else
892     {
893       aEndVertex = aVertex;
894     }
895     BRep_Builder().Add(aEdge, aVertex);
896     theCurve.myEdges.push_back(aEdge);
897     aPieceCount += aBSpline->NbKnots() - 1;
898     aPrevEdge = aEdge;
899   }
900
901   if (!IsClosed())
902   {
903     BRepAdaptor_Curve aCurve(aPrevEdge);
904     BRep_Builder().MakeVertex(aEndVertex,
905       aCurve.Value(aCurve.LastParameter()), Precision::Confusion());
906   }
907   BRep_Builder().Add(aPrevEdge, aEndVertex.Oriented(TopAbs_REVERSED));
908   return aPieceCount;
909 }
910
911 bool HYDROData_TopoCurve::ValuesInKnots(std::list<gp_XYZ>& theValues) const
912 {
913   std::list<TopoDS_Edge>::const_iterator aLastEIt = myEdges.end();
914   std::list<TopoDS_Edge>::const_iterator aEIt = myEdges.begin();
915   for (; aEIt != aLastEIt; ++aEIt)
916   {
917     Handle(Geom_BSplineCurve) aCurve;
918     {
919       TopLoc_Location aLoc;
920       double aParams[2];
921       aCurve = Handle(Geom_BSplineCurve)::
922         DownCast(BRep_Tool::Curve(*aEIt, aLoc, aParams[0], aParams[1]));
923       if (!aLoc.IsIdentity() || aEIt->Orientation() != TopAbs_FORWARD ||
924         aCurve.IsNull())
925       {
926         return false;
927       }
928     }
929
930     for (int aNbKnots = aCurve->NbKnots(), aKN = 1; aKN < aNbKnots; ++aKN)
931     {
932       theValues.push_back(aCurve->Value(aCurve->Knot(aKN)).XYZ());
933     }
934   }
935
936   if (!IsClosed())
937   {
938     TopLoc_Location aLoc;
939     double aParams[2];
940     Handle(Geom_Curve) aCurve =
941       BRep_Tool::Curve(myEdges.back(), aLoc, aParams[0], aParams[1]);
942     theValues.push_back(aCurve->Value(aParams[1]).XYZ());
943   }
944   return true;
945 }