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.
This commit is contained in:
abk 2015-06-24 21:20:39 +03:00
parent 047d8bf632
commit c3778fc96e
2 changed files with 269 additions and 138 deletions

View File

@ -183,116 +183,168 @@ gp_Pnt CurveCreator_Utils::ConvertClickToPoint( int x, int y, Handle(V3d_View) a
return ResultPoint; 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)
{
const int aPointCount = thePoints->Length();
if (aPointCount <= 1)
{
return false;
}
// 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);
}
}
// 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; BRep_Builder aBuilder;
TopoDS_Compound aComp; TopoDS_Compound aShape;
aBuilder.MakeCompound( aComp ); aBuilder.MakeCompound(aShape);
for( int iSection = 0 ; iSection < theCurve->getNbSections() ; iSection++ ) const int aSectionCount = theCurve->getNbSections();
for (int aSectionI = 0; aSectionI < aSectionCount; ++aSectionI)
{ {
int theISection = iSection; const int aTmpPointCount = theCurve->getNbPoints(aSectionI);
if (aTmpPointCount == 0)
CurveCreator::SectionType aSectType = theCurve->getSectionType( theISection ); {
int aPointSize = theCurve->getNbPoints( theISection );
if ( aPointSize == 0 )
continue; continue;
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<gp_Pnt> 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;
} }
int aNbPoints = aPoints.size();
if ( aNbPoints == 1 ) { // Get the different points.
aPoint = aPoints.front(); std::vector<gp_Pnt> aTmpPoints;
TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex(); gp_Pnt aFirstPoint;
aBuilder.Add( aComp, aVertex ); 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 ) { const bool isClosed = theCurve->isClosed(aSectionI);
Handle(TColgp_HArray1OfPnt) aHCurvePoints = new TColgp_HArray1OfPnt(1, aNbPoints); int aPointCount = aTmpPoints.size();
TColgp_Array1OfVec aTangents(1, aNbPoints); if (isClosed)
Handle(TColStd_HArray1OfBoolean) aTangentFlags = new TColStd_HArray1OfBoolean(1, aNbPoints); {
gp_Vec aNullVec(0, 0, 0); while (aPointCount > 1 &&
isEqualPoints(aFirstPoint, aTmpPoints[aPointCount - 1]))
TopoDS_Edge aPointEdge; {
TopoDS_Vertex aVertex; --aPointCount;
std::vector<gp_Pnt>::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++;
} }
}
aPrevPoint = aPoint; // Add the vertices to the shape.
aPointIt++; Handle(TColgp_HArray1OfPnt) aPoints =
for( ; aPointIt != aPointLast; aPointIt++ ) { new TColgp_HArray1OfPnt(1, aPointCount);
aPoint = *aPointIt; for (Standard_Integer aPI = 0; aPI < aPointCount; ++aPI)
aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex(); {
aBuilder.Add( aComp, aVertex ); aPoints->SetValue(aPI + 1, aTmpPoints[aPI]);
if ( isPolyline ) { aBuilder.Add(aShape, BRepBuilderAPI_MakeVertex(aTmpPoints[aPI]));
TopoDS_Edge aPointEdge = BRepBuilderAPI_MakeEdge( aPrevPoint, aPoint ).Edge(); }
aBuilder.Add( aComp, aPointEdge ); if (aPointCount == 1)
} {
else { continue;
aHCurvePoints->SetValue( aHIndex, aPoint ); }
aTangents.SetValue( aHIndex, aNullVec );
aTangentFlags->SetValue( aHIndex, Standard_False );
aHIndex++;
}
aPrevPoint = aPoint;
}
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( !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(); // Add the edges to the shape.
if ( aGBC.IsDone() ) const bool isPolyline =
aBSplineCurve = aGBC.Curve(); (theCurve->getSectionType(aSectionI) == CurveCreator::Polyline);
TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aBSplineCurve ).Edge(); if (isPolyline)
TopoDS_Wire aWire = BRepBuilderAPI_MakeWire( anEdge ).Wire(); {
aBuilder.Add( aComp, aWire ); 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 (isClosed)
{
aBuilder.Add(aShape, BRepBuilderAPI_MakeEdge(
BRepBuilderAPI_MakeVertex(aPoints->Value(aPointCount)),
BRepBuilderAPI_MakeVertex(aPoints->Value(1))));
}
}
else
{
Handle(Geom_BSplineCurve) aBSpline;
if (constructBSpline(aPoints, isClosed, aBSpline))
{
aBuilder.Add(aShape,
BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(aBSpline)));
} }
} }
} }
theShape = aComp; theShape = aShape;
} }
/** /**

View File

@ -32,7 +32,9 @@
#include <BRepBuilderAPI_MakeWire.hxx> #include <BRepBuilderAPI_MakeWire.hxx>
#include <ElSLib.hxx> #include <ElSLib.hxx>
#include <GeomAPI_Interpolate.hxx> #include <GeomAPI_Interpolate.hxx>
#include <TColgp_Array1OfVec.hxx>
#include <TColgp_HArray1OfPnt.hxx> #include <TColgp_HArray1OfPnt.hxx>
#include <TColStd_HArray1OfBoolean.hxx>
#include <TopoDS_Wire.hxx> #include <TopoDS_Wire.hxx>
const double POINT_CONFUSION_TOLERANCE = 0.0001; const double POINT_CONFUSION_TOLERANCE = 0.0001;
@ -97,58 +99,135 @@ TopoDS_Shape Sketcher_Utils::MakePolyline
return aResult; return aResult;
} }
//=======================================================================
// function : constructBSpline
// purpose : See function 'constructBSpline' in file 'CurveCreator_Utils.cxx'.
//=======================================================================
static bool constructBSpline(
const Handle(TColgp_HArray1OfPnt)& thePoints,
const Standard_Boolean theIsClosed,
Handle(Geom_BSplineCurve)& theBSpline)
{
const int aPointCount = thePoints->Length();
if (aPointCount <= 1)
{
return false;
}
// 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);
}
}
// Interpolate.
aInterpolator.Load(aTangents, aTangentFlags, Standard_False);
aInterpolator.Perform();
const bool aResult = (aInterpolator.IsDone() == Standard_True);
if (aResult)
{
theBSpline = aInterpolator.Curve();
}
return aResult;
}
//======================================================================= //=======================================================================
// function : MakeInterpolation // function : MakeInterpolation
// purpose : // purpose :
//======================================================================= //=======================================================================
TopoDS_Shape Sketcher_Utils::MakeInterpolation TopoDS_Shape Sketcher_Utils::MakeInterpolation(
(const std::list <double> &theCoords2D, const std::list<double>& theCoords2D,
const Standard_Boolean IsClosed, const Standard_Boolean theIsClosed,
const gp_Ax3 &thePlane) const gp_Ax3& thePlane)
{ {
std::list <gp_Pnt> aPoints; if (theCoords2D.size() == 0)
TopoDS_Shape aResult; {
return TopoDS_Shape();
}
To3D(theCoords2D, thePlane, aPoints); // Get the different points.
std::list<gp_Pnt> aTmpPoints;
Standard_Integer aNbPnts = aPoints.size(); To3D(theCoords2D, thePlane, aTmpPoints);
gp_Pnt aFirstPoint = aTmpPoints.front();
if (aNbPnts > 1) { gp_Pnt aPoint = aFirstPoint;
if (IsClosed && std::list<gp_Pnt>::iterator aPIt = aTmpPoints.begin();
aPoints.front().IsEqual(aPoints.back(), POINT_CONFUSION_TOLERANCE)) { for (++aPIt; aPIt != aTmpPoints.cend();)
// The polyline should be closed, first and last points are confused. {
// Remove the last point. const gp_Pnt aPoint2 = *aPIt;
aPoints.pop_back(); if (!aPoint.IsEqual(aPoint2, POINT_CONFUSION_TOLERANCE))
--aNbPnts; {
aPoint = aPoint2;
++aPIt;
}
else
{
aTmpPoints.erase(aPIt);
}
}
if (theIsClosed)
{
while (--aPIt != aTmpPoints.cbegin() &&
aFirstPoint.IsEqual(*aPIt, POINT_CONFUSION_TOLERANCE))
{
aTmpPoints.erase(aPIt);
} }
} }
if (aNbPnts == 1) { // Process the single point case.
// The result is vertex. const int aPointCount = aTmpPoints.size();
aResult = BRepBuilderAPI_MakeVertex(aPoints.front()).Vertex(); if (aPointCount == 1)
} else if (aNbPnts > 1) { {
std::list <gp_Pnt>::const_iterator anIter = aPoints.begin(); return BRepBuilderAPI_MakeVertex(aTmpPoints.front());
Handle(TColgp_HArray1OfPnt) aHCurvePoints =
new TColgp_HArray1OfPnt(1, aNbPnts);
Standard_Integer i;
for (i = 1; anIter != aPoints.end(); ++anIter, ++i) {
aHCurvePoints->SetValue(i, *anIter);
}
// Compute BSpline
Standard_Real aTol = Precision::Confusion();
GeomAPI_Interpolate aGBC(aHCurvePoints, IsClosed, aTol);
aGBC.Perform();
if (aGBC.IsDone()) {
TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge(aGBC.Curve()).Edge();
aResult = BRepBuilderAPI_MakeWire(anEdge).Wire();
}
} }
return aResult; // 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();
} }
//======================================================================= //=======================================================================