Salome HOME
Issue #17347: B-Splines in Sketcher
authorazv <azv@opencascade.com>
Mon, 30 Dec 2019 14:55:24 +0000 (17:55 +0300)
committerazv <azv@opencascade.com>
Mon, 30 Dec 2019 14:55:24 +0000 (17:55 +0300)
Process point-on-bspline constraint be the sketch solver.

18 files changed:
src/GeomAPI/CMakeLists.txt
src/GeomAPI/GeomAPI_BSpline2d.cpp [new file with mode: 0644]
src/GeomAPI/GeomAPI_BSpline2d.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h
src/SketchPlugin/SketchPlugin_BSpline.cpp
src/SketchPlugin/SketchPlugin_BSpline.h
src/SketchPlugin/SketchPlugin_MacroBSpline.cpp
src/SketchPlugin/SketchPlugin_MacroBSpline.h
src/SketchSolver/PlaneGCSSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.h

index cade6fc2f16ff15464185570981dc706b74fd3b4..0fda17637178a1004ffbafa9f0264a7cca8b87ee 100644 (file)
@@ -25,6 +25,7 @@ INCLUDE(UnitTest)
 
 SET(PROJECT_HEADERS
     GeomAPI.h
+    GeomAPI_BSpline2d.h
     GeomAPI_Circ.h
     GeomAPI_Circ2d.h
     GeomAPI_Interface.h
@@ -71,6 +72,7 @@ SET(PROJECT_HEADERS
 )
 
 SET(PROJECT_SOURCES
+    GeomAPI_BSpline2d.cpp
     GeomAPI_Circ.cpp
     GeomAPI_Circ2d.cpp
     GeomAPI_Interface.cpp
diff --git a/src/GeomAPI/GeomAPI_BSpline2d.cpp b/src/GeomAPI/GeomAPI_BSpline2d.cpp
new file mode 100644 (file)
index 0000000..ca5e189
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright (C) 2019-2020  CEA/DEN, EDF R&D
+//
+// 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 <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <Geom2d_BSplineCurve.hxx>
+
+#define MY_BSPLINE (*(implPtr<Handle_Geom2d_BSplineCurve>()))
+
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+    const std::list<double>& theWeights,
+    const int theDegree,
+    const bool thePeriodic)
+{
+  int aNbKnots = (int)thePoles.size() - theDegree + 1;
+  if (aNbKnots < 2)
+    return new Handle_Geom2d_BSplineCurve();
+
+  // collect arrays of poles, weights, knots and multiplicities
+  TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size());
+  TColStd_Array1OfReal aWeights(1, (int)theWeights.size());
+  TColStd_Array1OfReal aKnots(1, aNbKnots);
+  TColStd_Array1OfInteger aMults(1, aNbKnots);
+
+  int anIndex = 1;
+  for (std::list<GeomPnt2dPtr>::const_iterator aPIt = thePoles.begin();
+       aPIt != thePoles.end(); ++aPIt, ++anIndex)
+    aPoles.SetValue(anIndex, gp_Pnt2d((*aPIt)->x(), (*aPIt)->y()));
+  anIndex = 1;
+  for (std::list<double>::const_iterator aWIt = theWeights.begin();
+       aWIt != theWeights.end(); ++aWIt, ++anIndex)
+    aWeights.SetValue(anIndex, *aWIt);
+  anIndex = 1;
+  static const double aStartParam = 0.0;
+  static const double aEndParam = 1.0;
+  double aStep = aEndParam / (aNbKnots - 1);
+  for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep)
+    aKnots.SetValue(anIndex, aKnot);
+  aKnots.ChangeLast() = aEndParam;
+  anIndex = 1;
+  aMults.SetValue(anIndex, theDegree + 1);
+  for (++anIndex; anIndex < aNbKnots; ++anIndex)
+    aMults.SetValue(anIndex, 1);
+  aMults.SetValue(aNbKnots, theDegree + 1);
+
+  Handle(Geom2d_BSplineCurve) aCurve =
+    new Geom2d_BSplineCurve(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
+  return new Handle_Geom2d_BSplineCurve(aCurve);
+}
+
+static Handle_Geom2d_BSplineCurve* newBSpline2d(
+    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+    const std::list<double>& theWeights,
+    const bool thePeriodic)
+{
+  int aDegree = 3;
+  if ((int)thePoles.size() <= aDegree)
+    aDegree = (int)thePoles.size() - 1;
+  if (aDegree <= 0)
+    return new Handle_Geom2d_BSplineCurve();
+  return newBSpline2d(thePoles, theWeights, aDegree, thePeriodic);
+}
+
+
+GeomAPI_BSpline2d::GeomAPI_BSpline2d(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                                     const std::list<double>& theWeights,
+                                     const bool thePeriodic)
+  : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, thePeriodic))
+{
+  if (isNull())
+    throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve");
+}
+
+GeomAPI_BSpline2d::GeomAPI_BSpline2d(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                                     const std::list<double>& theWeights,
+                                     const int theDegree,
+                                     const bool thePeriodic)
+  : GeomAPI_Interface(newBSpline2d(thePoles, theWeights, theDegree, thePeriodic))
+{
+  if (isNull())
+    throw Standard_ConstructionError("GeomAPI_BSpline2d: Impossible to create B-spline curve");
+}
+
+bool GeomAPI_BSpline2d::isNull() const
+{
+  return MY_BSPLINE.IsNull();
+}
+
+int GeomAPI_BSpline2d::degree() const
+{
+  return MY_BSPLINE->Degree();
+}
+
+void GeomAPI_BSpline2d::D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
+{
+  gp_Pnt2d aPnt;
+  MY_BSPLINE->D0(theU, aPnt);
+  thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y()));
+}
+
+void GeomAPI_BSpline2d::D1(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
+                                              std::shared_ptr<GeomAPI_XY>& theDerivative)
+{
+  gp_Pnt2d aPnt;
+  gp_Vec2d aVec;
+  MY_BSPLINE->D1(theU, aPnt, aVec);
+  thePoint.reset(new GeomAPI_Pnt2d(aPnt.X(), aPnt.Y()));
+  theDerivative.reset(new GeomAPI_XY(aVec.X(), aVec.Y()));
+}
diff --git a/src/GeomAPI/GeomAPI_BSpline2d.h b/src/GeomAPI/GeomAPI_BSpline2d.h
new file mode 100644 (file)
index 0000000..2904586
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (C) 2019-2020  CEA/DEN, EDF R&D
+//
+// 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 GeomAPI_BSpline2d_H_
+#define GeomAPI_BSpline2d_H_
+
+#include <GeomAPI_Interface.h>
+
+#include <list>
+#include <memory>
+
+class GeomAPI_Pnt2d;
+class GeomAPI_XY;
+
+/** \class GeomAPI_BSpline2d
+ *  \ingroup DataModel
+ *  \brief B-spline curve in 2D
+ */
+class GeomAPI_BSpline2d : public GeomAPI_Interface
+{
+public:
+  /// Creation of B-spline curve defined by list of poles and weights
+  GEOMAPI_EXPORT GeomAPI_BSpline2d(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                                   const std::list<double>& theWeights,
+                                   const bool thePeriodic = false);
+
+  /// Creation of B-spline curve defined by list of poles and weights
+  GEOMAPI_EXPORT GeomAPI_BSpline2d(const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                                   const std::list<double>& theWeights,
+                                   const int theDegree,
+                                   const bool thePeriodic = false);
+
+  /// Returns true if curve is not initialized
+  GEOMAPI_EXPORT bool isNull() const;
+
+  /// Returns degree of the curve
+  GEOMAPI_EXPORT int degree() const;
+
+  /// \brief Calculate point on B-spline curve accrding to the given parameter
+  GEOMAPI_EXPORT void D0(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+  /// \brief Calculate point and first derivative for B-spline curve accrding to the given parameter
+  GEOMAPI_EXPORT void D1(const double theU, std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
+                                            std::shared_ptr<GeomAPI_XY>& theDerivative);
+};
+
+#endif
index 4e42c0a92adbf69ce6f31aa3dcc4a9ac8941b748..03145a117a4a7990435137d796d17ba5b4db2be4 100644 (file)
 #include <GeomAlgoAPI_EdgeBuilder.h>
 
 #include <GeomAPI_Ax2.h>
+#include <GeomAPI_BSpline2d.h>
 #include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Pln.h>
+#include <GeomAPI_Pnt2d.h>
 
 #include <gp_Pln.hxx>
 #include <BRepBuilderAPI_MakeEdge.hxx>
 #include <TopoDS_Face.hxx>
 #include <TopoDS.hxx>
 #include <BRep_Tool.hxx>
-#include <Geom_BSplineCurve.hxx>
+#include <Geom2d_BSplineCurve.hxx>
 #include <Geom_Plane.hxx>
 #include <Geom_CylindricalSurface.hxx>
 #include <Geom_RectangularTrimmedSurface.hxx>
+#include <GeomLib.hxx>
 
 #include <gp_Ax2.hxx>
 #include <gp_Circ.hxx>
@@ -268,49 +272,25 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipticArc(
   return aRes;
 }
 
-GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bspline(const std::vector<GeomPointPtr>& thePoles,
-                                             const std::vector<double>& theWeights,
-                                             const bool thePeriodic)
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(
+    const std::shared_ptr<GeomAPI_Pln>& thePlane,
+    const std::list<GeomPnt2dPtr>& thePoles,
+    const std::list<double>& theWeights,
+    const bool thePeriodic)
 {
-  int aDegree = 3;
-  if ((int)thePoles.size() <= aDegree)
-    aDegree = (int)thePoles.size() - 1;
-  if (aDegree <= 0)
-    return GeomEdgePtr();
-
-  int aNbKnots = (int)thePoles.size() - aDegree + 1;
-
-  // collect arrays of poles, weights, knots and multiplicities
-  TColgp_Array1OfPnt aPoles(1, (int)thePoles.size());
-  TColStd_Array1OfReal aWeights(1, (int)theWeights.size());
-  TColStd_Array1OfReal aKnots(1, aNbKnots);
-  TColStd_Array1OfInteger aMults(1, aNbKnots);
-
-  int anIndex = 1;
-  for (std::vector<GeomPointPtr>::const_iterator aPIt = thePoles.begin();
-       aPIt != thePoles.end(); ++aPIt, ++anIndex)
-    aPoles.SetValue(anIndex, gp_Pnt((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z()));
-  anIndex = 1;
-  for (std::vector<double>::const_iterator aWIt = theWeights.begin();
-       aWIt != theWeights.end(); ++aWIt, ++anIndex)
-    aWeights.SetValue(anIndex, *aWIt);
-  anIndex = 1;
-  static const double aStartParam = 0.0;
-  static const double aEndParam = 1.0;
-  double aStep = aEndParam / (aNbKnots - 1);
-  for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep)
-    aKnots.SetValue(anIndex, aKnot);
-  aKnots.ChangeLast() = aEndParam;
-  anIndex = 1;
-  aMults.SetValue(anIndex, aDegree + 1);
-  for (++anIndex; anIndex < aNbKnots; ++anIndex)
-    aMults.SetValue(anIndex, 1);
-  aMults.SetValue(aNbKnots, aDegree + 1);
-
-  Handle(Geom_BSplineCurve) aCurve =
-      new Geom_BSplineCurve(aPoles, aWeights, aKnots, aMults, aDegree, thePeriodic);
-
-  BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve, aStartParam, aEndParam);
+  std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+      new GeomAPI_BSpline2d(thePoles, theWeights, thePeriodic));
+  return bsplineOnPlane(thePlane, aBSplineCurve);
+}
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(
+    const std::shared_ptr<GeomAPI_Pln>& thePlane,
+    const std::shared_ptr<GeomAPI_BSpline2d>& theCurve)
+{
+  Handle(Geom_Curve) aCurve3D = GeomLib::To3d(thePlane->impl<gp_Pln>().Position().Ax2(),
+                                              theCurve->impl<Handle_Geom2d_BSplineCurve>());
+
+  BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve3D);
   GeomEdgePtr aRes(new GeomAPI_Edge);
   TopoDS_Edge anEdge = anEdgeBuilder.Edge();
   aRes->setImpl(new TopoDS_Shape(anEdge));
index d6185f3f51511d26c108b6afee12f1b8039946e7..ac4ca0286a631b8b56dc9696c1da46c9151e2889 100644 (file)
@@ -29,6 +29,8 @@
 #include <memory>
 #include <vector>
 
+class GeomAPI_BSpline2d;
+
 /**\class GeomAlgoAPI_EdgeBuilder
  * \ingroup DataAlgo
  * \brief Allows to create face-shapes by different parameters
@@ -91,10 +93,15 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder
       const std::shared_ptr<GeomAPI_Pnt>& theStart,
       const std::shared_ptr<GeomAPI_Pnt>& theEnd);
 
-  /// Creates B-spline edge
-  static GeomEdgePtr bspline(const std::vector<GeomPointPtr>& thePoles,
-                             const std::vector<double>& theWeights,
-                             const bool thePeriodic);
+  /// Creates planar B-spline edge
+  static GeomEdgePtr bsplineOnPlane(const std::shared_ptr<GeomAPI_Pln>& thePlane,
+                                    const std::list<std::shared_ptr<GeomAPI_Pnt2d> >& thePoles,
+                                    const std::list<double>& theWeights,
+                                    const bool thePeriodic);
+
+  /// Creates planar B-spline edge
+  static GeomEdgePtr bsplineOnPlane(const std::shared_ptr<GeomAPI_Pln>& thePlane,
+                                    const std::shared_ptr<GeomAPI_BSpline2d>& theCurve);
 };
 
 #endif
index f226e0657eb977d8dded3b1da0134bb9f603f15a..64fa4fcacddfb93c499c121004ebda3b4d2040e5 100644 (file)
@@ -32,6 +32,7 @@
 #include <GeomDataAPI_Point2DArray.h>
 
 #include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
@@ -52,6 +53,7 @@ void SketchPlugin_BSpline::initDerivedClassAttributes()
 {
   data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
   data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+  data()->addAttribute(DEGREE_ID(), ModelAPI_AttributeInteger::typeId());
 
   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
@@ -68,21 +70,20 @@ void SketchPlugin_BSpline::execute()
       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
   AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
 
-  // convert poles to 3D
-  std::vector<GeomPointPtr> aPoles3D;
-  aPoles3D.reserve(aPolesArray->size());
+  // collect poles
+  std::list<GeomPnt2dPtr> aPoles2D;
   for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
     GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
-    aPoles3D.push_back(aSketch->to3D(aPole->x(), aPole->y()));
+    aPoles2D.push_back(aPole);
   }
   // collect weights
-  std::vector<double> aWeights;
-  aWeights.reserve(aWeightsArray->size());
+  std::list<double> aWeights;
   for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
     aWeights.push_back(aWeightsArray->value(anIndex));
 
   // create result non-periodic B-spline curve
-  GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false);
+  GeomShapePtr anEdge =
+      GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->plane(), aPoles2D, aWeights, false);
 
   ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
   aResult->setShape(anEdge);
index c918a090c72eb26663d54c9201b549ec89070340..303dc1f0b09ccf13dc81bf9208486045011a2935 100644 (file)
@@ -51,6 +51,13 @@ public:
     return ID;
   }
 
+  /// attribute to store the degree of B-spline
+  inline static const std::string& DEGREE_ID()
+  {
+    static const std::string ID("degree");
+    return ID;
+  }
+
   /// Returns the kind of a feature
   SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
   {
index ee47982d88175055421338fdef9aeb9b0903662e..0b81547a3dbcafe0344ac313374d94acddfe80b2 100644 (file)
@@ -40,6 +40,8 @@
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_PointBuilder.h>
 
+#include <GeomAPI_BSpline2d.h>
+
 #include <sstream>
 
 // Create Point feature coincident with the B-spline pole
@@ -60,6 +62,7 @@ static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
 
 SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
   : SketchPlugin_SketchEntity(),
+    myDegree(3),
     myIsPeriodic(false)
 {
 }
@@ -138,6 +141,8 @@ FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
 {
   FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID());
 
+  aBSpline->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(myDegree);
+
   AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
       aBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
   AttributePoint2DArrayPtr aPolesMacro =
@@ -207,17 +212,20 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
   if (!aSketch)
     return AISObjectPtr();
 
+  static const bool PERIODIC = false;
+
   AttributePoint2DArrayPtr aPolesArray =
       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
   AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
 
+  if (aPolesArray->size() < 2)
+    return AISObjectPtr();
+
   std::list<GeomShapePtr> aShapes;
 
-  // convert poles to 3D and collect weights
-  std::vector<GeomPointPtr> aPoles3D;
-  aPoles3D.reserve(aPolesArray->size());
-  std::vector<double> aWeights;
-  aWeights.reserve(aWeightsArray->size());
+  // convert poles to vertices and collect weights
+  std::list<GeomPnt2dPtr> aPoles2D;
+  std::list<double> aWeights;
   for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
     double aWeight = aWeightsArray->value(anIndex);
     if (aWeight < 1.e-10)
@@ -226,16 +234,26 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
     aWeights.push_back(aWeight);
 
     GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+    aPoles2D.push_back(aPole);
     GeomPointPtr aPole3D = aSketch->to3D(aPole->x(), aPole->y());
-    aPoles3D.push_back(aPole3D);
     aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D));
   }
 
   // create result non-periodic B-spline curve
-  GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false);
+  std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+  try {
+    aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, PERIODIC));
+  } catch (...) {
+    // cannot build a B-spline curve
+    return AISObjectPtr();
+  }
+  GeomShapePtr anEdge =
+      GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->plane(), aBSplineCurve);
   if (!anEdge)
     return AISObjectPtr();
 
+  myDegree = aBSplineCurve->degree();
+
   aShapes.push_back(anEdge);
   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
 
index f74b5bb5084b386b29ceb69f81cb99cca3a7eb7b..0137962ed1993585ccfd8bec721cf34cb55c3152 100644 (file)
@@ -104,6 +104,7 @@ private:
   void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
   void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
 
+  int myDegree;
   bool myIsPeriodic;
 };
 
index 59f33e0f6de798010a77dec8df3b94cefb8d7600..61a812a8b2dbc88e7ce32178e012b01d394a638a 100644 (file)
@@ -33,6 +33,7 @@ SET(PLANEGCSSOLVER_HEADERS
     PlaneGCSSolver_AngleWrapper.h
     PlaneGCSSolver_BooleanWrapper.h
     PlaneGCSSolver_Tools.h
+    PlaneGCSSolver_GeoExtensions.h
 )
 
 SET(PLANEGCSSOLVER_SOURCES
@@ -47,6 +48,7 @@ SET(PLANEGCSSOLVER_SOURCES
     PlaneGCSSolver_AngleWrapper.cpp
     PlaneGCSSolver_BooleanWrapper.cpp
     PlaneGCSSolver_Tools.cpp
+    PlaneGCSSolver_GeoExtensions.cpp
 )
 
 SET(PLANEGCSSOLVER_BUILDER_HEADERS
index 7ccedd950459c17875e251758b919f9c7ca659f3..c8a6cb264fbb55a10da91fd8597ef5204d9ba5be 100644 (file)
@@ -30,6 +30,8 @@
 #include <GeomDataAPI_Point2DArray.h>
 #include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <SketchPlugin_BSpline.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_MultiRotation.h>
 
@@ -63,9 +65,17 @@ static EntityWrapperPtr createBoolean(const AttributePtr& theAttribute)
 static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
                                      PlaneGCSSolver_Storage* theStorage)
 {
-  AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
-  if (!aScalar)
-    return EntityWrapperPtr();
+  double aValue = 0.0;
+  AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+  if (aDouble)
+    aValue = aDouble->isInitialized() ? aDouble->value() : 0.0;
+  else {
+    AttributeIntegerPtr anInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
+    if (anInt)
+      aValue = anInt->isInitialized() ? anInt->value() : 0.0;
+    else
+      return EntityWrapperPtr();
+  }
 
   ScalarWrapperPtr aWrapper;
   // following attributes should be converted from degrees to radians
@@ -77,11 +87,14 @@ static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
      (theAttribute->id() == SketchPlugin_MultiRotation::ANGLE_ID() &&
       anOwner->getKind() == SketchPlugin_MultiRotation::ID()))
     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_AngleWrapper(createParameter(theStorage)));
+  else if (anOwner->getKind() == SketchPlugin_BSpline::ID() &&
+           theAttribute->id() == SketchPlugin_BSpline::DEGREE_ID())
+    // Degree of B-spline is not processed by the solver
+    aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(nullptr)));
   else
     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage)));
 
-  if (aScalar->isInitialized())
-    aWrapper->setValue(aScalar->value());
+  aWrapper->setValue(aValue);
   return aWrapper;
 }
 
@@ -93,11 +106,18 @@ static EntityWrapperPtr createScalarArray(const AttributePtr&     theAttribute,
   if (!anArray || !anArray->isInitialized())
     return EntityWrapperPtr();
 
+  PlaneGCSSolver_Storage* aStorage = theStorage;
+  // Weights of B-spline curve are not processed by the solver
+  FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+  if (anOwner->getKind() == SketchPlugin_BSpline::ID() &&
+      theAttribute->id() == SketchPlugin_BSpline::WEIGHTS_ID())
+    aStorage = 0;
+
   int aSize = anArray->size();
   GCS::VEC_pD aParameters;
   aParameters.reserve(aSize);
   for (int index = 0; index < aSize; ++index) {
-    double* aParam = createParameter(theStorage);
+    double* aParam = createParameter(aStorage);
     *aParam = anArray->value(index);
     aParameters.push_back(aParam);
   }
index 78dc0d7c985913e9dbcda2c95476bf0db25de391..b8ac3e1dd98dd188a515925d2db4c5e11da81b82 100644 (file)
 //
 
 #include <PlaneGCSSolver_FeatureBuilder.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
 #include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_GeoExtensions.h>
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <PlaneGCSSolver_PointArrayWrapper.h>
 #include <PlaneGCSSolver_ScalarWrapper.h>
 #include <PlaneGCSSolver_ScalarArrayWrapper.h>
-#include <PlaneGCSSolver_BooleanWrapper.h>
 #include <PlaneGCSSolver_Tools.h>
 
 #include <SketchPlugin_Arc.h>
@@ -297,7 +298,7 @@ EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
 
 EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
 {
-  std::shared_ptr<GCS::BSpline> aNewSpline(new GCS::BSpline);
+  std::shared_ptr<GCS::BSplineImpl> aNewSpline(new GCS::BSplineImpl);
 
   aNewSpline->degree = 3;
   aNewSpline->periodic = false;
@@ -322,6 +323,11 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
       aNewSpline->weights = anArray->array();
     }
+    else if (anAttrID == SketchPlugin_BSpline::DEGREE_ID()) {
+      ScalarWrapperPtr aScalar =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+      aNewSpline->degree = (int)aScalar->value();
+    }
   }
 
   return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
@@ -370,7 +376,8 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th
   }
   else if (theOwnerName == SketchPlugin_BSpline::ID()) {
     return theAttrName == SketchPlugin_BSpline::POLES_ID() ||
-           theAttrName == SketchPlugin_BSpline::WEIGHTS_ID();
+           theAttrName == SketchPlugin_BSpline::WEIGHTS_ID() ||
+           theAttrName == SketchPlugin_BSpline::DEGREE_ID();
   }
 
   // suppose that all remaining features are points
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.cpp
new file mode 100644 (file)
index 0000000..a979760
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright (C) 2019-2020  CEA/DEN, EDF R&D
+//
+// 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 <PlaneGCSSolver_GeoExtensions.h>
+
+#include <GeomAPI_BSpline2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+
+#include <cmath>
+
+namespace GCS
+{
+
+DeriVector2 BSplineImpl::Value(double u, double du, double* derivparam)
+{
+  if (!isCacheValid())
+    rebuildCache();
+
+  std::shared_ptr<GeomAPI_Pnt2d> aValue;
+  std::shared_ptr<GeomAPI_XY> aDeriv;
+  myCurve->D1(u, aValue, aDeriv);
+
+  return DeriVector2(aValue->x(), aValue->y(), aDeriv->x() * du, aDeriv->y() * du);
+}
+
+BSplineImpl* BSplineImpl::Copy()
+{
+  return new BSplineImpl(*this);
+}
+
+
+bool BSplineImpl::isCacheValid() const
+{
+  // curve has to be initialized
+  bool isValid = myCurve.get() && !myCurve->isNull();
+
+  static const double THE_TOLERANCE = 1.e-7;
+  // compare poles
+  isValid = isValid && poles.size() == myCachedPoles.size();
+  std::list<GeomPnt2dPtr>::const_iterator aCachePIt = myCachedPoles.begin();
+  GCS::VEC_P::const_iterator aPolesIt = poles.begin();
+  for (; isValid && aPolesIt != poles.end(); ++aPolesIt, ++aCachePIt) {
+    isValid = isValid && fabs((*aCachePIt)->x() - *aPolesIt->x) < THE_TOLERANCE
+                      && fabs((*aCachePIt)->y() - *aPolesIt->y) < THE_TOLERANCE;
+  }
+
+  // compare weights
+  isValid = isValid && weights.size() == myCachedWeights.size();
+  std::list<double>::const_iterator aCacheWIt = myCachedWeights.begin();
+  GCS::VEC_pD::const_iterator aWeightsIt = weights.begin();
+  for (; isValid && aWeightsIt != weights.end(); ++aWeightsIt, ++aCacheWIt)
+    isValid = isValid && fabs(*aCacheWIt - **aWeightsIt) < THE_TOLERANCE;
+
+  return isValid;
+}
+
+void BSplineImpl::rebuildCache()
+{
+  myCachedPoles.clear();
+  myCachedWeights.clear();
+
+  for (GCS::VEC_P::iterator anIt = poles.begin(); anIt != poles.end(); ++anIt)
+    myCachedPoles.push_back(GeomPnt2dPtr(new GeomAPI_Pnt2d(*anIt->x, *anIt->y)));
+  for (GCS::VEC_pD::iterator anIt = weights.begin(); anIt != weights.end(); ++anIt)
+    myCachedWeights.push_back(**anIt);
+
+  myCurve.reset(new GeomAPI_BSpline2d(myCachedPoles, myCachedWeights, degree, periodic));
+}
+
+} // namespace GCS
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_GeoExtensions.h
new file mode 100644 (file)
index 0000000..87f6665
--- /dev/null
@@ -0,0 +1,53 @@
+// Copyright (C) 2019-2020  CEA/DEN, EDF R&D
+//
+// 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 PlaneGCSSolver_GeomExtensions_H_
+#define PlaneGCSSolver_GeomExtensions_H_
+
+#include <PlaneGCSSolver_Defs.h>
+
+#include <list>
+#include <memory>
+
+class GeomAPI_BSpline2d;
+class GeomAPI_Pnt2d;
+
+namespace GCS {
+  /// \brife SHAPER's implementation of B-spline curves in PlaneGCS solver
+  class BSplineImpl : public BSpline
+  {
+  public:
+    virtual DeriVector2 Value(double u, double du, double* derivparam = 0);
+
+    virtual BSplineImpl* Copy();
+
+  private:
+    /// Verify the cached curve satisfies to the parameters
+    bool isCacheValid() const;
+    /// Poles or weights are changed, cache curve has to be rebuilt
+    void rebuildCache();
+
+  private:
+    std::shared_ptr<GeomAPI_BSpline2d> myCurve; /// cached B-spline curve
+    std::list<std::shared_ptr<GeomAPI_Pnt2d> > myCachedPoles; /// cached B-spline poles
+    std::list<double> myCachedWeights; /// cached B-spline weights
+  };
+}
+
+#endif
index 9349f5c3099b0a33577095a3f7639a6474545566..328b7144c03e363e4a934e4e7af27d5bcfd70418 100644 (file)
@@ -582,6 +582,8 @@ double* PlaneGCSSolver_Storage::createParameter()
 void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
 {
   mySketchSolver->removeParameters(theParams);
+  for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it)
+    delete *it;
 }
 
 // indicates attribute containing in the external feature
index c1b83d3f85865e04de66ee6297fe9b888df37627..5fe371915581cac21ca251761c48e73475332353 100644 (file)
@@ -77,7 +77,8 @@ static ConstraintWrapperPtr
 static ConstraintWrapperPtr
   createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType,
                                 std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
-                                std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+                                std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+                                std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue);
 static ConstraintWrapperPtr
   createConstraintPointsCollinear(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint1,
                                   std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint2,
@@ -134,6 +135,7 @@ static GCS::SET_pD circleParameters(const EdgeWrapperPtr& theCircle);
 static GCS::SET_pD arcParameters(const EdgeWrapperPtr& theArc);
 static GCS::SET_pD ellipseParameters(const EdgeWrapperPtr& theEllipse);
 static GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc);
+static GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge);
 
 static double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2);
 
@@ -221,8 +223,9 @@ ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
     aResult = createConstraintCoincidence(aPoint1, aPoint2);
     break;
   case CONSTRAINT_PT_ON_CURVE:
-    aResult = anEntity1 ? createConstraintPointOnEntity(theType, aPoint1, anEntity1):
-              createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1));
+    aResult = anEntity1 ?
+        createConstraintPointOnEntity(theType, aPoint1, anEntity1, GCS_SCALAR_WRAPPER(theValue)) :
+        createConstraintPointsCollinear(aPoint1, aPoint2, GCS_POINT_WRAPPER(theEntity1));
     break;
   case CONSTRAINT_MIDDLE_POINT:
     aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2);
@@ -408,6 +411,8 @@ GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity)
     return ellipseParameters(GCS_EDGE_WRAPPER(theEntity));
   case ENTITY_ELLIPTIC_ARC:
     return ellipticArcParameters(GCS_EDGE_WRAPPER(theEntity));
+  case ENTITY_BSPLINE:
+    return bsplineParameters(GCS_EDGE_WRAPPER(theEntity));
   default: break;
   }
   return GCS::SET_pD();
@@ -440,7 +445,8 @@ ConstraintWrapperPtr createConstraintCoincidence(
 ConstraintWrapperPtr createConstraintPointOnEntity(
     const SketchSolver_ConstraintType& theType,
     std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
-    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
+    std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+    std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theValue)
 {
   GCSConstraintPtr aNewConstr;
 
@@ -466,6 +472,14 @@ ConstraintWrapperPtr createConstraintPointOnEntity(
         new GCS::ConstraintPointOnEllipse(*(thePoint->point()), *anEllipse));
     break;
     }
+  case ENTITY_BSPLINE: {
+    std::list<GCSConstraintPtr> aConstraints;
+    aConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+        *thePoint->point(), thePoint->point()->x, *theEntity->entity(), theValue->scalar())));
+    aConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+        *thePoint->point(), thePoint->point()->y, *theEntity->entity(), theValue->scalar())));
+    return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aConstraints, theType));
+  }
   default:
     return ConstraintWrapperPtr();
   }
@@ -813,6 +827,23 @@ GCS::SET_pD ellipticArcParameters(const EdgeWrapperPtr& theEllipticArc)
   return aParams;
 }
 
+GCS::SET_pD bsplineParameters(const EdgeWrapperPtr& theEdge)
+{
+  GCS::SET_pD aParams;
+
+  std::shared_ptr<GCS::BSpline> aBSpline =
+    std::dynamic_pointer_cast<GCS::BSpline>(theEdge->entity());
+
+  for (GCS::VEC_P::iterator it = aBSpline->poles.begin(); it != aBSpline->poles.end(); ++it) {
+    aParams.insert(it->x);
+    aParams.insert(it->y);
+  }
+  for (GCS::VEC_pD::iterator it = aBSpline->weights.begin(); it != aBSpline->weights.end(); ++it)
+    aParams.insert(*it);
+
+  return aParams;
+}
+
 double distance(const GCS::Point& thePnt1, const GCS::Point& thePnt2)
 {
   double x = *thePnt1.x - *thePnt2.x;
index f4b616b9ee30c6bcb2fd19e9bd61ca834169693a..990297396e2f99f5355e750b084388e26e2c9f77 100644 (file)
@@ -20,6 +20,7 @@
 #include <SketchSolver_ConstraintCoincidence.h>
 #include <SketchSolver_Error.h>
 #include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
 #include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateCoincidence.h>
 
@@ -224,7 +225,7 @@ void SketchSolver_ConstraintCoincidence::process()
 
   mySolverConstraint = PlaneGCSSolver_Tools::createConstraint(
       myBaseConstraint, getType(),
-      aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+      myAuxValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
 
   myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
   myStorage->notify(myBaseConstraint);
@@ -235,6 +236,13 @@ bool SketchSolver_ConstraintCoincidence::remove()
   myInSolver = false;
   myFeatureExtremities[0] = EntityWrapperPtr();
   myFeatureExtremities[1] = EntityWrapperPtr();
+  if (myAuxValue) {
+    std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+        std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+    GCS::SET_pD aParams;
+    aParams.insert(myAuxValue->scalar());
+    aStorage->removeParameters(aParams);
+  }
   return SketchSolver_Constraint::remove();
 }
 
@@ -257,8 +265,16 @@ void SketchSolver_ConstraintCoincidence::getAttributes(
                                   theAttributes, myFeatureExtremities);
   } else if (theAttributes[2]) {
     myType = CONSTRAINT_PT_ON_CURVE;
-    // obtain extremity points of the coincident feature for further checking of multi-coincidence
-    getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
+    // point-on-bspline requires additional parameter
+    if (theAttributes[2]->type() == ENTITY_BSPLINE) {
+      std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+          std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+      myAuxValue.reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
+    }
+    else {
+      // obtain extremity points of the coincident feature for further checking of multi-coincidence
+      getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
+    }
   } else
     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
 
index 871314b926afa2d6993b1667e725eb66158eb3d7..f520b75d0ef28aeef2519536719bcd2120fb758e 100644 (file)
@@ -55,6 +55,7 @@ protected:
 protected:
   bool myInSolver; ///< shows the constraint is added to the solver
   EntityWrapperPtr myFeatureExtremities[2]; ///< extremities of a feature, a point is coincident to
+  ScalarWrapperPtr myAuxValue; ///< parameter on B-spline curve
 };
 
 #endif