Salome HOME
Methods 'CurveCreator_Utils::constructShape' and
authorabk <abk@opencascade.com>
Wed, 24 Jun 2015 18:20:39 +0000 (21:20 +0300)
committerabk <abk@opencascade.com>
Wed, 24 Jun 2015 18:22:41 +0000 (21:22 +0300)
'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.

src/CurveCreator/CurveCreator_Utils.cxx
src/SKETCHER/Sketcher_Utils.cxx

index 7b6075c2b3063c1fabe73885852eecc60a78ac3e..52fab0c1c4fbf4dbf2b6b47ad861d4bc7d35d322 100644 (file)
@@ -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<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;
+  // 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<gp_Pnt> 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<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++;
+    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;
 }
 
 /**
index d707546faf1a392b4462ac38af789c4fd8813308..aeb4d9f1ee57bae9307158ba393f102e9e5379b2 100644 (file)
@@ -32,7 +32,9 @@
 #include <BRepBuilderAPI_MakeWire.hxx>
 #include <ElSLib.hxx>
 #include <GeomAPI_Interpolate.hxx>
+#include <TColgp_Array1OfVec.hxx>
 #include <TColgp_HArray1OfPnt.hxx>
+#include <TColStd_HArray1OfBoolean.hxx>
 #include <TopoDS_Wire.hxx>
 
 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 <double> &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 <gp_Pnt> 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 <gp_Pnt>::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<double>& 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<gp_Pnt> aTmpPoints;
+  To3D(theCoords2D, thePlane, aTmpPoints);
+  gp_Pnt aFirstPoint = aTmpPoints.front();
+  gp_Pnt aPoint = aFirstPoint;
+  std::list<gp_Pnt>::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();
 }
 
 //=======================================================================