From c9bbaf3e757559646f7b9aefea06ef56fe919f0e Mon Sep 17 00:00:00 2001 From: abk Date: Tue, 7 Jul 2015 15:17:54 +0300 Subject: [PATCH] Algorithms to convert 'TopoDS_Wire' object to a wire composed of B-spline edges were created. An automatic conversion of each complex polyline to polyline composed of spline section was created based on these algorithms. The deflection of the conversion is uncontrolled now. The data structures and the algorithms to work with the topological curves were formed as class 'HYDROData_TopoCurve'. --- src/HYDROData/CMakeLists.txt | 6 +- src/HYDROData/HYDROData_PolylineOperator.cxx | 858 ++---------------- src/HYDROData/HYDROData_PolylineOperator.h | 14 +- src/HYDROData/HYDROData_TopoCurve.cxx | 894 +++++++++++++++++++ src/HYDROData/HYDROData_TopoCurve.h | 179 ++++ src/HYDROGUI/HYDROGUI_PolylineOp.cxx | 81 +- 6 files changed, 1208 insertions(+), 824 deletions(-) create mode 100644 src/HYDROData/HYDROData_TopoCurve.cxx create mode 100644 src/HYDROData/HYDROData_TopoCurve.h diff --git a/src/HYDROData/CMakeLists.txt b/src/HYDROData/CMakeLists.txt index dfa8bf1b..fd9899d4 100644 --- a/src/HYDROData/CMakeLists.txt +++ b/src/HYDROData/CMakeLists.txt @@ -43,8 +43,9 @@ set(PROJECT_HEADERS HYDROData_Stream.h HYDROData_StreamAltitude.h HYDROData_StricklerTable.h - HYDROData_LandCover.h + HYDROData_LandCover.h HYDROData_Tool.h + HYDROData_TopoCurve.h HYDROData_Transform.h HYDROData_VisualState.h HYDROData_Warning.h @@ -99,8 +100,9 @@ set(PROJECT_SOURCES HYDROData_Stream.cxx HYDROData_StreamAltitude.cxx HYDROData_StricklerTable.cxx - HYDROData_LandCover.cxx + HYDROData_LandCover.cxx HYDROData_Tool.cxx + HYDROData_TopoCurve.cxx HYDROData_Transform.cxx HYDROData_VisualState.cxx HYDROData_Zone.cxx diff --git a/src/HYDROData/HYDROData_PolylineOperator.cxx b/src/HYDROData/HYDROData_PolylineOperator.cxx index ac75dcd8..4326e525 100644 --- a/src/HYDROData/HYDROData_PolylineOperator.cxx +++ b/src/HYDROData/HYDROData_PolylineOperator.cxx @@ -17,6 +17,7 @@ // #include +#include #include #include #include @@ -55,683 +56,6 @@ template void append( std::vector& theList, const std::vector& th theList[i] = theList2[j]; } -static TopoDS_Edge ReplaceVertex( - const TopoDS_Edge& theEdge, Standard_Integer theVertexIndex) -{ - TopoDS_Vertex aVertices[] = - {TopExp::FirstVertex(theEdge), TopExp::LastVertex(theEdge)}; - const TopAbs_Orientation aOrient = theEdge.Orientation(); - if (aOrient == TopAbs_REVERSED) - { - theVertexIndex ^= 1; - } - aVertices[theVertexIndex].EmptyCopy(); - aVertices[0].Orientation(TopAbs_FORWARD); - aVertices[1].Orientation(TopAbs_REVERSED); - TopoDS_Edge aFE = TopoDS::Edge(theEdge.Oriented(TopAbs_FORWARD)); - TopoDS_Edge aNewEdge = - ShapeBuild_Edge().CopyReplaceVertices(aFE, aVertices[0], aVertices[1]); - return TopoDS::Edge(aNewEdge.Oriented(aOrient)); -} - -template -static Standard_Boolean WireToCurve( - const TopoDS_Wire& theWire, - TCurveType& theCurve, - Standard_Boolean& theIsClosed) -{ - TopTools_IndexedDataMapOfShapeListOfShape aVertexToEdges; - TopExp::MapShapesAndAncestors(theWire, - TopAbs_VERTEX, TopAbs_EDGE, aVertexToEdges); - const Standard_Integer aVCount = aVertexToEdges.Extent(); - if (aVCount == 0) - { - return Standard_False; - } - - { - Standard_Integer aEndCount = 0; - for (Standard_Integer aVN = 1; aVN <= aVCount; ++aVN) - { - const Standard_Integer aEdgeCount = - aVertexToEdges.FindFromIndex(aVN).Extent(); - if (aEdgeCount == 1) - { - ++aEndCount; - } - if (aEdgeCount > 2) - { - return Standard_False; - } - } - theIsClosed = (aEndCount == 0); - if (!theIsClosed && aEndCount != 2) - { - return Standard_False; - } - } - - Standard_Integer aVN = 1; - if (!theIsClosed) - { - while (aVN <= aVCount && - aVertexToEdges.FindFromIndex(aVN).Extent() == 2) - { - ++aVN; - } - } - - TopTools_ListOfShape* aEdges = &aVertexToEdges.ChangeFromIndex(aVN); - while (!aEdges->IsEmpty()) - { - const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First()); - aEdges->RemoveFirst(); - theCurve.Append(aEdge); - Standard_Integer aVN2 = - aVertexToEdges.FindIndex(TopExp::FirstVertex(aEdge)); - if (aVN2 == aVN) - { - aVN2 = aVertexToEdges.FindIndex(TopExp::LastVertex(aEdge)); - } - aVN = aVN2; - - aEdges = &aVertexToEdges.ChangeFromIndex(aVN2); - if (aEdges->First().IsEqual(aEdge)) - { - aEdges->RemoveFirst(); - } - else - { - const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First()); - aEdges->Clear(); - aEdges->Append(aEdge); - } - } - return (!theIsClosed && theCurve.Size() == aVCount - 1) || - (theIsClosed && theCurve.Size() == aVCount); -} - -template -static void CurveToWire(const TCurveType& theCurve, TopoDS_Wire& theWire) -{ - BRep_Builder aBulder; - aBulder.MakeWire(theWire); - for (TCurveType::Iterator aEIt(theCurve); aEIt.More(); aEIt.Next()) - { - aBulder.Add(theWire, aEIt.Value()); - } -} - -static void CurveToWire( - const NCollection_Vector& theEdges1, - const NCollection_Vector& theEdges2, - TopoDS_Wire& theWire) -{ - BRep_Builder aBulder; - aBulder.MakeWire(theWire); - const NCollection_Vector* aEdges[] = {&theEdges1, &theEdges2}; - for (Standard_Integer aEI = 0; aEI < 2; ++aEI) - { - NCollection_Vector::Iterator aEIt(*aEdges[aEI]); - for (; aEIt.More(); aEIt.Next()) - { - aBulder.Add(theWire, aEIt.Value()); - } - } -} - -static Standard_Real ProjectPointToCurve( - const gp_Pnt& thePoint, - const Adaptor3d_Curve& theCurve, - Standard_Real& theParameter) -{ - Extrema_ExtPC aAlgo(thePoint, theCurve); - Standard_Integer aMinEN = -2; - Standard_Real aMinSqDist = DBL_MAX; - if (aAlgo.IsDone()) - { - const Standard_Integer aECount = aAlgo.NbExt(); - for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN) - { - const gp_Pnt& aP = aAlgo.Point(aEN).Value(); - const Standard_Real aSqDist = thePoint.SquareDistance(aP); - if (aMinSqDist > aSqDist) - { - aMinSqDist = aSqDist; - aMinEN = aEN; - } - } - } - - const Standard_Real aParams[] = - {theCurve.FirstParameter(), theCurve.LastParameter()}; - const gp_Pnt aEnds[] = - {theCurve.Value(aParams[0]), theCurve.Value(aParams[1])}; - const Standard_Real aSqDists[] = - {thePoint.SquareDistance(aEnds[0]), thePoint.SquareDistance(aEnds[1])}; - for (Standard_Integer aEI = 0; aEI < 2; ++aEI) - { - if (aMinSqDist > aSqDists[aEI]) - { - aMinSqDist = aSqDists[aEI]; - aMinEN = -aEI; - } - } - - if (aMinEN <= 0) - { - theParameter = aParams[-aMinEN]; - return aMinSqDist; - } - - const Extrema_POnCurv& aPOnC = aAlgo.Point(aMinEN); - const gp_Pnt& aPoint = aPOnC.Value(); - theParameter = aPOnC.Parameter(); - for (Standard_Integer aEI = 0; aEI < 2; ++aEI) - { - if (Abs(theParameter - aParams[aEI]) < Precision::PConfusion() || - aPoint.SquareDistance(aEnds[aEI]) < Precision::SquareConfusion()) - { - theParameter = aParams[aEI]; - } - } - return aMinSqDist; -} - -static Standard_Real ProjectPointToEdge( - const gp_Pnt& thePoint, - const TopoDS_Edge& theEdge, - Standard_Real& theParameter) -{ - return ProjectPointToCurve(thePoint, BRepAdaptor_Curve(theEdge), theParameter); -} - -static void SplitCurveByPoint( - const NCollection_Vector& theEdges, - const Standard_Integer theEdgeIndex, - const Standard_Real theParameter, - NCollection_Vector& theEdges1, - NCollection_Vector& theEdges2) -{ - for (Standard_Integer aEI = 0; aEI < theEdgeIndex; ++aEI) - { - theEdges1.Append(theEdges(aEI)); - } - - const TopoDS_Edge& aEdge = theEdges(theEdgeIndex); - BRepAdaptor_Curve aCurve(aEdge); - Standard_Integer aParamI = -1; - const Standard_Real aEdgeEndParams[] = - {aCurve.FirstParameter(), aCurve.LastParameter()}; - if (Abs(theParameter - aEdgeEndParams[0]) < Precision::PConfusion()) - { - aParamI = 0; - } - else if (Abs(theParameter - aEdgeEndParams[1]) < Precision::PConfusion()) - { - aParamI = 1; - } - - const TopAbs_Orientation aOrient = aEdge.Orientation(); - if (aOrient == TopAbs_REVERSED) - { - aParamI ^= 1; - } - - NCollection_Vector* aEdges = &theEdges2; - const Standard_Integer aECount = theEdges.Size(); - if (aParamI == 0) - { - aEdges = (theEdgeIndex == 0) ? &theEdges1 : &theEdges2; - aEdges->Append(ReplaceVertex(aEdge, 0)); - } - else if (aParamI == 1) - { - theEdges1.Append(ReplaceVertex(aEdge, 1)); - } - else - { - TopoDS_Edge aFE = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)); - ShapeAnalysis_TransferParametersProj aSATPP(aFE, TopoDS_Face()); - aSATPP.SetMaxTolerance(Precision::Confusion()); - TopoDS_Vertex aSplitV1, aSplitV2; - BRep_Builder().MakeVertex( - aSplitV1, aCurve.Value(theParameter), Precision::Confusion()); - BRep_Builder().MakeVertex( - aSplitV2, aCurve.Value(theParameter), Precision::Confusion()); - TopoDS_Edge aEParts[] = { - ShapeBuild_Edge().CopyReplaceVertices(aFE, TopoDS_Vertex(), - TopoDS::Vertex(aSplitV1.Oriented(TopAbs_REVERSED))), - ShapeBuild_Edge().CopyReplaceVertices(aFE, aSplitV2, TopoDS_Vertex())}; - ShapeBuild_Edge().CopyPCurves(aEParts[0], aFE); - ShapeBuild_Edge().CopyPCurves(aEParts[1], aFE); - BRep_Builder().SameRange(aEParts[0], Standard_False); - BRep_Builder().SameRange(aEParts[1], Standard_False); - BRep_Builder().SameParameter(aEParts[0], Standard_False); - BRep_Builder().SameParameter(aEParts[1], Standard_False); - aSATPP.TransferRange(aEParts[0], - aEdgeEndParams[0], theParameter, Standard_False); - aSATPP.TransferRange(aEParts[1], - theParameter, aEdgeEndParams[1], Standard_False); - aEParts[0].Orientation(aOrient); - aEParts[1].Orientation(aOrient); - - const Standard_Integer aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1; - theEdges1.Append(aEParts[aFirstPI]); - theEdges2.Append(aEParts[1 - aFirstPI]); - } - for (Standard_Integer aEI = theEdgeIndex + 1; aEI < aECount; ++aEI) - { - aEdges->Append(theEdges(aEI)); - } -} - -static void SplitCurveByPoints( - const NCollection_Vector& theCurve, - const NCollection_Vector >& theParameters, - NCollection_Vector >& theSplittedCurves) -{ - NCollection_Vector aCurves[3]; - aCurves[0] = theCurve; - Standard_Integer aCI = 0, aEI = 0; - NCollection_Vector::Iterator aEIt(theCurve); - for (NCollection_Vector >::Iterator - aPLIt(theParameters); aPLIt.More(); ++aEI, aEIt.Next(), aPLIt.Next()) - { - const Standard_Boolean isForward = - (aEIt.Value().Orientation() != TopAbs_REVERSED); - for (NCollection_Sequence::Iterator - aPIt(aPLIt.Value(), isForward); aPIt.More(); aPIt.Next()) - { - const Standard_Integer aCI1 = (aCI + 1) % 3, aCI2 = (aCI + 2) % 3; - SplitCurveByPoint(aCurves[aCI], aEI, - aPIt.Value(), aCurves[aCI1], aCurves[aCI2]); - if (!aCurves[aCI2].IsEmpty()) - { - theSplittedCurves.Append(aCurves[aCI1]); - aCurves[aCI].Clear(); - aCI = aCI2; - aEI = 0; - } - aCurves[aCI1].Clear(); - } - } - theSplittedCurves.Append(aCurves[aCI]); -} - -static Standard_Integer AppendIntersectionPoint( - const Adaptor3d_Curve& theCurve, - const Standard_Real theParameter, - NCollection_Sequence& theParameters) -{ - // Check the coincidence. - NCollection_Sequence aEndParams; - aEndParams.Append(theCurve.FirstParameter()); - aEndParams.Append(theCurve.LastParameter()); - NCollection_Sequence* aParams[] = - {&theParameters, &aEndParams}; - const gp_Pnt aPoint = theCurve.Value(theParameter); - for (Standard_Integer aLI = 0; aLI < 2; ++aLI) - { - NCollection_Sequence::Iterator aPIt(*aParams[aLI]); - for (Standard_Integer aPI = 0; aPIt.More(); aPIt.Next(), ++aPI) - { - const Standard_Real aParam = aPIt.Value(); - if (Abs(theParameter - aParam) < Precision::PConfusion() || - aPoint.SquareDistance(theCurve.Value(aParam)) <= - Precision::SquareConfusion()) - { - Standard_Integer aIntCount = 0; - if (aLI != 0) - { - if (aPI == 0) - { - theParameters.Prepend(aEndParams.First()); - } - else - { - theParameters.Append(aEndParams.Last()); - } - ++aIntCount; - } - return aIntCount; - } - } - } - - // Calculate the position to insert. - NCollection_Sequence::Iterator aPIt(theParameters); - if (aPIt.More() && aPIt.Value() < theParameter) - { - NCollection_Sequence::Iterator aPIt2 = aPIt; - aPIt2.Next(); - for (; aPIt2.More() && aPIt2.Value() < theParameter; - aPIt.Next(), aPIt2.Next()); - theParameters.InsertAfter(aPIt, theParameter); - } - else - { - theParameters.Prepend(theParameter); - } - return 1; -} - -static Standard_Integer IntersectEdge( - const TopoDS_Edge& theEdge1, - const TopoDS_Edge& theEdge2, - NCollection_Sequence& theParameters) -{ - // Process the ends. - Standard_Integer aIntCount = 0; - BRepAdaptor_Curve aCurve1 = BRepAdaptor_Curve(theEdge1); - BRepAdaptor_Curve aCurve2 = BRepAdaptor_Curve(theEdge2); - const gp_Pnt aEndPs[] = {aCurve2.Value(aCurve2.FirstParameter()), - aCurve2.Value(aCurve2.LastParameter())}; - for (Standard_Integer aPI = 0; aPI < 2; ++aPI) - { - Standard_Real aParameter; - if (ProjectPointToCurve(aEndPs[aPI], aCurve1, aParameter) <= - Precision::SquareConfusion()) - { - AppendIntersectionPoint(aCurve1, aParameter, theParameters); - } - } - - // Process the internal extrema. - Extrema_ExtCC aAlgo(aCurve1, aCurve2); - if (aAlgo.IsDone()) - { - const Standard_Integer aECount = aAlgo.NbExt(); - for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN) - { - Extrema_POnCurv aP1, aP2; - aAlgo.Points(aEN, aP1, aP2); - if (aP1.Value().SquareDistance(aP2.Value()) <= - Precision::SquareConfusion()) - { - AppendIntersectionPoint(aCurve1, aP1.Parameter(), theParameters); - } - } - } - return aIntCount; -} - -static Standard_Integer IntersectCurve( - const NCollection_Vector& theEdges, - const TopoDS_Wire& theWire, - NCollection_Vector >& theParameters) -{ - Standard_Integer aIntCount = 0; - const Standard_Integer aECount1 = theEdges.Size(); - for (Standard_Integer aEI1 = 0; aEI1 < aECount1; ++aEI1) - { - const TopoDS_Edge& aEdge1 = theEdges(aEI1); - TopExp_Explorer aEIt2(theWire, TopAbs_EDGE); - for (; aEIt2.More(); aEIt2.Next()) - { - aIntCount += IntersectEdge(aEdge1, - TopoDS::Edge(aEIt2.Current()), theParameters(aEI1)); - } - } - return aIntCount; -} - -static void CloseCurve(NCollection_Sequence& theCurve) -{ - const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex( - theCurve.Last(), Standard_True).Oriented(TopAbs_FORWARD)); - const TopoDS_Edge& aEdge = theCurve.First(); - const TopoDS_Edge aForwardEdge = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)); - theCurve.ChangeFirst() = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices( - aForwardEdge, aVertex, TopoDS_Vertex()).Oriented(aEdge.Orientation())); -} - -static Standard_Boolean IsClosed( - const NCollection_Sequence& theCurve) -{ - return TopExp::FirstVertex(theCurve.First(), Standard_True). - IsSame(TopExp::LastVertex(theCurve.Last(), Standard_True)); -} - -static void ExtendCurve( - const Standard_Integer thePosition, - NCollection_Sequence& theCurve, - NCollection_Sequence& theExtension) -{ - if (thePosition == 0) - { - const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex( - theExtension.Last(), Standard_True).Oriented(TopAbs_FORWARD)); - TopoDS_Edge& aEdge = theCurve.ChangeFirst(); - aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices( - TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), aVertex, TopoDS_Vertex()). - Oriented(aEdge.Orientation())); - theCurve.Prepend(theExtension); - } - else - { - const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::FirstVertex( - theExtension.First(), Standard_True).Oriented(TopAbs_REVERSED)); - TopoDS_Edge& aEdge = theCurve.ChangeLast(); - aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices( - TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), TopoDS_Vertex(), aVertex). - Oriented(aEdge.Orientation())); - theCurve.Append(theExtension); - } -} - -static void ExtendCurve( - const Standard_Integer thePosition, - const TopoDS_Edge& theExtension, - NCollection_Sequence& theCurve) -{ - NCollection_Sequence aExtension; - aExtension.Append(theExtension); - ExtendCurve(thePosition, theCurve, aExtension); -} - -static gp_XYZ Tangent( - const Adaptor3d_Curve& theCurve, const Standard_Integer thePosition) -{ - const Standard_Real aParam = (thePosition == 0) ? - theCurve.FirstParameter() : theCurve.LastParameter(); - gp_Pnt aP; - gp_Vec aV; - theCurve.D1(aParam, aP, aV); - Standard_Real aNorm = aV.Magnitude(); - aNorm = (aNorm >= Precision::PConfusion()) ? aNorm : 0; - return ((1 / aNorm) * aV).XYZ(); -} - -static gp_XYZ Tangent( - const TopoDS_Edge& theEdge, const Standard_Integer thePosition) -{ - BRepAdaptor_Curve aCurve(theEdge); - return Tangent(BRepAdaptor_Curve(theEdge), thePosition); -} - -static Standard_Boolean Interpolate( - const gp_Pnt thePoint1, - const gp_Pnt thePoint2, - const gp_Vec theTangent1, - const gp_Vec theTangent2, - Handle(Geom_BSplineCurve)& theBSpline) -{ - Handle(TColgp_HArray1OfPnt) aPs = new TColgp_HArray1OfPnt(1, 2); - TColgp_Array1OfVec aTs(1, 2); - Handle(TColStd_HArray1OfBoolean) aTFs = new TColStd_HArray1OfBoolean(1, 2); - aPs->SetValue(1, thePoint1); - aPs->SetValue(2, thePoint2); - aTs.SetValue(1, theTangent1); - aTs.SetValue(2, theTangent2); - aTFs->SetValue(1, Standard_True); - aTFs->SetValue(2, Standard_True); - GeomAPI_Interpolate aInterpolator(aPs, Standard_False, 0); - aInterpolator.Load(aTs, aTFs, Standard_False); - aInterpolator.Perform(); - const Standard_Boolean aResult = (aInterpolator.IsDone() == Standard_True); - if (aResult) - { - theBSpline = aInterpolator.Curve(); - } - return aResult; -} - -static Standard_Boolean Merge( - const TopoDS_Wire& theWire, - const Standard_Real theTolerance, - NCollection_Vector >& theMergedCurves) -{ - NCollection_Sequence aCurve; - Standard_Boolean isClosed; - if (!WireToCurve(theWire, aCurve, isClosed)) - { - return Standard_False; - } - - if (isClosed) - { - theMergedCurves.Append(aCurve); - return Standard_True; - } - - const Standard_Real aSqTol = theTolerance * theTolerance; - const gp_Pnt aPs[] = { - BRep_Tool::Pnt(TopExp::FirstVertex(aCurve.First(), Standard_True)), - BRep_Tool::Pnt(TopExp::LastVertex(aCurve.Last(), Standard_True))}; - if (!isClosed && aPs[0].SquareDistance(aPs[1]) <= aSqTol) - { - CloseCurve(aCurve); - theMergedCurves.Append(aCurve); - return Standard_True; - } - - NCollection_Sequence* aCurves[] = {NULL, NULL}; - Standard_Integer aOrder = 0; - for (NCollection_Vector >::Iterator - aCIt(theMergedCurves); aCIt.More(); aCIt.Next()) - { - NCollection_Sequence& aC = aCIt.ChangeValue(); - if (aC.IsEmpty() || IsClosed(aC)) - { - continue; - } - - const gp_Pnt aP1 = - BRep_Tool::Pnt(TopExp::FirstVertex(aC.First(), Standard_True)); - if (aCurves[0] == NULL && aP1.SquareDistance(aPs[1]) <= aSqTol) - { - aCurves[0] = &aC; - } - - const gp_Pnt aP2 = - BRep_Tool::Pnt(TopExp::LastVertex(aC.Last(), Standard_True)); - if (aCurves[1] == NULL && aP2.SquareDistance(aPs[0]) <= aSqTol) - { - aCurves[1] = &aC; - aOrder = (aCurves[0] == NULL) ? 1 : 0; - } - } - - if (aCurves[0] == NULL && aCurves[1] == NULL) - { - theMergedCurves.Append(aCurve); - } - else if (aCurves[1] == NULL) - { - ExtendCurve(0, *aCurves[0], aCurve); - } - else if (aCurves[0] == NULL) - { - ExtendCurve(1, *aCurves[1], aCurve); - } - else - { - ExtendCurve(aOrder, *aCurves[aOrder], aCurve); - if (aCurves[0] != aCurves[1]) - { - ExtendCurve(aOrder, *aCurves[aOrder], *aCurves[1 - aOrder]); - } - else - { - CloseCurve(*aCurves[aOrder]); - } - } - return Standard_True; -} - -static Standard_Boolean Connect( - const TopoDS_Wire& theWire, - const Standard_Real theTolerance, - NCollection_Vector >& theMergedCurves) -{ - NCollection_Sequence aCurve; - Standard_Boolean isClosed; - if (!WireToCurve(theWire, aCurve, isClosed)) - { - return Standard_False; - } - - if (isClosed) - { - theMergedCurves.Append(aCurve); - return Standard_True; - } - - const Standard_Real aSqTol = theTolerance * theTolerance; - const gp_Pnt aPs[] = { - BRep_Tool::Pnt(TopExp::FirstVertex(aCurve.First(), Standard_True)), - BRep_Tool::Pnt(TopExp::LastVertex(aCurve.Last(), Standard_True))}; - if (!isClosed && aPs[0].SquareDistance(aPs[1]) <= aSqTol) - { - CloseCurve(aCurve); - theMergedCurves.Append(aCurve); - return Standard_True; - } - - for (NCollection_Vector >::Iterator - aCIt(theMergedCurves); aCIt.More(); aCIt.Next()) - { - NCollection_Sequence& aCurve2 = aCIt.ChangeValue(); - if (aCurve2.IsEmpty() || IsClosed(aCurve2)) - { - continue; - } - - const TopoDS_Edge* aEdges2[] = {&aCurve2.First(), &aCurve2.Last()}; - const gp_Pnt aPs2[] = { - BRep_Tool::Pnt(TopExp::FirstVertex(*aEdges2[0], Standard_True)), - BRep_Tool::Pnt(TopExp::LastVertex(*aEdges2[1], Standard_True))}; - const Standard_Real aSqDists[] = - {aPs2[0].SquareDistance(aPs[1]), aPs2[1].SquareDistance(aPs[0])}; - const Standard_Integer aOrder = (aSqDists[0] <= aSqDists[1]) ? 0 : 1; - if (aSqDists[aOrder] > aSqTol) - { - const TopoDS_Edge& aEdge = (aOrder == 0) ? aCurve.Last() : aCurve.First(); - const gp_Pnt aPs3[] = {aPs[1 - aOrder], aPs2[aOrder]}; - const gp_XYZ aTs[] = - {Tangent(aEdge, 1 - aOrder), Tangent(*aEdges2[aOrder], aOrder)}; - Handle(Geom_BSplineCurve) aBSpline; - if (!Interpolate(aPs3[aOrder], aPs3[1 - aOrder], - aTs[aOrder], aTs[1 - aOrder], aBSpline)) - { - return Standard_False; - } - - ExtendCurve(aOrder, BRepBuilderAPI_MakeEdge(aBSpline), aCurve2); - } - ExtendCurve(aOrder, aCurve2, aCurve); - if (aSqDists[1 - aOrder] <= aSqTol) - { - CloseCurve(aCurve2); - } - return Standard_True; - } - - theMergedCurves.Append(aCurve); - return Standard_True; -} - bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc, const Handle( HYDROData_PolylineXY )& thePolyline, const gp_Pnt2d& thePoint, @@ -739,11 +63,13 @@ bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theD { std::vector aPointsList( 1 ); aPointsList[0] = thePoint; - std::vector aCurves = GetWires( thePolyline ); + std::vector aCurves; + GetWires(thePolyline, aCurves); bool isOK = true; for( int i=0, n=aCurves.size(); i aCurvesList = Split( aCurves[i], thePoint, theTolerance ); + std::vector aCurvesList; + Split(aCurves[i], thePoint, theTolerance, aCurvesList); bool isLocalOK = CreatePolylines( theDoc, thePolyline->GetName(), aCurvesList, true ); isOK = isOK && isLocalOK; } @@ -780,19 +106,20 @@ bool HYDROData_PolylineOperator::Merge( const Handle( HYDROData_Document )& theD bool isConnectByNewSegment, double theTolerance ) { - NCollection_Vector > aMergedCurves; + std::deque aMergedCurves; HYDROData_SequenceOfObjects::Iterator aPIt(thePolylines); for (; aPIt.More(); aPIt.Next()) { Handle(HYDROData_PolylineXY) aPolyline = Handle(HYDROData_PolylineXY)::DownCast(aPIt.Value()); - std::vector aWires = GetWires(aPolyline); + std::vector aWires; + GetWires(aPolyline, aWires); for (std::vector::const_iterator aWIt = aWires.begin(), aLastWIt = aWires.end(); aWIt != aLastWIt; ++aWIt) { const Standard_Boolean aResult = !isConnectByNewSegment ? - ::Merge(*aWIt, theTolerance, aMergedCurves) : - Connect(*aWIt, theTolerance, aMergedCurves); + HYDROData_TopoCurve::Merge(theTolerance, *aWIt, aMergedCurves) : + HYDROData_TopoCurve::Connect(theTolerance, *aWIt, aMergedCurves); if (!aResult) { return false; @@ -803,14 +130,13 @@ bool HYDROData_PolylineOperator::Merge( const Handle( HYDROData_Document )& theD TopoDS_Compound aWireSet; BRep_Builder aBuilder; aBuilder.MakeCompound(aWireSet); - for (NCollection_Vector >::Iterator - aCIt(aMergedCurves); aCIt.More(); aCIt.Next()) + std::deque::iterator aCIt = aMergedCurves.begin(); + std::deque::iterator aLastCIt = aMergedCurves.end(); + for (; aCIt != aLastCIt; ++aCIt) { - if (!aCIt.Value().IsEmpty()) + if (!aCIt->IsEmpty()) { - TopoDS_Wire aWire; - CurveToWire(aCIt.Value(), aWire); - aBuilder.Add(aWireSet, aWire); + aBuilder.Add(aWireSet, aCIt->Wire()); } } @@ -826,14 +152,17 @@ bool HYDROData_PolylineOperator::split( const Handle( HYDROData_Document )& theD double theTolerance, int theIgnoreIndex ) const { - std::vector aCurves = GetWires( thePolyline ); + std::vector aCurves; + GetWires(thePolyline, aCurves); std::vector aToolCurves; for( int i=theTools.Lower(), n=theTools.Upper(); i<=n; i++ ) if( i!=theIgnoreIndex ) { Handle( HYDROData_PolylineXY ) aToolPolyline = Handle( HYDROData_PolylineXY )::DownCast( theTools.Value( i ) ); - append( aToolCurves, GetWires( aToolPolyline ) ); + std::vector aTCurves; + GetWires(aToolPolyline, aTCurves); + append( aToolCurves, aTCurves); } const int aPSCount = aCurves.size(); @@ -841,71 +170,27 @@ bool HYDROData_PolylineOperator::split( const Handle( HYDROData_Document )& theD std::vector aResult; for (int aPSI = 0; aPSI < aPSCount; ++aPSI) { - NCollection_Vector aCurve; - Standard_Boolean aIsClosed; - if (!WireToCurve(aCurves[aPSI], aCurve, aIsClosed)) + HYDROData_TopoCurve aCurve; + if (!aCurve.Initialize(aCurves[aPSI])) { continue; } - NCollection_Vector > aParams; - aParams.SetValue(aCurve.Size() - 1, NCollection_Sequence()); + std::deque > aParams; for (int aTSI = 0; aTSI < aTSCount; ++aTSI) { - IntersectCurve(aCurve, aToolCurves[aTSI], aParams); + aCurve.Intersect(aToolCurves[aTSI], aParams); } - NCollection_Vector > aSplittedCurves; - SplitCurveByPoints(aCurve, aParams, aSplittedCurves); - - Standard_Boolean aIsClosed2 = aIsClosed; - if (aIsClosed2) + std::deque aSplittedCurves; + aCurve.Cut(aParams, aSplittedCurves); + std::deque::const_iterator aCIt = + aSplittedCurves.begin(); + std::deque::const_iterator aLastCIt = + aSplittedCurves.end(); + for (; aCIt != aLastCIt; ++aCIt) { - const NCollection_Sequence& aPs = aParams.First(); - if (!aPs.IsEmpty()) - { - const TopoDS_Edge& aEdge = aCurve.First(); - const Standard_Boolean isForward = - (aEdge.Orientation() != TopAbs_REVERSED); - const Standard_Real aParam = isForward ? aPs.First() : aPs.Last(); - BRepAdaptor_Curve aCurve(aEdge); - const Standard_Real aEndParam = isForward ? - aCurve.FirstParameter() : aCurve.LastParameter(); - aIsClosed2 = (Abs(aParam - aEndParam) > Precision::PConfusion()); - } - - if (aIsClosed2) - { - const NCollection_Sequence& aPs = aParams.Last(); - if (!aPs.IsEmpty()) - { - const TopoDS_Edge& aEdge = aCurve.Last(); - const Standard_Boolean isForward = - (aEdge.Orientation() != TopAbs_REVERSED); - const Standard_Real aParam = isForward ? aPs.Last() : aPs.First(); - BRepAdaptor_Curve aCurve(aEdge); - const Standard_Real aEndParam = isForward ? - aCurve.LastParameter() : aCurve.FirstParameter(); - aIsClosed2 = (Abs(aParam - aEndParam) >= Precision::PConfusion()); - } - } - } - - Standard_Integer aFSCI = 0, aLSCI = aSplittedCurves.Size() - 1; - if (aIsClosed2 && aFSCI < aLSCI) - { - TopoDS_Wire aWire; - CurveToWire(aSplittedCurves(aLSCI), aSplittedCurves(aFSCI), aWire); - aResult.push_back(aWire); - ++aFSCI; - --aLSCI; - } - - for (Standard_Integer aSCI = aFSCI; aSCI <= aLSCI; ++aSCI) - { - TopoDS_Wire aWire; - CurveToWire(aSplittedCurves(aSCI), aWire); - aResult.push_back(aWire); + aResult.push_back(aCIt->Wire()); } } @@ -913,82 +198,49 @@ bool HYDROData_PolylineOperator::split( const Handle( HYDROData_Document )& theD return true; } -std::vector HYDROData_PolylineOperator::GetWires( const Handle( HYDROData_PolylineXY )& thePolyline ) +void HYDROData_PolylineOperator::GetWires( + const Handle( HYDROData_PolylineXY )& thePolyline, + std::vector& theWires) { - std::vector aResult; - TopoDS_Shape aShape = thePolyline->GetShape(); - if( aShape.ShapeType()==TopAbs_WIRE ) { - aResult.push_back( TopoDS::Wire( aShape ) ); + theWires.push_back( TopoDS::Wire( aShape ) ); } else { TopExp_Explorer anExp( aShape, TopAbs_WIRE ); for( ; anExp.More(); anExp.Next() ) { - aResult.push_back( TopoDS::Wire( anExp.Current() ) ); + theWires.push_back( TopoDS::Wire( anExp.Current() ) ); } } - return aResult; } -std::vector HYDROData_PolylineOperator::Split( const TopoDS_Wire& theWire, - const gp_Pnt2d& thePoint, - double theTolerance ) +void HYDROData_PolylineOperator::Split( + const TopoDS_Wire& theWire, + const gp_Pnt2d& thePoint, + double theTolerance, + std::vector& theWires) { - std::vector aResult; - NCollection_Vector aEdges; - Standard_Boolean isClosed; - if (!WireToCurve(theWire, aEdges, isClosed)) + HYDROData_TopoCurve aCurve; + if (!aCurve.Initialize(theWire)) { - aResult.push_back(theWire); - return aResult; - } - - const gp_Pnt aP(thePoint.X(), thePoint.Y(), 0); - Standard_Real aMinSqDist = DBL_MAX; - int aSEI = -1; - Standard_Real aSParam; - for (int aECount = aEdges.Size(), aEI = 0; aEI < aECount; ++aEI) - { - Standard_Real aParam; - const Standard_Real aSqDist = - ProjectPointToEdge(aP, aEdges(aEI), aParam); - if (aMinSqDist > aSqDist) - { - aMinSqDist = aSqDist; - aSEI = aEI; - aSParam = aParam; - } + theWires.push_back(theWire); + return; } - NCollection_Vector aEdges1, aEdges2; - SplitCurveByPoint(aEdges, aSEI, aSParam, aEdges1, aEdges2); - TopoDS_Wire aWire; - if (!isClosed) - { - CurveToWire(aEdges1, aWire); - if (!aEdges2.IsEmpty()) - { - aResult.push_back(aWire); - CurveToWire(aEdges2, aWire); - } - } - else + const gp_XYZ aP(thePoint.X(), thePoint.Y(), 0); + std::list::const_iterator aEPos; + double aParam; + aCurve.Project(aP, aEPos, aParam); + HYDROData_TopoCurve aCurve1, aCurve2; + aCurve.Cut(aEPos, aParam, aCurve1, aCurve2); + theWires.push_back(aCurve1.Wire()); + if (!aCurve2.IsEmpty()) { - if (!aEdges2.IsEmpty()) - { - CurveToWire(aEdges2, aEdges1, aWire); - } - else - { - CurveToWire(aEdges1, aWire); - } + theWires.push_back(aCurve2.Wire()); } - aResult.push_back(aWire); - return aResult; } bool HYDROData_PolylineOperator::CreatePolylines( const Handle( HYDROData_Document )& theDoc, diff --git a/src/HYDROData/HYDROData_PolylineOperator.h b/src/HYDROData/HYDROData_PolylineOperator.h index 0b0fdcee..ed658ffb 100644 --- a/src/HYDROData/HYDROData_PolylineOperator.h +++ b/src/HYDROData/HYDROData_PolylineOperator.h @@ -46,6 +46,10 @@ public: bool isConnectByNewSegment, double theTolerance ); + static void GetWires( + const Handle( HYDROData_PolylineXY )& thePolyline, + std::vector& theWires); + protected: bool split( const Handle( HYDROData_Document )& theDoc, const Handle( HYDROData_PolylineXY )& thePolyline, @@ -53,11 +57,11 @@ protected: double theTolerance, int theIgnoreIndex ) const; - static std::vector GetWires( const Handle( HYDROData_PolylineXY )& thePolyline ); - - static std::vector Split( const TopoDS_Wire& theWire, - const gp_Pnt2d& thePoint, - double theTolerance ); + static void Split( + const TopoDS_Wire& theWire, + const gp_Pnt2d& thePoint, + double theTolerance, + std::vector& theWires); static bool CreatePolylines( const Handle( HYDROData_Document )& theDoc, const QString& theNamePrefix, diff --git a/src/HYDROData/HYDROData_TopoCurve.cxx b/src/HYDROData/HYDROData_TopoCurve.cxx new file mode 100644 index 00000000..449db4c9 --- /dev/null +++ b/src/HYDROData/HYDROData_TopoCurve.cxx @@ -0,0 +1,894 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//! The type is intended to traverse the container +//! either from the begin to the end or vice versa. +template +class Iterator +{ +private: + IteratorType myIterator; //!< The iterator. + IteratorType myIteratorLimit; //!< The iterator limit. + + //! The pointer to the method to traverse the next item. + IteratorType& (IteratorType::*myNext)(); + +public: + //! The constructor. + Iterator( + const ContainerType& theContainer, + const bool theIsForward) + { + if (theIsForward) + { + myIterator = theContainer.begin(); + myIteratorLimit = theContainer.end(); + myNext = &IteratorType::operator++; + } + else + { + myIterator = --theContainer.end(); + myIteratorLimit = --theContainer.begin(); + myNext = &IteratorType::operator--; + } + } + + //! Returna 'true' if the container contains not yet traversed item. + bool More() const + { + return myIterator != myIteratorLimit; + } + + //! Traverses to the next item. + IteratorType& operator ++() + { + return (myIterator.*myNext)(); + } + + //! Returns the iterator. + IteratorType& operator *() {return myIterator;} +}; + +// Inserts the value after the position. +template static void InsertAfter( + const typename std::list::iterator& thePosition, + const ItemType& theValue, + std::list& theList) +{ + std::list::iterator aEIt2 = thePosition; + if (++aEIt2 != theList.end()) + { + theList.insert(aEIt2, theValue); + } + else + { + theList.push_back(theValue); + } +} + +// Converts the curve to a smooth cubic B-spline using the deflection. +static Handle(Geom_BSplineCurve) BSpline( + const BRepAdaptor_Curve& theCurve, const double theDeflection) +{ + Handle(BRepAdaptor_HCurve) aCurve = new BRepAdaptor_HCurve(theCurve); + Approx_Curve3d aConverter(aCurve, theDeflection, GeomAbs_C1, 4, 3); + Handle(Geom_BSplineCurve) aBSpline; + return aConverter.HasResult() ? aConverter.Curve() : aBSpline; +} + +// Replaces the vertex of the edge considering the edge orientation. +static TopoDS_Edge ReplaceVertex( + const TopoDS_Edge& theEdge, const bool theIsEndVertex) +{ + TopoDS_Vertex aVertices[] = { + TopExp::FirstVertex(theEdge, Standard_True), + TopExp::LastVertex(theEdge, Standard_True)}; + aVertices[theIsEndVertex ? 1 : 0].EmptyCopy(); + TopoDS_Edge aNewEdge = TopoDS::Edge(theEdge.Oriented(TopAbs_FORWARD)); + aNewEdge = + ShapeBuild_Edge().CopyReplaceVertices(aNewEdge, aVertices[0], aVertices[1]); + aNewEdge.Orientation(theEdge.Orientation()); + return aNewEdge; +} + +// Projects the point to the curve. +static double ProjectPointToCurve( + const gp_XYZ& thePoint, + const Adaptor3d_Curve& theCurve, + double& theParameter) +{ + // Calculate the nearest curve internal extremum. + Extrema_ExtPC aAlgo(thePoint, theCurve); + int aMinEN = -2; + double aMinSqDist = DBL_MAX; + if (aAlgo.IsDone()) + { + const int aECount = aAlgo.NbExt(); + for (int aEN = 1; aEN <= aECount; ++aEN) + { + const gp_XYZ& aP = aAlgo.Point(aEN).Value().XYZ(); + const double aSqDist = (thePoint - aP).SquareModulus(); + if (aMinSqDist > aSqDist) + { + aMinSqDist = aSqDist; + aMinEN = aEN; + } + } + } + + // Calculate the nearest curve end extremum. + const double aParams[] = + {theCurve.FirstParameter(), theCurve.LastParameter()}; + const gp_XYZ aEnds[] = + {theCurve.Value(aParams[0]).XYZ(), theCurve.Value(aParams[1]).XYZ()}; + const double aSqDists[] = { + (thePoint - aEnds[0]).SquareModulus(), + (thePoint - aEnds[1]).SquareModulus()}; + for (int aEI = 0; aEI < 2; ++aEI) + { + if (aMinSqDist > aSqDists[aEI]) + { + aMinSqDist = aSqDists[aEI]; + aMinEN = -aEI; + } + } + + if (aMinEN <= 0) + { + theParameter = aParams[-aMinEN]; + return aMinSqDist; + } + + const Extrema_POnCurv& aPOnC = aAlgo.Point(aMinEN); + const gp_XYZ& aP = aPOnC.Value().XYZ(); + theParameter = aPOnC.Parameter(); + for (int aEI = 0; aEI < 2; ++aEI) + { + if (Abs(theParameter - aParams[aEI]) < Precision::PConfusion() || + (aP - aEnds[aEI]).SquareModulus() < Precision::SquareConfusion()) + { + theParameter = aParams[aEI]; + } + } + return aMinSqDist; +} + +// Projects the point to the edge. +static double ProjectPointToEdge( + const gp_XYZ& thePoint, const TopoDS_Edge& theEdge, double& theParameter) +{ + return ProjectPointToCurve(thePoint, BRepAdaptor_Curve(theEdge), theParameter); +} + +// Adds the parameter to the curve parameter list. +static int AddParameter( + const Adaptor3d_Curve& theCurve, + const double theParameter, + std::list& theParameters) +{ + // Check the coincidence. + std::list aEndParams; + aEndParams.push_back(theCurve.FirstParameter()); + aEndParams.push_back(theCurve.LastParameter()); + std::list* aParams[] = {&theParameters, &aEndParams}; + const gp_XYZ aPoint = theCurve.Value(theParameter).XYZ(); + for (int aLI = 0; aLI < 2; ++aLI) + { + std::list::iterator aPIt = aParams[aLI]->begin(); + std::list::iterator aLastPIt = aParams[aLI]->end(); + for (int aPI = 0; aPIt != aLastPIt; ++aPI, ++aPIt) + { + const double aParam = *aPIt; + if (Abs(theParameter - aParam) < Precision::PConfusion() || + (theCurve.Value(aParam).XYZ() - aPoint).SquareModulus() <= + Precision::SquareConfusion()) + { + int aIntCount = 0; + if (aLI != 0) + { + if (aPI == 0) + { + theParameters.push_front(aEndParams.front()); + } + else + { + theParameters.push_back(aEndParams.back()); + } + ++aIntCount; + } + return aIntCount; + } + } + } + + // Calculate the position to insert. + std::list::iterator aPIt = theParameters.begin(); + std::list::iterator aLastPIt = theParameters.end(); + if (aPIt != aLastPIt && *aPIt < theParameter) + { + for (++aPIt; aPIt != aLastPIt && *aPIt < theParameter; ++aPIt); + if (aPIt != aLastPIt) + { + theParameters.insert(aPIt, theParameter); + } + else + { + theParameters.push_back(theParameter); + } + } + else + { + theParameters.push_front(theParameter); + } + return 1; +} + +// Intersects the first curve by the second one and +// adds the intersection parameters to the ordered list. +static int IntersectCurve( + const Adaptor3d_Curve& theCurve1, + const Adaptor3d_Curve& theCurve2, + std::list& theParameters) +{ + // Process the ends. + int aIntCount = 0; + const gp_XYZ aEndPs[] = { + theCurve2.Value(theCurve2.FirstParameter()).XYZ(), + theCurve2.Value(theCurve2.LastParameter()).XYZ()}; + for (int aPI = 0; aPI < 2; ++aPI) + { + double aParameter; + if (ProjectPointToCurve(aEndPs[aPI], theCurve1, aParameter) <= + Precision::SquareConfusion()) + { + aIntCount += AddParameter(theCurve1, aParameter, theParameters); + } + } + + // Process the internal extremums. + Extrema_ExtCC aAlgo(theCurve1, theCurve2); + if (aAlgo.IsDone()) + { + const int aECount = aAlgo.NbExt(); + for (int aEN = 1; aEN <= aECount; ++aEN) + { + Extrema_POnCurv aP1, aP2; + aAlgo.Points(aEN, aP1, aP2); + if (aP1.Value().SquareDistance(aP2.Value()) <= + Precision::SquareConfusion()) + { + aIntCount += AddParameter(theCurve1, aP1.Parameter(), theParameters); + } + } + } + return aIntCount; +} + +// Intersects the first edge by the second one and +// adds the intersection parameters to the ordered list. +static int IntersectEdge( + const TopoDS_Edge& theEdge1, + const TopoDS_Edge& theEdge2, + std::list& theParameters) +{ + BRepAdaptor_Curve aCurve1 = BRepAdaptor_Curve(theEdge1); + BRepAdaptor_Curve aCurve2 = BRepAdaptor_Curve(theEdge2); + return IntersectCurve(aCurve1, aCurve2, theParameters); +} + +// Returns the curve tangent in the position: 0 - start, 1 - end. +static gp_XYZ Tangent(const Adaptor3d_Curve& theCurve, const int thePosition) +{ + const Standard_Real aParam = (thePosition == 0) ? + theCurve.FirstParameter() : theCurve.LastParameter(); + gp_Pnt aP; + gp_Vec aV; + theCurve.D1(aParam, aP, aV); + Standard_Real aNorm = aV.Magnitude(); + aNorm = (aNorm >= Precision::PConfusion()) ? aNorm : 0; + return ((1 / aNorm) * aV).XYZ(); +} + +// Returns the edge tangent in the position: 0 - start, 1 - end. +static gp_XYZ Tangent(const TopoDS_Edge& theEdge, const int thePosition) +{ + BRepAdaptor_Curve aCurve(theEdge); + return Tangent(BRepAdaptor_Curve(theEdge), thePosition); +} + +static bool Interpolate( + const gp_XYZ thePoint1, + const gp_XYZ thePoint2, + const gp_XYZ theTangent1, + const gp_XYZ theTangent2, + Handle(Geom_BSplineCurve)& theBSpline) +{ + Handle(TColgp_HArray1OfPnt) aPs = new TColgp_HArray1OfPnt(1, 2); + TColgp_Array1OfVec aTs(1, 2); + Handle(TColStd_HArray1OfBoolean) aTFs = new TColStd_HArray1OfBoolean(1, 2); + aPs->SetValue(1, thePoint1); + aPs->SetValue(2, thePoint2); + aTs.SetValue(1, theTangent1); + aTs.SetValue(2, theTangent2); + aTFs->SetValue(1, Standard_True); + aTFs->SetValue(2, Standard_True); + GeomAPI_Interpolate aInterpolator(aPs, Standard_False, 0); + aInterpolator.Load(aTs, aTFs, Standard_False); + aInterpolator.Perform(); + const bool aResult = (aInterpolator.IsDone() == Standard_True); + if (aResult) + { + theBSpline = aInterpolator.Curve(); + } + return aResult; +} + +bool HYDROData_TopoCurve::Initialize(const TopoDS_Wire& theWire) +{ + // Check for nonemptiness. + myEdges.clear(); + TopTools_IndexedDataMapOfShapeListOfShape aVertexToEdges; + TopExp::MapShapesAndAncestors(theWire, + TopAbs_VERTEX, TopAbs_EDGE, aVertexToEdges); + const int aVCount = aVertexToEdges.Extent(); + if (aVCount == 0) + { + return false; + } + + // Check for 1 manifoldness. + bool isClosed = false; + { + int aEndCount = 0; + for (int aVN = 1; aVN <= aVCount; ++aVN) + { + const int aEdgeCount = aVertexToEdges.FindFromIndex(aVN).Extent(); + if (aEdgeCount == 1) + { + ++aEndCount; + } + if (aEdgeCount > 2) + { + return false; + } + } + isClosed = (aEndCount == 0); + if (!isClosed && aEndCount != 2) + { + return false; + } + } + + // Find the start. + int aVN = 1; + if (!isClosed) + { + for (; aVertexToEdges.FindFromIndex(aVN).Extent() == 2; ++aVN); + if (!aVertexToEdges.FindKey(aVN).IsEqual(TopExp::FirstVertex( + TopoDS::Edge(aVertexToEdges.FindFromIndex(aVN).First()), Standard_True))) + { + for (; aVertexToEdges.FindFromIndex(aVN).Extent() == 2; ++aVN); + } + } + else + { + TopTools_ListOfShape& aEdges = aVertexToEdges.ChangeFromIndex(1); + if (!aVertexToEdges.FindKey(aVN).IsEqual( + TopExp::FirstVertex(TopoDS::Edge(aEdges.First()), Standard_True))) + { + const TopoDS_Shape aEdge = aEdges.First(); + aEdges.First() = aEdges.Last(); + aEdges.Last() = aEdge; + } + } + + // Calculate the edge order. + TopTools_ListOfShape* aEdges = &aVertexToEdges.ChangeFromIndex(aVN); + while (!aEdges->IsEmpty()) + { + const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First()); + aEdges->RemoveFirst(); + myEdges.push_back(aEdge); + int aVN2 = aVertexToEdges.FindIndex(TopExp::FirstVertex(aEdge)); + if (aVN2 == aVN) + { + aVN2 = aVertexToEdges.FindIndex(TopExp::LastVertex(aEdge)); + } + aVN = aVN2; + + aEdges = &aVertexToEdges.ChangeFromIndex(aVN2); + const TopoDS_Edge aEdge2 = TopoDS::Edge(aEdges->First()); + if (aEdge2.IsEqual(aEdge)) + { + aEdges->RemoveFirst(); + } + else + { + aEdges->Clear(); + aEdges->Append(aEdge2); + } + } + + // Check for connectedness and free vertex. + return aVCount - myEdges.size() == (isClosed ? 0 : 1); +} + +TopoDS_Wire HYDROData_TopoCurve::Wire() const +{ + TopoDS_Wire aWire; + BRep_Builder aBulder; + aBulder.MakeWire(aWire); + std::list::const_iterator aEItLast = myEdges.end(); + std::list::const_iterator aEIt = myEdges.begin(); + for (; aEIt != aEItLast; ++aEIt) + { + aBulder.Add(aWire, *aEIt); + } + return aWire; +} + +void HYDROData_TopoCurve::Cut( + const std::list::iterator& theEdgePosition, + const double theParameter, + HYDROData_TopoCurve& theCurve) +{ + // Locate the edge. + std::list::iterator aFirstEIt = myEdges.begin(); + std::list::iterator aEIt = aFirstEIt; + for (; aEIt != theEdgePosition; ++aEIt); + + // Cut the edge. + TopoDS_Edge aEdge = *aEIt; + BRepAdaptor_Curve aCurve(aEdge); + int aParamI = -1; + const double aEdgeEndParams[] = + {aCurve.FirstParameter(), aCurve.LastParameter()}; + if (Abs(theParameter - aEdgeEndParams[0]) < Precision::PConfusion()) + { + aParamI = 0; + } + else if (Abs(theParameter - aEdgeEndParams[1]) < Precision::PConfusion()) + { + aParamI = 1; + } + const TopAbs_Orientation aOrient = aEdge.Orientation(); + if (aOrient == TopAbs_REVERSED) + { + aParamI ^= 1; + } + if (aParamI < 0) + { + aEdge.Orientation(TopAbs_FORWARD); + TopoDS_Vertex aSplitV1, aSplitV2; + BRep_Builder().MakeVertex( + aSplitV1, aCurve.Value(theParameter), Precision::Confusion()); + BRep_Builder().MakeVertex( + aSplitV2, aCurve.Value(theParameter), Precision::Confusion()); + TopoDS_Edge aEParts[] = { + ShapeBuild_Edge().CopyReplaceVertices(aEdge, TopoDS_Vertex(), + TopoDS::Vertex(aSplitV1.Oriented(TopAbs_REVERSED))), + ShapeBuild_Edge().CopyReplaceVertices(aEdge, aSplitV2, TopoDS_Vertex())}; + ShapeBuild_Edge().CopyPCurves(aEParts[0], aEdge); + ShapeBuild_Edge().CopyPCurves(aEParts[1], aEdge); + BRep_Builder().SameRange(aEParts[0], Standard_False); + BRep_Builder().SameRange(aEParts[1], Standard_False); + BRep_Builder().SameParameter(aEParts[0], Standard_False); + BRep_Builder().SameParameter(aEParts[1], Standard_False); + ShapeAnalysis_TransferParametersProj aSATPP(aEdge, TopoDS_Face()); + aSATPP.SetMaxTolerance(Precision::Confusion()); + aSATPP.TransferRange(aEParts[0], + aEdgeEndParams[0], theParameter, Standard_False); + aSATPP.TransferRange(aEParts[1], + theParameter, aEdgeEndParams[1], Standard_False); + aEParts[0].Orientation(aOrient); + aEParts[1].Orientation(aOrient); + + const int aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1; + *aEIt = aEParts[aFirstPI]; + InsertAfter(aEIt, aEParts[1 - aFirstPI], myEdges); + ++aEIt; + } + else if (aParamI > 0) + { + ++aEIt; + } + + // Calculate the curve parts. + std::list::iterator aLastEIt = myEdges.end(); + if (aEIt != aFirstEIt && aEIt != aLastEIt) + { + std::list* aEdges = !IsClosed() ? &theCurve.myEdges : &myEdges; + aEdges->splice(aEdges->begin(), myEdges, aEIt, aLastEIt); + } +} + +void HYDROData_TopoCurve::Cut( + const std::list::const_iterator& theEdgePosition, + const double theParameter, + HYDROData_TopoCurve& theCurve1, + HYDROData_TopoCurve& theCurve2) const +{ + theCurve1 = *this; + std::list::const_iterator aEPos = myEdges.begin(); + std::list::iterator aEPos1 = theCurve1.myEdges.begin(); + for (; aEPos != theEdgePosition; ++aEPos1, ++aEPos); + theCurve1.Cut(aEPos1, theParameter, theCurve2); +} + +void HYDROData_TopoCurve::Cut( + const std::deque >& theParameters, + std::deque& theCurves) const +{ + HYDROData_TopoCurve aCurves[2]; + aCurves[0] = *this; + int aCI = 0; + std::list::iterator aEIt = aCurves[0].myEdges.begin(); + std::deque >::const_iterator aPLIt = theParameters.begin(); + for (std::deque >::const_iterator aLastPLIt = + theParameters.end(); aPLIt != aLastPLIt; ++aEIt, ++aPLIt) + { + for (Iterator, std::list::const_iterator> aPIt( + *aPLIt, (aEIt->Orientation() != TopAbs_REVERSED)); aPIt.More(); ++aPIt) + { + const int aCI1 = 1 - aCI; + aCurves[aCI].Cut(aEIt, **aPIt, aCurves[aCI1]); + if (!aCurves[aCI1].IsEmpty()) + { + theCurves.push_back(HYDROData_TopoCurve()); + theCurves.back().append(aCurves[aCI]); + aEIt = aCurves[aCI1].myEdges.begin(); + aCI = aCI1; + } + else + { + aEIt = aCurves[aCI].myEdges.begin(); + } + } + } + theCurves.push_back(aCurves[aCI]); +} + +double HYDROData_TopoCurve::Project( + const gp_XYZ& thePoint, + std::list::const_iterator& theEdgeIterator, + double& theParameter) const +{ + double aMinSqDist = DBL_MAX; + std::list::const_iterator aEIt = myEdges.begin(); + std::list::const_iterator aLastEIt = myEdges.end(); + for (; aEIt != aLastEIt; ++aEIt) + { + double aParam; + const double aSqDist = ProjectPointToEdge(thePoint, *aEIt, aParam); + if (aMinSqDist > aSqDist) + { + aMinSqDist = aSqDist; + theEdgeIterator = aEIt; + theParameter = aParam; + } + } + return aMinSqDist; +} + +int HYDROData_TopoCurve::Intersect( + const TopoDS_Wire& theWire, + std::deque >& theParameters) const +{ + int aIntCount = 0; + theParameters.resize(myEdges.size()); + std::list::const_iterator aEIt = myEdges.begin(); + std::list::const_iterator aLastEIt = myEdges.end(); + std::deque >::iterator aPIt = theParameters.begin(); + for (; aEIt != aLastEIt; ++aPIt, ++aEIt) + { + const TopoDS_Edge& aEdge = *aEIt; + std::list& aParams = *aPIt; + TopExp_Explorer aEIt2(theWire, TopAbs_EDGE); + for (; aEIt2.More(); aEIt2.Next()) + { + aIntCount += IntersectEdge(aEdge,TopoDS::Edge(aEIt2.Current()), aParams); + } + } + return aIntCount; +} + +void HYDROData_TopoCurve::CloseCurve() +{ + const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex( + myEdges.back(), Standard_True).Oriented(TopAbs_FORWARD)); + TopoDS_Edge& aEdge = myEdges.front(); + const TopoDS_Edge aForwardEdge = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)); + aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices( + aForwardEdge, aVertex, TopoDS_Vertex()).Oriented(aEdge.Orientation())); +} + +void HYDROData_TopoCurve::Merge( + const int thePosition, HYDROData_TopoCurve& theCurve) +{ + if (thePosition == 0) + { + const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::LastVertex( + theCurve.myEdges.back(), Standard_True).Oriented(TopAbs_FORWARD)); + TopoDS_Edge& aEdge = myEdges.front(); + aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices( + TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), aVertex, TopoDS_Vertex()). + Oriented(aEdge.Orientation())); + prepend(theCurve); + } + else + { + const TopoDS_Vertex aVertex = TopoDS::Vertex(TopExp::FirstVertex( + theCurve.myEdges.front(), Standard_True).Oriented(TopAbs_REVERSED)); + TopoDS_Edge& aEdge = myEdges.back(); + aEdge = TopoDS::Edge(ShapeBuild_Edge().CopyReplaceVertices( + TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD)), TopoDS_Vertex(), aVertex). + Oriented(aEdge.Orientation())); + append(theCurve); + } +} + +void HYDROData_TopoCurve::Merge( + const double theTolerance, std::deque& theCurves) +{ + // Process the curve closeness. + const double aSqTol = theTolerance * theTolerance; + const gp_XYZ aPs[] = { + BRep_Tool::Pnt(TopExp::FirstVertex(myEdges.front(), Standard_True)).XYZ(), + BRep_Tool::Pnt(TopExp::LastVertex(myEdges.back(), Standard_True)).XYZ()}; + bool isClosed = IsClosed(); + if (!isClosed && (aPs[0] - aPs[1]).SquareModulus() <= aSqTol) + { + CloseCurve(); + isClosed = true; + } + + // Find the merge places. + HYDROData_TopoCurve* aCurves[] = {NULL, NULL}; + int aOrder = 0; + if (!isClosed) + { + std::deque::iterator aCIt = theCurves.begin(); + std::deque::iterator aLastCIt = theCurves.end(); + for (; aCIt != aLastCIt; ++aCIt) + { + HYDROData_TopoCurve& aCurve = *aCIt; + if (aCurve.IsEmpty() || aCurve.IsClosed()) + { + continue; + } + + const gp_XYZ aP1 = BRep_Tool::Pnt( + TopExp::FirstVertex(aCurve.myEdges.front(), Standard_True)).XYZ(); + if (aCurves[0] == NULL && (aPs[1] - aP1).SquareModulus() <= aSqTol) + { + aCurves[0] = &aCurve; + } + + const gp_XYZ aP2 = BRep_Tool::Pnt( + TopExp::LastVertex(aCurve.myEdges.back(), Standard_True)).XYZ(); + if (aCurves[1] == NULL && (aPs[0] - aP2).SquareModulus() <= aSqTol) + { + aCurves[1] = &aCurve; + aOrder = (aCurves[0] == NULL) ? 1 : 0; + } + } + } + + if (aCurves[0] == NULL && aCurves[1] == NULL) + { + theCurves.push_back(HYDROData_TopoCurve()); + theCurves.back().append(*this); + } + else if (aCurves[1] == NULL) + { + aCurves[0]->Merge(0, *this); + } + else if (aCurves[0] == NULL) + { + aCurves[1]->Merge(1, *this); + } + else + { + aCurves[aOrder]->Merge(aOrder, *this); + if (aCurves[0] != aCurves[1]) + { + aCurves[aOrder]->Merge(aOrder, *aCurves[1 - aOrder]); + } + else + { + aCurves[aOrder]->CloseCurve(); + } + } +} + +bool HYDROData_TopoCurve::Connect( + const Standard_Real theTolerance, std::deque& theCurves) +{ + const double aSqTol = theTolerance * theTolerance; + const gp_XYZ aPs[] = { + BRep_Tool::Pnt(TopExp::FirstVertex(myEdges.front(), Standard_True)).XYZ(), + BRep_Tool::Pnt(TopExp::LastVertex(myEdges.back(), Standard_True)).XYZ()}; + bool isClosed = IsClosed(); + if (!isClosed && (aPs[0] - aPs[1]).SquareModulus() <= aSqTol) + { + CloseCurve(); + isClosed = true; + } + + if (!isClosed) + { + std::deque::iterator aCIt = theCurves.begin(); + std::deque::iterator aLastCIt = theCurves.end(); + for (; aCIt != aLastCIt; ++aCIt) + { + HYDROData_TopoCurve& aCurve2 = *aCIt; + if (aCurve2.IsEmpty() || aCurve2.IsClosed()) + { + continue; + } + + const TopoDS_Edge* aEdges2[] = + {&aCurve2.myEdges.front(), &aCurve2.myEdges.back()}; + const gp_XYZ aPs2[] = { + BRep_Tool::Pnt(TopExp::FirstVertex(*aEdges2[0], Standard_True)).XYZ(), + BRep_Tool::Pnt(TopExp::LastVertex(*aEdges2[1], Standard_True)).XYZ()}; + const double aSqDists[] = + {(aPs[1] - aPs2[0]).SquareModulus(), (aPs[0] - aPs2[1]).SquareModulus()}; + const int aOrder = (aSqDists[0] <= aSqDists[1]) ? 0 : 1; + if (aSqDists[aOrder] > aSqTol) + { + const TopoDS_Edge& aEdge = + (aOrder == 0) ? myEdges.back() : myEdges.front(); + const gp_XYZ aPs3[] = {aPs[1 - aOrder], aPs2[aOrder]}; + const gp_XYZ aTs[] = + {Tangent(aEdge, 1 - aOrder), Tangent(*aEdges2[aOrder], aOrder)}; + Handle(Geom_BSplineCurve) aBSpline; + if (!Interpolate(aPs3[aOrder], aPs3[1 - aOrder], + aTs[aOrder], aTs[1 - aOrder], aBSpline)) + { + return false; + } + + HYDROData_TopoCurve aECurve = BRepBuilderAPI_MakeEdge(aBSpline); + aCurve2.Merge(aOrder, aECurve); + } + aCurve2.Merge(aOrder, *this); + if (aSqDists[1 - aOrder] <= aSqTol) + { + aCurve2.CloseCurve(); + } + return true; + } + } + + theCurves.push_back(HYDROData_TopoCurve()); + theCurves.back().append(*this); + return true; +} + +bool HYDROData_TopoCurve::BSplinePiecewiseCurve( + const double theDeflection, HYDROData_TopoCurve& theCurve) const +{ + std::list::const_iterator aLastEIt = myEdges.end(); + std::list::const_iterator aEIt = myEdges.begin(); + TopoDS_Vertex aEndVertex; + TopoDS_Edge aPrevEdge; + for (; aEIt != aLastEIt; ++aEIt) + { + Handle(Geom_BSplineCurve) aBSpline = + ::BSpline(BRepAdaptor_Curve(*aEIt), theDeflection); + if (aBSpline.IsNull()) + { + return false; + } + + if (aEIt->Orientation() == TopAbs_REVERSED) + { + aBSpline->Reverse(); + } + + TopoDS_Edge aEdge; + BRep_Builder().MakeEdge(aEdge, aBSpline, Precision::Confusion()); + TopoDS_Vertex aVertex; + BRep_Builder().MakeVertex(aVertex, + aBSpline->Value(aBSpline->FirstParameter()), Precision::Confusion()); + if (!aPrevEdge.IsNull()) + { + BRep_Builder().Add(aPrevEdge, aVertex.Oriented(TopAbs_REVERSED)); + } + else + { + aEndVertex = aVertex; + } + BRep_Builder().Add(aEdge, aVertex); + theCurve.myEdges.push_back(aEdge); + aPrevEdge = aEdge; + } + + if (!IsClosed()) + { + BRepAdaptor_Curve aCurve(aPrevEdge); + BRep_Builder().MakeVertex(aEndVertex, + aCurve.Value(aCurve.LastParameter()), Precision::Confusion()); + } + BRep_Builder().Add(aPrevEdge, aEndVertex.Oriented(TopAbs_REVERSED)); + return true; +} + +bool HYDROData_TopoCurve::ValuesInKnots(std::deque& theValues) const +{ + std::list::const_iterator aLastEIt = myEdges.end(); + std::list::const_iterator aEIt = myEdges.begin(); + for (; aEIt != aLastEIt; ++aEIt) + { + Handle(Geom_BSplineCurve) aCurve; + { + TopLoc_Location aLoc; + double aParams[2]; + aCurve = Handle(Geom_BSplineCurve):: + DownCast(BRep_Tool::Curve(*aEIt, aLoc, aParams[0], aParams[1])); + if (!aLoc.IsIdentity() || aEIt->Orientation() != TopAbs_FORWARD || + aCurve.IsNull()) + { + return false; + } + } + + for (int aNbKnots = aCurve->NbKnots(), aKN = 1; aKN < aNbKnots; ++aKN) + { + theValues.push_back(aCurve->Value(aCurve->Knot(aKN)).XYZ()); + } + } + + if (!IsClosed()) + { + TopLoc_Location aLoc; + double aParams[2]; + Handle(Geom_Curve) aCurve = + BRep_Tool::Curve(myEdges.back(), aLoc, aParams[0], aParams[1]); + theValues.push_back(aCurve->Value(aParams[1]).XYZ()); + } + return true; +} diff --git a/src/HYDROData/HYDROData_TopoCurve.h b/src/HYDROData/HYDROData_TopoCurve.h new file mode 100644 index 00000000..abafe899 --- /dev/null +++ b/src/HYDROData/HYDROData_TopoCurve.h @@ -0,0 +1,179 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef HYDRODATA_TOPOCURVE_H +#define HYDRODATA_TOPOCURVE_H + +#include +#include +#include +#include +#include +#include +#include + +class TopoDS_Wire; + +//! The type represents a 1 monifold connected topo curve +//! with forward orientation. +class HYDROData_TopoCurve +{ +public: + //! The default computer. + HYDROData_TopoCurve() {} + + //! Constructs the curve from the edge. + HYDROData_TopoCurve(const TopoDS_Edge& theEdge) {myEdges.push_back(theEdge);} + + //! Initializes the curve by the wire. + //! Returns 'false' if the wire is not 1 monifold or + //! is disconnected or is empty. + HYDRODATA_EXPORT bool Initialize(const TopoDS_Wire& theWire); + + //! Converts the curve to the wire. + HYDRODATA_EXPORT TopoDS_Wire Wire() const; + + //! Returns 'true' if the curve has no edges. + bool IsEmpty() const {return myEdges.empty();} + + //! Returns 'true' whether the curve is closed. + bool IsClosed() const + { + return TopExp::LastVertex(myEdges.back(), Standard_True). + IsSame(TopExp::FirstVertex(myEdges.front(), Standard_True)) == + Standard_True; + } + + //! Returns the curve edges. + const std::list& Edges() const {return myEdges;} + + //! Cuts the curve in the given parameter of the given edge and + //! fills the cut part. + HYDRODATA_EXPORT void Cut( + const std::list::iterator& theEdgePosition, + const double theParameter, + HYDROData_TopoCurve& theCurve); + + //! Cuts the curve in the given parameter of the given edge and + //! fills the cut parts. + HYDRODATA_EXPORT void Cut( + const std::list::const_iterator& theEdgePosition, + const double theParameter, + HYDROData_TopoCurve& theCurve1, + HYDROData_TopoCurve& theCurve2) const; + + //! Cuts the curve at the parameters. + //! Each parameter vector list corresponds to the curve edge and + //! is ordered in the ascending order. + HYDRODATA_EXPORT void Cut( + const std::deque >& theParameters, + std::deque& theCurves) const; + + //! Projects the point to the nearest point of the curve. + //! Fills the iterator of the edge and + //! the parameter on the edge for the projection. + //! Returns the square distance from the point to the projection. + HYDRODATA_EXPORT double Project( + const gp_XYZ& thePoint, + std::list::const_iterator& theEdgeIterator, + double& theParameter) const; + + //! Adds the intersection parameters of the curve with the wire to the vector. + HYDRODATA_EXPORT int Intersect( + const TopoDS_Wire& theWire, + std::deque >& theParameters) const; + + //! Replaces the first vertex by the last one. + HYDRODATA_EXPORT void CloseCurve(); + + //! Topologically extends the curve by the parameter at the position: + //! 0 - start, 1 - end. + HYDRODATA_EXPORT void Merge( + const int thePosition, HYDROData_TopoCurve& theCurve); + + //! Topologically merges the curve to the curves. + HYDRODATA_EXPORT void Merge( + const double theTolerance, std::deque& theCurves); + + //! Topologically merges the wire curve to the curves. + //! Returns 'false' if the wire is not a curve. + static bool Merge( + const double theTolerance, + const TopoDS_Wire& theWire, + std::deque& theCurves) + { + HYDROData_TopoCurve aCurve; + const bool aResult = aCurve.Initialize(theWire); + if (aResult) + { + aCurve.Merge(theTolerance, theCurves); + } + return aResult; + } + + //! Topologically connects the curve to the first open one of the curves. + //! If the gap between the curve and the first open curve is more than the + //! tolerance then the gap is smoothly filled by a curve. + //! It is assumed that only one of the parameter curves may be open. + //! If the curve is closed then it is added to the curves. + HYDRODATA_EXPORT bool Connect( + const Standard_Real theTolerance, + std::deque& theCurves); + + //! Works by the same way as the above method. + static bool Connect( + const Standard_Real theTolerance, + const TopoDS_Wire& theWire, + std::deque& theCurves) + { + HYDROData_TopoCurve aCurve; + if (!aCurve.Initialize(theWire)) + { + return aCurve.Connect(theTolerance, theCurves); + } + + return false; + } + + //! Creates a B-spline piecewise curve corresponding to the curve + //! and using the deflection. + HYDRODATA_EXPORT bool BSplinePiecewiseCurve( + const double theDeflection, HYDROData_TopoCurve& theCurve) const; + + //! Calculates the values of the curve in its knots. + //! Returns 'false' if a curve edge has a nonidentity location or a nonforward + //! orientation or has no a B-spline representation. + HYDRODATA_EXPORT bool ValuesInKnots(std::deque& theValues) const; + +private: + //! Transfers the edges of the parameter to this curve end. + void append(HYDROData_TopoCurve& theCurve) + {myEdges.splice(myEdges.end(), theCurve.myEdges);} + + //! Transfers the edges of the parameter to this curve start. + void prepend(HYDROData_TopoCurve& theCurve) + {myEdges.splice(myEdges.begin(), theCurve.myEdges);} + + std::list myEdges; //!< The ordered curve edges. +}; + +#endif diff --git a/src/HYDROGUI/HYDROGUI_PolylineOp.cxx b/src/HYDROGUI/HYDROGUI_PolylineOp.cxx index 745cf67d..31c3ab2d 100755 --- a/src/HYDROGUI/HYDROGUI_PolylineOp.cxx +++ b/src/HYDROGUI/HYDROGUI_PolylineOp.cxx @@ -25,6 +25,8 @@ #include "HYDROGUI_UpdateFlags.h" #include +#include +#include #include #include @@ -44,6 +46,9 @@ #include #include +#include +#include + //static int ZValueIncrement = 0; HYDROGUI_PolylineOp::HYDROGUI_PolylineOp( HYDROGUI_Module* theModule, bool theIsEdit ) @@ -148,27 +153,75 @@ void HYDROGUI_PolylineOp::startOperation() NCollection_Sequence aSectClosures; myEditedObject->GetSections( aSectNames, aSectTypes, aSectClosures ); - for ( int i = 1, n = aSectNames.Size(); i <= n; ++i ) + if (!aSectNames.IsEmpty()) { - QString aSectName = HYDROGUI_Tool::ToQString( aSectNames.Value( i ) ); - HYDROData_PolylineXY::SectionType aSectType = aSectTypes.Value( i ); - bool aSectClosure = aSectClosures.Value( i ); + for ( int i = 1, n = aSectNames.Size(); i <= n; ++i ) + { + QString aSectName = HYDROGUI_Tool::ToQString( aSectNames.Value( i ) ); + HYDROData_PolylineXY::SectionType aSectType = aSectTypes.Value( i ); + bool aSectClosure = aSectClosures.Value( i ); + + CurveCreator::SectionType aCurveType = CurveCreator::Polyline; + if( aSectType == HYDROData_PolylineXY::SECTION_SPLINE ) + aCurveType = CurveCreator::Spline; - CurveCreator::SectionType aCurveType = CurveCreator::Polyline; - if( aSectType == HYDROData_PolylineXY::SECTION_SPLINE ) - aCurveType = CurveCreator::Spline; + CurveCreator::Coordinates aCurveCoords; - CurveCreator::Coordinates aCurveCoords; + HYDROData_PolylineXY::PointsList aSectPointsList = + myEditedObject->GetPoints( i - 1 ); + for (int k = 1, aNbPoints = aSectPointsList.Size(); k <= aNbPoints; ++k) + { + const HYDROData_PolylineXY::Point& aSectPoint = + aSectPointsList.Value( k ); + aCurveCoords.push_back( aSectPoint.X() ); + aCurveCoords.push_back( aSectPoint.Y() ); + } - HYDROData_PolylineXY::PointsList aSectPointsList = myEditedObject->GetPoints( i - 1 ); - for ( int k = 1, aNbPoints = aSectPointsList.Size(); k <= aNbPoints; ++k ) + myCurve->addSectionInternal( aSectName.toStdString(), + aCurveType, aSectClosure, aCurveCoords ); + } + } + else + { + std::deque aPs; + std::deque isCloseds; + std::vector aWires; + HYDROData_PolylineOperator::GetWires(myEditedObject, aWires); + const int aSCount = aWires.size(); + bool isError = false; + for (int aSI = 0; aSI < aSCount; ++aSI) { - const HYDROData_PolylineXY::Point& aSectPoint = aSectPointsList.Value( k ); - aCurveCoords.push_back( aSectPoint.X() ); - aCurveCoords.push_back( aSectPoint.Y() ); + HYDROData_TopoCurve aCurve, aCurve2; + std::deque aPs2; + if (!aCurve.Initialize(aWires[aSI]) || + !aCurve.BSplinePiecewiseCurve(Precision::Confusion(), aCurve2) || + !aCurve2.ValuesInKnots(aPs2)) + { + isError = true; + break; + } + + aPs.push_back(CurveCreator::Coordinates()); + CurveCreator::Coordinates& aPs3 = aPs.back(); + const Standard_Integer aPCount = aPs2.size(); + for (Standard_Integer aPI = 0; aPI < aPCount; ++aPI) + { + const gp_XYZ aP = aPs2[aPI]; + aPs3.push_back(aP.X()); + aPs3.push_back(aP.Y()); + } + isCloseds.push_back(aCurve.IsClosed()); } - myCurve->addSectionInternal( aSectName.toStdString(), aCurveType, aSectClosure, aCurveCoords ); + if (!isError) + { + const TCollection_AsciiString aNamePrefix = "Section_"; + for (int aSI = 0; aSI < aSCount; ++aSI) + { + myCurve->addSectionInternal((aNamePrefix + (aSI + 1)).ToCString(), + CurveCreator::Spline, isCloseds[aSI], aPs[aSI]); + } + } } aPolylineName = myEditedObject->GetName(); -- 2.39.2