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.
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.
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
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #include <HYDROData_PolylineOperator.h>
20 #include <HYDROData_Document.h>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRep_Builder.hxx>
23 #include <BRep_Tool.hxx>
24 #include <BRepBuilderAPI_MakeEdge2d.hxx>
25 #include <BRepBuilderAPI_MakeEdge.hxx>
26 #include <BRepBuilderAPI_MakeWire.hxx>
27 #include <Extrema_ExtCC.hxx>
28 #include <Extrema_ExtPC.hxx>
29 #include <GeomAPI_Interpolate.hxx>
30 #include <NCollection_Vector.hxx>
31 #include <Precision.hxx>
32 #include <ShapeAnalysis_TransferParametersProj.hxx>
33 #include <ShapeBuild_Edge.hxx>
34 #include <TColgp_Array1OfVec.hxx>
35 #include <TColgp_HArray1OfPnt.hxx>
36 #include <TColStd_HArray1OfBoolean.hxx>
38 #include <TopoDS_Edge.hxx>
39 #include <TopoDS_Wire.hxx>
41 #include <TopExp_Explorer.hxx>
42 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
45 template<class T> void append( std::vector<T>& theList, const std::vector<T>& theList2 )
47 int aSize = theList.size();
48 int aNewSize = aSize + theList2.size();
53 theList.resize( aNewSize );
54 for( int i=aSize, j=0; i<aNewSize; i++, j++ )
55 theList[i] = theList2[j];
58 static TopoDS_Edge ReplaceVertex(
59 const TopoDS_Edge& theEdge, Standard_Integer theVertexIndex)
61 TopoDS_Vertex aVertices[] =
62 {TopExp::FirstVertex(theEdge), TopExp::LastVertex(theEdge)};
63 const TopAbs_Orientation aOrient = theEdge.Orientation();
64 if (aOrient == TopAbs_REVERSED)
68 aVertices[theVertexIndex].EmptyCopy();
69 aVertices[0].Orientation(TopAbs_FORWARD);
70 aVertices[1].Orientation(TopAbs_REVERSED);
71 TopoDS_Edge aFE = TopoDS::Edge(theEdge.Oriented(TopAbs_FORWARD));
72 TopoDS_Edge aNewEdge =
73 ShapeBuild_Edge().CopyReplaceVertices(aFE, aVertices[0], aVertices[1]);
74 return TopoDS::Edge(aNewEdge.Oriented(aOrient));
77 template<typename TCurveType>
78 static Standard_Boolean WireToCurve(
79 const TopoDS_Wire& theWire,
81 Standard_Boolean& theIsClosed)
83 TopTools_IndexedDataMapOfShapeListOfShape aVertexToEdges;
84 TopExp::MapShapesAndAncestors(theWire,
85 TopAbs_VERTEX, TopAbs_EDGE, aVertexToEdges);
86 const Standard_Integer aVCount = aVertexToEdges.Extent();
89 return Standard_False;
93 Standard_Integer aEndCount = 0;
94 for (Standard_Integer aVN = 1; aVN <= aVCount; ++aVN)
96 const Standard_Integer aEdgeCount =
97 aVertexToEdges.FindFromIndex(aVN).Extent();
104 return Standard_False;
107 theIsClosed = (aEndCount == 0);
108 if (!theIsClosed && aEndCount != 2)
110 return Standard_False;
114 Standard_Integer aVN = 1;
117 while (aVN <= aVCount &&
118 aVertexToEdges.FindFromIndex(aVN).Extent() == 2)
124 TopTools_ListOfShape* aEdges = &aVertexToEdges.ChangeFromIndex(aVN);
125 while (!aEdges->IsEmpty())
127 const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
128 aEdges->RemoveFirst();
129 theCurve.Append(aEdge);
130 Standard_Integer aVN2 =
131 aVertexToEdges.FindIndex(TopExp::FirstVertex(aEdge));
134 aVN2 = aVertexToEdges.FindIndex(TopExp::LastVertex(aEdge));
138 aEdges = &aVertexToEdges.ChangeFromIndex(aVN2);
139 if (aEdges->First().IsEqual(aEdge))
141 aEdges->RemoveFirst();
145 const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
147 aEdges->Append(aEdge);
150 return (!theIsClosed && theCurve.Size() == aVCount - 1) ||
151 (theIsClosed && theCurve.Size() == aVCount);
154 template<typename TCurveType>
155 static void CurveToWire(const TCurveType& theCurve, TopoDS_Wire& theWire)
157 BRep_Builder aBulder;
158 aBulder.MakeWire(theWire);
159 for (typename TCurveType::Iterator aEIt(theCurve); aEIt.More(); aEIt.Next())
161 aBulder.Add(theWire, aEIt.Value());
165 static void CurveToWire(
166 const NCollection_Vector<TopoDS_Edge>& theEdges1,
167 const NCollection_Vector<TopoDS_Edge>& theEdges2,
168 TopoDS_Wire& theWire)
170 BRep_Builder aBulder;
171 aBulder.MakeWire(theWire);
172 const NCollection_Vector<TopoDS_Edge>* aEdges[] = {&theEdges1, &theEdges2};
173 for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
175 NCollection_Vector<TopoDS_Edge>::Iterator aEIt(*aEdges[aEI]);
176 for (; aEIt.More(); aEIt.Next())
178 aBulder.Add(theWire, aEIt.Value());
183 static Standard_Real ProjectPointToCurve(
184 const gp_Pnt& thePoint,
185 const Adaptor3d_Curve& theCurve,
186 Standard_Real& theParameter)
188 Extrema_ExtPC aAlgo(thePoint, theCurve);
189 Standard_Integer aMinEN = -2;
190 Standard_Real aMinSqDist = DBL_MAX;
193 const Standard_Integer aECount = aAlgo.NbExt();
194 for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN)
196 const gp_Pnt& aP = aAlgo.Point(aEN).Value();
197 const Standard_Real aSqDist = thePoint.SquareDistance(aP);
198 if (aMinSqDist > aSqDist)
200 aMinSqDist = aSqDist;
206 const Standard_Real aParams[] =
207 {theCurve.FirstParameter(), theCurve.LastParameter()};
208 const gp_Pnt aEnds[] =
209 {theCurve.Value(aParams[0]), theCurve.Value(aParams[1])};
210 const Standard_Real aSqDists[] =
211 {thePoint.SquareDistance(aEnds[0]), thePoint.SquareDistance(aEnds[1])};
212 for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
214 if (aMinSqDist > aSqDists[aEI])
216 aMinSqDist = aSqDists[aEI];
223 theParameter = aParams[-aMinEN];
227 const Extrema_POnCurv& aPOnC = aAlgo.Point(aMinEN);
228 const gp_Pnt& aPoint = aPOnC.Value();
229 theParameter = aPOnC.Parameter();
230 for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
232 if (Abs(theParameter - aParams[aEI]) < Precision::PConfusion() ||
233 aPoint.SquareDistance(aEnds[aEI]) < Precision::SquareConfusion())
235 theParameter = aParams[aEI];
241 static Standard_Real ProjectPointToEdge(
242 const gp_Pnt& thePoint,
243 const TopoDS_Edge& theEdge,
244 Standard_Real& theParameter)
246 return ProjectPointToCurve(thePoint, BRepAdaptor_Curve(theEdge), theParameter);
249 static void SplitCurveByPoint(
250 const NCollection_Vector<TopoDS_Edge>& theEdges,
251 const Standard_Integer theEdgeIndex,
252 const Standard_Real theParameter,
253 NCollection_Vector<TopoDS_Edge>& theEdges1,
254 NCollection_Vector<TopoDS_Edge>& theEdges2)
256 for (Standard_Integer aEI = 0; aEI < theEdgeIndex; ++aEI)
258 theEdges1.Append(theEdges(aEI));
261 const TopoDS_Edge& aEdge = theEdges(theEdgeIndex);
262 BRepAdaptor_Curve aCurve(aEdge);
263 Standard_Integer aParamI = -1;
264 const Standard_Real aEdgeEndParams[] =
265 {aCurve.FirstParameter(), aCurve.LastParameter()};
266 if (Abs(theParameter - aEdgeEndParams[0]) < Precision::PConfusion())
270 else if (Abs(theParameter - aEdgeEndParams[1]) < Precision::PConfusion())
275 const TopAbs_Orientation aOrient = aEdge.Orientation();
276 if (aOrient == TopAbs_REVERSED)
281 NCollection_Vector<TopoDS_Edge>* aEdges = &theEdges2;
282 const Standard_Integer aECount = theEdges.Size();
285 aEdges = (theEdgeIndex == 0) ? &theEdges1 : &theEdges2;
286 aEdges->Append(ReplaceVertex(aEdge, 0));
288 else if (aParamI == 1)
290 theEdges1.Append(ReplaceVertex(aEdge, 1));
294 TopoDS_Edge aFE = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD));
295 ShapeAnalysis_TransferParametersProj aSATPP(aFE, TopoDS_Face());
296 aSATPP.SetMaxTolerance(Precision::Confusion());
297 TopoDS_Vertex aSplitV1, aSplitV2;
298 BRep_Builder().MakeVertex(
299 aSplitV1, aCurve.Value(theParameter), Precision::Confusion());
300 BRep_Builder().MakeVertex(
301 aSplitV2, aCurve.Value(theParameter), Precision::Confusion());
302 TopoDS_Edge aEParts[] = {
303 ShapeBuild_Edge().CopyReplaceVertices(aFE, TopoDS_Vertex(),
304 TopoDS::Vertex(aSplitV1.Oriented(TopAbs_REVERSED))),
305 ShapeBuild_Edge().CopyReplaceVertices(aFE, aSplitV2, TopoDS_Vertex())};
306 ShapeBuild_Edge().CopyPCurves(aEParts[0], aFE);
307 ShapeBuild_Edge().CopyPCurves(aEParts[1], aFE);
308 BRep_Builder().SameRange(aEParts[0], Standard_False);
309 BRep_Builder().SameRange(aEParts[1], Standard_False);
310 BRep_Builder().SameParameter(aEParts[0], Standard_False);
311 BRep_Builder().SameParameter(aEParts[1], Standard_False);
312 aSATPP.TransferRange(aEParts[0],
313 aEdgeEndParams[0], theParameter, Standard_False);
314 aSATPP.TransferRange(aEParts[1],
315 theParameter, aEdgeEndParams[1], Standard_False);
316 aEParts[0].Orientation(aOrient);
317 aEParts[1].Orientation(aOrient);
319 const Standard_Integer aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1;
320 theEdges1.Append(aEParts[aFirstPI]);
321 theEdges2.Append(aEParts[1 - aFirstPI]);
323 for (Standard_Integer aEI = theEdgeIndex + 1; aEI < aECount; ++aEI)
325 aEdges->Append(theEdges(aEI));
329 static void SplitCurveByPoints(
330 const NCollection_Vector<TopoDS_Edge>& theCurve,
331 const NCollection_Vector<NCollection_Sequence<Standard_Real> >& theParameters,
332 NCollection_Vector<NCollection_Vector<TopoDS_Edge> >& theSplittedCurves)
334 NCollection_Vector<TopoDS_Edge> aCurves[3];
335 aCurves[0] = theCurve;
336 Standard_Integer aCI = 0, aEI = 0;
337 NCollection_Vector<TopoDS_Edge>::Iterator aEIt(theCurve);
338 for (NCollection_Vector<NCollection_Sequence<Standard_Real> >::Iterator
339 aPLIt(theParameters); aPLIt.More(); ++aEI, aEIt.Next(), aPLIt.Next())
341 const Standard_Boolean isForward =
342 (aEIt.Value().Orientation() != TopAbs_REVERSED);
343 for (NCollection_Sequence<Standard_Real>::Iterator
344 aPIt(aPLIt.Value(), isForward); aPIt.More(); aPIt.Next())
346 const Standard_Integer aCI1 = (aCI + 1) % 3, aCI2 = (aCI + 2) % 3;
347 SplitCurveByPoint(aCurves[aCI], aEI,
348 aPIt.Value(), aCurves[aCI1], aCurves[aCI2]);
349 if (!aCurves[aCI2].IsEmpty())
351 theSplittedCurves.Append(aCurves[aCI1]);
352 aCurves[aCI].Clear();
356 aCurves[aCI1].Clear();
359 theSplittedCurves.Append(aCurves[aCI]);
362 static Standard_Integer AppendIntersectionPoint(
363 const Adaptor3d_Curve& theCurve,
364 const Standard_Real theParameter,
365 NCollection_Sequence<Standard_Real>& theParameters)
367 // Check the coincidence.
368 NCollection_Sequence<Standard_Real> aEndParams;
369 aEndParams.Append(theCurve.FirstParameter());
370 aEndParams.Append(theCurve.LastParameter());
371 NCollection_Sequence<Standard_Real>* aParams[] =
372 {&theParameters, &aEndParams};
373 const gp_Pnt aPoint = theCurve.Value(theParameter);
374 for (Standard_Integer aLI = 0; aLI < 2; ++aLI)
376 NCollection_Sequence<Standard_Real>::Iterator aPIt(*aParams[aLI]);
377 for (Standard_Integer aPI = 0; aPIt.More(); aPIt.Next(), ++aPI)
379 const Standard_Real aParam = aPIt.Value();
380 if (Abs(theParameter - aParam) < Precision::PConfusion() ||
381 aPoint.SquareDistance(theCurve.Value(aParam)) <=
382 Precision::SquareConfusion())
384 Standard_Integer aIntCount = 0;
389 theParameters.Prepend(aEndParams.First());
393 theParameters.Append(aEndParams.Last());
402 // Calculate the position to insert.
403 NCollection_Sequence<Standard_Real>::Iterator aPIt(theParameters);
404 if (aPIt.More() && aPIt.Value() < theParameter)
406 NCollection_Sequence<Standard_Real>::Iterator aPIt2 = aPIt;
408 for (; aPIt2.More() && aPIt2.Value() < theParameter;
409 aPIt.Next(), aPIt2.Next());
410 theParameters.InsertAfter(aPIt, theParameter);
414 theParameters.Prepend(theParameter);
419 static Standard_Integer IntersectEdge(
420 const TopoDS_Edge& theEdge1,
421 const TopoDS_Edge& theEdge2,
422 NCollection_Sequence<Standard_Real>& theParameters)
425 Standard_Integer aIntCount = 0;
426 BRepAdaptor_Curve aCurve1 = BRepAdaptor_Curve(theEdge1);
427 BRepAdaptor_Curve aCurve2 = BRepAdaptor_Curve(theEdge2);
428 const gp_Pnt aEndPs[] = {aCurve2.Value(aCurve2.FirstParameter()),
429 aCurve2.Value(aCurve2.LastParameter())};
430 for (Standard_Integer aPI = 0; aPI < 2; ++aPI)
432 Standard_Real aParameter;
433 if (ProjectPointToCurve(aEndPs[aPI], aCurve1, aParameter) <=
434 Precision::SquareConfusion())
436 AppendIntersectionPoint(aCurve1, aParameter, theParameters);
440 // Process the internal extrema.
441 Extrema_ExtCC aAlgo(aCurve1, aCurve2);
444 const Standard_Integer aECount = aAlgo.NbExt();
445 for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN)
447 Extrema_POnCurv aP1, aP2;
448 aAlgo.Points(aEN, aP1, aP2);
449 if (aP1.Value().SquareDistance(aP2.Value()) <=
450 Precision::SquareConfusion())
452 AppendIntersectionPoint(aCurve1, aP1.Parameter(), theParameters);
459 static Standard_Integer IntersectCurve(
460 const NCollection_Vector<TopoDS_Edge>& theEdges,
461 const TopoDS_Wire& theWire,
462 NCollection_Vector<NCollection_Sequence<Standard_Real> >& theParameters)
464 Standard_Integer aIntCount = 0;
465 const Standard_Integer aECount1 = theEdges.Size();
466 for (Standard_Integer aEI1 = 0; aEI1 < aECount1; ++aEI1)
468 const TopoDS_Edge& aEdge1 = theEdges(aEI1);
469 TopExp_Explorer aEIt2(theWire, TopAbs_EDGE);
470 for (; aEIt2.More(); aEIt2.Next())
472 aIntCount += IntersectEdge(aEdge1,
473 TopoDS::Edge(aEIt2.Current()), theParameters(aEI1));
479 static void CloseCurve(NCollection_Sequence<TopoDS_Edge>& theCurve)
481 const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex(
482 theCurve.Last(), Standard_True).Oriented(TopAbs_FORWARD));
483 const TopoDS_Edge& aEdge = theCurve.First();
484 const TopoDS_Edge aForwardEdge = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD));
485 theCurve.ChangeFirst() = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices(
486 aForwardEdge, aVertex, TopoDS_Vertex()).Oriented(aEdge.Orientation()));
489 static Standard_Boolean IsClosed(
490 const NCollection_Sequence<TopoDS_Edge>& theCurve)
492 return TopExp::FirstVertex(theCurve.First(), Standard_True).
493 IsSame(TopExp::LastVertex(theCurve.Last(), Standard_True));
496 static void ExtendCurve(
497 const Standard_Integer thePosition,
498 NCollection_Sequence<TopoDS_Edge>& theCurve,
499 NCollection_Sequence<TopoDS_Edge>& theExtension)
501 if (thePosition == 0)
503 const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex(
504 theExtension.Last(), Standard_True).Oriented(TopAbs_FORWARD));
505 TopoDS_Edge& aEdge = theCurve.ChangeFirst();
506 aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices(
507 TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), aVertex, TopoDS_Vertex()).
508 Oriented(aEdge.Orientation()));
509 theCurve.Prepend(theExtension);
513 const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::FirstVertex(
514 theExtension.First(), Standard_True).Oriented(TopAbs_REVERSED));
515 TopoDS_Edge& aEdge = theCurve.ChangeLast();
516 aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices(
517 TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), TopoDS_Vertex(), aVertex).
518 Oriented(aEdge.Orientation()));
519 theCurve.Append(theExtension);
523 static void ExtendCurve(
524 const Standard_Integer thePosition,
525 const TopoDS_Edge& theExtension,
526 NCollection_Sequence<TopoDS_Edge>& theCurve)
528 NCollection_Sequence<TopoDS_Edge> aExtension;
529 aExtension.Append(theExtension);
530 ExtendCurve(thePosition, theCurve, aExtension);
533 static gp_XYZ Tangent(
534 const Adaptor3d_Curve& theCurve, const Standard_Integer thePosition)
536 const Standard_Real aParam = (thePosition == 0) ?
537 theCurve.FirstParameter() : theCurve.LastParameter();
540 theCurve.D1(aParam, aP, aV);
541 Standard_Real aNorm = aV.Magnitude();
542 aNorm = (aNorm >= Precision::PConfusion()) ? aNorm : 0;
543 return ((1 / aNorm) * aV).XYZ();
546 static gp_XYZ Tangent(
547 const TopoDS_Edge& theEdge, const Standard_Integer thePosition)
549 BRepAdaptor_Curve aCurve(theEdge);
550 return Tangent(BRepAdaptor_Curve(theEdge), thePosition);
553 static Standard_Boolean Interpolate(
554 const gp_Pnt thePoint1,
555 const gp_Pnt thePoint2,
556 const gp_Vec theTangent1,
557 const gp_Vec theTangent2,
558 Handle(Geom_BSplineCurve)& theBSpline)
560 Handle(TColgp_HArray1OfPnt) aPs = new TColgp_HArray1OfPnt(1, 2);
561 TColgp_Array1OfVec aTs(1, 2);
562 Handle(TColStd_HArray1OfBoolean) aTFs = new TColStd_HArray1OfBoolean(1, 2);
563 aPs->SetValue(1, thePoint1);
564 aPs->SetValue(2, thePoint2);
565 aTs.SetValue(1, theTangent1);
566 aTs.SetValue(2, theTangent2);
567 aTFs->SetValue(1, Standard_True);
568 aTFs->SetValue(2, Standard_True);
569 GeomAPI_Interpolate aInterpolator(aPs, Standard_False, 0);
570 aInterpolator.Load(aTs, aTFs, Standard_False);
571 aInterpolator.Perform();
572 const Standard_Boolean aResult = (aInterpolator.IsDone() == Standard_True);
575 theBSpline = aInterpolator.Curve();
580 static Standard_Boolean Merge(
581 const TopoDS_Wire& theWire,
582 const Standard_Real theTolerance,
583 NCollection_Vector<NCollection_Sequence<TopoDS_Edge> >& theMergedCurves)
585 NCollection_Sequence<TopoDS_Edge> aCurve;
586 Standard_Boolean isClosed;
587 if (!WireToCurve(theWire, aCurve, isClosed))
589 return Standard_False;
594 theMergedCurves.Append(aCurve);
595 return Standard_True;
598 const Standard_Real aSqTol = theTolerance * theTolerance;
599 const gp_Pnt aPs[] = {
600 BRep_Tool::Pnt(TopExp::FirstVertex(aCurve.First(), Standard_True)),
601 BRep_Tool::Pnt(TopExp::LastVertex(aCurve.Last(), Standard_True))};
602 if (!isClosed && aPs[0].SquareDistance(aPs[1]) <= aSqTol)
605 theMergedCurves.Append(aCurve);
606 return Standard_True;
609 NCollection_Sequence<TopoDS_Edge>* aCurves[] = {NULL, NULL};
610 Standard_Integer aOrder = 0;
611 for (NCollection_Vector<NCollection_Sequence<TopoDS_Edge> >::Iterator
612 aCIt(theMergedCurves); aCIt.More(); aCIt.Next())
614 NCollection_Sequence<TopoDS_Edge>& aC = aCIt.ChangeValue();
615 if (aC.IsEmpty() || IsClosed(aC))
621 BRep_Tool::Pnt(TopExp::FirstVertex(aC.First(), Standard_True));
622 if (aCurves[0] == NULL && aP1.SquareDistance(aPs[1]) <= aSqTol)
628 BRep_Tool::Pnt(TopExp::LastVertex(aC.Last(), Standard_True));
629 if (aCurves[1] == NULL && aP2.SquareDistance(aPs[0]) <= aSqTol)
632 aOrder = (aCurves[0] == NULL) ? 1 : 0;
636 if (aCurves[0] == NULL && aCurves[1] == NULL)
638 theMergedCurves.Append(aCurve);
640 else if (aCurves[1] == NULL)
642 ExtendCurve(0, *aCurves[0], aCurve);
644 else if (aCurves[0] == NULL)
646 ExtendCurve(1, *aCurves[1], aCurve);
650 ExtendCurve(aOrder, *aCurves[aOrder], aCurve);
651 if (aCurves[0] != aCurves[1])
653 ExtendCurve(aOrder, *aCurves[aOrder], *aCurves[1 - aOrder]);
657 CloseCurve(*aCurves[aOrder]);
660 return Standard_True;
663 static Standard_Boolean Connect(
664 const TopoDS_Wire& theWire,
665 const Standard_Real theTolerance,
666 NCollection_Vector<NCollection_Sequence<TopoDS_Edge> >& theMergedCurves)
668 NCollection_Sequence<TopoDS_Edge> aCurve;
669 Standard_Boolean isClosed;
670 if (!WireToCurve(theWire, aCurve, isClosed))
672 return Standard_False;
677 theMergedCurves.Append(aCurve);
678 return Standard_True;
681 const Standard_Real aSqTol = theTolerance * theTolerance;
682 const gp_Pnt aPs[] = {
683 BRep_Tool::Pnt(TopExp::FirstVertex(aCurve.First(), Standard_True)),
684 BRep_Tool::Pnt(TopExp::LastVertex(aCurve.Last(), Standard_True))};
685 if (!isClosed && aPs[0].SquareDistance(aPs[1]) <= aSqTol)
688 theMergedCurves.Append(aCurve);
689 return Standard_True;
692 for (NCollection_Vector<NCollection_Sequence<TopoDS_Edge> >::Iterator
693 aCIt(theMergedCurves); aCIt.More(); aCIt.Next())
695 NCollection_Sequence<TopoDS_Edge>& aCurve2 = aCIt.ChangeValue();
696 if (aCurve2.IsEmpty() || IsClosed(aCurve2))
701 const TopoDS_Edge* aEdges2[] = {&aCurve2.First(), &aCurve2.Last()};
702 const gp_Pnt aPs2[] = {
703 BRep_Tool::Pnt(TopExp::FirstVertex(*aEdges2[0], Standard_True)),
704 BRep_Tool::Pnt(TopExp::LastVertex(*aEdges2[1], Standard_True))};
705 const Standard_Real aSqDists[] =
706 {aPs2[0].SquareDistance(aPs[1]), aPs2[1].SquareDistance(aPs[0])};
707 const Standard_Integer aOrder = (aSqDists[0] <= aSqDists[1]) ? 0 : 1;
708 if (aSqDists[aOrder] > aSqTol)
710 const TopoDS_Edge& aEdge = (aOrder == 0) ? aCurve.Last() : aCurve.First();
711 const gp_Pnt aPs3[] = {aPs[1 - aOrder], aPs2[aOrder]};
713 {Tangent(aEdge, 1 - aOrder), Tangent(*aEdges2[aOrder], aOrder)};
714 Handle(Geom_BSplineCurve) aBSpline;
715 if (!Interpolate(aPs3[aOrder], aPs3[1 - aOrder],
716 aTs[aOrder], aTs[1 - aOrder], aBSpline))
718 return Standard_False;
721 ExtendCurve(aOrder, BRepBuilderAPI_MakeEdge(aBSpline), aCurve2);
723 ExtendCurve(aOrder, aCurve2, aCurve);
724 if (aSqDists[1 - aOrder] <= aSqTol)
728 return Standard_True;
731 theMergedCurves.Append(aCurve);
732 return Standard_True;
735 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
736 const Handle( HYDROData_PolylineXY )& thePolyline,
737 const gp_Pnt2d& thePoint,
738 double theTolerance ) const
740 std::vector<gp_Pnt2d> aPointsList( 1 );
741 aPointsList[0] = thePoint;
742 std::vector<TopoDS_Wire> aCurves = GetWires( thePolyline );
744 for( int i=0, n=aCurves.size(); i<n; i++ )
746 std::vector<TopoDS_Shape> aCurvesList = Split( aCurves[i], thePoint, theTolerance );
747 bool isLocalOK = CreatePolylines( theDoc, thePolyline->GetName(), aCurvesList, true );
748 isOK = isOK && isLocalOK;
753 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
754 const Handle( HYDROData_PolylineXY )& thePolyline,
755 const Handle( HYDROData_PolylineXY )& theTool,
756 double theTolerance ) const
758 HYDROData_SequenceOfObjects aSeq;
759 aSeq.Append( theTool );
760 return split( theDoc, thePolyline, aSeq, theTolerance, -1 );
763 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
764 const HYDROData_SequenceOfObjects& thePolylines,
765 double theTolerance )
767 int f = thePolylines.Lower(), l = thePolylines.Upper();
768 for( int i=f; i<=l; i++ )
770 Handle( HYDROData_PolylineXY ) aPolyline = Handle( HYDROData_PolylineXY )::DownCast( thePolylines.Value( i ) );
771 if( !split( theDoc, aPolyline, thePolylines, theTolerance, i ) )
777 bool HYDROData_PolylineOperator::Merge( const Handle( HYDROData_Document )& theDoc,
778 const QString& theName,
779 const HYDROData_SequenceOfObjects& thePolylines,
780 bool isConnectByNewSegment,
781 double theTolerance )
783 NCollection_Vector<NCollection_Sequence<TopoDS_Edge> > aMergedCurves;
784 HYDROData_SequenceOfObjects::Iterator aPIt(thePolylines);
785 for (; aPIt.More(); aPIt.Next())
787 Handle(HYDROData_PolylineXY) aPolyline =
788 Handle(HYDROData_PolylineXY)::DownCast(aPIt.Value());
789 std::vector<TopoDS_Wire> aWires = GetWires(aPolyline);
790 for (std::vector<TopoDS_Wire>::const_iterator aWIt = aWires.begin(),
791 aLastWIt = aWires.end(); aWIt != aLastWIt; ++aWIt)
793 const Standard_Boolean aResult = !isConnectByNewSegment ?
794 ::Merge(*aWIt, theTolerance, aMergedCurves) :
795 Connect(*aWIt, theTolerance, aMergedCurves);
803 TopoDS_Compound aWireSet;
804 BRep_Builder aBuilder;
805 aBuilder.MakeCompound(aWireSet);
806 for (NCollection_Vector<NCollection_Sequence<TopoDS_Edge> >::Iterator
807 aCIt(aMergedCurves); aCIt.More(); aCIt.Next())
809 if (!aCIt.Value().IsEmpty())
812 CurveToWire(aCIt.Value(), aWire);
813 aBuilder.Add(aWireSet, aWire);
817 std::vector<TopoDS_Shape> aPolylines(1);
818 aPolylines[0] = aWireSet;
819 CreatePolylines(theDoc, theName, aPolylines, false);
823 bool HYDROData_PolylineOperator::split( const Handle( HYDROData_Document )& theDoc,
824 const Handle( HYDROData_PolylineXY )& thePolyline,
825 const HYDROData_SequenceOfObjects& theTools,
827 int theIgnoreIndex ) const
829 std::vector<TopoDS_Wire> aCurves = GetWires( thePolyline );
830 std::vector<TopoDS_Wire> aToolCurves;
831 for( int i=theTools.Lower(), n=theTools.Upper(); i<=n; i++ )
832 if( i!=theIgnoreIndex )
834 Handle( HYDROData_PolylineXY ) aToolPolyline =
835 Handle( HYDROData_PolylineXY )::DownCast( theTools.Value( i ) );
836 append( aToolCurves, GetWires( aToolPolyline ) );
839 const int aPSCount = aCurves.size();
840 const int aTSCount = aToolCurves.size();
841 std::vector<TopoDS_Shape> aResult;
842 for (int aPSI = 0; aPSI < aPSCount; ++aPSI)
844 NCollection_Vector<TopoDS_Edge> aCurve;
845 Standard_Boolean aIsClosed;
846 if (!WireToCurve(aCurves[aPSI], aCurve, aIsClosed))
851 NCollection_Vector<NCollection_Sequence<Standard_Real> > aParams;
852 aParams.SetValue(aCurve.Size() - 1, NCollection_Sequence<Standard_Real>());
853 for (int aTSI = 0; aTSI < aTSCount; ++aTSI)
855 IntersectCurve(aCurve, aToolCurves[aTSI], aParams);
858 NCollection_Vector<NCollection_Vector<TopoDS_Edge> > aSplittedCurves;
859 SplitCurveByPoints(aCurve, aParams, aSplittedCurves);
861 Standard_Boolean aIsClosed2 = aIsClosed;
864 const NCollection_Sequence<Standard_Real>& aPs = aParams.First();
867 const TopoDS_Edge& aEdge = aCurve.First();
868 const Standard_Boolean isForward =
869 (aEdge.Orientation() != TopAbs_REVERSED);
870 const Standard_Real aParam = isForward ? aPs.First() : aPs.Last();
871 BRepAdaptor_Curve aCurve(aEdge);
872 const Standard_Real aEndParam = isForward ?
873 aCurve.FirstParameter() : aCurve.LastParameter();
874 aIsClosed2 = (Abs(aParam - aEndParam) > Precision::PConfusion());
879 const NCollection_Sequence<Standard_Real>& aPs = aParams.Last();
882 const TopoDS_Edge& aEdge = aCurve.Last();
883 const Standard_Boolean isForward =
884 (aEdge.Orientation() != TopAbs_REVERSED);
885 const Standard_Real aParam = isForward ? aPs.Last() : aPs.First();
886 BRepAdaptor_Curve aCurve(aEdge);
887 const Standard_Real aEndParam = isForward ?
888 aCurve.LastParameter() : aCurve.FirstParameter();
889 aIsClosed2 = (Abs(aParam - aEndParam) >= Precision::PConfusion());
894 Standard_Integer aFSCI = 0, aLSCI = aSplittedCurves.Size() - 1;
895 if (aIsClosed2 && aFSCI < aLSCI)
898 CurveToWire(aSplittedCurves(aLSCI), aSplittedCurves(aFSCI), aWire);
899 aResult.push_back(aWire);
904 for (Standard_Integer aSCI = aFSCI; aSCI <= aLSCI; ++aSCI)
907 CurveToWire(aSplittedCurves(aSCI), aWire);
908 aResult.push_back(aWire);
912 CreatePolylines(theDoc, thePolyline->GetName(), aResult, true);
916 std::vector<TopoDS_Wire> HYDROData_PolylineOperator::GetWires( const Handle( HYDROData_PolylineXY )& thePolyline )
918 std::vector<TopoDS_Wire> aResult;
920 TopoDS_Shape aShape = thePolyline->GetShape();
922 if( aShape.ShapeType()==TopAbs_WIRE )
924 aResult.push_back( TopoDS::Wire( aShape ) );
928 TopExp_Explorer anExp( aShape, TopAbs_WIRE );
929 for( ; anExp.More(); anExp.Next() )
931 aResult.push_back( TopoDS::Wire( anExp.Current() ) );
937 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const TopoDS_Wire& theWire,
938 const gp_Pnt2d& thePoint,
939 double theTolerance )
941 std::vector<TopoDS_Shape> aResult;
942 NCollection_Vector<TopoDS_Edge> aEdges;
943 Standard_Boolean isClosed;
944 if (!WireToCurve(theWire, aEdges, isClosed))
946 aResult.push_back(theWire);
950 const gp_Pnt aP(thePoint.X(), thePoint.Y(), 0);
951 Standard_Real aMinSqDist = DBL_MAX;
953 Standard_Real aSParam;
954 for (int aECount = aEdges.Size(), aEI = 0; aEI < aECount; ++aEI)
956 Standard_Real aParam;
957 const Standard_Real aSqDist =
958 ProjectPointToEdge(aP, aEdges(aEI), aParam);
959 if (aMinSqDist > aSqDist)
961 aMinSqDist = aSqDist;
967 NCollection_Vector<TopoDS_Edge> aEdges1, aEdges2;
968 SplitCurveByPoint(aEdges, aSEI, aSParam, aEdges1, aEdges2);
972 CurveToWire(aEdges1, aWire);
973 if (!aEdges2.IsEmpty())
975 aResult.push_back(aWire);
976 CurveToWire(aEdges2, aWire);
981 if (!aEdges2.IsEmpty())
983 CurveToWire(aEdges2, aEdges1, aWire);
987 CurveToWire(aEdges1, aWire);
990 aResult.push_back(aWire);
994 bool HYDROData_PolylineOperator::CreatePolylines( const Handle( HYDROData_Document )& theDoc,
995 const QString& theNamePrefix,
996 const std::vector<TopoDS_Shape>& theShapes,
999 if( theDoc.IsNull() )
1002 int n = theShapes.size();
1004 for( int i=0; i<n; i++ )
1006 Handle( HYDROData_PolylineXY ) aPolyline =
1007 Handle( HYDROData_PolylineXY )::DownCast( theDoc->CreateObject( KIND_POLYLINEXY ) );
1008 if( aPolyline.IsNull() )
1011 aPolyline->SetShape( theShapes[i] );
1015 QString aNewName = theNamePrefix + "_" + QString::number( anIndex );
1016 if( theDoc->FindObjectByName( aNewName ).IsNull() ) // the object with such a name is not found
1017 aPolyline->SetName( aNewName );
1022 aPolyline->SetName( theNamePrefix );