From: abk Date: Wed, 24 Jun 2015 18:20:39 +0000 (+0300) Subject: Methods 'CurveCreator_Utils::constructShape' and X-Git-Tag: V8_0_0a1~3^2~9 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c3778fc96ed24ce5cf1ef7f3fca152390c6c279f;p=modules%2Fgeom.git Methods 'CurveCreator_Utils::constructShape' and 'Sketcher_Utils::MakeInterpolation' were changed to interpolate each spline section by the cubic B-spline passing through the control points that the tangent vector in each control point P is calculated by the following way: - if point P is preceded by a control point A and is followed by a control point B then the tangent vector is equal to (P - A) / |P - A| + (B - P) / |B - P|; - if point P is preceded by a control point A but is not followed by any control point then the tangent vector is equal to P - A; - if point P is followed by a control point B but is not preceded by any control point then the tangent vector is equal to B - P. --- diff --git a/src/CurveCreator/CurveCreator_Utils.cxx b/src/CurveCreator/CurveCreator_Utils.cxx index 7b6075c2b..52fab0c1c 100644 --- a/src/CurveCreator/CurveCreator_Utils.cxx +++ b/src/CurveCreator/CurveCreator_Utils.cxx @@ -183,116 +183,168 @@ gp_Pnt CurveCreator_Utils::ConvertClickToPoint( int x, int y, Handle(V3d_View) a return ResultPoint; } -void CurveCreator_Utils::constructShape( const CurveCreator_ICurve* theCurve, - TopoDS_Shape& theShape ) +//======================================================================= +// function : constructBSpline +// purpose : +// The algorithm builds the cubic B-spline passing through the points that the +// tangent vector in each given point P is calculated by the following way: +// if point P is preceded by a point A and is followed by a point B then +// the tangent vector is equal to (P - A) / |P - A| + (B - P) / |B - P|; +// if point P is preceded by a point A but is not followed by any point then +// the tangent vector is equal to P - A; +// if point P is followed by a point B but is not preceded by any point then +// the tangent vector is equal to B - P. +//======================================================================= +static bool constructBSpline( + const Handle(TColgp_HArray1OfPnt)& thePoints, + const Standard_Boolean theIsClosed, + Handle(Geom_BSplineCurve)& theBSpline) { - BRep_Builder aBuilder; - TopoDS_Compound aComp; - aBuilder.MakeCompound( aComp ); - for( int iSection = 0 ; iSection < theCurve->getNbSections() ; iSection++ ) + const int aPointCount = thePoints->Length(); + if (aPointCount <= 1) { - int theISection = iSection; + return false; + } - CurveCreator::SectionType aSectType = theCurve->getSectionType( theISection ); - int aPointSize = theCurve->getNbPoints( theISection ); - if ( aPointSize == 0 ) - continue; + // Calculate the tangents. + TColgp_Array1OfVec aTangents(1, aPointCount); + Handle(TColStd_HArray1OfBoolean) aTangentFlags = + new TColStd_HArray1OfBoolean(1, aPointCount); + GeomAPI_Interpolate aInterpolator(thePoints, theIsClosed, 0); + if (aPointCount == 2) + { + aTangentFlags->SetValue(1, Standard_False); + aTangentFlags->SetValue(2, Standard_False); + } + else + { + for (Standard_Integer aPN = 1; aPN <= aPointCount; ++aPN) + { + gp_Vec aTangent; + if (aPN != 1 || theIsClosed) + { + const Standard_Integer aPN1 = (aPN != 1) ? (aPN - 1) : aPointCount; + aTangent = gp_Vec(thePoints->Value(aPN1), + thePoints->Value(aPN)).Normalized(); + } + if (aPN < aPointCount || theIsClosed) + { + const Standard_Integer aPN2 = (aPN != aPointCount) ? (aPN + 1) : 1; + const gp_Vec aTangent2 = aTangent + + gp_Vec(thePoints->Value(aPN), thePoints->Value(aPN2)).Normalized(); + if (aTangent2.SquareMagnitude() >= Precision::SquareConfusion()) + { + aTangent = aTangent2.Normalized(); + } + else + { + aTangent = -aTangent; + } + } + aTangents.SetValue(aPN, aTangent); + aTangentFlags->SetValue(aPN, Standard_True); + } + } - bool aSectIsClosed = theCurve->isClosed( theISection ); - bool isPolyline = aSectType == CurveCreator::Polyline; - - int iPoint = 0; - gp_Pnt aPrevPoint, aPoint; - // filters the curve points to skip equal points - std::vector aPoints; - CurveCreator_UtilsICurve::getPoint( theCurve, theISection, iPoint, aPoint ); - aPoints.push_back( aPoint ); - aPrevPoint = aPoint; - iPoint++; - for( ; iPoint < aPointSize; iPoint++ ) { - CurveCreator_UtilsICurve::getPoint( theCurve, theISection, iPoint, aPoint ); - if ( !isEqualPoints( aPrevPoint, aPoint ) ) - aPoints.push_back( aPoint ); - aPrevPoint = aPoint; + // Interpolate. + aInterpolator.Load(aTangents, aTangentFlags, Standard_False); + aInterpolator.Perform(); + const bool aResult = (aInterpolator.IsDone() == Standard_True); + if (aResult) + { + theBSpline = aInterpolator.Curve(); + } + return aResult; +} + +//======================================================================= +// function : constructShape +// purpose : +//======================================================================= +void CurveCreator_Utils::constructShape( + const CurveCreator_ICurve* theCurve, TopoDS_Shape& theShape) +{ + BRep_Builder aBuilder; + TopoDS_Compound aShape; + aBuilder.MakeCompound(aShape); + const int aSectionCount = theCurve->getNbSections(); + for (int aSectionI = 0; aSectionI < aSectionCount; ++aSectionI) + { + const int aTmpPointCount = theCurve->getNbPoints(aSectionI); + if (aTmpPointCount == 0) + { + continue; } - int aNbPoints = aPoints.size(); - if ( aNbPoints == 1 ) { - aPoint = aPoints.front(); - TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex(); - aBuilder.Add( aComp, aVertex ); + // Get the different points. + std::vector aTmpPoints; + gp_Pnt aFirstPoint; + CurveCreator_UtilsICurve::getPoint(theCurve, aSectionI, 0, aFirstPoint); + gp_Pnt aPoint = aFirstPoint; + aTmpPoints.push_back(aPoint); + for (int aPI = 1; aPI < aTmpPointCount; ++aPI) + { + gp_Pnt aPoint2; + CurveCreator_UtilsICurve::getPoint(theCurve, aSectionI, aPI, aPoint2); + if (!isEqualPoints(aPoint, aPoint2)) + { + aPoint = aPoint2; + aTmpPoints.push_back(aPoint); + } } - else if ( aNbPoints > 1 ) { - Handle(TColgp_HArray1OfPnt) aHCurvePoints = new TColgp_HArray1OfPnt(1, aNbPoints); - TColgp_Array1OfVec aTangents(1, aNbPoints); - Handle(TColStd_HArray1OfBoolean) aTangentFlags = new TColStd_HArray1OfBoolean(1, aNbPoints); - gp_Vec aNullVec(0, 0, 0); - - TopoDS_Edge aPointEdge; - TopoDS_Vertex aVertex; - - std::vector::const_iterator aPointIt = aPoints.begin(), aPointLast = aPoints.end(); - aPoint = *aPointIt; - - int aHIndex = 1; - aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex(); - aBuilder.Add( aComp, aVertex ); - if ( !isPolyline ) { - aHCurvePoints->SetValue( aHIndex, aPoint ); - aTangents.SetValue( aHIndex, aNullVec ); - aTangentFlags->SetValue( aHIndex, Standard_False ); - aHIndex++; + const bool isClosed = theCurve->isClosed(aSectionI); + int aPointCount = aTmpPoints.size(); + if (isClosed) + { + while (aPointCount > 1 && + isEqualPoints(aFirstPoint, aTmpPoints[aPointCount - 1])) + { + --aPointCount; } + } - aPrevPoint = aPoint; - aPointIt++; - for( ; aPointIt != aPointLast; aPointIt++ ) { - aPoint = *aPointIt; - aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex(); - aBuilder.Add( aComp, aVertex ); - if ( isPolyline ) { - TopoDS_Edge aPointEdge = BRepBuilderAPI_MakeEdge( aPrevPoint, aPoint ).Edge(); - aBuilder.Add( aComp, aPointEdge ); - } - else { - aHCurvePoints->SetValue( aHIndex, aPoint ); - aTangents.SetValue( aHIndex, aNullVec ); - aTangentFlags->SetValue( aHIndex, Standard_False ); - aHIndex++; - } - aPrevPoint = aPoint; + // Add the vertices to the shape. + Handle(TColgp_HArray1OfPnt) aPoints = + new TColgp_HArray1OfPnt(1, aPointCount); + for (Standard_Integer aPI = 0; aPI < aPointCount; ++aPI) + { + aPoints->SetValue(aPI + 1, aTmpPoints[aPI]); + aBuilder.Add(aShape, BRepBuilderAPI_MakeVertex(aTmpPoints[aPI])); + } + if (aPointCount == 1) + { + continue; + } + + // Add the edges to the shape. + const bool isPolyline = + (theCurve->getSectionType(aSectionI) == CurveCreator::Polyline); + if (isPolyline) + { + for (Standard_Integer aPN = 1; aPN < aPointCount; ++aPN) + { + aBuilder.Add(aShape, BRepBuilderAPI_MakeEdge( + BRepBuilderAPI_MakeVertex(aPoints->Value(aPN)), + BRepBuilderAPI_MakeVertex(aPoints->Value(aPN + 1)))); } - if( aSectIsClosed && ( aNbPoints > 2 ) ) { - aPoint = aPoints.front(); - aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex(); - aBuilder.Add( aComp, aVertex ); - if ( isPolyline ) { - aPointEdge = BRepBuilderAPI_MakeEdge( aPrevPoint, aPoint ).Edge(); - aBuilder.Add( aComp, aPointEdge ); - } + if (isClosed) + { + aBuilder.Add(aShape, BRepBuilderAPI_MakeEdge( + BRepBuilderAPI_MakeVertex(aPoints->Value(aPointCount)), + BRepBuilderAPI_MakeVertex(aPoints->Value(1)))); } - if( !isPolyline ) { - // compute BSpline - Handle(Geom_BSplineCurve) aBSplineCurve; - GeomAPI_Interpolate aGBC(aHCurvePoints, aSectIsClosed, gp::Resolution()); - // correct the spline degree to be as 3 for non-periodic spline if number of points - // less than 3. It is need to have a knot in each spline point. This knots are used - // to found a neighbour points when a new point is inserted between two existing. - if (!aSectIsClosed ) { - if (aHCurvePoints->Length() == 3) - aGBC.Load(aTangents, aTangentFlags); - } - - aGBC.Perform(); - if ( aGBC.IsDone() ) - aBSplineCurve = aGBC.Curve(); - TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aBSplineCurve ).Edge(); - TopoDS_Wire aWire = BRepBuilderAPI_MakeWire( anEdge ).Wire(); - aBuilder.Add( aComp, aWire ); + } + else + { + Handle(Geom_BSplineCurve) aBSpline; + if (constructBSpline(aPoints, isClosed, aBSpline)) + { + aBuilder.Add(aShape, + BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(aBSpline))); } } } - theShape = aComp; + theShape = aShape; } /** diff --git a/src/SKETCHER/Sketcher_Utils.cxx b/src/SKETCHER/Sketcher_Utils.cxx index d707546fa..aeb4d9f1e 100644 --- a/src/SKETCHER/Sketcher_Utils.cxx +++ b/src/SKETCHER/Sketcher_Utils.cxx @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include const double POINT_CONFUSION_TOLERANCE = 0.0001; @@ -98,57 +100,134 @@ TopoDS_Shape Sketcher_Utils::MakePolyline } //======================================================================= -// function : MakeInterpolation -// purpose : +// function : constructBSpline +// purpose : See function 'constructBSpline' in file 'CurveCreator_Utils.cxx'. //======================================================================= -TopoDS_Shape Sketcher_Utils::MakeInterpolation - (const std::list &theCoords2D, - const Standard_Boolean IsClosed, - const gp_Ax3 &thePlane) +static bool constructBSpline( + const Handle(TColgp_HArray1OfPnt)& thePoints, + const Standard_Boolean theIsClosed, + Handle(Geom_BSplineCurve)& theBSpline) { - std::list aPoints; - TopoDS_Shape aResult; - - To3D(theCoords2D, thePlane, aPoints); - - Standard_Integer aNbPnts = aPoints.size(); - - if (aNbPnts > 1) { - if (IsClosed && - aPoints.front().IsEqual(aPoints.back(), POINT_CONFUSION_TOLERANCE)) { - // The polyline should be closed, first and last points are confused. - // Remove the last point. - aPoints.pop_back(); - --aNbPnts; - } + const int aPointCount = thePoints->Length(); + if (aPointCount <= 1) + { + return false; } - if (aNbPnts == 1) { - // The result is vertex. - aResult = BRepBuilderAPI_MakeVertex(aPoints.front()).Vertex(); - } else if (aNbPnts > 1) { - std::list ::const_iterator anIter = aPoints.begin(); - Handle(TColgp_HArray1OfPnt) aHCurvePoints = - new TColgp_HArray1OfPnt(1, aNbPnts); - Standard_Integer i; - - for (i = 1; anIter != aPoints.end(); ++anIter, ++i) { - aHCurvePoints->SetValue(i, *anIter); + // Calculate the tangents. + TColgp_Array1OfVec aTangents(1, aPointCount); + Handle(TColStd_HArray1OfBoolean) aTangentFlags = + new TColStd_HArray1OfBoolean(1, aPointCount); + GeomAPI_Interpolate aInterpolator(thePoints, theIsClosed, 0); + if (aPointCount == 2) + { + aTangentFlags->SetValue(1, Standard_False); + aTangentFlags->SetValue(2, Standard_False); + } + else + { + for (Standard_Integer aPN = 1; aPN <= aPointCount; ++aPN) + { + gp_Vec aTangent; + if (aPN != 1 || theIsClosed) + { + const Standard_Integer aPN1 = (aPN != 1) ? (aPN - 1) : aPointCount; + aTangent = gp_Vec(thePoints->Value(aPN1), + thePoints->Value(aPN)).Normalized(); + } + if (aPN < aPointCount || theIsClosed) + { + const Standard_Integer aPN2 = (aPN != aPointCount) ? (aPN + 1) : 1; + const gp_Vec aTangent2 = aTangent + + gp_Vec(thePoints->Value(aPN), thePoints->Value(aPN2)).Normalized(); + if (aTangent2.SquareMagnitude() >= Precision::SquareConfusion()) + { + aTangent = aTangent2.Normalized(); + } + else + { + aTangent = -aTangent; + } + } + aTangents.SetValue(aPN, aTangent); + aTangentFlags->SetValue(aPN, Standard_True); } + } - // Compute BSpline - Standard_Real aTol = Precision::Confusion(); - GeomAPI_Interpolate aGBC(aHCurvePoints, IsClosed, aTol); + // Interpolate. + aInterpolator.Load(aTangents, aTangentFlags, Standard_False); + aInterpolator.Perform(); + const bool aResult = (aInterpolator.IsDone() == Standard_True); + if (aResult) + { + theBSpline = aInterpolator.Curve(); + } + return aResult; +} - aGBC.Perform(); +//======================================================================= +// function : MakeInterpolation +// purpose : +//======================================================================= +TopoDS_Shape Sketcher_Utils::MakeInterpolation( + const std::list& theCoords2D, + const Standard_Boolean theIsClosed, + const gp_Ax3& thePlane) +{ + if (theCoords2D.size() == 0) + { + return TopoDS_Shape(); + } - if (aGBC.IsDone()) { - TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(aGBC.Curve()).Edge(); - aResult = BRepBuilderAPI_MakeWire(anEdge).Wire(); + // Get the different points. + std::list aTmpPoints; + To3D(theCoords2D, thePlane, aTmpPoints); + gp_Pnt aFirstPoint = aTmpPoints.front(); + gp_Pnt aPoint = aFirstPoint; + std::list::iterator aPIt = aTmpPoints.begin(); + for (++aPIt; aPIt != aTmpPoints.cend();) + { + const gp_Pnt aPoint2 = *aPIt; + if (!aPoint.IsEqual(aPoint2, POINT_CONFUSION_TOLERANCE)) + { + aPoint = aPoint2; + ++aPIt; + } + else + { + aTmpPoints.erase(aPIt); + } + } + if (theIsClosed) + { + while (--aPIt != aTmpPoints.cbegin() && + aFirstPoint.IsEqual(*aPIt, POINT_CONFUSION_TOLERANCE)) + { + aTmpPoints.erase(aPIt); } } - return aResult; + // Process the single point case. + const int aPointCount = aTmpPoints.size(); + if (aPointCount == 1) + { + return BRepBuilderAPI_MakeVertex(aTmpPoints.front()); + } + + // Process the other cases. + Handle(TColgp_HArray1OfPnt) aPoints = + new TColgp_HArray1OfPnt(1, aPointCount); + aPIt = aTmpPoints.begin(); + for (Standard_Integer aPN = 1; aPIt != aTmpPoints.cend(); ++aPIt, ++aPN) + { + aPoints->SetValue(aPN, *aPIt); + } + Handle(Geom_BSplineCurve) aBSpline; + if (constructBSpline(aPoints, theIsClosed, aBSpline)) + { + return BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(aBSpline)); + } + return TopoDS_Shape(); } //=======================================================================